From 9c7ae8d788a0dad32d60557f2c03217b9435361d Mon Sep 17 00:00:00 2001 From: Dovydas Stankevicius Date: Wed, 8 May 2024 17:01:05 +0100 Subject: [PATCH 1/6] feat: added pairIdentifiers service method --- .../sdk/authentication-jwt-bearer/services.ts | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts index bea7b6abc6..14b17909a3 100644 --- a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts +++ b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts @@ -7,6 +7,9 @@ import { AuthType } from './types'; export const NONCE_URL = (env: Env) => `${getEnvUrls(env).authApiUrl}/api/v2/nonce`; +export const PAIR_IDENTIFIERS = (env: Env) => + `${getEnvUrls(env).authApiUrl}/api/v2/identifiers/pair`; + export const OIDC_TOKEN_URL = (env: Env) => `${getEnvUrls(env).oidcApiUrl}/oauth2/token`; @@ -16,6 +19,13 @@ export const SRP_LOGIN_URL = (env: Env) => export const SIWE_LOGIN_URL = (env: Env) => `${getEnvUrls(env).authApiUrl}/api/v2/siwe/login`; +export type Login = { + signature: string; + rawMessage: string; + encryptedStorageKey: string; + identifierType: 'SIWE' | 'SRP'; +}; + const getAuthenticationUrl = (authType: AuthType, env: Env): string => { switch (authType) { case AuthType.SRP: @@ -36,6 +46,60 @@ type NonceResponse = { expiresIn: number; }; +/** + * Pair multiple identifiers under a single profile + * + * @param nonce - request nonce + * @param logins - an array proving the ownership of identifiers + * @param accessToken - JWT access token used to access protected resources + * @param env - server environment + * @returns void. + */ +export async function pairIdentifiers( + nonce: string, + logins: Login[], + accessToken: string, + env: Env, +): Promise { + const pairUrl = new URL(PAIR_IDENTIFIERS(env)); + + // Helper function to convert login fields from camelCase to snake_case + const formatLogin = (login: Login) => { + return { + signature: login.signature, + raw_message: login.rawMessage, + encrypted_storage_key: login.encryptedStorageKey, + identifier_type: login.identifierType, + }; + }; + + try { + const response = await fetch(pairUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${accessToken}`, + }, + body: JSON.stringify({ + nonce, + logins: logins.map((login) => formatLogin(login)), + }), + }); + + if (!response.ok) { + const responseBody = (await response.json()) as ErrorMessage; + throw new Error( + `HTTP error message: ${responseBody.message}, error: ${responseBody.error}`, + ); + } + } catch (e) { + /* istanbul ignore next */ + const errorMessage = + e instanceof Error ? e.message : JSON.stringify(e ?? ''); + throw new SignInError(`unable to pair identifiers: ${errorMessage}`); + } +} + /** * Service to Get Nonce for JWT Bearer Flow * From af401b1c2cf5ed75468a1d46b4d4ed58603e0e00 Mon Sep 17 00:00:00 2001 From: Dovydas Stankevicius Date: Tue, 14 May 2024 14:47:07 +0100 Subject: [PATCH 2/6] feat: added pairIdentifiers method --- .../sdk/authentication-jwt-bearer/services.ts | 32 +++++++----------- .../sdk/authentication-jwt-bearer/types.ts | 6 ++++ .../src/sdk/authentication.ts | 33 ++++++++++++++++++- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts index 14b17909a3..9fd7a77ad6 100644 --- a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts +++ b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts @@ -19,13 +19,6 @@ export const SRP_LOGIN_URL = (env: Env) => export const SIWE_LOGIN_URL = (env: Env) => `${getEnvUrls(env).authApiUrl}/api/v2/siwe/login`; -export type Login = { - signature: string; - rawMessage: string; - encryptedStorageKey: string; - identifierType: 'SIWE' | 'SRP'; -}; - const getAuthenticationUrl = (authType: AuthType, env: Env): string => { switch (authType) { case AuthType.SRP: @@ -46,33 +39,30 @@ type NonceResponse = { expiresIn: number; }; +type PairRequest = { + signature: string; + raw_message: string; + encrypted_storage_key: string; + identifier_type: 'SIWE' | 'SRP'; +}; + /** * Pair multiple identifiers under a single profile * - * @param nonce - request nonce - * @param logins - an array proving the ownership of identifiers + * @param nonce - session nonce + * @param logins - pairing request payload * @param accessToken - JWT access token used to access protected resources * @param env - server environment * @returns void. */ export async function pairIdentifiers( nonce: string, - logins: Login[], + logins: PairRequest[], accessToken: string, env: Env, ): Promise { const pairUrl = new URL(PAIR_IDENTIFIERS(env)); - // Helper function to convert login fields from camelCase to snake_case - const formatLogin = (login: Login) => { - return { - signature: login.signature, - raw_message: login.rawMessage, - encrypted_storage_key: login.encryptedStorageKey, - identifier_type: login.identifierType, - }; - }; - try { const response = await fetch(pairUrl, { method: 'POST', @@ -82,7 +72,7 @@ export async function pairIdentifiers( }, body: JSON.stringify({ nonce, - logins: logins.map((login) => formatLogin(login)), + logins, }), }); diff --git a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/types.ts b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/types.ts index 205b27f1fe..00d9080943 100644 --- a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/types.ts +++ b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/types.ts @@ -70,3 +70,9 @@ export type ErrorMessage = { message: string; error: string; }; + +export type Pair = { + identifier: string; + encryptedStorageKey: string; + identifierType: 'SIWE' | 'SRP'; +}; diff --git a/packages/profile-sync-controller/src/sdk/authentication.ts b/packages/profile-sync-controller/src/sdk/authentication.ts index 9ff671768a..cc01df5dad 100644 --- a/packages/profile-sync-controller/src/sdk/authentication.ts +++ b/packages/profile-sync-controller/src/sdk/authentication.ts @@ -1,7 +1,12 @@ import { SIWEJwtBearerAuth } from './authentication-jwt-bearer/flow-siwe'; import { SRPJwtBearerAuth } from './authentication-jwt-bearer/flow-srp'; -import type { UserProfile } from './authentication-jwt-bearer/types'; +import { + getNonce, + pairIdentifiers, +} from './authentication-jwt-bearer/services'; +import type { UserProfile, Pair } from './authentication-jwt-bearer/types'; import { AuthType } from './authentication-jwt-bearer/types'; +import type { Env } from './env'; import { UnsupportedAuthTypeError } from './errors'; // Computing the Classes, so we only get back the public methods for the interface. @@ -16,10 +21,13 @@ type JwtBearerAuthParams = SiweParams | SRPParams; export class JwtBearerAuth implements SIWEInterface, SRPInterface { #type: AuthType; + #env: Env; + #sdk: SIWEJwtBearerAuth | SRPJwtBearerAuth; constructor(...args: JwtBearerAuthParams) { this.#type = args[0].type; + this.#env = args[0].env; if (args[0].type === AuthType.SRP) { this.#sdk = new SRPJwtBearerAuth(args[0], args[1]); @@ -50,6 +58,29 @@ export class JwtBearerAuth implements SIWEInterface, SRPInterface { return await this.#sdk.signMessage(message); } + async pairIdentifiers( + pairing: Pair[], + signMessage: (message: string) => Promise, + ) { + const profile = await this.getUserProfile(); + const n = await getNonce(profile.profileId, this.#env); + const logins = await Promise.all( + pairing.map(async (p) => { + const raw = `metamask:${n.nonce}:${p.identifier}`; + const sig = await signMessage(raw); + return { + signature: sig, + raw_message: raw, + encrypted_storage_key: p.encryptedStorageKey, + identifier_type: p.identifierType, + }; + }), + ); + + const accessToken = await this.getAccessToken(); + await pairIdentifiers(n.nonce, logins, accessToken, this.#env); + } + prepare(signer: { address: string; chainId: number; From 37401c88c80da5d299f8f857004c7223a3dd5f3f Mon Sep 17 00:00:00 2001 From: Dovydas Stankevicius Date: Tue, 14 May 2024 14:58:19 +0100 Subject: [PATCH 3/6] feat: updated return type definition --- packages/profile-sync-controller/src/sdk/authentication.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/profile-sync-controller/src/sdk/authentication.ts b/packages/profile-sync-controller/src/sdk/authentication.ts index cc01df5dad..e335186a2f 100644 --- a/packages/profile-sync-controller/src/sdk/authentication.ts +++ b/packages/profile-sync-controller/src/sdk/authentication.ts @@ -61,7 +61,7 @@ export class JwtBearerAuth implements SIWEInterface, SRPInterface { async pairIdentifiers( pairing: Pair[], signMessage: (message: string) => Promise, - ) { + ): Promise { const profile = await this.getUserProfile(); const n = await getNonce(profile.profileId, this.#env); const logins = await Promise.all( @@ -78,7 +78,7 @@ export class JwtBearerAuth implements SIWEInterface, SRPInterface { ); const accessToken = await this.getAccessToken(); - await pairIdentifiers(n.nonce, logins, accessToken, this.#env); + return pairIdentifiers(n.nonce, logins, accessToken, this.#env); } prepare(signer: { From 0e43618cea7823c691ca0a90f851c7fa4d66bf45 Mon Sep 17 00:00:00 2001 From: Dovydas Stankevicius Date: Tue, 14 May 2024 16:02:55 +0100 Subject: [PATCH 4/6] feat: adding unit tests --- .../src/sdk/__fixtures__/mock-auth.ts | 17 ++++ .../sdk/authentication-jwt-bearer/services.ts | 9 +- .../src/sdk/authentication.test.ts | 85 ++++++++++++++++++- .../src/sdk/authentication.ts | 1 + .../profile-sync-controller/src/sdk/errors.ts | 7 ++ 5 files changed, 116 insertions(+), 3 deletions(-) diff --git a/packages/profile-sync-controller/src/sdk/__fixtures__/mock-auth.ts b/packages/profile-sync-controller/src/sdk/__fixtures__/mock-auth.ts index f26779434c..557b1aba07 100644 --- a/packages/profile-sync-controller/src/sdk/__fixtures__/mock-auth.ts +++ b/packages/profile-sync-controller/src/sdk/__fixtures__/mock-auth.ts @@ -5,6 +5,7 @@ import { SIWE_LOGIN_URL, SRP_LOGIN_URL, OIDC_TOKEN_URL, + PAIR_IDENTIFIERS, } from '../authentication-jwt-bearer/services'; import { Env } from '../env'; @@ -15,6 +16,7 @@ type MockReply = { const MOCK_NONCE_URL = NONCE_URL(Env.DEV); const MOCK_SIWE_LOGIN_URL = SIWE_LOGIN_URL(Env.DEV); +const MOCK_PAIR_IDENTIFIERS_URL = PAIR_IDENTIFIERS(Env.DEV); const MOCK_SRP_LOGIN_URL = SRP_LOGIN_URL(Env.DEV); const MOCK_OIDC_TOKEN_URL = OIDC_TOKEN_URL(Env.DEV); @@ -83,6 +85,16 @@ export const handleMockSiweLogin = (mockReply?: MockReply) => { return mockLoginEndpoint; }; +export const handleMockPairIdentifiers = (mockReply?: MockReply) => { + const reply = mockReply ?? { status: 204 }; + const mockPairIdentifiersEndpoint = nock(MOCK_PAIR_IDENTIFIERS_URL) + .persist() + .post('') + .reply(reply.status, reply.body); + + return mockPairIdentifiersEndpoint; +}; + export const handleMockSrpLogin = (mockReply?: MockReply) => { const reply = mockReply ?? { status: 200, body: MOCK_SRP_LOGIN_RESPONSE }; const mockLoginEndpoint = nock(MOCK_SRP_LOGIN_URL) @@ -108,16 +120,21 @@ export const arrangeAuthAPIs = (options?: { mockOAuth2TokenUrl?: MockReply; mockSrpLoginUrl?: MockReply; mockSiweLoginUrl?: MockReply; + mockPairIdentifiers?: MockReply; }) => { const mockNonceUrl = handleMockNonce(options?.mockNonceUrl); const mockOAuth2TokenUrl = handleMockOAuth2Token(options?.mockOAuth2TokenUrl); const mockSrpLoginUrl = handleMockSrpLogin(options?.mockSrpLoginUrl); const mockSiweLoginUrl = handleMockSiweLogin(options?.mockSiweLoginUrl); + const mockPairIdentifiersUrl = handleMockPairIdentifiers( + options?.mockPairIdentifiers, + ); return { mockNonceUrl, mockOAuth2TokenUrl, mockSrpLoginUrl, mockSiweLoginUrl, + mockPairIdentifiersUrl, }; }; diff --git a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts index 9fd7a77ad6..b46acc2499 100644 --- a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts +++ b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/services.ts @@ -1,6 +1,11 @@ import type { Env } from '../env'; import { getEnvUrls, getOidcClientId } from '../env'; -import { NonceRetrievalError, SignInError, ValidationError } from '../errors'; +import { + NonceRetrievalError, + PairError, + SignInError, + ValidationError, +} from '../errors'; import type { AccessToken, ErrorMessage, UserProfile } from './types'; import { AuthType } from './types'; @@ -86,7 +91,7 @@ export async function pairIdentifiers( /* istanbul ignore next */ const errorMessage = e instanceof Error ? e.message : JSON.stringify(e ?? ''); - throw new SignInError(`unable to pair identifiers: ${errorMessage}`); + throw new PairError(`unable to pair identifiers: ${errorMessage}`); } } diff --git a/packages/profile-sync-controller/src/sdk/authentication.test.ts b/packages/profile-sync-controller/src/sdk/authentication.test.ts index e1a71c2a12..64bf17bfcd 100644 --- a/packages/profile-sync-controller/src/sdk/authentication.test.ts +++ b/packages/profile-sync-controller/src/sdk/authentication.test.ts @@ -6,10 +6,11 @@ import { import type { MockVariable } from './__fixtures__/test-utils'; import { arrangeAuth } from './__fixtures__/test-utils'; import { JwtBearerAuth } from './authentication'; -import type { LoginResponse } from './authentication-jwt-bearer/types'; +import type { LoginResponse, Pair } from './authentication-jwt-bearer/types'; import { Env } from './env'; import { NonceRetrievalError, + PairError, SignInError, UnsupportedAuthTypeError, ValidationError, @@ -19,6 +20,88 @@ import * as Eip6963MetamaskProvider from './utils/eip-6963-metamask-provider'; const MOCK_SRP = '0x6265617665726275696c642e6f7267'; const MOCK_ADDRESS = '0x68757d15a4d8d1421c17003512AFce15D3f3FaDa'; +describe('Identifier Pairing', () => { + it('should pair identifiers', async () => { + const { auth, mockSignMessage } = arrangeAuth('SRP', MOCK_SRP); + const { mockNonceUrl, mockPairIdentifiersUrl, mockSrpLoginUrl } = + arrangeAuthAPIs(); + + const pairing: Pair[] = [ + { + encryptedStorageKey: 'encrypted', + identifier: + '0xc89a614e873c2c1f08fc8d72590e13c961ea856cc7a9cd08af4bf3d3fca53046', + identifierType: 'SRP', + }, + ]; + await auth.pairIdentifiers(pairing, mockSignMessage); + + // API + expect(mockSrpLoginUrl.isDone()).toBe(true); + expect(mockNonceUrl.isDone()).toBe(true); + expect(mockPairIdentifiersUrl.isDone()).toBe(true); + }); + + it('should handle pair identifiers errors', async () => { + const { auth, mockSignMessage } = arrangeAuth('SRP', MOCK_SRP); + const { mockNonceUrl, mockPairIdentifiersUrl, mockSrpLoginUrl } = + arrangeAuthAPIs({ + mockPairIdentifiers: { + status: 401, + body: { + message: 'invalid pair signature', + error: 'invalid-pair-request', + }, + }, + }); + + const pairing: Pair[] = [ + { + encryptedStorageKey: 'encrypted', + identifier: + '0xc89a614e873c2c1f08fc8d72590e13c961ea856cc7a9cd08af4bf3d3fca11111', + identifierType: 'SRP', + }, + ]; + + await expect( + auth.pairIdentifiers(pairing, mockSignMessage), + ).rejects.toThrow(PairError); + + // API + expect(mockSrpLoginUrl.isDone()).toBe(true); + expect(mockNonceUrl.isDone()).toBe(true); + expect(mockPairIdentifiersUrl.isDone()).toBe(true); + }); + + it('should handle nonce errors', async () => { + const { auth, mockSignMessage } = arrangeAuth('SRP', MOCK_SRP); + + const { mockNonceUrl, mockPairIdentifiersUrl } = arrangeAuthAPIs({ + mockNonceUrl: { + status: 400, + body: { message: 'invalid identifier', error: 'validation-error' }, + }, + }); + + const pairing: Pair[] = [ + { + encryptedStorageKey: 'encrypted', + identifier: '0x12345', + identifierType: 'SRP', + }, + ]; + + await expect( + auth.pairIdentifiers(pairing, mockSignMessage), + ).rejects.toThrow(NonceRetrievalError); + + // API + expect(mockNonceUrl.isDone()).toBe(true); + expect(mockPairIdentifiersUrl.isDone()).toBe(false); + }); +}); + describe('Authentication - constructor()', () => { it('errors on invalid auth type', async () => { expect(() => { diff --git a/packages/profile-sync-controller/src/sdk/authentication.ts b/packages/profile-sync-controller/src/sdk/authentication.ts index e335186a2f..d26c0ef153 100644 --- a/packages/profile-sync-controller/src/sdk/authentication.ts +++ b/packages/profile-sync-controller/src/sdk/authentication.ts @@ -63,6 +63,7 @@ export class JwtBearerAuth implements SIWEInterface, SRPInterface { signMessage: (message: string) => Promise, ): Promise { const profile = await this.getUserProfile(); + const n = await getNonce(profile.profileId, this.#env); const logins = await Promise.all( pairing.map(async (p) => { diff --git a/packages/profile-sync-controller/src/sdk/errors.ts b/packages/profile-sync-controller/src/sdk/errors.ts index 10531a3e11..40ce5bc778 100644 --- a/packages/profile-sync-controller/src/sdk/errors.ts +++ b/packages/profile-sync-controller/src/sdk/errors.ts @@ -12,6 +12,13 @@ export class SignInError extends Error { } } +export class PairError extends Error { + constructor(message: string) { + super(message); + this.name = 'PairError'; + } +} + export class UserStorageError extends Error { constructor(message: string) { super(message); From 99351ccd8f59559e747bfcc8de5e51844832ab62 Mon Sep 17 00:00:00 2001 From: Dovydas Stankevicius Date: Tue, 14 May 2024 16:26:55 +0100 Subject: [PATCH 5/6] feat: added sign method to pairing object --- .../sdk/authentication-jwt-bearer/types.ts | 1 + .../src/sdk/authentication.test.ts | 44 +++++++++++++++---- .../src/sdk/authentication.ts | 34 ++++++++------ 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/types.ts b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/types.ts index 00d9080943..66aef881ba 100644 --- a/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/types.ts +++ b/packages/profile-sync-controller/src/sdk/authentication-jwt-bearer/types.ts @@ -75,4 +75,5 @@ export type Pair = { identifier: string; encryptedStorageKey: string; identifierType: 'SIWE' | 'SRP'; + signMessage: (message: string) => Promise; }; diff --git a/packages/profile-sync-controller/src/sdk/authentication.test.ts b/packages/profile-sync-controller/src/sdk/authentication.test.ts index 64bf17bfcd..e09e5043e2 100644 --- a/packages/profile-sync-controller/src/sdk/authentication.test.ts +++ b/packages/profile-sync-controller/src/sdk/authentication.test.ts @@ -32,9 +32,10 @@ describe('Identifier Pairing', () => { identifier: '0xc89a614e873c2c1f08fc8d72590e13c961ea856cc7a9cd08af4bf3d3fca53046', identifierType: 'SRP', + signMessage: mockSignMessage, }, ]; - await auth.pairIdentifiers(pairing, mockSignMessage); + await auth.pairIdentifiers(pairing); // API expect(mockSrpLoginUrl.isDone()).toBe(true); @@ -42,7 +43,7 @@ describe('Identifier Pairing', () => { expect(mockPairIdentifiersUrl.isDone()).toBe(true); }); - it('should handle pair identifiers errors', async () => { + it('should handle pair identifiers API errors', async () => { const { auth, mockSignMessage } = arrangeAuth('SRP', MOCK_SRP); const { mockNonceUrl, mockPairIdentifiersUrl, mockSrpLoginUrl } = arrangeAuthAPIs({ @@ -61,12 +62,11 @@ describe('Identifier Pairing', () => { identifier: '0xc89a614e873c2c1f08fc8d72590e13c961ea856cc7a9cd08af4bf3d3fca11111', identifierType: 'SRP', + signMessage: mockSignMessage, }, ]; - await expect( - auth.pairIdentifiers(pairing, mockSignMessage), - ).rejects.toThrow(PairError); + await expect(auth.pairIdentifiers(pairing)).rejects.toThrow(PairError); // API expect(mockSrpLoginUrl.isDone()).toBe(true); @@ -74,6 +74,33 @@ describe('Identifier Pairing', () => { expect(mockPairIdentifiersUrl.isDone()).toBe(true); }); + it('should handle sign message errors', async () => { + const { auth } = arrangeAuth('SRP', MOCK_SRP); + const { mockNonceUrl, mockPairIdentifiersUrl, mockSrpLoginUrl } = + arrangeAuthAPIs(); + + const pairing: Pair[] = [ + { + encryptedStorageKey: 'encrypted', + identifier: + '0xc89a614e873c2c1f08fc8d72590e13c961ea856cc7a9cd08af4bf3d3fca11111', + identifierType: 'SRP', + signMessage: async (message: string): Promise => { + return new Promise((_, reject) => { + reject(new Error(`unable to sign message: ${message}`)); + }); + }, + }, + ]; + + await expect(auth.pairIdentifiers(pairing)).rejects.toThrow(PairError); + + // API + expect(mockSrpLoginUrl.isDone()).toBe(true); + expect(mockNonceUrl.isDone()).toBe(true); + expect(mockPairIdentifiersUrl.isDone()).toBe(false); + }); + it('should handle nonce errors', async () => { const { auth, mockSignMessage } = arrangeAuth('SRP', MOCK_SRP); @@ -89,12 +116,13 @@ describe('Identifier Pairing', () => { encryptedStorageKey: 'encrypted', identifier: '0x12345', identifierType: 'SRP', + signMessage: mockSignMessage, }, ]; - await expect( - auth.pairIdentifiers(pairing, mockSignMessage), - ).rejects.toThrow(NonceRetrievalError); + await expect(auth.pairIdentifiers(pairing)).rejects.toThrow( + NonceRetrievalError, + ); // API expect(mockNonceUrl.isDone()).toBe(true); diff --git a/packages/profile-sync-controller/src/sdk/authentication.ts b/packages/profile-sync-controller/src/sdk/authentication.ts index d26c0ef153..49550c2c8b 100644 --- a/packages/profile-sync-controller/src/sdk/authentication.ts +++ b/packages/profile-sync-controller/src/sdk/authentication.ts @@ -7,7 +7,7 @@ import { import type { UserProfile, Pair } from './authentication-jwt-bearer/types'; import { AuthType } from './authentication-jwt-bearer/types'; import type { Env } from './env'; -import { UnsupportedAuthTypeError } from './errors'; +import { PairError, UnsupportedAuthTypeError } from './errors'; // Computing the Classes, so we only get back the public methods for the interface. type Compute = T extends infer U ? { [K in keyof U]: U[K] } : never; @@ -58,23 +58,29 @@ export class JwtBearerAuth implements SIWEInterface, SRPInterface { return await this.#sdk.signMessage(message); } - async pairIdentifiers( - pairing: Pair[], - signMessage: (message: string) => Promise, - ): Promise { + async pairIdentifiers(pairing: Pair[]): Promise { const profile = await this.getUserProfile(); - const n = await getNonce(profile.profileId, this.#env); + const logins = await Promise.all( pairing.map(async (p) => { - const raw = `metamask:${n.nonce}:${p.identifier}`; - const sig = await signMessage(raw); - return { - signature: sig, - raw_message: raw, - encrypted_storage_key: p.encryptedStorageKey, - identifier_type: p.identifierType, - }; + try { + const raw = `metamask:${n.nonce}:${p.identifier}`; + const sig = await p.signMessage(raw); + return { + signature: sig, + raw_message: raw, + encrypted_storage_key: p.encryptedStorageKey, + identifier_type: p.identifierType, + }; + } catch (e) { + /* istanbul ignore next */ + const errorMessage = + e instanceof Error ? e.message : JSON.stringify(e ?? ''); + throw new PairError( + `failed to sign pairing message: ${errorMessage}`, + ); + } }), ); From 9db6bb031edbe8c0b631af07ad5d40ffd54e64c7 Mon Sep 17 00:00:00 2001 From: Dovydas Stankevicius Date: Wed, 15 May 2024 10:58:09 +0100 Subject: [PATCH 6/6] feat: awaiting for pairIdentifiers --- packages/profile-sync-controller/src/sdk/authentication.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/profile-sync-controller/src/sdk/authentication.ts b/packages/profile-sync-controller/src/sdk/authentication.ts index 49550c2c8b..d3cf10ace8 100644 --- a/packages/profile-sync-controller/src/sdk/authentication.ts +++ b/packages/profile-sync-controller/src/sdk/authentication.ts @@ -85,7 +85,7 @@ export class JwtBearerAuth implements SIWEInterface, SRPInterface { ); const accessToken = await this.getAccessToken(); - return pairIdentifiers(n.nonce, logins, accessToken, this.#env); + await pairIdentifiers(n.nonce, logins, accessToken, this.#env); } prepare(signer: {