diff --git a/helper/metadata.go b/helper/metadata.go index 978981d..be09475 100644 --- a/helper/metadata.go +++ b/helper/metadata.go @@ -7,27 +7,18 @@ 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 { - tmp, err := c.GetUserPrivateKeyCopy() - if err != nil { - return "", fmt.Errorf("Get Private Key Copy: %w", err) - } - metadatakey = tmp - } else { - key, err := GetMetadataKeyById(ctx, c, resource.MetadataKeyID) - if err != nil { - return "", fmt.Errorf("Get Metadata Key by ID: %w", err) - } - metadatakey = key + _, _, 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) @@ -87,7 +78,7 @@ func validateMetadata(rType *api.ResourceType, metadata string) error { err = schema.Validate(strings.NewReader(metadata)) if err != nil { - return fmt.Errorf("Validating Metadata with Schema: %w", err) + return fmt.Errorf("Validating Secret Data: %w", err) } return nil } diff --git a/helper/metadatakey.go b/helper/metadatakey.go index 701d786..14c77da 100644 --- a/helper/metadatakey.go +++ b/helper/metadatakey.go @@ -75,55 +75,3 @@ func GetMetadataKey(ctx context.Context, c *api.Client, personal bool) (string, return keys[0].ID, api.MetadataKeyTypeSharedKey, metadataPrivateKeyObj, nil } - -// GetMetadataKeyById is for fetching a specific metadatakey if needed for Decryption -func GetMetadataKeyById(ctx context.Context, c *api.Client, id string) (*crypto.Key, error) { - keys, err := c.GetMetadataKeys(ctx, &api.GetMetadataKeysOptions{ - ContainMetadataPrivateKeys: true, - }) - if err != nil { - return nil, fmt.Errorf("Get Metadata Key: %w", err) - } - var key *api.MetadataKey - for _, k := range keys { - if k.ID == id { - key = &k - break - } - } - - if key == nil { - return nil, fmt.Errorf("Metadata key not found: %v", id) - } - - if len(key.MetadataPrivateKeys) == 0 { - return nil, fmt.Errorf("No Metadata Private key for our user") - } - - if len(key.MetadataPrivateKeys) > 1 { - return nil, fmt.Errorf("More than 1 metadata Private key for our user") - } - - var privMetdata api.MetadataPrivateKey = key.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 metadataPrivateKeyObj, nil -} diff --git a/helper/resources.go b/helper/resources.go index 49dfa12..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" ) @@ -390,150 +389,46 @@ func UpdateResource(ctx context.Context, c *api.Client, resourceID, name, userna ID: resourceID, // This needs to be specified or it will revert to a legacy password ResourceTypeID: resource.ResourceTypeID, + Name: resource.Name, + Username: resource.Username, + URI: resource.URI, } + + if name != "" { + newResource.Name = name + } + if username != "" { + newResource.Username = username + } + if uri != "" { + newResource.URI = uri + } + var secretData string - - // Check if this is a v5 or Later Resource - if resource.Metadata != "" { - // Get Metadata - orgMetadata, err := GetResourceMetadata(ctx, c, resource, rType) - if err != nil { - return fmt.Errorf("Get Resource metadata: %w", err) + switch rType.Slug { + case "password-string": + newResource.Description = resource.Description + if description != "" { + newResource.Description = description } - - var metadataMap map[string]any - err = json.Unmarshal([]byte(orgMetadata), &metadataMap) - if err != nil { - return fmt.Errorf("Marshalling metadata: %w", err) - } - - var newMetadata []byte - switch rType.Slug { - case "v5-default": - // Modify Metadata - if name != "" { - metadataMap["name"] = name - } - if username != "" { - metadataMap["username"] = username - } - if uri != "" { - metadataMap["uris"] = []string{uri} - } - case "v5-password-string": - // Modify Metadata - if name != "" { - metadataMap["name"] = name - } - if username != "" { - metadataMap["username"] = username - } - if uri != "" { - metadataMap["uris"] = []string{uri} - } - if description != "" { - metadataMap["description"] = description - } - case "v5-default-with-totp": - // Modify Metadata - if name != "" { - metadataMap["name"] = name - } - if username != "" { - metadataMap["username"] = username - } - if uri != "" { - metadataMap["uris"] = []string{uri} - } - case "v5-totp-standalone": - // Modify Metadata - if name != "" { - metadataMap["name"] = name - } - if uri != "" { - metadataMap["uris"] = []string{uri} - } - default: - return fmt.Errorf("Unknown ResourceType: %v", rType.Slug) - } - - newMetadata, err = json.Marshal(&metadataMap) - if err != nil { - return fmt.Errorf("Marshalling metadata: %w", err) - } - - // Validate Metadata - err = validateMetadata(rType, string(newMetadata)) - if err != nil { - return fmt.Errorf("Validating metadata: %w", err) - } - - metadataKeyID, metadataKeyType, publicMetadataKey, err := GetMetadataKey(ctx, c, true) - if err != nil { - return fmt.Errorf("Get Metadata Key: %w", err) - } - newResource.MetadataKeyID = metadataKeyID - newResource.MetadataKeyType = metadataKeyType - - encMetadata, err := c.EncryptMessageWithKey(publicMetadataKey, string(newMetadata)) - if err != nil { - return fmt.Errorf("Encrypt Metadata: %w", err) - } - newResource.Metadata = encMetadata - - // Modify Secret - switch rType.Slug { - case "v5-default": - tmp := api.SecretDataTypeV5Default{ - Password: password, - Description: description, - } - tmp.ObjectType = api.PASSBOLT_OBJECT_TYPE_SECRET_DATA - tmp.ResourceTypeID = rType.ID - if password != "" || description != "" { - secret, err := c.GetSecret(ctx, resourceID) - if err != nil { - return fmt.Errorf("Getting Secret: %w", err) - } - oldSecretData, err := c.DecryptMessage(secret.Data) - if err != nil { - return fmt.Errorf("Decrypting Secret: %w", err) - } - var oldSecret api.SecretDataTypeV5Default - err = json.Unmarshal([]byte(oldSecretData), &oldSecret) - if err != nil { - return fmt.Errorf("Parsing Decrypted Secret Data: %w", err) - } - if password == "" { - tmp.Password = oldSecret.Password - } - if description == "" { - tmp.Description = oldSecret.Description - } - } - res, err := json.Marshal(&tmp) + if password != "" { + secretData = password + } else { + secret, err := c.GetSecret(ctx, resourceID) if err != nil { - return fmt.Errorf("Marshalling Secret Data: %w", err) + return fmt.Errorf("Getting Secret: %w", err) } - secretData = string(res) - case "v5-password-string": - newResource.Description = resource.Description - if description != "" { - newResource.Description = description + secretData, err = c.DecryptMessage(secret.Data) + if err != nil { + return fmt.Errorf("Decrypting Secret: %w", err) } - if password != "" { - secretData = password - } else { - secret, err := c.GetSecret(ctx, resourceID) - if err != nil { - return fmt.Errorf("Getting Secret: %w", err) - } - secretData, err = c.DecryptMessage(secret.Data) - if err != nil { - return fmt.Errorf("Decrypting Secret: %w", err) - } - } - case "v5-default-with-totp": + } + case "password-and-description": + tmp := api.SecretDataTypePasswordAndDescription{ + Password: password, + Description: description, + } + if password != "" || description != "" { secret, err := c.GetSecret(ctx, resourceID) if err != nil { return fmt.Errorf("Getting Secret: %w", err) @@ -542,163 +437,72 @@ func UpdateResource(ctx context.Context, c *api.Client, resourceID, name, userna if err != nil { return fmt.Errorf("Decrypting Secret: %w", err) } - var oldSecret api.SecretDataTypeV5DefaultWithTOTP - err = json.Unmarshal([]byte(oldSecretData), &secretData) + var oldSecret api.SecretDataTypePasswordAndDescription + err = json.Unmarshal([]byte(oldSecretData), &oldSecret) if err != nil { return fmt.Errorf("Parsing Decrypted Secret Data: %w", err) } - if password != "" { - oldSecret.Password = password + if password == "" { + tmp.Password = oldSecret.Password } - if description != "" { - oldSecret.Description = description + if description == "" { + tmp.Description = oldSecret.Description } - - res, err := json.Marshal(&oldSecret) - if err != nil { - return fmt.Errorf("Marshalling Secret Data: %w", err) - } - secretData = string(res) - case "v5-totp-standalone": - secret, err := c.GetSecret(ctx, resourceID) - if err != nil { - return fmt.Errorf("Getting Secret: %w", err) - } - oldSecretData, err := c.DecryptMessage(secret.Data) - if err != nil { - return fmt.Errorf("Decrypting Secret: %w", err) - } - var oldSecret api.SecretDataTypeTOTP - err = json.Unmarshal([]byte(oldSecretData), &secretData) - if err != nil { - return fmt.Errorf("Parsing Decrypted Secret Data: %w", err) - } - // since we don't have totp parameters we don't do anything - - res, err := json.Marshal(&oldSecret) - if err != nil { - return fmt.Errorf("Marshalling Secret Data: %w", err) - } - secretData = string(res) - default: - return fmt.Errorf("Unknown ResourceType: %v", rType.Slug) } - } else { - // V4 Resource - newResource.Name = resource.Name - newResource.Username = resource.Username - newResource.URI = resource.URI - - if name != "" { - newResource.Name = name + res, err := json.Marshal(&tmp) + if err != nil { + return fmt.Errorf("Marshalling Secret Data: %w", err) } - if username != "" { - newResource.Username = username + secretData = string(res) + case "password-description-totp": + secret, err := c.GetSecret(ctx, resourceID) + if err != nil { + return fmt.Errorf("Getting Secret: %w", err) } - if uri != "" { - newResource.URI = uri + oldSecretData, err := c.DecryptMessage(secret.Data) + if err != nil { + return fmt.Errorf("Decrypting Secret: %w", err) + } + var oldSecret api.SecretDataTypePasswordDescriptionTOTP + err = json.Unmarshal([]byte(oldSecretData), &secretData) + if err != nil { + return fmt.Errorf("Parsing Decrypted Secret Data: %w", err) + } + if password != "" { + oldSecret.Password = password + } + if description != "" { + oldSecret.Description = description } - // Secret - switch rType.Slug { - case "password-string": - newResource.Description = resource.Description - if description != "" { - newResource.Description = description - } - if password != "" { - secretData = password - } else { - secret, err := c.GetSecret(ctx, resourceID) - if err != nil { - return fmt.Errorf("Getting Secret: %w", err) - } - secretData, err = c.DecryptMessage(secret.Data) - if err != nil { - return fmt.Errorf("Decrypting Secret: %w", err) - } - } - case "password-and-description": - tmp := api.SecretDataTypePasswordAndDescription{ - Password: password, - Description: description, - } - if password != "" || description != "" { - secret, err := c.GetSecret(ctx, resourceID) - if err != nil { - return fmt.Errorf("Getting Secret: %w", err) - } - oldSecretData, err := c.DecryptMessage(secret.Data) - if err != nil { - return fmt.Errorf("Decrypting Secret: %w", err) - } - var oldSecret api.SecretDataTypePasswordAndDescription - err = json.Unmarshal([]byte(oldSecretData), &oldSecret) - if err != nil { - return fmt.Errorf("Parsing Decrypted Secret Data: %w", err) - } - if password == "" { - tmp.Password = oldSecret.Password - } - if description == "" { - tmp.Description = oldSecret.Description - } - } - res, err := json.Marshal(&tmp) - if err != nil { - return fmt.Errorf("Marshalling Secret Data: %w", err) - } - secretData = string(res) - case "password-description-totp": - secret, err := c.GetSecret(ctx, resourceID) - if err != nil { - return fmt.Errorf("Getting Secret: %w", err) - } - oldSecretData, err := c.DecryptMessage(secret.Data) - if err != nil { - return fmt.Errorf("Decrypting Secret: %w", err) - } - var oldSecret api.SecretDataTypePasswordDescriptionTOTP - err = json.Unmarshal([]byte(oldSecretData), &secretData) - if err != nil { - return fmt.Errorf("Parsing Decrypted Secret Data: %w", err) - } - if password != "" { - oldSecret.Password = password - } - if description != "" { - oldSecret.Description = description - } - - res, err := json.Marshal(&oldSecret) - if err != nil { - return fmt.Errorf("Marshalling Secret Data: %w", err) - } - secretData = string(res) - case "totp": - secret, err := c.GetSecret(ctx, resourceID) - if err != nil { - return fmt.Errorf("Getting Secret: %w", err) - } - oldSecretData, err := c.DecryptMessage(secret.Data) - if err != nil { - return fmt.Errorf("Decrypting Secret: %w", err) - } - var oldSecret api.SecretDataTypeTOTP - err = json.Unmarshal([]byte(oldSecretData), &secretData) - if err != nil { - return fmt.Errorf("Parsing Decrypted Secret Data: %w", err) - } - // since we don't have totp parameters we don't do anything - - res, err := json.Marshal(&oldSecret) - if err != nil { - return fmt.Errorf("Marshalling Secret Data: %w", err) - } - secretData = string(res) - default: - return fmt.Errorf("Unknown ResourceType: %v", rType.Slug) + res, err := json.Marshal(&oldSecret) + if err != nil { + return fmt.Errorf("Marshalling Secret Data: %w", err) } + secretData = string(res) + case "totp": + secret, err := c.GetSecret(ctx, resourceID) + if err != nil { + return fmt.Errorf("Getting Secret: %w", err) + } + oldSecretData, err := c.DecryptMessage(secret.Data) + if err != nil { + return fmt.Errorf("Decrypting Secret: %w", err) + } + var oldSecret api.SecretDataTypeTOTP + err = json.Unmarshal([]byte(oldSecretData), &secretData) + if err != nil { + return fmt.Errorf("Parsing Decrypted Secret Data: %w", err) + } + // since we don't have totp parameters we don't do anything + + res, err := json.Marshal(&oldSecret) + if err != nil { + return fmt.Errorf("Marshalling Secret Data: %w", err) + } + secretData = string(res) + default: + return fmt.Errorf("Unknown ResourceType: %v", rType.Slug) } err = validateSecretData(rType, secretData) @@ -716,12 +520,7 @@ func UpdateResource(ctx context.Context, c *api.Client, resourceID, name, userna return fmt.Errorf("Encrypting Secret Data for User me: %w", err) } } else { - publicKey, err := crypto.NewKeyFromArmored(user.GPGKey.ArmoredKey) - if err != nil { - return fmt.Errorf("Get Public Key: %w", err) - } - - encSecretData, err = c.EncryptMessageWithKey(publicKey, secretData) + encSecretData, err = c.EncryptMessageWithPublicKey(user.GPGKey.ArmoredKey, secretData) if err != nil { return fmt.Errorf("Encrypting Secret Data for User %v: %w", user.ID, err) } diff --git a/helper/secret.go b/helper/secret.go index 586ac26..f6849dc 100644 --- a/helper/secret.go +++ b/helper/secret.go @@ -57,7 +57,7 @@ func validateSecretData(rType *api.ResourceType, secretData string) error { err = schema.Validate(strings.NewReader(secretData)) if err != nil { - return fmt.Errorf("Validating Secret Data with Schema: %w", err) + return fmt.Errorf("Validating Secret Data: %w", err) } return nil }