From b4cf29482d53a1e9a2657ad23789da6534dc9374 Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Mon, 12 May 2025 21:05:58 +0200 Subject: [PATCH] Move Metadatakey logic to seperate function, use pointer --- helper/metadata.go | 62 ++++------------------------------- helper/metadatakey.go | 75 +++++++++++++++++++++++++++++++++++++++++++ helper/resources.go | 49 +++++----------------------- 3 files changed, 90 insertions(+), 96 deletions(-) create mode 100644 helper/metadatakey.go diff --git a/helper/metadata.go b/helper/metadata.go index 0363e8f..be09475 100644 --- a/helper/metadata.go +++ b/helper/metadata.go @@ -7,72 +7,24 @@ import ( "fmt" "strings" - "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/passbolt/go-passbolt/api" "github.com/santhosh-tekuri/jsonschema" ) -func GetResourceMetadata(ctx context.Context, c *api.Client, resource api.Resource, rType api.ResourceType) (string, error) { - var metadatakey *crypto.Key - if resource.MetadataKeyType == api.MetadataKeyTypeUserKey { - key, err := c.GetUserPrivateKeyCopy() - if err != nil { - return "", fmt.Errorf("Get User Private Key Copy: %W", err) - } - - metadatakey = key - } else { - // Must be a shared key - keys, err := c.GetMetadataKeys(ctx, &api.GetMetadataKeysOptions{ - ContainMetadataPrivateKeys: true, - }) - if err != nil { - return "", fmt.Errorf("Get Metadata Key: %w", err) - } - - // TODO Get Key by id? - if len(keys) != 1 { - return "", fmt.Errorf("Not Exactly One Metadatakey Available") - } - - if len(keys[0].MetadataPrivateKeys) == 0 { - return "", fmt.Errorf("No Metadata Private key for our user") - } - - if len(keys[0].MetadataPrivateKeys) > 1 { - return "", fmt.Errorf("More than 1 metadata Private key for our user") - } - - var privMetdata api.MetadataPrivateKey = keys[0].MetadataPrivateKeys[0] - if *privMetdata.UserID != c.GetUserID() { - return "", fmt.Errorf("MetadataPrivateKey is not for our user id: %v", privMetdata.UserID) - } - - decPrivMetadatakey, err := c.DecryptMessage(privMetdata.Data) - if err != nil { - return "", fmt.Errorf("Decrypt Metadata Private Key Data: %w", err) - } - - var data api.MetadataPrivateKeyData - err = json.Unmarshal([]byte(decPrivMetadatakey), &data) - if err != nil { - return "", fmt.Errorf("Parse Metadata Private Key Data") - } - - metadataPrivateKeyObj, err := api.GetPrivateKeyFromArmor(data.ArmoredKey, []byte(data.Passphrase)) - if err != nil { - return "", fmt.Errorf("Get Metadata Private Key: %w", err) - } - - metadatakey = metadataPrivateKeyObj +func GetResourceMetadata(ctx context.Context, c *api.Client, resource *api.Resource, rType *api.ResourceType) (string, error) { + _, _, metadatakey, err := GetMetadataKey(ctx, c, resource.MetadataKeyType == api.MetadataKeyTypeUserKey) + if err != nil { + return "", fmt.Errorf("Get Metadata Key: %w", err) } + // TODO should we instead get the Metadata key of this resource by id? + decMetadata, err := c.DecryptMetadata(metadatakey, resource.Metadata) if err != nil { return "", fmt.Errorf("Decrypt Metadata: %w", err) } - err = validateMetadata(&rType, string(decMetadata)) + err = validateMetadata(rType, string(decMetadata)) if err != nil { return "", fmt.Errorf("Validate Metadata: %w", err) } diff --git a/helper/metadatakey.go b/helper/metadatakey.go new file mode 100644 index 0000000..0e7bb16 --- /dev/null +++ b/helper/metadatakey.go @@ -0,0 +1,75 @@ +package helper + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/ProtonMail/gopenpgp/v3/crypto" + "github.com/passbolt/go-passbolt/api" +) + +// GetMetadataKey gets a Metadata key, Personal indicates if the function should return the personal key, +// If personal keys have been disabled on the server then we return the shared key +// Returns the Key ID, Key Type and the Key itself +func GetMetadataKey(ctx context.Context, c *api.Client, personal bool) (string, api.MetadataKeyType, *crypto.Key, error) { + // if personal is requsted and it is allowed by the server, then return that + if personal && c.MetadataKeySettings().AllowUsageOfPersonalKeys { + key, err := c.GetUserPrivateKeyCopy() + if err != nil { + return "", "", nil, fmt.Errorf("Get User Private Key: %w", err) + } + + me, err := c.GetMe(ctx) + if err != nil { + return "", "", nil, fmt.Errorf("Get User Me: %w", err) + } + + if me.GPGKey == nil { + return "", "", nil, fmt.Errorf("User Me GPG Key nil") + } + + return me.GPGKey.ID, api.MetadataKeyTypeUserKey, key, nil + } + + keys, err := c.GetMetadataKeys(ctx, nil) + if err != nil { + return "", "", nil, fmt.Errorf("Get Metadata Key: %w", err) + } + + // TODO Get Key by id? + if len(keys) != 1 { + return "", "", nil, fmt.Errorf("Not Exactly One Metadatakey Available") + } + + if len(keys[0].MetadataPrivateKeys) == 0 { + return "", "", nil, fmt.Errorf("No Metadata Private key for our user") + } + + if len(keys[0].MetadataPrivateKeys) > 1 { + return "", "", nil, fmt.Errorf("More than 1 metadata Private key for our user") + } + + var privMetdata api.MetadataPrivateKey = keys[0].MetadataPrivateKeys[0] + if *privMetdata.UserID != c.GetUserID() { + return "", "", nil, fmt.Errorf("MetadataPrivateKey is not for our user id: %v", privMetdata.UserID) + } + + decPrivMetadatakey, err := c.DecryptMessage(privMetdata.Data) + if err != nil { + return "", "", nil, fmt.Errorf("Decrypt Metadata Private Key Data: %w", err) + } + + var data api.MetadataPrivateKeyData + err = json.Unmarshal([]byte(decPrivMetadatakey), &data) + if err != nil { + return "", "", nil, fmt.Errorf("Parse Metadata Private Key Data") + } + + metadataPrivateKeyObj, err := api.GetPrivateKeyFromArmor(data.ArmoredKey, []byte(data.Passphrase)) + if err != nil { + return "", "", nil, fmt.Errorf("Get Metadata Private Key: %w", err) + } + + return keys[0].ID, api.MetadataKeyTypeSharedKey, metadataPrivateKeyObj, nil +} diff --git a/helper/resources.go b/helper/resources.go index 5444c9b..5163ecb 100644 --- a/helper/resources.go +++ b/helper/resources.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" - "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/passbolt/go-passbolt/api" ) @@ -64,44 +63,12 @@ func CreateResourceV5(ctx context.Context, c *api.Client, folderParentID, name, return "", fmt.Errorf("Validating metadata: %w", err) } - var publicMetadataKey *crypto.Key - // Since we are not sharing, use the Personal Key if allowed - if c.MetadataKeySettings().AllowUsageOfPersonalKeys { - publicMetadataKey, err = c.GetUserPrivateKeyCopy() - if err != nil { - return "", fmt.Errorf("Get User Private Key: %w", err) - } - - me, err := c.GetMe(ctx) - if err != nil { - return "", fmt.Errorf("Get User Me: %w", err) - } - - if me.GPGKey == nil { - return "", fmt.Errorf("User Me GPG Key nil") - } - - resource.MetadataKeyID = me.GPGKey.ID - resource.MetadataKeyType = api.MetadataKeyTypeUserKey - } else { - keys, err := c.GetMetadataKeys(ctx, nil) - if err != nil { - return "", fmt.Errorf("Get Metadata Key: %w", err) - } - - // TODO Get Key by id? - if len(keys) != 1 { - return "", fmt.Errorf("Not Exactly One Metadatakey Available") - } - - publicMetadataKey, err = crypto.NewKeyFromArmored(keys[0].ArmoredKey) - if err != nil { - return "", fmt.Errorf("Get Metadata Public Key: %w", err) - } - - resource.MetadataKeyID = keys[0].ID - resource.MetadataKeyType = api.MetadataKeyTypeSharedKey + metadataKeyID, metadataKeyType, publicMetadataKey, err := GetMetadataKey(ctx, c, true) + if err != nil { + return "", fmt.Errorf("Get Metadata Key: %w", err) } + resource.MetadataKeyID = metadataKeyID + resource.MetadataKeyType = metadataKeyType encMetadata, err := c.EncryptMessageWithKey(publicMetadataKey, string(metaData)) if err != nil { @@ -303,7 +270,7 @@ func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret uri = resource.URI // nothing fits into the interface in this case case "v5-default": - rawMetadata, err := GetResourceMetadata(ctx, c, resource, rType) + rawMetadata, err := GetResourceMetadata(ctx, c, &resource, &rType) if err != nil { return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err) } @@ -333,7 +300,7 @@ func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret pw = secretData.Password desc = secretData.Description case "v5-default-with-totp": - rawMetadata, err := GetResourceMetadata(ctx, c, resource, rType) + rawMetadata, err := GetResourceMetadata(ctx, c, &resource, &rType) if err != nil { return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err) } @@ -363,7 +330,7 @@ func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret pw = secretData.Password desc = secretData.Description case "v5-password-string": - rawMetadata, err := GetResourceMetadata(ctx, c, resource, rType) + rawMetadata, err := GetResourceMetadata(ctx, c, &resource, &rType) if err != nil { return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err) }