Add experimental send creation support
This commit is contained in:
parent
b297bf1ea3
commit
d0e0d66509
30
agent/actions/send.go
Normal file
30
agent/actions/send.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/quexten/goldwarden/agent/bitwarden"
|
||||||
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
|
"github.com/quexten/goldwarden/agent/sockets"
|
||||||
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
|
"github.com/quexten/goldwarden/ipc/messages"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleCreateSend(msg messages.IPCMessage, cfg *config.Config, vault *vault.Vault, callingContext *sockets.CallingContext) (response messages.IPCMessage, err error) {
|
||||||
|
token, err := cfg.GetToken()
|
||||||
|
if err != nil {
|
||||||
|
return messages.IPCMessage{}, fmt.Errorf("error getting token: %w", err)
|
||||||
|
}
|
||||||
|
parsedMsg := messages.ParsePayload(msg).(messages.CreateSendRequest)
|
||||||
|
|
||||||
|
ctx := context.WithValue(context.TODO(), bitwarden.AuthToken{}, token.AccessToken)
|
||||||
|
_, err = bitwarden.CreateSend(ctx, cfg, vault, parsedMsg.Name, parsedMsg.Text)
|
||||||
|
|
||||||
|
response, err = messages.IPCMessageFromPayload(messages.CreateSendResponse{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
AgentActionsRegistry.Register(messages.MessageTypeForEmptyPayload(messages.CreateSendRequest{}), ensureIsNotLocked(ensureIsLoggedIn(handleCreateSend)))
|
||||||
|
}
|
@ -218,6 +218,20 @@ func EncryptWith(data []byte, encType EncStringType, key SymmetricEncryptionKey)
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EncryptWithToString(data []byte, encType EncStringType, key SymmetricEncryptionKey) (string, error) {
|
||||||
|
s, err := EncryptWith(data, encType, key)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
marshalled, err := s.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(marshalled), nil
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateAsymmetric(useMemguard bool) (AsymmetricEncryptionKey, error) {
|
func GenerateAsymmetric(useMemguard bool) (AsymmetricEncryptionKey, error) {
|
||||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
107
agent/bitwarden/send.go
Normal file
107
agent/bitwarden/send.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package bitwarden
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/quexten/goldwarden/agent/bitwarden/crypto"
|
||||||
|
"github.com/quexten/goldwarden/agent/config"
|
||||||
|
"github.com/quexten/goldwarden/agent/vault"
|
||||||
|
"golang.org/x/crypto/hkdf"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SendFileMetadata struct {
|
||||||
|
FileName string `json:"fileName"`
|
||||||
|
Id string `json:"id"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
SizeName string `json:"sizeName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SendTextMetadata struct {
|
||||||
|
Hidden bool `json:"hidden"`
|
||||||
|
Response *string `json:"response"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SendMetadata struct {
|
||||||
|
CreatorIdentifier string
|
||||||
|
ExpirationDate string
|
||||||
|
File SendFileMetadata
|
||||||
|
Id string
|
||||||
|
Name string
|
||||||
|
Object string
|
||||||
|
Text SendTextMetadata
|
||||||
|
Type int
|
||||||
|
}
|
||||||
|
|
||||||
|
type SendCreateRequest struct {
|
||||||
|
DeletionDate string `json:"deletionDate"`
|
||||||
|
Disabled bool `json:"disabled"`
|
||||||
|
ExpirationDate *string `json:"expirationDate"`
|
||||||
|
HideEmail bool `json:"hideEmail"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
MaxAccessCount *int `json:"maxAccessCount"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Notes *string `json:"notes"`
|
||||||
|
Text SendTextMetadata `json:"text"`
|
||||||
|
Type int `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateSend(ctx context.Context, cfg *config.Config, vault *vault.Vault, name string, text string) (SendMetadata, error) {
|
||||||
|
timestampIn14Days := time.Now().AddDate(0, 0, 14)
|
||||||
|
timestampIn14DaysStr := timestampIn14Days.Format("2006-01-02T15:04:05Z")
|
||||||
|
|
||||||
|
// generate 32 byte key
|
||||||
|
sendSourceKey := make([]byte, 32)
|
||||||
|
_, err := io.ReadFull(rand.Reader, sendSourceKey)
|
||||||
|
if err != nil {
|
||||||
|
return SendMetadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedSendSourceKey, err := crypto.EncryptWithToString(sendSourceKey, crypto.AesCbc256_HmacSha256_B64, vault.Keyring.GetAccountKey())
|
||||||
|
if err != nil {
|
||||||
|
return SendMetadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sendUseKeyPairBytes := make([]byte, 64)
|
||||||
|
hkdf.New(sha256.New, sendSourceKey, []byte("bitwarden-send"), []byte("send")).Read(sendUseKeyPairBytes)
|
||||||
|
|
||||||
|
sendUseKeyPair, err := crypto.MemorySymmetricEncryptionKeyFromBytes(sendUseKeyPairBytes)
|
||||||
|
if err != nil {
|
||||||
|
return SendMetadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedName, err := crypto.EncryptWithToString([]byte(name), crypto.AesCbc256_HmacSha256_B64, sendUseKeyPair)
|
||||||
|
if err != nil {
|
||||||
|
return SendMetadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptedText, err := crypto.EncryptWithToString([]byte(text), crypto.AesCbc256_HmacSha256_B64, sendUseKeyPair)
|
||||||
|
if err != nil {
|
||||||
|
return SendMetadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sendRequest := SendCreateRequest{
|
||||||
|
DeletionDate: timestampIn14DaysStr,
|
||||||
|
Disabled: false,
|
||||||
|
HideEmail: false,
|
||||||
|
Key: encryptedSendSourceKey,
|
||||||
|
Name: encryptedName,
|
||||||
|
Text: SendTextMetadata{
|
||||||
|
Hidden: false,
|
||||||
|
Text: encryptedText,
|
||||||
|
},
|
||||||
|
Type: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
var result interface{}
|
||||||
|
err = authenticatedHTTPPost(ctx, cfg.ConfigFile.ApiUrl+"/sends", &result, sendRequest)
|
||||||
|
if err != nil {
|
||||||
|
return SendMetadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return SendMetadata{}, nil
|
||||||
|
}
|
53
cmd/send.go
Normal file
53
cmd/send.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/quexten/goldwarden/ipc/messages"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sendCmd = &cobra.Command{
|
||||||
|
Use: "send",
|
||||||
|
Short: "Commands for managing sends",
|
||||||
|
Long: `Commands for managing sends.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
cmd.Help()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendCreateCmd = &cobra.Command{
|
||||||
|
Use: "create",
|
||||||
|
Short: "Uploads a Bitwarden send.",
|
||||||
|
Long: `Uploads a Bitwarden send.`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
loginIfRequired()
|
||||||
|
name, _ := cmd.Flags().GetString("name")
|
||||||
|
text, _ := cmd.Flags().GetString("text")
|
||||||
|
|
||||||
|
result, err := commandClient.SendToAgent(messages.CreateSendRequest{
|
||||||
|
Name: name,
|
||||||
|
Text: text,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
handleSendToAgentError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch result.(type) {
|
||||||
|
case messages.CreateSendResponse:
|
||||||
|
fmt.Println("Send created: " + result.(messages.CreateSendResponse).URL)
|
||||||
|
break
|
||||||
|
case messages.ActionResponse:
|
||||||
|
println("Error: " + result.(messages.ActionResponse).Message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(sendCmd)
|
||||||
|
sendCmd.AddCommand(sendCreateCmd)
|
||||||
|
sendCreateCmd.Flags().StringP("name", "n", "", "Name of the send")
|
||||||
|
sendCreateCmd.Flags().StringP("text", "t", "", "Text of the send")
|
||||||
|
}
|
72
ipc/messages/send.go
Normal file
72
ipc/messages/send.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package messages
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
type GetSendRequest struct {
|
||||||
|
Name string
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetSendResponse struct {
|
||||||
|
Found bool
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateSendRequest struct {
|
||||||
|
Name string
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateSendResponse struct {
|
||||||
|
URL string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListSendsRequest struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||||
|
var req GetSendRequest
|
||||||
|
err := json.Unmarshal(payload, &req)
|
||||||
|
if err != nil {
|
||||||
|
panic("Unmarshal: " + err.Error())
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}, GetSendRequest{})
|
||||||
|
|
||||||
|
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||||
|
var req GetSendResponse
|
||||||
|
err := json.Unmarshal(payload, &req)
|
||||||
|
if err != nil {
|
||||||
|
panic("Unmarshal: " + err.Error())
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}, GetSendResponse{})
|
||||||
|
|
||||||
|
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||||
|
var req CreateSendRequest
|
||||||
|
err := json.Unmarshal(payload, &req)
|
||||||
|
if err != nil {
|
||||||
|
panic("Unmarshal: " + err.Error())
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}, CreateSendRequest{})
|
||||||
|
|
||||||
|
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||||
|
var req CreateSendResponse
|
||||||
|
err := json.Unmarshal(payload, &req)
|
||||||
|
if err != nil {
|
||||||
|
panic("Unmarshal: " + err.Error())
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}, CreateSendResponse{})
|
||||||
|
|
||||||
|
registerPayloadParser(func(payload []byte) (interface{}, error) {
|
||||||
|
var req ListSendsRequest
|
||||||
|
err := json.Unmarshal(payload, &req)
|
||||||
|
if err != nil {
|
||||||
|
panic("Unmarshal: " + err.Error())
|
||||||
|
}
|
||||||
|
return req, nil
|
||||||
|
}, ListSendsRequest{})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user