From 2197d9e0f7fc50e23d799586fbf38ae9d6c89c6d Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Wed, 19 Mar 2025 16:02:31 +0100 Subject: [PATCH] Add Metadata Decryption --- api/metadata.go | 41 +++++++++++++++++++ helper/metadata.go | 100 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 api/metadata.go create mode 100644 helper/metadata.go diff --git a/api/metadata.go b/api/metadata.go new file mode 100644 index 0000000..03d556c --- /dev/null +++ b/api/metadata.go @@ -0,0 +1,41 @@ +package api + +import ( + "fmt" + + "github.com/ProtonMail/gopenpgp/v3/crypto" +) + +// ResourceMetadataTypePasswordAndDescription +type ResourceMetadataTypePasswordAndDescription struct { + ObjectType string `json:"object_type"` + ResourceTypeID string `json:"resource_type_id,omitempty"` + Name string `json:"name,omitempty"` + Username string `json:"username,omitempty"` + URIs []string `json:"uris,omitempty"` + Description string `json:"description,omitempty"` +} + +func (c *Client) DecryptMetadata(metadataKey *crypto.Key, armoredCiphertext string) (string, error) { + // TODO Get SessionKey from Cache + var sessionKey *crypto.SessionKey = nil + + if sessionKey != nil { + message, err := c.DecryptMessageWithSessionKey(sessionKey, armoredCiphertext) + // If Decrypt was successfull + if err == nil { + return message, nil + } + // if this failed, fall through + } + + metadata, newSessionKey, err := c.DecryptMessageWithPrivateKeyAndReturnSessionKey(metadataKey, armoredCiphertext) + if err != nil { + return "", fmt.Errorf("Decrypting Metadata: %w", err) + } + + // TODO Save newSessionKey to cache + _ = newSessionKey + + return metadata, nil +} diff --git a/helper/metadata.go b/helper/metadata.go new file mode 100644 index 0000000..eebb89e --- /dev/null +++ b/helper/metadata.go @@ -0,0 +1,100 @@ +package helper + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/passbolt/go-passbolt/api" +) + +func GetResourceMetadata(ctx context.Context, c *api.Client, resource api.Resource, rType api.ResourceType) (string, error) { + 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) + } + + decMetadata, err := c.DecryptMetadata(metadataPrivateKeyObj, resource.Metadata) + if err != nil { + return "", fmt.Errorf("Decrypt Metadata: %w", err) + } + /* + + + var schemaDefinition api.ResourceTypeSchema + err = json.Unmarshal([]byte(rType.Definition), &schemaDefinition) + if err != nil { + // Workaround for inconsistant API Responses where sometime the Schema is embedded directly and sometimes it's escaped as a string + if err.Error() == "json: cannot unmarshal string into Go value of type api.ResourceTypeSchema" { + var tmp string + err = json.Unmarshal([]byte(rType.Definition), &tmp) + if err != nil { + return "", fmt.Errorf("Workaround Unmarshal Json Schema String: %w", err) + } + + err = json.Unmarshal([]byte(tmp), &schemaDefinition) + if err != nil { + return "", fmt.Errorf("Workaround Unmarshal Json Schema: %w", err) + } + + } else { + return "", fmt.Errorf("Unmarshal Json Schema: %w", err) + } + } + + comp := jsonschema.NewCompiler() + + err = comp.AddResource("metadata.json", bytes.NewReader(schemaDefinition.Secret)) + if err != nil { + return "", fmt.Errorf("Adding Json Schema: %w", err) + } + + schema, err := comp.Compile("metadata.json") + if err != nil { + return "", fmt.Errorf("Compiling Json Schema: %w", err) + } + + err = schema.Validate(strings.NewReader(decMetadata)) + if err != nil { + return "", fmt.Errorf("Validating Secret Data: %w", err) + } + */ + + return decMetadata, nil +}