From 8733d8f6fc1c3fd575463bced83039f65e5829ad Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Wed, 12 Mar 2025 18:14:59 +0100 Subject: [PATCH 01/10] Add Metadata Key Structs, Types and Getter --- api/metadatakey.go | 86 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 api/metadatakey.go diff --git a/api/metadatakey.go b/api/metadatakey.go new file mode 100644 index 0000000..482c864 --- /dev/null +++ b/api/metadatakey.go @@ -0,0 +1,86 @@ +package api + +import ( + "context" + "encoding/json" +) + +type MetadataKeyType string + +const ( + MetadataKeyTypeUserKey MetadataKeyType = "user_key" + MetadataKeyTypeSharedKey = "shared_key" +) + +func (s MetadataKeyType) IsValid() bool { + switch s { + case MetadataKeyTypeUserKey, MetadataKeyTypeSharedKey: + return true + } + return false +} + +// MetadataKey is a MetadataKey +type MetadataKey struct { + ID string `json:"id,omitempty"` + Fingerprint string `json:"fingerprint,omitempty"` + ArmoredKey string `json:"armored_key,omitempty"` + Created Time `json:"created,omitempty"` + Modified Time `json:"modified,omitempty"` + + // These are always null? Used for Key Rotation? + //"expired": null, + //"deleted": null, + + CreatedBy *string `json:"created_by,omitempty"` + ModifiedBy *string `json:"modified_by,omitempty"` + + MetadataPrivateKeys []MetadataPrivateKey `json:"metadata_private_keys,omitempty"` +} + +// MetadataPrivateKey is a MetadataPrivateKey +type MetadataPrivateKey struct { + ID string `json:"id,omitempty"` + MetadataKeyID string `json:"metadata_key_id,omitempty"` + UserID *string `json:"user_id,omitempty"` // TODO, is this nullable. The Docs says yes and no + Data string `json:"data,omitempty"` + Created Time `json:"created,omitempty"` + Modified Time `json:"modified,omitempty"` + CreatedBy *string `json:"created_by,omitempty"` + ModifiedBy *string `json:"modified_by,omitempty"` +} + +// MetadataPrivateKeyData is a MetadataPrivateKeyData +type MetadataPrivateKeyData struct { + // ObjectType Must always be PASSBOLT_METADATA_PRIVATE_KEY + ObjectType string `json:"object_type,omitempty"` + // Domain Must be the Passbolt Server URL + Domain string `json:"domain,omitempty"` + Fingerprint string `json:"fingerprint,omitempty"` + ArmoredKey string `json:"armored_key,omitempty"` + // Passphrase must be Empty for Server Keys + Passphrase string `json:"passphrase,omitempty"` +} + +// GetMetadataKeysOptions are all available query parameters +type GetMetadataKeysOptions struct { + FilterDeleted bool `url:"filter[deleted,omitempty"` + FilterExpired bool `url:"filter[expired,omitempty"` + + ContainMetadataPrivateKeys bool `url:"contain[metadata_private_keys],omitempty"` +} + +// GetMetadataKeys gets all Passbolt GetMetadataKeys +func (c *Client) GetMetadataKeys(ctx context.Context, opts *GetMetadataKeysOptions) ([]MetadataKey, error) { + msg, err := c.DoCustomRequest(ctx, "GET", "/metadata/keys.json", "v2", nil, opts) + if err != nil { + return nil, err + } + + var metadataKeys []MetadataKey + err = json.Unmarshal(msg.Body, &metadataKeys) + if err != nil { + return nil, err + } + return metadataKeys, nil +} From 862201be89597e6c8c2c8fec648c4f29521e4f2a Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Wed, 12 Mar 2025 18:16:05 +0100 Subject: [PATCH 02/10] Add Metadata Related Field to Resource and GetResourcesOptions --- api/resources.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/api/resources.go b/api/resources.go index c25ddaf..2215686 100644 --- a/api/resources.go +++ b/api/resources.go @@ -9,6 +9,7 @@ import ( // Resource is a Resource. // Warning: Since Passbolt v3 some fields here may not be populated as they may be in the Secret depending on the ResourceType, // for now the only Field like that is the Description. +// With Passbolt v5 it is now Possible that all Unencrypted User Supplied Fields are empty, and need to be decrypted from the Metadata Message type Resource struct { ID string `json:"id,omitempty"` Created *Time `json:"created,omitempty"` @@ -27,8 +28,13 @@ type Resource struct { FolderParentID string `json:"folder_parent_id,omitempty"` ResourceTypeID string `json:"resource_type_id,omitempty"` ResourceType ResourceType `json:"resource_type,omitempty"` - Secrets []Secret `json:"secrets,omitempty"` - Tags []Tag `json:"tags,omitempty"` + + MetadataKeyID string `json:"metadata_key_id,omitempty"` + MetadataKeyType MetadataKeyType `json:"metadata_key_type,omitempty"` + Metadata string `json:"metadata,omitempty"` + + Secrets []Secret `json:"secrets,omitempty"` + Tags []Tag `json:"tags,omitempty"` } // Tag is a Passbolt Password Tag @@ -48,6 +54,8 @@ type GetResourcesOptions struct { // Parent Folder id FilterHasParent []string `url:"filter[has-parent][],omitempty"` FilterHasTag string `url:"filter[has-tag],omitempty"` + // TODO Are undescores correct heare? + MetadataKeyType MetadataKeyType `url:"filter[metadata_key_type],omitempty"` ContainCreator bool `url:"contain[creator],omitempty"` ContainFavorites bool `url:"contain[favorite],omitempty"` From 53b7d7504a465d5d81170ec0f544fbbfc919461b Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Wed, 12 Mar 2025 18:21:40 +0100 Subject: [PATCH 03/10] Add Foreign Model Enum for Session Keys --- api/foreign_model.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 api/foreign_model.go diff --git a/api/foreign_model.go b/api/foreign_model.go new file mode 100644 index 0000000..ca87e2f --- /dev/null +++ b/api/foreign_model.go @@ -0,0 +1,19 @@ +package api + +type ForeignModelTypes string + +const ( + ForeignModelTypesResource ForeignModelTypes = "Resource" + ForeignModelTypesSecret ForeignModelTypes = "Secret" + ForeignModelTypesFolder = "Folder" + ForeignModelTypesComment = "Comment" + ForeignModelTypesTag = "Tag" +) + +func (s ForeignModelTypes) IsValid() bool { + switch s { + case ForeignModelTypesResource, ForeignModelTypesSecret, ForeignModelTypesFolder, ForeignModelTypesComment, ForeignModelTypesTag: + return true + } + return false +} From 02e63472ddf1cf6e2029a8b0afde4376bf19fd19 Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Wed, 12 Mar 2025 18:26:02 +0100 Subject: [PATCH 04/10] Add Missing MetadataKeys and Get Option to Users, fix User Me --- api/users.go | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/api/users.go b/api/users.go index 9ce240b..a53e068 100644 --- a/api/users.go +++ b/api/users.go @@ -24,6 +24,9 @@ type User struct { GPGKey *GPGKey `json:"gpgKey,omitempty"` LastLoggedIn string `json:"last_logged_in,omitempty"` Locale string `json:"locale,omitempty"` + + // Admin only, needs contains + MissingMetadataKeyIDs []string `json:"missing_metadata_key_ids,omitempty"` } // Profile is a Profile @@ -42,6 +45,8 @@ type GetUsersOptions struct { FilterHasGroup []string `url:"filter[has-group][],omitempty"` FilterHasAccess []string `url:"filter[has-access][],omitempty"` FilterIsAdmin bool `url:"filter[is-admin],omitempty"` + // Admin only, TODO are underscores correct? + MissingMetadataKeyIDs bool `url:"filter[missing_metadata_key_ids],omitempty"` ContainLastLoggedIn bool `url:"contain[LastLoggedIn],omitempty"` } @@ -82,9 +87,11 @@ func (c *Client) GetMe(ctx context.Context) (*User, error) { // GetUser gets a Passbolt User func (c *Client) GetUser(ctx context.Context, userID string) (*User, error) { - err := checkUUIDFormat(userID) - if err != nil { - return nil, fmt.Errorf("Checking ID format: %w", err) + if userID != "me" { + err := checkUUIDFormat(userID) + if err != nil { + return nil, fmt.Errorf("Checking ID format: %w", err) + } } msg, err := c.DoCustomRequest(ctx, "GET", "/users/"+userID+".json", "v2", nil, nil) if err != nil { @@ -101,9 +108,11 @@ func (c *Client) GetUser(ctx context.Context, userID string) (*User, error) { // UpdateUser Updates a existing Passbolt User func (c *Client) UpdateUser(ctx context.Context, userID string, user User) (*User, error) { - err := checkUUIDFormat(userID) - if err != nil { - return nil, fmt.Errorf("Checking ID format: %w", err) + if userID != "me" { + err := checkUUIDFormat(userID) + if err != nil { + return nil, fmt.Errorf("Checking ID format: %w", err) + } } msg, err := c.DoCustomRequest(ctx, "PUT", "/users/"+userID+".json", "v2", user, nil) if err != nil { @@ -119,11 +128,13 @@ func (c *Client) UpdateUser(ctx context.Context, userID string, user User) (*Use // DeleteUser Deletes a Passbolt User func (c *Client) DeleteUser(ctx context.Context, userID string) error { - err := checkUUIDFormat(userID) - if err != nil { - return fmt.Errorf("Checking ID format: %w", err) + if userID != "me" { + err := checkUUIDFormat(userID) + if err != nil { + return fmt.Errorf("Checking ID format: %w", err) + } } - _, err = c.DoCustomRequest(ctx, "DELETE", "/users/"+userID+".json", "v2", nil, nil) + _, err := c.DoCustomRequest(ctx, "DELETE", "/users/"+userID+".json", "v2", nil, nil) if err != nil { return err } From 9348a96af53a157b2699aaa3b74e2af70e0cb6b7 Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Wed, 12 Mar 2025 18:32:12 +0100 Subject: [PATCH 05/10] Add Basic Metadata Session Key Structs and functions --- api/metadata_sessionkey.go | 61 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 api/metadata_sessionkey.go diff --git a/api/metadata_sessionkey.go b/api/metadata_sessionkey.go new file mode 100644 index 0000000..cf18abe --- /dev/null +++ b/api/metadata_sessionkey.go @@ -0,0 +1,61 @@ +package api + +import ( + "context" + "encoding/json" + "fmt" +) + +// MetadataSessionKey is a MetadataSessionKey +type MetadataSessionKey struct { + ID string `json:"id,omitempty"` + UserID string `json:"user_id,omitempty"` + Data string `json:"data,omitempty"` + Created Time `json:"created,omitempty"` + Modified Time `json:"modified,omitempty"` +} + +// MetadataSessionKeyData is a MetadataSessionKeyData +type MetadataSessionKeyData struct { + // ObjectType Must always be PASSBOLT_SESSION_KEYS + ObjectType string `json:"object_type,omitempty"` + SessionKeys []MetadataSessionKeyDataElement `json:"session_keys,omitempty"` +} + +// MetadataSessionKeyData is a MetadataSessionKeyData +type MetadataSessionKeyDataElement struct { + ForeignModel ForeignModelTypes `json:"foreign_model"` + ForeignID string `json:"foreign_id"` + SessionKey string `json:"session_key"` + Modified Time `json:"modified"` +} + +// GetMetadataTypeSettings gets the Servers Settings about which Types to use +func (c *Client) GetMetadataSessionKeys(ctx context.Context) ([]MetadataSessionKey, error) { + msg, err := c.DoCustomRequest(ctx, "GET", "/metadata/session-keys.json", "v2", nil, nil) + if err != nil { + return nil, err + } + + var metadataSessionKeys []MetadataSessionKey + err = json.Unmarshal(msg.Body, &metadataSessionKeys) + if err != nil { + return nil, err + } + return metadataSessionKeys, nil +} + +// TODO add Create and Update + +// DeleteSessionKey Deletes a Passbolt SessionKey +func (c *Client) DeleteSessionKey(ctx context.Context, sessionKeyID string) error { + err := checkUUIDFormat(sessionKeyID) + if err != nil { + return fmt.Errorf("Checking ID format: %w", err) + } + _, err = c.DoCustomRequest(ctx, "DELETE", "/metadata/session-keys/"+sessionKeyID+".json", "v2", nil, nil) + if err != nil { + return err + } + return nil +} From 35e95a21a3fee160feb5728e68000a4b531dcc02 Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Thu, 13 Mar 2025 17:38:03 +0100 Subject: [PATCH 06/10] go.mod Update gopenpgp to v3 --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index 64273dd..5c98b95 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( require ( github.com/ProtonMail/go-crypto v1.1.6 // indirect github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect + github.com/ProtonMail/gopenpgp/v3 v3.1.3 // indirect github.com/cloudflare/circl v1.6.0 // indirect github.com/pkg/errors v0.9.1 // indirect golang.org/x/crypto v0.35.0 // indirect diff --git a/go.sum b/go.sum index 24212a3..ba1847f 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/ProtonMail/gopenpgp/v2 v2.7.5 h1:STOY3vgES59gNgoOt2w0nyHBjKViB/qSg7Nj github.com/ProtonMail/gopenpgp/v2 v2.7.5/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= github.com/ProtonMail/gopenpgp/v2 v2.8.3 h1:1jHlELwCR00qovx2B50DkL/FjYwt/P91RnlsqeOp2Hs= github.com/ProtonMail/gopenpgp/v2 v2.8.3/go.mod h1:LiuOTbnJit8w9ZzOoLscj0kmdALY7hfoCVh5Qlb0bcg= +github.com/ProtonMail/gopenpgp/v3 v3.1.3 h1:nxUd0Na4MeElx0sA1t6U8/IxmjmCv3MKnTJGhEUK+qY= +github.com/ProtonMail/gopenpgp/v3 v3.1.3/go.mod h1:Ve9JYzwGau9DT0F9C9gsuEBU/T3Zbk0j1/+mPpWBogc= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE= From 2949cd58b112b6f6c5bb939fc1336917f70fc55f Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Thu, 13 Mar 2025 17:38:43 +0100 Subject: [PATCH 07/10] Client update to gopenpgp v3 --- api/client.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/api/client.go b/api/client.go index 001fce3..e51ee08 100644 --- a/api/client.go +++ b/api/client.go @@ -6,12 +6,11 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "path" - "github.com/ProtonMail/gopenpgp/v2/crypto" + "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/google/go-querystring/query" ) @@ -39,6 +38,9 @@ type Client struct { // You need to Return the Cookie that Passbolt expects to verify you MFA, usually it is called passbolt_mfa MFACallback func(ctx context.Context, c *Client, res *APIResponse) (http.Cookie, error) + // gopengpg Handler, allow for custom settings in the future + pgp *crypto.PGPHandle + // Enable Debug Logging Debug bool } @@ -67,6 +69,8 @@ func NewClient(httpClient *http.Client, UserAgent, BaseURL, UserPrivateKey, User return nil, fmt.Errorf("Parsing Base URL: %w", err) } + pgp := crypto.PGP() + // Verify that the Given Privatekey and Password are valid and work Together if we were provieded one if UserPrivateKey != "" { privateKeyObj, err := crypto.NewKeyFromArmored(UserPrivateKey) @@ -93,6 +97,7 @@ func NewClient(httpClient *http.Client, UserAgent, BaseURL, UserPrivateKey, User userAgent: UserAgent, userPassword: []byte(UserPassword), userPrivateKey: UserPrivateKey, + pgp: pgp, } return c, err } @@ -150,7 +155,7 @@ func (c *Client) do(ctx context.Context, req *http.Request, v *APIResponse) (*ht resp.Body.Close() }() - bodyBytes, err := ioutil.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return resp, fmt.Errorf("Error Reading Resopnse Body: %w", err) } @@ -231,3 +236,8 @@ func (c *Client) setMetadataTypeSettings(ctx context.Context) error { } return nil } + +// GetPGPHandle Gets the Gopgenpgp Handler +func (c *Client) GetPGPHandle() *crypto.PGPHandle { + return c.pgp +} From 7e9d0e035be1c18df49fab4120e12d89775f5f19 Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Thu, 13 Mar 2025 17:39:12 +0100 Subject: [PATCH 08/10] encryption.go update to gopenpgp v3 --- api/encryption.go | 133 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 12 deletions(-) diff --git a/api/encryption.go b/api/encryption.go index e87537e..ee5e40c 100644 --- a/api/encryption.go +++ b/api/encryption.go @@ -3,33 +3,142 @@ package api import ( "fmt" - "github.com/ProtonMail/gopenpgp/v2/helper" + "github.com/ProtonMail/gopenpgp/v3/crypto" ) // EncryptMessage encrypts a message using the users public key and then signes the message using the users private key func (c *Client) EncryptMessage(message string) (string, error) { - if c.userPrivateKey == "" { - return "", fmt.Errorf("Client has no Private Key") - } else if c.userPublicKey == "" { - return "", fmt.Errorf("Client has no Public Key") + key, err := c.getPrivateKey(c.userPrivateKey, c.userPassword) + if err != nil { + return "", fmt.Errorf("Get Private Key: %w", err) } - return helper.EncryptSignMessageArmored(c.userPublicKey, c.userPrivateKey, c.userPassword, message) + + defer key.ClearPrivateParams() + + encHandle, err := c.pgp.Encryption().SigningKey(key).Recipient(key).New() + if err != nil { + return "", fmt.Errorf("New Encryptor: %w", err) + } + + defer encHandle.ClearPrivateParams() + + encMessage, err := encHandle.Encrypt([]byte(message)) + if err != nil { + return "", fmt.Errorf("Encrypt Message: %w", err) + } + + encArmor, err := encMessage.Armor() + if err != nil { + return "", fmt.Errorf("Armor Message: %w", err) + } + return encArmor, nil } // EncryptMessageWithPublicKey encrypts a message using the provided public key and then signes the message using the users private key func (c *Client) EncryptMessageWithPublicKey(publickey, message string) (string, error) { - if c.userPrivateKey == "" { - return "", fmt.Errorf("Client has no Private Key") + key, err := c.getPrivateKey(c.userPrivateKey, c.userPassword) + if err != nil { + return "", fmt.Errorf("Get Private Key: %w", err) } - return helper.EncryptSignMessageArmored(publickey, c.userPrivateKey, c.userPassword, message) + + defer key.ClearPrivateParams() + + publicKey, err := crypto.NewKeyFromArmored(publickey) + if err != nil { + return "", fmt.Errorf("Get Public Key: %w", err) + } + + encHandle, err := c.pgp.Encryption().SigningKey(key).Recipient(publicKey).New() + if err != nil { + return "", fmt.Errorf("New Encryptor: %w", err) + } + + defer encHandle.ClearPrivateParams() + + encMessage, err := encHandle.Encrypt([]byte(message)) + if err != nil { + return "", fmt.Errorf("Encrypt Message: %w", err) + } + + encArmor, err := encMessage.Armor() + if err != nil { + return "", fmt.Errorf("Armor Message: %w", err) + } + return encArmor, nil } // DecryptMessage decrypts a message using the users Private Key func (c *Client) DecryptMessage(message string) (string, error) { - if c.userPrivateKey == "" { - return "", fmt.Errorf("Client has no Private Key") + key, err := c.getPrivateKey(c.userPrivateKey, c.userPassword) + if err != nil { + return "", fmt.Errorf("Get Private Key: %w", err) } + + defer key.ClearPrivateParams() + + decHandle, err := c.pgp.Decryption().DecryptionKey(key).New() + if err != nil { + return "", fmt.Errorf("New Decryptor: %w", err) + } + + defer decHandle.ClearPrivateParams() + + res, err := decHandle.Decrypt([]byte(message), crypto.Armor) + if err != nil { + return "", fmt.Errorf("Decrypt Message: %w", err) + } + // We cant Verify the signature as we don't store other users public keys locally and don't know which user did encrypt it //return helper.DecryptVerifyMessageArmored(c.userPublicKey, c.userPrivateKey, c.userPassword, message) - return helper.DecryptMessageArmored(c.userPrivateKey, c.userPassword, message) + + return res.String(), nil +} + +// TODO change []byte to string? +func (c *Client) DecryptMessageWithPrivateKey(privateKey string, passphrase []byte, ciphertextArmored string) (string, error) { + key, err := c.getPrivateKey(privateKey, passphrase) + if err != nil { + return "", fmt.Errorf("Get Private Key: %w", err) + } + + defer key.ClearPrivateParams() + + decHandle, err := c.pgp.Decryption().DecryptionKey(key).New() + if err != nil { + return "", fmt.Errorf("New Decryptor: %w", err) + } + + defer decHandle.ClearPrivateParams() + + res, err := decHandle.Decrypt([]byte(ciphertextArmored), crypto.Armor) + if err != nil { + return "", fmt.Errorf("Decrypt: %w", err) + } + + return string(res.Bytes()), nil +} + +func (c *Client) getPrivateKey(privateKey string, passphrase []byte) (*crypto.Key, error) { + if c.userPrivateKey == "" { + return nil, fmt.Errorf("Client has no Private Key") + } + + key, err := crypto.NewKeyFromArmored(privateKey) + if err != nil { + return nil, fmt.Errorf("Key From Armored: %w", err) + } + + locked, err := key.IsLocked() + if err != nil { + return nil, fmt.Errorf("Is Key Locked: %w", err) + } + + if locked { + unlocked, err := key.Unlock(passphrase) + if err != nil { + return nil, fmt.Errorf("Unlock Key: %w", err) + } + return unlocked, nil + } + return key, nil } From 94992dbd4b95d846ae3fc220495e1c258d262c8f Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Thu, 13 Mar 2025 17:39:34 +0100 Subject: [PATCH 09/10] verify.go update to gopenpgp v3 --- api/verify.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/verify.go b/api/verify.go index 89a15b8..74e35b6 100644 --- a/api/verify.go +++ b/api/verify.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/ProtonMail/gopenpgp/v2/crypto" + "github.com/ProtonMail/gopenpgp/v3/crypto" "github.com/google/uuid" ) From 146fe6662c7ab43df67090fed7092d0aeb3ad6dc Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Thu, 13 Mar 2025 17:40:16 +0100 Subject: [PATCH 10/10] Setup update to gopenpgp v3 --- helper/setup.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/helper/setup.go b/helper/setup.go index 7fdc006..37e202c 100644 --- a/helper/setup.go +++ b/helper/setup.go @@ -6,9 +6,6 @@ import ( "strings" "github.com/passbolt/go-passbolt/api" - - "github.com/ProtonMail/gopenpgp/v2/crypto" - "github.com/ProtonMail/gopenpgp/v2/helper" ) // ParseInviteUrl Parses a Passbolt Invite URL into a user id and token @@ -31,21 +28,34 @@ func SetupAccount(ctx context.Context, c *api.Client, userID, token, password st keyName := install.Profile.FirstName + " " + install.Profile.LastName + " " + install.Username - privateKey, err := helper.GenerateKey(keyName, install.Username, []byte(password), "rsa", 4096) + pgp := c.GetPGPHandle() + + keyHandler := pgp.KeyGeneration().AddUserId(keyName, install.Username).New() + + key, err := keyHandler.GenerateKey() if err != nil { return "", fmt.Errorf("Generating Private Key: %w", err) } - key, err := crypto.NewKeyFromArmoredReader(strings.NewReader(privateKey)) - if err != nil { - return "", fmt.Errorf("Reading Private Key: %w", err) - } + defer key.ClearPrivateParams() publicKey, err := key.GetArmoredPublicKey() if err != nil { return "", fmt.Errorf("Get Public Key: %w", err) } + lockedKey, err := pgp.LockKey(key, []byte(password)) + if err != nil { + return "", fmt.Errorf("Locking Private Key: %w", err) + } + + defer lockedKey.ClearPrivateParams() + + privateKey, err := lockedKey.Armor() + if err != nil { + return "", fmt.Errorf("Get Private Key: %w", err) + } + request := api.SetupCompleteRequest{ AuthenticationToken: api.AuthenticationToken{ Token: token,