mirror of
https://github.com/passbolt/go-passbolt.git
synced 2025-05-10 01:48:22 +00:00
commit
0538e86ddd
6 changed files with 152 additions and 16 deletions
|
@ -57,6 +57,10 @@ func (c *Client) CheckSession(ctx context.Context) bool {
|
||||||
// Login gets a Session and CSRF Token from Passbolt and Stores them in the Clients Cookie Jar
|
// Login gets a Session and CSRF Token from Passbolt and Stores them in the Clients Cookie Jar
|
||||||
func (c *Client) Login(ctx context.Context) error {
|
func (c *Client) Login(ctx context.Context) error {
|
||||||
|
|
||||||
|
if c.userPrivateKey == "" {
|
||||||
|
return fmt.Errorf("Client has no Private Key")
|
||||||
|
}
|
||||||
|
|
||||||
privateKeyObj, err := crypto.NewKeyFromArmored(c.userPrivateKey)
|
privateKeyObj, err := crypto.NewKeyFromArmored(c.userPrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Parsing User Private Key: %w", err)
|
return fmt.Errorf("Parsing User Private Key: %w", err)
|
||||||
|
|
|
@ -36,6 +36,8 @@ type Client struct {
|
||||||
// NewClient Returns a new Passbolt Client.
|
// NewClient Returns a new Passbolt Client.
|
||||||
// if httpClient is nil http.DefaultClient will be used.
|
// if httpClient is nil http.DefaultClient will be used.
|
||||||
// if UserAgent is "" "goPassboltClient/1.0" will be used.
|
// if UserAgent is "" "goPassboltClient/1.0" will be used.
|
||||||
|
// if UserPrivateKey is "" Key Setup is Skipped to Enable using the Client for User Registration, Most other function will be broken.
|
||||||
|
// After Registration a new Client Should be Created.
|
||||||
func NewClient(httpClient *http.Client, UserAgent, BaseURL, UserPrivateKey, UserPassword string) (*Client, error) {
|
func NewClient(httpClient *http.Client, UserAgent, BaseURL, UserPrivateKey, UserPassword string) (*Client, error) {
|
||||||
if httpClient == nil {
|
if httpClient == nil {
|
||||||
httpClient = http.DefaultClient
|
httpClient = http.DefaultClient
|
||||||
|
@ -49,22 +51,24 @@ func NewClient(httpClient *http.Client, UserAgent, BaseURL, UserPrivateKey, User
|
||||||
return nil, fmt.Errorf("Parsing Base URL: %w", err)
|
return nil, fmt.Errorf("Parsing Base URL: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that the Given Privatekey and Password are valid and work Together
|
// Verify that the Given Privatekey and Password are valid and work Together if we were provieded one
|
||||||
privateKeyObj, err := crypto.NewKeyFromArmored(UserPrivateKey)
|
if UserPrivateKey != "" {
|
||||||
if err != nil {
|
privateKeyObj, err := crypto.NewKeyFromArmored(UserPrivateKey)
|
||||||
return nil, fmt.Errorf("Unable to Create Key From UserPrivateKey string: %w", err)
|
if err != nil {
|
||||||
}
|
return nil, fmt.Errorf("Unable to Create Key From UserPrivateKey string: %w", err)
|
||||||
unlockedKeyObj, err := privateKeyObj.Unlock([]byte(UserPassword))
|
}
|
||||||
if err != nil {
|
unlockedKeyObj, err := privateKeyObj.Unlock([]byte(UserPassword))
|
||||||
return nil, fmt.Errorf("Unable to Unlock UserPrivateKey using UserPassword: %w", err)
|
if err != nil {
|
||||||
}
|
return nil, fmt.Errorf("Unable to Unlock UserPrivateKey using UserPassword: %w", err)
|
||||||
privateKeyRing, err := crypto.NewKeyRing(unlockedKeyObj)
|
}
|
||||||
if err != nil {
|
privateKeyRing, err := crypto.NewKeyRing(unlockedKeyObj)
|
||||||
return nil, fmt.Errorf("Unable to Create a new Key Ring using the unlocked UserPrivateKey: %w", err)
|
if err != nil {
|
||||||
}
|
return nil, fmt.Errorf("Unable to Create a new Key Ring using the unlocked UserPrivateKey: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup Secrets
|
// Cleanup Secrets
|
||||||
privateKeyRing.ClearPrivateParams()
|
privateKeyRing.ClearPrivateParams()
|
||||||
|
}
|
||||||
|
|
||||||
// Create Client Object
|
// Create Client Object
|
||||||
c := &Client{
|
c := &Client{
|
||||||
|
|
|
@ -1,19 +1,34 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import "github.com/ProtonMail/gopenpgp/v2/helper"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ProtonMail/gopenpgp/v2/helper"
|
||||||
|
)
|
||||||
|
|
||||||
// EncryptMessage encrypts a message using the users public key and then signes the message using the users private key
|
// 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) {
|
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")
|
||||||
|
}
|
||||||
return helper.EncryptSignMessageArmored(c.userPublicKey, c.userPrivateKey, c.userPassword, message)
|
return helper.EncryptSignMessageArmored(c.userPublicKey, c.userPrivateKey, c.userPassword, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncryptMessageWithPublicKey encrypts a message using the provided public key and then signes the message using the users private key
|
// 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) {
|
func (c *Client) EncryptMessageWithPublicKey(publickey, message string) (string, error) {
|
||||||
|
if c.userPrivateKey == "" {
|
||||||
|
return "", fmt.Errorf("Client has no Private Key")
|
||||||
|
}
|
||||||
return helper.EncryptSignMessageArmored(publickey, c.userPrivateKey, c.userPassword, message)
|
return helper.EncryptSignMessageArmored(publickey, c.userPrivateKey, c.userPassword, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecryptMessage decrypts a message using the users Private Key
|
// DecryptMessage decrypts a message using the users Private Key
|
||||||
func (c *Client) DecryptMessage(message string) (string, error) {
|
func (c *Client) DecryptMessage(message string) (string, error) {
|
||||||
|
if c.userPrivateKey == "" {
|
||||||
|
return "", fmt.Errorf("Client has no Private Key")
|
||||||
|
}
|
||||||
// We cant Verify the signature as we don't store other users public keys locally and don't know which user did encrypt it
|
// 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.DecryptVerifyMessageArmored(c.userPublicKey, c.userPrivateKey, c.userPassword, message)
|
||||||
return helper.DecryptMessageArmored(c.userPrivateKey, c.userPassword, message)
|
return helper.DecryptMessageArmored(c.userPrivateKey, c.userPassword, message)
|
||||||
|
|
44
api/setup.go
Normal file
44
api/setup.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SetupInstallResponse struct {
|
||||||
|
User `json:"user,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthenticationToken struct {
|
||||||
|
Token string `json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetupCompleteRequest struct {
|
||||||
|
AuthenticationToken AuthenticationToken `json:"authenticationtoken,omitempty"`
|
||||||
|
GPGKey GPGKey `json:"gpgkey,omitempty"`
|
||||||
|
User User `json:"user,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupInstall validates the userid and token used for Account setup, gives back the User Information
|
||||||
|
func (c *Client) SetupInstall(ctx context.Context, userID, token string) (*SetupInstallResponse, error) {
|
||||||
|
msg, err := c.DoCustomRequest(ctx, "GET", "/setup/install/"+userID+"/"+token+".json", "v2", nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var install SetupInstallResponse
|
||||||
|
err = json.Unmarshal(msg.Body, &install)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &install, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupComplete Completes setup of a Passbolt Account
|
||||||
|
func (c *Client) SetupComplete(ctx context.Context, userID string, request SetupCompleteRequest) error {
|
||||||
|
_, err := c.DoCustomRequest(ctx, "POST", "/setup/complete/"+userID+".json", "v2", request, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const UserLocaleENUK = "en-UK"
|
||||||
|
|
||||||
// User contains information about a passbolt User
|
// User contains information about a passbolt User
|
||||||
type User struct {
|
type User struct {
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
|
@ -20,6 +22,7 @@ type User struct {
|
||||||
Role *Role `json:"role,omitempty"`
|
Role *Role `json:"role,omitempty"`
|
||||||
GPGKey *GPGKey `json:"gpgKey,omitempty"`
|
GPGKey *GPGKey `json:"gpgKey,omitempty"`
|
||||||
LastLoggedIn string `json:"last_logged_in,omitempty"`
|
LastLoggedIn string `json:"last_logged_in,omitempty"`
|
||||||
|
Locale string `json:"locale,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile is a Profile
|
// Profile is a Profile
|
||||||
|
|
66
helper/setup.go
Normal file
66
helper/setup.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/speatzle/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
|
||||||
|
func ParseInviteUrl(url string) (string, string, error) {
|
||||||
|
split := strings.Split(url, "/")
|
||||||
|
if len(split) < 4 {
|
||||||
|
return "", "", fmt.Errorf("Invite URL does not have enough slashes")
|
||||||
|
}
|
||||||
|
return split[len(split)-2], strings.TrimSuffix(split[len(split)-1], ".json"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupAccount Setup a Account for a Invited User.
|
||||||
|
// (Use ParseInviteUrl to get the userid and token from a Invite URL)
|
||||||
|
func SetupAccount(ctx context.Context, c *api.Client, userID, token, password string) (string, error) {
|
||||||
|
|
||||||
|
install, err := c.SetupInstall(ctx, userID, token)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Get Setup Install Data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
keyName := install.Profile.FirstName + " " + install.Profile.LastName + " " + install.Username
|
||||||
|
|
||||||
|
privateKey, err := helper.GenerateKey(keyName, install.Username, []byte(password), "rsa", 2048)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
publicKey, err := key.GetArmoredPublicKey()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Get Public Key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request := api.SetupCompleteRequest{
|
||||||
|
AuthenticationToken: api.AuthenticationToken{
|
||||||
|
Token: token,
|
||||||
|
},
|
||||||
|
User: api.User{
|
||||||
|
Locale: api.UserLocaleENUK,
|
||||||
|
},
|
||||||
|
GPGKey: api.GPGKey{
|
||||||
|
ArmoredKey: publicKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.SetupComplete(ctx, userID, request)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Setup Completion Failed: %w", err)
|
||||||
|
}
|
||||||
|
return privateKey, nil
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue