diff --git a/api/encryption.go b/api/encryption.go index 2c393ee..c39eee3 100644 --- a/api/encryption.go +++ b/api/encryption.go @@ -33,19 +33,12 @@ func (c *Client) EncryptMessage(message string) (string, error) { } // EncryptMessageWithPublicKey encrypts a message using the provided public key and then signes the message using the users private key -// -// Deprecated: EncryptMessageWithPublicKey is deprecated. Use EncryptMessageWithKey instead func (c *Client) EncryptMessageWithPublicKey(publickey, message string) (string, error) { publicKey, err := crypto.NewKeyFromArmored(publickey) if err != nil { return "", fmt.Errorf("Get Public Key: %w", err) } - return c.EncryptMessageWithKey(publicKey, message) -} - -// EncryptMessageWithKey encrypts a message using the provided key and then signes the message using the users private key -func (c *Client) EncryptMessageWithKey(publicKey *crypto.Key, message string) (string, error) { key, err := c.userPrivateKey.Copy() if err != nil { return "", fmt.Errorf("Get Private Key Copy: %w", err) diff --git a/api/metadata.go b/api/metadata.go deleted file mode 100644 index cc40425..0000000 --- a/api/metadata.go +++ /dev/null @@ -1,81 +0,0 @@ -package api - -import ( - "fmt" - - "github.com/ProtonMail/gopenpgp/v3/crypto" -) - -// ResourceMetadataTypeV5Default -type ResourceMetadataTypeV5Default 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"` -} - -// ResourceMetadataTypeV5DefaultWithTOTP -type ResourceMetadataTypeV5DefaultWithTOTP 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"` -} - -// ResourceMetadataTypeV5PasswordString -type ResourceMetadataTypeV5PasswordString 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"` -} - -// ResourceMetadataTypeV5TOTPStandalone -type ResourceMetadataTypeV5TOTPStandalone struct { - ObjectType string `json:"object_type"` - ResourceTypeID string `json:"resource_type_id,omitempty"` - Name string `json:"name,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 -} - -func (c *Client) EncryptMetadata(metadataKey *crypto.Key, data string) (string, error) { - armoredCiphertext, err := c.EncryptMessageWithKey(metadataKey, data) - if err != nil { - return "", fmt.Errorf("Encrypting Metadata: %w", err) - } - - // TODO save Session Key to cache - - return armoredCiphertext, nil -} diff --git a/api/schema.go b/api/schema.go deleted file mode 100644 index b9fe6d4..0000000 --- a/api/schema.go +++ /dev/null @@ -1,231 +0,0 @@ -package api - -import "encoding/json" - -// Fallback Schema, Only to be used if we encounter a Broken Server (v5.0), Not API Stable! -var ResourceSchemas = map[string]json.RawMessage{ - "v5-default": json.RawMessage(` -{ - "resource": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "maxLength": 255 - }, - "username": { - "type": "string", - "maxLength": 255, - "nullable": true - }, - "uris": { - "type": "array", - "items": { - "type": "string", - "maxLength": 1024, - "nullable": true - } - }, - "description": { - "type": "string", - "maxLength": 10000, - "nullable": true - } - } - }, - "secret": { - "type": "object", - "required": ["password"], - "properties": { - "object_type": { - "type": "string", - "enum": ["PASSBOLT_SECRET_DATA"] - }, - "password": { - "type": "string", - "maxLength": 4096, - "nullable": true - }, - "description": { - "type": "string", - "maxLength": 10000, - "nullable": true - } - } - } -}`), - "v5-password-string": json.RawMessage(` -{ - "resource": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "maxLength": 255 - }, - "username": { - "type": "string", - "maxLength": 255, - "nullable": true - }, - "uris": { - "type": "array", - "items": { - "type": "string", - "maxLength": 1024, - "nullable": true - } - }, - "description": { - "type": "string", - "maxLength": 10000, - "nullable": true - } - } - }, - "secret": { - "type": "string", - "maxLength": 4096 - } -}`), - "v5-default-with-totp": json.RawMessage(` -{ - "resource": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "maxLength": 255 - }, - "username": { - "type": "string", - "maxLength": 255, - "nullable": true - }, - "uris": { - "type": "array", - "items": { - "type": "string", - "maxLength": 1024, - "nullable": true - } - }, - "description": { - "type": "string", - "maxLength": 10000, - "nullable": true - } - } - }, - "secret": { - "type": "object", - "required": ["totp"], - "properties": { - "object_type": { - "type": "string", - "enum": ["PASSBOLT_SECRET_DATA"] - }, - "password": { - "type": "string", - "maxLength": 4096, - "nullable": true - }, - "description": { - "type": "string", - "maxLength": 10000, - "nullable": true - }, - "totp": { - "type": "object", - "required": ["secret_key", "digits", "algorithm"], - "properties": { - "algorithm": { - "type": "string", - "minLength": 4, - "maxLength": 6 - }, - "secret_key": { - "type": "string", - "maxLength": 1024 - }, - "digits": { - "type": "number", - "minimum": 6, - "maximum": 8 - }, - "period": { - "type": "number" - } - } - } - } - } -}`), - "v5-totp-standalone": json.RawMessage(` -{ - "resource": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "maxLength": 255 - }, - "username": { - "type": "string", - "maxLength": 255, - "nullable": true - }, - "uris": { - "type": "array", - "items": { - "type": "string", - "maxLength": 1024, - "nullable": true - } - }, - "description": { - "type": "string", - "maxLength": 10000, - "nullable": true - } - } - }, - "secret": { - "type": "object", - "required": ["totp"], - "properties": { - "object_type": { - "type": "string", - "enum": ["PASSBOLT_SECRET_DATA"] - }, - "totp": { - "type": "object", - "required": ["secret_key", "digits", "algorithm"], - "properties": { - "algorithm": { - "type": "string", - "minLength": 4, - "maxLength": 6 - }, - "secret_key": { - "type": "string", - "maxLength": 1024 - }, - "digits": { - "type": "number", - "minimum": 6, - "maximum": 8 - }, - "period": { - "type": "number" - } - } - } - } - } -}`), -} diff --git a/api/schema_test.go b/api/schema_test.go deleted file mode 100644 index a9069e4..0000000 --- a/api/schema_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package api - -import ( - "encoding/json" - "testing" -) - -func TestResourceJsonSchema(t *testing.T) { - for slug, schema := range ResourceSchemas { - var schemaDefinition ResourceTypeSchema - err := json.Unmarshal(schema, &schemaDefinition) - if err != nil { - t.Errorf("Error While Parsing Resource Schema %v: %v", slug, err) - } else { - t.Logf("Schema for type %v is ok", slug) - } - } -} diff --git a/api/secrets.go b/api/secrets.go index 60c8d6a..8bcad6c 100644 --- a/api/secrets.go +++ b/api/secrets.go @@ -41,33 +41,6 @@ type SecretDataTypePasswordDescriptionTOTP struct { TOTP SecretDataTOTP `json:"totp"` } -// SecretDataTypeV5Default -type SecretDataTypeV5Default struct { - ObjectType string `json:"object_type"` - ResourceTypeID string `json:"resource_type_id,omitempty"` - Password string `json:"password,omitempty"` - Description string `json:"description,omitempty"` -} - -// SecretDataTypeV5DefaultWithTOTP -type SecretDataTypeV5DefaultWithTOTP struct { - ObjectType string `json:"object_type"` - ResourceTypeID string `json:"resource_type_id,omitempty"` - Password string `json:"password,omitempty"` - Description string `json:"description,omitempty"` - TOTP SecretDataTOTP `json:"totp"` -} - -// SecretDataTypeV5PasswordString, is just the Password directly -type SecretDataTypeV5PasswordString string - -// SecretDataTypeV5TOTPStandalone -type SecretDataTypeV5TOTPStandalone struct { - ObjectType string `json:"object_type"` - ResourceTypeID string `json:"resource_type_id,omitempty"` - TOTP SecretDataTOTP `json:"totp"` -} - // GetSecret gets a Passbolt Secret func (c *Client) GetSecret(ctx context.Context, resourceID string) (*Secret, error) { err := checkUUIDFormat(resourceID) diff --git a/helper/metadata.go b/helper/metadata.go deleted file mode 100644 index e89cb78..0000000 --- a/helper/metadata.go +++ /dev/null @@ -1,109 +0,0 @@ -package helper - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "strings" - - "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) { - 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) - } - - if tmp == "[]" { - // Use The Builtin Fallback Schemas in this Case - schema, ok := api.ResourceSchemas[rType.Slug] - if !ok { - return "", fmt.Errorf("Server Does not have the Required json Schema and there is no fallback available for type: %v", rType.Slug) - } - tmp = string(schema) - } - - 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.Resource)) - 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 -} diff --git a/helper/resources.go b/helper/resources.go index 9c2d31a..6a4f786 100644 --- a/helper/resources.go +++ b/helper/resources.go @@ -104,26 +104,16 @@ func GetResource(ctx context.Context, c *api.Client, resourceID string) (folderP } // GetResourceFromData Decrypts Resources using only local data, the Resource object must inlude the secret -// With v5 This needs network calls for Metadata of v5 Resources -func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret, rType api.ResourceType) (string, string, string, string, string, string, error) { - var name string - var username string - var uri string +func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret, rType api.ResourceType) (folderParentID, name, username, uri, password, description string, err error) { var pw string var desc string - ctx := context.TODO() - switch rType.Slug { case "password-string": - var err error pw, err = c.DecryptMessage(secret.Data) if err != nil { return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err) } - name = resource.Name - username = resource.Username - uri = resource.URI desc = resource.Description case "password-and-description": rawSecretData, err := c.DecryptMessage(secret.Data) @@ -136,9 +126,6 @@ func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret if err != nil { return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err) } - name = resource.Name - username = resource.Username - uri = resource.URI pw = secretData.Password desc = secretData.Description case "password-description-totp": @@ -152,109 +139,14 @@ func GetResourceFromData(c *api.Client, resource api.Resource, secret api.Secret if err != nil { return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err) } - name = resource.Name - username = resource.Username - uri = resource.URI pw = secretData.Password desc = secretData.Description case "totp": - name = resource.Name - username = resource.Username - uri = resource.URI - // nothing fits into the interface in this case - case "v5-default": - rawMetadata, err := GetResourceMetadata(ctx, c, resource, rType) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err) - } - - var metadata api.ResourceMetadataTypeV5Default - err = json.Unmarshal([]byte(rawMetadata), &metadata) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Metadata: %w", err) - } - - name = metadata.Name - username = metadata.Username - if len(metadata.URIs) != 0 { - uri = metadata.URIs[0] - } - - rawSecretData, err := c.DecryptMessage(secret.Data) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err) - } - - var secretData api.SecretDataTypeV5Default - err = json.Unmarshal([]byte(rawSecretData), &secretData) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err) - } - pw = secretData.Password - desc = secretData.Description - case "v5-default-with-totp": - rawMetadata, err := GetResourceMetadata(ctx, c, resource, rType) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err) - } - - var metadata api.ResourceMetadataTypeV5DefaultWithTOTP - err = json.Unmarshal([]byte(rawMetadata), &metadata) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Metadata: %w", err) - } - - name = metadata.Name - username = metadata.Username - if len(metadata.URIs) != 0 { - uri = metadata.URIs[0] - } - - rawSecretData, err := c.DecryptMessage(secret.Data) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err) - } - - var secretData api.SecretDataTypeV5DefaultWithTOTP - err = json.Unmarshal([]byte(rawSecretData), &secretData) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Secret Data: %w", err) - } - pw = secretData.Password - desc = secretData.Description - case "v5-password-string": - rawMetadata, err := GetResourceMetadata(ctx, c, resource, rType) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Getting Metadata: %w", err) - } - - var metadata api.ResourceMetadataTypeV5PasswordString - err = json.Unmarshal([]byte(rawMetadata), &metadata) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Parsing Decrypted Metadata: %w", err) - } - - name = metadata.Name - username = metadata.Username - if len(metadata.URIs) != 0 { - uri = metadata.URIs[0] - } - - // Not available in the Secret - desc = metadata.Description - - rawSecretData, err := c.DecryptMessage(secret.Data) - if err != nil { - return "", "", "", "", "", "", fmt.Errorf("Decrypting Secret Data: %w", err) - } - - pw = rawSecretData - case "v5-totp-standalone": // nothing fits into the interface in this case default: return "", "", "", "", "", "", fmt.Errorf("Unknown ResourceType: %v", rType.Slug) } - return resource.FolderParentID, name, username, uri, pw, desc, nil + return resource.FolderParentID, resource.Name, resource.Username, resource.URI, pw, desc, nil } // UpdateResource Updates all Fields.