diff --git a/client.go b/client.go index 635d3d0..998eb42 100644 --- a/client.go +++ b/client.go @@ -681,6 +681,7 @@ type ToznySDKV3 struct { *identityClient.E3dbIdentityClient *storageClient.StorageClient *pdsClient.E3dbPDSClient + *accountClient.E3dbAccountClientV2 // Account public authentication material for creating and deriving account credentials AccountUsername string // Account private authentication material for creating and deriving account credentials @@ -713,22 +714,24 @@ type ToznySDKConfig struct { // NewToznySDK returns a new instance of the ToznySDK initialized with the provided // config or error (if any). func NewToznySDKV3(config ToznySDKConfig) (*ToznySDKV3, error) { + accountServiceV2Client := accountClient.NewV2(config.ClientConfig) accountServiceClient := accountClient.New(config.ClientConfig) identityClient := identityClient.New(config.ClientConfig) storageClient := storageClient.New(config.ClientConfig) pdsClient := pdsClient.New(config.ClientConfig) return &ToznySDKV3{ - E3dbAccountClient: &accountServiceClient, - E3dbIdentityClient: &identityClient, - StorageClient: &storageClient, - E3dbPDSClient: &pdsClient, - AccountUsername: config.AccountUsername, - AccountPassword: config.AccountPassword, - APIEndpoint: config.APIEndpoint, - ClientID: config.ClientID, - CurrentIdentity: config.TozIDSessionIdentityData, - config: config.ClientConfig, + E3dbAccountClient: &accountServiceClient, + E3dbAccountClientV2: &accountServiceV2Client, + E3dbIdentityClient: &identityClient, + StorageClient: &storageClient, + E3dbPDSClient: &pdsClient, + AccountUsername: config.AccountUsername, + AccountPassword: config.AccountPassword, + APIEndpoint: config.APIEndpoint, + ClientID: config.ClientID, + CurrentIdentity: config.TozIDSessionIdentityData, + config: config.ClientConfig, }, nil } @@ -1141,6 +1144,76 @@ func (c *ToznySDKV3) Register(ctx context.Context, name string, email string, pa return createResponse, nil } +func (c *ToznySDKV3) DeriveAccountCredentials(ctx context.Context, name string, email string, password string, apiURL string) (accountClient.CreateAccountRequest, error) { + if apiURL == "" { + apiURL = DefaultStorageURL + } + const ( + pwEncSalt = "pwEncSalt" + pwAuthSalt = "pwAuthSalt" + pkEncSalt = "pkEncSalt" + pkAuthSalt = "pkAuthSalt" + ) + var createRequest accountClient.CreateAccountRequest + paperKeyRaw := make([]byte, 64) + _, err := rand.Read(paperKeyRaw) + if err != nil { + return createRequest, fmt.Errorf("reading bytes for paper key: %v", err) + } + paperKey := base64.RawURLEncoding.EncodeToString(paperKeyRaw) + + salts := make(map[string][]byte, 4) + for _, name := range []string{pwEncSalt, pwAuthSalt, pkEncSalt, pkAuthSalt} { + salt := make([]byte, e3dbClients.SaltSize) + _, err = rand.Read(salt) + if err != nil { + return createRequest, fmt.Errorf("reading bytes for salt %s: %v", name, err) + } + salts[name] = salt + } + + // Derive keys + pwSigningKey, _ := e3dbClients.DeriveSigningKey([]byte(password), salts[pwAuthSalt], e3dbClients.AccountDerivationRounds) + pkSigningKey, _ := e3dbClients.DeriveSigningKey([]byte(paperKey), salts[pwAuthSalt], e3dbClients.AccountDerivationRounds) + // Generate client keys + encryptionKeypair, err := e3dbClients.GenerateKeyPair() + if err != nil { + return createRequest, fmt.Errorf("Failed generating encryption key pair %s", err) + } + signingKeys, err := e3dbClients.GenerateSigningKeys() + if err != nil { + return createRequest, fmt.Errorf("Failed generating signing key pair %s", err) + } + createRequest = accountClient.CreateAccountRequest{ + Profile: accountClient.Profile{ + Name: email, + Email: email, + AuthenticationSalt: base64.RawURLEncoding.EncodeToString(salts[pwAuthSalt]), + EncodingSalt: base64.RawURLEncoding.EncodeToString(salts[pwEncSalt]), + SigningKey: accountClient.EncryptionKey{ + Ed25519: base64.RawURLEncoding.EncodeToString(pwSigningKey[:]), + }, + PaperAuthenticationSalt: base64.RawURLEncoding.EncodeToString(salts[pkAuthSalt]), + PaperEncodingSalt: base64.RawURLEncoding.EncodeToString(salts[pkEncSalt]), + PaperSigningKey: accountClient.EncryptionKey{ + Ed25519: base64.RawURLEncoding.EncodeToString(pkSigningKey[:]), + }, + }, + Account: accountClient.Account{ + Company: name, + Plan: "free0", + PublicKey: accountClient.ClientKey{ + Curve25519: encryptionKeypair.Public.Material, + }, + SigningKey: accountClient.EncryptionKey{ + Ed25519: signingKeys.Public.Material, + }, + }, + } + + return createRequest, nil +} + // Login derives the needed keys and fetches an active account session func (c *ToznySDKV3) Login(ctx context.Context, email string, password string, salt string, apiEndpoint string) (Account, error) { var account Account diff --git a/go.mod b/go.mod index 400ca97..9b13af2 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/jawher/mow.cli v1.2.0 github.com/mitchellh/go-homedir v1.1.0 github.com/stretchr/testify v1.7.0 // indirect - github.com/tozny/e3db-clients-go v0.0.146 + github.com/tozny/e3db-clients-go v0.0.149 golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c ) diff --git a/go.sum b/go.sum index aaea8af..16b06ea 100644 --- a/go.sum +++ b/go.sum @@ -141,8 +141,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/tozny/e3db-clients-go v0.0.146 h1:pSJKF5W9d/RSVj4QgQylBQIZUT3AWoflQ1t4AMg70Ko= -github.com/tozny/e3db-clients-go v0.0.146/go.mod h1:xqnK5S5r0qLrKCUms5Mi/3oij2ppNg2lk/8iggyn7IQ= +github.com/tozny/e3db-clients-go v0.0.149 h1:BBx0V9H52yfS/9oEk5Q15CDjUb6T6upgkYgbzZbtHDg= +github.com/tozny/e3db-clients-go v0.0.149/go.mod h1:xqnK5S5r0qLrKCUms5Mi/3oij2ppNg2lk/8iggyn7IQ= github.com/tozny/utils-go v0.0.35 h1:gPvhlQ8QCoLBUjIx1COfYy6o4dfSM8Lrh+2FV9Ask+g= github.com/tozny/utils-go v0.0.35/go.mod h1:SHi9wnpPEEzAxbwcBhRd+jW32r+gY6S+AcWweuGytRw= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=