From 264641d1008657e464e3af9df4762aee06d6e824 Mon Sep 17 00:00:00 2001 From: lwin Date: Tue, 13 May 2025 13:09:59 +0800 Subject: [PATCH 1/6] feat: update metadata class to support multiple secret types --- .../src/SecretMetadata.ts | 202 ++++++++++++++++++ .../src/SeedPhraseMetadata.ts | 181 ---------------- .../src/SeedlessOnboardingController.ts | 10 +- .../src/constants.ts | 7 +- .../src/types.ts | 15 ++ 5 files changed, 230 insertions(+), 185 deletions(-) create mode 100644 packages/seedless-onboarding-controller/src/SecretMetadata.ts delete mode 100644 packages/seedless-onboarding-controller/src/SeedPhraseMetadata.ts diff --git a/packages/seedless-onboarding-controller/src/SecretMetadata.ts b/packages/seedless-onboarding-controller/src/SecretMetadata.ts new file mode 100644 index 00000000000..1df2fcfa760 --- /dev/null +++ b/packages/seedless-onboarding-controller/src/SecretMetadata.ts @@ -0,0 +1,202 @@ +import { + base64ToBytes, + bytesToBase64, + stringToBytes, + bytesToString, +} from '@metamask/utils'; + +import { SeedlessOnboardingControllerError, SecretType } from './constants'; +import type { SecretMetadataOptions } from './types'; + +type ISecretMetadata = { + data: Uint8Array; + timestamp: number; + toBytes: () => Uint8Array; +}; + +// SecretMetadata type without the data and toBytes methods +// in which the data is base64 encoded for more compacted metadata +type IBase64SecretMetadata = Omit & { + data: string; // base64 encoded string +}; + +/** + * SecretMetadata is a class that adds metadata to the secret. + * + * It contains the secret and the timestamp when it was created. + * It is used to store the secret in the metadata store. + * + * @example + * ```ts + * const secretMetadata = new SecretMetadata(secret); + * ``` + */ +export class SecretMetadata implements ISecretMetadata { + readonly #secret: Uint8Array; + + readonly #timestamp: number; + + readonly #type: SecretType; + + /** + * Create a new SecretMetadata instance. + * + * @param secret - The secret to add metadata to. + * @param options - The options for the secret metadata. + * @param options.timestamp - The timestamp when the secret was created. + * @param options.type - The type of the secret. + */ + constructor(secret: Uint8Array, options?: Partial) { + this.#secret = secret; + this.#timestamp = options?.timestamp ?? Date.now(); + this.#type = options?.type ?? SecretType.Mnemonic; + } + + /** + * Create an Array of SecretMetadata instances from an array of secrets. + * + * To respect the order of the secrets, we add the index to the timestamp + * so that the first secret backup will have the oldest timestamp + * and the last secret backup will have the newest timestamp. + * + * @param data - The data to add metadata to. + * @param data.value - The SeedPhrase/PrivateKey to add metadata to. + * @param data.options - The options for the seed phrase metadata. + * @returns The SecretMetadata instances. + */ + static fromBatch( + data: { + value: Uint8Array; + options?: Partial; + }[], + ): SecretMetadata[] { + const timestamp = Date.now(); + return data.map((d, index) => { + // To respect the order of the seed phrases, we add the index to the timestamp + // so that the first seed phrase backup will have the oldest timestamp + // and the last seed phrase backup will have the newest timestamp + const backupCreatedAt = d.options?.timestamp ?? timestamp + index * 5; + return new SecretMetadata(d.value, { + timestamp: backupCreatedAt, + type: d.options?.type, + }); + }); + } + + /** + * Assert that the provided value is a valid seed phrase metadata. + * + * @param value - The value to check. + * @throws If the value is not a valid seed phrase metadata. + */ + static assertIsBase64SecretMetadata( + value: unknown, + ): asserts value is IBase64SecretMetadata { + if ( + typeof value !== 'object' || + !value || + !('data' in value) || + typeof value.data !== 'string' || + !('timestamp' in value) || + typeof value.timestamp !== 'number' + ) { + throw new Error(SeedlessOnboardingControllerError.InvalidSecretMetadata); + } + } + + /** + * Parse the SecretMetadata from the metadata store and return the array of SecretMetadata instances. + * + * This method also sorts the secrets by timestamp in ascending order, i.e. the oldest secret will be the first element in the array. + * + * @param secretMetadataArr - The array of SecretMetadata from the metadata store. + * @returns The array of SecretMetadata instances. + */ + static parseSecretsFromMetadataStore( + secretMetadataArr: Uint8Array[], + ): SecretMetadata[] { + const parsedSecertMetadata = secretMetadataArr.map((metadata) => + SecretMetadata.fromRawMetadata(metadata), + ); + + const secrets = SecretMetadata.sort(parsedSecertMetadata); + + return secrets; + } + + /** + * Parse and create the SecretMetadata instance from the raw metadata. + * + * @param rawMetadata - The raw metadata. + * @param type - The type of the secret. + * @returns The parsed secret metadata. + */ + static fromRawMetadata( + rawMetadata: Uint8Array, + type: SecretType = SecretType.Mnemonic, + ): SecretMetadata { + const serializedMetadata = bytesToString(rawMetadata); + const parsedMetadata = JSON.parse(serializedMetadata); + + SecretMetadata.assertIsBase64SecretMetadata(parsedMetadata); + + const bytes = base64ToBytes(parsedMetadata.data); + return new SecretMetadata(bytes, { + timestamp: parsedMetadata.timestamp, + type, + }); + } + + /** + * Sort the seed phrases by timestamp. + * + * @param secrets - The seed phrases to sort. + * @param order - The order to sort the seed phrases. Default is `desc`. + * + * @returns The sorted seed phrases. + */ + static sort( + secrets: SecretMetadata[], + order: 'asc' | 'desc' = 'asc', + ): SecretMetadata[] { + return secrets.sort((a, b) => { + if (order === 'asc') { + return a.timestamp - b.timestamp; + } + return b.timestamp - a.timestamp; + }); + } + + get data() { + return this.#secret; + } + + get timestamp() { + return this.#timestamp; + } + + get type() { + return this.#type; + } + + /** + * Serialize the secret metadata and convert it to a Uint8Array. + * + * @returns The serialized SecretMetadata value in bytes. + */ + toBytes(): Uint8Array { + // encode the raw secret to base64 encoded string + // to create more compacted metadata + const b64Data = bytesToBase64(this.#secret); + + // serialize the metadata to a JSON string + const serializedMetadata = JSON.stringify({ + data: b64Data, + timestamp: this.#timestamp, + type: this.#type, + }); + + // convert the serialized metadata to bytes(Uint8Array) + return stringToBytes(serializedMetadata); + } +} diff --git a/packages/seedless-onboarding-controller/src/SeedPhraseMetadata.ts b/packages/seedless-onboarding-controller/src/SeedPhraseMetadata.ts deleted file mode 100644 index d932d15fd81..00000000000 --- a/packages/seedless-onboarding-controller/src/SeedPhraseMetadata.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { - base64ToBytes, - bytesToBase64, - stringToBytes, - bytesToString, -} from '@metamask/utils'; - -import { SeedlessOnboardingControllerError } from './constants'; - -type ISeedPhraseMetadata = { - seedPhrase: Uint8Array; - timestamp: number; - toBytes: () => Uint8Array; -}; - -// SeedPhraseMetadata type without the seedPhrase and toBytes methods -// in which the seedPhrase is base64 encoded for more compacted metadata -type IBase64SeedPhraseMetadata = Omit< - ISeedPhraseMetadata, - 'seedPhrase' | 'toBytes' -> & { - seedPhrase: string; // base64 encoded string -}; - -/** - * SeedPhraseMetadata is a class that adds metadata to the seed phrase. - * - * It contains the seed phrase and the timestamp when it was created. - * It is used to store the seed phrase in the metadata store. - * - * @example - * ```ts - * const seedPhraseMetadata = new SeedPhraseMetadata(seedPhrase); - * ``` - */ -export class SeedPhraseMetadata implements ISeedPhraseMetadata { - readonly #seedPhrase: Uint8Array; - - readonly #timestamp: number; - - /** - * Create a new SeedPhraseMetadata instance. - * - * @param seedPhrase - The seed phrase to add metadata to. - * @param timestamp - The timestamp when the seed phrase was created. - */ - constructor(seedPhrase: Uint8Array, timestamp: number = Date.now()) { - this.#seedPhrase = seedPhrase; - this.#timestamp = timestamp; - } - - /** - * Create an Array of SeedPhraseMetadata instances from an array of seed phrases. - * - * To respect the order of the seed phrases, we add the index to the timestamp - * so that the first seed phrase backup will have the oldest timestamp - * and the last seed phrase backup will have the newest timestamp. - * - * @param seedPhrases - The seed phrases to add metadata to. - * @returns The SeedPhraseMetadata instances. - */ - static fromBatchSeedPhrases(seedPhrases: Uint8Array[]): SeedPhraseMetadata[] { - const timestamp = Date.now(); - return seedPhrases.map((seedPhrase, index) => { - // To respect the order of the seed phrases, we add the index to the timestamp - // so that the first seed phrase backup will have the oldest timestamp - // and the last seed phrase backup will have the newest timestamp - const backupCreatedAt = timestamp + index * 5; - return new SeedPhraseMetadata(seedPhrase, backupCreatedAt); - }); - } - - /** - * Assert that the provided value is a valid seed phrase metadata. - * - * @param value - The value to check. - * @throws If the value is not a valid seed phrase metadata. - */ - static assertIsBase64SeedphraseMetadata( - value: unknown, - ): asserts value is IBase64SeedPhraseMetadata { - if ( - typeof value !== 'object' || - !value || - !('seedPhrase' in value) || - typeof value.seedPhrase !== 'string' || - !('timestamp' in value) || - typeof value.timestamp !== 'number' - ) { - throw new Error( - SeedlessOnboardingControllerError.InvalidSeedPhraseMetadata, - ); - } - } - - /** - * Parse the seed phrase metadata from the metadata store and return the array of raw seed phrases. - * - * This method also sorts the seed phrases by timestamp in ascending order, i.e. the oldest seed phrase will be the first element in the array. - * - * @param seedPhraseMetadataArr - The array of SeedPhrase Metadata from the metadata store. - * @returns The array of raw seed phrases. - */ - static parseSeedPhraseFromMetadataStore( - seedPhraseMetadataArr: Uint8Array[], - ): Uint8Array[] { - const parsedSeedPhraseMetadata = seedPhraseMetadataArr.map((metadata) => - SeedPhraseMetadata.fromRawMetadata(metadata), - ); - - const seedPhrases = SeedPhraseMetadata.sort(parsedSeedPhraseMetadata); - - return seedPhrases.map( - (seedPhraseMetadata) => seedPhraseMetadata.seedPhrase, - ); - } - - /** - * Parse and create the SeedPhraseMetadata instance from the raw metadata. - * - * @param rawMetadata - The raw metadata. - * @returns The parsed seed phrase metadata. - */ - static fromRawMetadata(rawMetadata: Uint8Array): SeedPhraseMetadata { - const serializedMetadata = bytesToString(rawMetadata); - const parsedMetadata = JSON.parse(serializedMetadata); - - SeedPhraseMetadata.assertIsBase64SeedphraseMetadata(parsedMetadata); - - const seedPhraseBytes = base64ToBytes(parsedMetadata.seedPhrase); - return new SeedPhraseMetadata(seedPhraseBytes, parsedMetadata.timestamp); - } - - /** - * Sort the seed phrases by timestamp. - * - * @param seedPhrases - The seed phrases to sort. - * @param order - The order to sort the seed phrases. Default is `desc`. - * - * @returns The sorted seed phrases. - */ - static sort( - seedPhrases: SeedPhraseMetadata[], - order: 'asc' | 'desc' = 'asc', - ): SeedPhraseMetadata[] { - return seedPhrases.sort((a, b) => { - if (order === 'asc') { - return a.timestamp - b.timestamp; - } - return b.timestamp - a.timestamp; - }); - } - - get seedPhrase() { - return this.#seedPhrase; - } - - get timestamp() { - return this.#timestamp; - } - - /** - * Serialize the seed phrase metadata and convert it to a Uint8Array. - * - * @returns The serialized SeedPhraseMetadata value in bytes. - */ - toBytes(): Uint8Array { - // encode the raw SeedPhrase to base64 encoded string - // to create more compacted metadata - const b64SeedPhrase = bytesToBase64(this.#seedPhrase); - - // serialize the metadata to a JSON string - const serializedMetadata = JSON.stringify({ - seedPhrase: b64SeedPhrase, - timestamp: this.#timestamp, - }); - - // convert the serialized metadata to bytes(Uint8Array) - return stringToBytes(serializedMetadata); - } -} diff --git a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.ts b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.ts index bb083a43f9d..e3f4aa3c2c5 100644 --- a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.ts +++ b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.ts @@ -19,12 +19,13 @@ import { Mutex } from 'async-mutex'; import { type AuthConnection, controllerName, + SecretType, SeedlessOnboardingControllerError, Web3AuthNetwork, } from './constants'; import { RecoveryError } from './errors'; import { projectLogger, createModuleLogger } from './logger'; -import { SeedPhraseMetadata } from './SeedPhraseMetadata'; +import { SecretMetadata } from './SecretMetadata'; import type { MutuallyExclusiveCallback, SeedlessOnboardingControllerMessenger, @@ -313,7 +314,10 @@ export class SeedlessOnboardingController extends BaseController< }); } - return SeedPhraseMetadata.parseSeedPhraseFromMetadataStore(secretData); + const secrets = SecretMetadata.parseSecretsFromMetadataStore(secretData); + return secrets + .filter((secret) => secret.type === SecretType.Mnemonic) + .map((secret) => secret.data); } catch (error) { log('Error fetching seed phrase metadata', error); throw new Error( @@ -550,7 +554,7 @@ export class SeedlessOnboardingController extends BaseController< try { const { keyringId, seedPhrase, encKey, authKeyPair } = params; - const seedPhraseMetadata = new SeedPhraseMetadata(seedPhrase); + const seedPhraseMetadata = new SecretMetadata(seedPhrase); const secretData = seedPhraseMetadata.toBytes(); await this.#withPersistedSeedPhraseBackupsState(async () => { await this.toprfClient.addSecretDataItem({ diff --git a/packages/seedless-onboarding-controller/src/constants.ts b/packages/seedless-onboarding-controller/src/constants.ts index df26d8a55c5..c58cec354bd 100644 --- a/packages/seedless-onboarding-controller/src/constants.ts +++ b/packages/seedless-onboarding-controller/src/constants.ts @@ -11,6 +11,11 @@ export enum AuthConnection { Apple = 'apple', } +export enum SecretType { + Mnemonic = 'mnemonic', + PrivateKey = 'privateKey', +} + export enum SeedlessOnboardingControllerError { ControllerLocked = `${controllerName} - The operation cannot be completed while the controller is locked.`, AuthenticationError = `${controllerName} - Authentication error`, @@ -25,7 +30,7 @@ export enum SeedlessOnboardingControllerError { InvalidVaultData = `${controllerName} - Invalid vault data`, VaultDataError = `${controllerName} - The decrypted vault has an unexpected shape.`, VaultError = `${controllerName} - Cannot unlock without a previous vault.`, - InvalidSeedPhraseMetadata = `${controllerName} - Invalid seed phrase metadata`, + InvalidSecretMetadata = `${controllerName} - Invalid secret metadata`, FailedToEncryptAndStoreSeedPhraseBackup = `${controllerName} - Failed to encrypt and store seed phrase backup`, FailedToFetchSeedPhraseMetadata = `${controllerName} - Failed to fetch seed phrase metadata`, FailedToChangePassword = `${controllerName} - Failed to change password`, diff --git a/packages/seedless-onboarding-controller/src/types.ts b/packages/seedless-onboarding-controller/src/types.ts index 052bd920163..d9d833e4ec7 100644 --- a/packages/seedless-onboarding-controller/src/types.ts +++ b/packages/seedless-onboarding-controller/src/types.ts @@ -12,6 +12,7 @@ import type { MutexInterface } from 'async-mutex'; import type { AuthConnection, controllerName, + SecretType, Web3AuthNetwork, } from './constants'; @@ -181,3 +182,17 @@ export type VaultData = { */ toprfAuthKeyPair: string; }; + +/** + * The constructor options for the seed phrase metadata. + */ +export type SecretMetadataOptions = { + /** + * The timestamp when the seed phrase was created. + */ + timestamp: number; + /** + * The type of the seed phrase. + */ + type: SecretType; +}; From fd81fc49a407ead8fb4ce8e5b7b8ba3138153813 Mon Sep 17 00:00:00 2001 From: lwin Date: Tue, 13 May 2025 13:10:05 +0800 Subject: [PATCH 2/6] test: updated tests --- .../seedless-onboarding-controller.tgz | Bin 50686 -> 51318 bytes .../src/SeedlessOnboardingController.test.ts | 71 ++++++++++-------- .../tests/mocks/toprf.ts | 14 ++-- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/packages/seedless-onboarding-controller/seedless-onboarding-controller.tgz b/packages/seedless-onboarding-controller/seedless-onboarding-controller.tgz index 7dc85b7aa655af1a3ad02cfa628b53c453f2ff19..2cc948fd3a6536ac68b99e8efa6361f2e719cef7 100644 GIT binary patch delta 48841 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

m#qA!wGtO;*QiOf^ixZz8HGoKE@4z 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≤bX!EkAa)6v6uJs-U^t%`CXqdH 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 IOBjg%11X9#00000 diff --git a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts index 294685f7109..e1e7bda7372 100644 --- a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts +++ b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts @@ -24,13 +24,14 @@ import { Web3AuthNetwork, SeedlessOnboardingControllerError, AuthConnection, + SecretType, } from './constants'; import { RecoveryError } from './errors'; +import { SecretMetadata } from './SecretMetadata'; import { getDefaultSeedlessOnboardingControllerState, SeedlessOnboardingController, } from './SeedlessOnboardingController'; -import { SeedPhraseMetadata } from './SeedPhraseMetadata'; import type { AllowedActions, AllowedEvents, @@ -48,7 +49,7 @@ import { } from '../tests/__fixtures__/topfClient'; import { createMockSecretDataGetResponse, - MULTIPLE_MOCK_SEEDPHRASE_METADATA, + MULTIPLE_MOCK_SECRET_METADATA, } from '../tests/mocks/toprf'; import { MockToprfEncryptorDecryptor } from '../tests/mocks/toprfEncryptor'; import MockVaultEncryptor from '../tests/mocks/vaultEncryptor'; @@ -1263,7 +1264,7 @@ describe('SeedlessOnboardingController', () => { const mockSecretDataGet = handleMockSecretDataGet({ status: 200, body: createMockSecretDataGetResponse( - MULTIPLE_MOCK_SEEDPHRASE_METADATA, + MULTIPLE_MOCK_SECRET_METADATA, MOCK_PASSWORD, ), }); @@ -2117,29 +2118,43 @@ describe('SeedlessOnboardingController', () => { }); describe('SeedPhraseMetadata', () => { - it('should be able to create a seed phrase metadata', () => { + it('should be able to create a seed phrase metadata with default options', () => { // should be able to create a SeedPhraseMetadata instance via constructor - const seedPhraseMetadata = new SeedPhraseMetadata(MOCK_SEED_PHRASE); - expect(seedPhraseMetadata.seedPhrase).toBeDefined(); + const seedPhraseMetadata = new SecretMetadata(MOCK_SEED_PHRASE); + expect(seedPhraseMetadata.data).toBeDefined(); expect(seedPhraseMetadata.timestamp).toBeDefined(); // should be able to create a SeedPhraseMetadata instance with a timestamp via constructor const timestamp = 18_000; - const seedPhraseMetadata2 = new SeedPhraseMetadata( - MOCK_SEED_PHRASE, + const seedPhraseMetadata2 = new SecretMetadata(MOCK_SEED_PHRASE, { timestamp, - ); - expect(seedPhraseMetadata2.seedPhrase).toBeDefined(); + }); + expect(seedPhraseMetadata2.data).toBeDefined(); expect(seedPhraseMetadata2.timestamp).toBe(timestamp); - expect(seedPhraseMetadata2.seedPhrase).toStrictEqual(MOCK_SEED_PHRASE); + expect(seedPhraseMetadata2.data).toStrictEqual(MOCK_SEED_PHRASE); + expect(seedPhraseMetadata2.type).toBe(SecretType.Mnemonic); + }); + + it('should be able to add metadata to a seed phrase', () => { + const timestamp = 18_000; + const seedPhraseMetadata = new SecretMetadata(MOCK_SEED_PHRASE, { + type: SecretType.PrivateKey, + timestamp, + }); + expect(seedPhraseMetadata.type).toBe(SecretType.PrivateKey); + expect(seedPhraseMetadata.timestamp).toBe(timestamp); }); it('should be able to correctly create `SeedPhraseMetadata` Array for batch seedphrases', () => { const seedPhrases = ['seed phrase 1', 'seed phrase 2', 'seed phrase 3']; - const rawSeedPhrases = seedPhrases.map(stringToBytes); + const rawSeedPhrases = seedPhrases.map((srp) => ({ + value: stringToBytes(srp), + options: { + type: SecretType.Mnemonic, + }, + })); - const seedPhraseMetadataArray = - SeedPhraseMetadata.fromBatchSeedPhrases(rawSeedPhrases); + const seedPhraseMetadataArray = SecretMetadata.fromBatch(rawSeedPhrases); expect(seedPhraseMetadataArray).toHaveLength(seedPhrases.length); // check the timestamp, the first one should be the oldest @@ -2152,31 +2167,27 @@ describe('SeedlessOnboardingController', () => { }); it('should be able to serialized and parse a seed phrase metadata', () => { - const seedPhraseMetadata = new SeedPhraseMetadata(MOCK_SEED_PHRASE); + const seedPhraseMetadata = new SecretMetadata(MOCK_SEED_PHRASE); const serializedSeedPhraseBytes = seedPhraseMetadata.toBytes(); - const parsedSeedPhraseMetadata = SeedPhraseMetadata.fromRawMetadata( + const parsedSeedPhraseMetadata = SecretMetadata.fromRawMetadata( serializedSeedPhraseBytes, ); - expect(parsedSeedPhraseMetadata.seedPhrase).toBeDefined(); + expect(parsedSeedPhraseMetadata.data).toBeDefined(); expect(parsedSeedPhraseMetadata.timestamp).toBeDefined(); - expect(parsedSeedPhraseMetadata.seedPhrase).toStrictEqual( - MOCK_SEED_PHRASE, - ); + expect(parsedSeedPhraseMetadata.data).toStrictEqual(MOCK_SEED_PHRASE); }); it('should be able to sort seed phrase metadata', () => { - const mockSeedPhraseMetadata1 = new SeedPhraseMetadata( - MOCK_SEED_PHRASE, - 1000, - ); - const mockSeedPhraseMetadata2 = new SeedPhraseMetadata( - MOCK_SEED_PHRASE, - 2000, - ); + const mockSeedPhraseMetadata1 = new SecretMetadata(MOCK_SEED_PHRASE, { + timestamp: 1000, + }); + const mockSeedPhraseMetadata2 = new SecretMetadata(MOCK_SEED_PHRASE, { + timestamp: 2000, + }); // sort in ascending order - const sortedSeedPhraseMetadata = SeedPhraseMetadata.sort( + const sortedSeedPhraseMetadata = SecretMetadata.sort( [mockSeedPhraseMetadata1, mockSeedPhraseMetadata2], 'asc', ); @@ -2185,7 +2196,7 @@ describe('SeedlessOnboardingController', () => { ); // sort in descending order - const sortedSeedPhraseMetadataDesc = SeedPhraseMetadata.sort( + const sortedSeedPhraseMetadataDesc = SecretMetadata.sort( [mockSeedPhraseMetadata1, mockSeedPhraseMetadata2], 'desc', ); diff --git a/packages/seedless-onboarding-controller/tests/mocks/toprf.ts b/packages/seedless-onboarding-controller/tests/mocks/toprf.ts index dafddf6be60..a240e8a1127 100644 --- a/packages/seedless-onboarding-controller/tests/mocks/toprf.ts +++ b/packages/seedless-onboarding-controller/tests/mocks/toprf.ts @@ -50,17 +50,17 @@ export const MOCK_RELEASE_METADATA_LOCK_RESPONSE = { status: 1, }; -export const MULTIPLE_MOCK_SEEDPHRASE_METADATA = [ +export const MULTIPLE_MOCK_SECRET_METADATA = [ { - seedPhrase: new Uint8Array(Buffer.from('seedPhrase1', 'utf-8')), + data: new Uint8Array(Buffer.from('seedPhrase1', 'utf-8')), timestamp: 10, }, { - seedPhrase: new Uint8Array(Buffer.from('seedPhrase3', 'utf-8')), + data: new Uint8Array(Buffer.from('seedPhrase3', 'utf-8')), timestamp: 60, }, { - seedPhrase: new Uint8Array(Buffer.from('seedPhrase2', 'utf-8')), + data: new Uint8Array(Buffer.from('seedPhrase2', 'utf-8')), timestamp: 20, }, ]; @@ -73,7 +73,7 @@ export const MULTIPLE_MOCK_SEEDPHRASE_METADATA = [ * @returns The mock secret data get response */ export function createMockSecretDataGetResponse< - T extends Uint8Array | { seedPhrase: Uint8Array; timestamp: number }, + T extends Uint8Array | { data: Uint8Array; timestamp: number }, >(secretDataArr: T[], password: string) { const mockToprfEncryptor = new MockToprfEncryptorDecryptor(); const ids: string[] = []; @@ -84,12 +84,12 @@ export function createMockSecretDataGetResponse< if (secretData instanceof Uint8Array) { b64SecretData = Buffer.from(secretData).toString('base64'); } else { - b64SecretData = Buffer.from(secretData.seedPhrase).toString('base64'); + b64SecretData = Buffer.from(secretData.data).toString('base64'); timestamp = secretData.timestamp; } const metadata = JSON.stringify({ - seedPhrase: b64SecretData, + data: b64SecretData, timestamp, }); From 25eef9460b6ac73d4bcd6d96c4228bd2214b506f Mon Sep 17 00:00:00 2001 From: lwin Date: Tue, 13 May 2025 14:25:15 +0800 Subject: [PATCH 3/6] chore: update 'ISecretMetadata' to include SecretType --- packages/seedless-onboarding-controller/src/SecretMetadata.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/seedless-onboarding-controller/src/SecretMetadata.ts b/packages/seedless-onboarding-controller/src/SecretMetadata.ts index 1df2fcfa760..f6bfca2dfe9 100644 --- a/packages/seedless-onboarding-controller/src/SecretMetadata.ts +++ b/packages/seedless-onboarding-controller/src/SecretMetadata.ts @@ -11,6 +11,7 @@ import type { SecretMetadataOptions } from './types'; type ISecretMetadata = { data: Uint8Array; timestamp: number; + type: SecretType; toBytes: () => Uint8Array; }; From 0b67570b54d2c46d164b542a0ae9e95807ca933c Mon Sep 17 00:00:00 2001 From: lwin Date: Wed, 14 May 2025 11:16:38 +0800 Subject: [PATCH 4/6] feat: add 'version' to SecretMetadata --- .../src/SecretMetadata.ts | 53 +++++++++++++------ .../src/SeedlessOnboardingController.test.ts | 3 ++ .../src/constants.ts | 4 ++ .../src/types.ts | 5 ++ 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/packages/seedless-onboarding-controller/src/SecretMetadata.ts b/packages/seedless-onboarding-controller/src/SecretMetadata.ts index f6bfca2dfe9..45cd32fe518 100644 --- a/packages/seedless-onboarding-controller/src/SecretMetadata.ts +++ b/packages/seedless-onboarding-controller/src/SecretMetadata.ts @@ -5,13 +5,18 @@ import { bytesToString, } from '@metamask/utils'; -import { SeedlessOnboardingControllerError, SecretType } from './constants'; +import { + SeedlessOnboardingControllerError, + SecretType, + SecretMetadataVersion, +} from './constants'; import type { SecretMetadataOptions } from './types'; type ISecretMetadata = { data: Uint8Array; timestamp: number; type: SecretType; + version: SecretMetadataVersion; toBytes: () => Uint8Array; }; @@ -33,24 +38,27 @@ type IBase64SecretMetadata = Omit & { * ``` */ export class SecretMetadata implements ISecretMetadata { - readonly #secret: Uint8Array; + readonly #data: Uint8Array; readonly #timestamp: number; readonly #type: SecretType; + readonly #version: SecretMetadataVersion; + /** * Create a new SecretMetadata instance. * - * @param secret - The secret to add metadata to. + * @param data - The secret to add metadata to. * @param options - The options for the secret metadata. * @param options.timestamp - The timestamp when the secret was created. * @param options.type - The type of the secret. */ - constructor(secret: Uint8Array, options?: Partial) { - this.#secret = secret; + constructor(data: Uint8Array, options?: Partial) { + this.#data = data; this.#timestamp = options?.timestamp ?? Date.now(); this.#type = options?.type ?? SecretType.Mnemonic; + this.#version = options?.version ?? SecretMetadataVersion.V1; } /** @@ -129,38 +137,46 @@ export class SecretMetadata implements ISecretMetadata { * Parse and create the SecretMetadata instance from the raw metadata. * * @param rawMetadata - The raw metadata. - * @param type - The type of the secret. * @returns The parsed secret metadata. */ - static fromRawMetadata( - rawMetadata: Uint8Array, - type: SecretType = SecretType.Mnemonic, - ): SecretMetadata { + static fromRawMetadata(rawMetadata: Uint8Array): SecretMetadata { const serializedMetadata = bytesToString(rawMetadata); const parsedMetadata = JSON.parse(serializedMetadata); SecretMetadata.assertIsBase64SecretMetadata(parsedMetadata); + let type = SecretType.Mnemonic; + let version = SecretMetadataVersion.V1; + + if (parsedMetadata.type) { + type = parsedMetadata.type; + } + + if (parsedMetadata.version) { + version = parsedMetadata.version; + } + const bytes = base64ToBytes(parsedMetadata.data); return new SecretMetadata(bytes, { timestamp: parsedMetadata.timestamp, type, + version, }); } /** * Sort the seed phrases by timestamp. * - * @param secrets - The seed phrases to sort. + * @param data - The secret metadata array to sort. * @param order - The order to sort the seed phrases. Default is `desc`. * - * @returns The sorted seed phrases. + * @returns The sorted secret metadata array. */ static sort( - secrets: SecretMetadata[], + data: SecretMetadata[], order: 'asc' | 'desc' = 'asc', ): SecretMetadata[] { - return secrets.sort((a, b) => { + return data.sort((a, b) => { if (order === 'asc') { return a.timestamp - b.timestamp; } @@ -169,7 +185,7 @@ export class SecretMetadata implements ISecretMetadata { } get data() { - return this.#secret; + return this.#data; } get timestamp() { @@ -180,6 +196,10 @@ export class SecretMetadata implements ISecretMetadata { return this.#type; } + get version() { + return this.#version; + } + /** * Serialize the secret metadata and convert it to a Uint8Array. * @@ -188,13 +208,14 @@ export class SecretMetadata implements ISecretMetadata { toBytes(): Uint8Array { // encode the raw secret to base64 encoded string // to create more compacted metadata - const b64Data = bytesToBase64(this.#secret); + const b64Data = bytesToBase64(this.#data); // serialize the metadata to a JSON string const serializedMetadata = JSON.stringify({ data: b64Data, timestamp: this.#timestamp, type: this.#type, + version: this.#version, }); // convert the serialized metadata to bytes(Uint8Array) diff --git a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts index e1e7bda7372..0db1fda280f 100644 --- a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts +++ b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts @@ -25,6 +25,7 @@ import { SeedlessOnboardingControllerError, AuthConnection, SecretType, + SecretMetadataVersion, } from './constants'; import { RecoveryError } from './errors'; import { SecretMetadata } from './SecretMetadata'; @@ -2123,6 +2124,8 @@ describe('SeedlessOnboardingController', () => { const seedPhraseMetadata = new SecretMetadata(MOCK_SEED_PHRASE); expect(seedPhraseMetadata.data).toBeDefined(); expect(seedPhraseMetadata.timestamp).toBeDefined(); + expect(seedPhraseMetadata.type).toBe(SecretType.Mnemonic); + expect(seedPhraseMetadata.version).toBe(SecretMetadataVersion.V1); // should be able to create a SeedPhraseMetadata instance with a timestamp via constructor const timestamp = 18_000; diff --git a/packages/seedless-onboarding-controller/src/constants.ts b/packages/seedless-onboarding-controller/src/constants.ts index c58cec354bd..8428546e048 100644 --- a/packages/seedless-onboarding-controller/src/constants.ts +++ b/packages/seedless-onboarding-controller/src/constants.ts @@ -16,6 +16,10 @@ export enum SecretType { PrivateKey = 'privateKey', } +export enum SecretMetadataVersion { + V1 = 'v1', +} + export enum SeedlessOnboardingControllerError { ControllerLocked = `${controllerName} - The operation cannot be completed while the controller is locked.`, AuthenticationError = `${controllerName} - Authentication error`, diff --git a/packages/seedless-onboarding-controller/src/types.ts b/packages/seedless-onboarding-controller/src/types.ts index d9d833e4ec7..806f85d99f5 100644 --- a/packages/seedless-onboarding-controller/src/types.ts +++ b/packages/seedless-onboarding-controller/src/types.ts @@ -12,6 +12,7 @@ import type { MutexInterface } from 'async-mutex'; import type { AuthConnection, controllerName, + SecretMetadataVersion, SecretType, Web3AuthNetwork, } from './constants'; @@ -195,4 +196,8 @@ export type SecretMetadataOptions = { * The type of the seed phrase. */ type: SecretType; + /** + * The version of the seed phrase metadata. + */ + version: SecretMetadataVersion; }; From ceda10ed24df78a315f86b6e5bb108bace69f547 Mon Sep 17 00:00:00 2001 From: lwin Date: Wed, 14 May 2025 12:20:18 +0800 Subject: [PATCH 5/6] feat: make 'data' field to Generic in SecretMetadata --- .../src/SecretMetadata.ts | 91 +++++++++++-------- .../src/SeedlessOnboardingController.ts | 9 +- .../src/types.ts | 2 + 3 files changed, 61 insertions(+), 41 deletions(-) diff --git a/packages/seedless-onboarding-controller/src/SecretMetadata.ts b/packages/seedless-onboarding-controller/src/SecretMetadata.ts index 45cd32fe518..63643155051 100644 --- a/packages/seedless-onboarding-controller/src/SecretMetadata.ts +++ b/packages/seedless-onboarding-controller/src/SecretMetadata.ts @@ -10,10 +10,10 @@ import { SecretType, SecretMetadataVersion, } from './constants'; -import type { SecretMetadataOptions } from './types'; +import type { SecretDataType, SecretMetadataOptions } from './types'; -type ISecretMetadata = { - data: Uint8Array; +type ISecretMetadata = { + data: DataType; timestamp: number; type: SecretType; version: SecretMetadataVersion; @@ -22,7 +22,10 @@ type ISecretMetadata = { // SecretMetadata type without the data and toBytes methods // in which the data is base64 encoded for more compacted metadata -type IBase64SecretMetadata = Omit & { +type SecretMetadataJson = Omit< + ISecretMetadata, + 'data' | 'toBytes' +> & { data: string; // base64 encoded string }; @@ -37,8 +40,10 @@ type IBase64SecretMetadata = Omit & { * const secretMetadata = new SecretMetadata(secret); * ``` */ -export class SecretMetadata implements ISecretMetadata { - readonly #data: Uint8Array; +export class SecretMetadata + implements ISecretMetadata +{ + readonly #data: DataType; readonly #timestamp: number; @@ -54,7 +59,7 @@ export class SecretMetadata implements ISecretMetadata { * @param options.timestamp - The timestamp when the secret was created. * @param options.type - The type of the secret. */ - constructor(data: Uint8Array, options?: Partial) { + constructor(data: DataType, options?: Partial) { this.#data = data; this.#timestamp = options?.timestamp ?? Date.now(); this.#type = options?.type ?? SecretType.Mnemonic; @@ -73,12 +78,12 @@ export class SecretMetadata implements ISecretMetadata { * @param data.options - The options for the seed phrase metadata. * @returns The SecretMetadata instances. */ - static fromBatch( + static fromBatch( data: { - value: Uint8Array; + value: DataType; options?: Partial; }[], - ): SecretMetadata[] { + ): SecretMetadata[] { const timestamp = Date.now(); return data.map((d, index) => { // To respect the order of the seed phrases, we add the index to the timestamp @@ -98,9 +103,9 @@ export class SecretMetadata implements ISecretMetadata { * @param value - The value to check. * @throws If the value is not a valid seed phrase metadata. */ - static assertIsBase64SecretMetadata( - value: unknown, - ): asserts value is IBase64SecretMetadata { + static assertIsValidSecretMetadataJson< + DataType extends SecretDataType = Uint8Array, + >(value: unknown): asserts value is SecretMetadataJson { if ( typeof value !== 'object' || !value || @@ -119,45 +124,54 @@ export class SecretMetadata implements ISecretMetadata { * This method also sorts the secrets by timestamp in ascending order, i.e. the oldest secret will be the first element in the array. * * @param secretMetadataArr - The array of SecretMetadata from the metadata store. + * @param filterType - The type of the secret to filter. * @returns The array of SecretMetadata instances. */ - static parseSecretsFromMetadataStore( + static parseSecretsFromMetadataStore< + DataType extends SecretDataType = Uint8Array, + >( secretMetadataArr: Uint8Array[], - ): SecretMetadata[] { + filterType?: SecretType, + ): SecretMetadata[] { const parsedSecertMetadata = secretMetadataArr.map((metadata) => - SecretMetadata.fromRawMetadata(metadata), + SecretMetadata.fromRawMetadata(metadata), ); const secrets = SecretMetadata.sort(parsedSecertMetadata); + if (filterType) { + return secrets.filter((secret) => secret.type === filterType); + } + return secrets; } /** - * Parse and create the SecretMetadata instance from the raw metadata. + * Parse and create the SecretMetadata instance from the raw metadata bytes. * * @param rawMetadata - The raw metadata. * @returns The parsed secret metadata. */ - static fromRawMetadata(rawMetadata: Uint8Array): SecretMetadata { + static fromRawMetadata( + rawMetadata: Uint8Array, + ): SecretMetadata { const serializedMetadata = bytesToString(rawMetadata); const parsedMetadata = JSON.parse(serializedMetadata); - SecretMetadata.assertIsBase64SecretMetadata(parsedMetadata); + SecretMetadata.assertIsValidSecretMetadataJson(parsedMetadata); - let type = SecretType.Mnemonic; - let version = SecretMetadataVersion.V1; + // if the type is not provided, we default to Mnemonic for the backwards compatibility + const type = parsedMetadata.type ?? SecretType.Mnemonic; + const version = parsedMetadata.version ?? SecretMetadataVersion.V1; - if (parsedMetadata.type) { - type = parsedMetadata.type; + let data: DataType; + try { + data = base64ToBytes(parsedMetadata.data) as DataType; + } catch { + data = parsedMetadata.data as DataType; } - if (parsedMetadata.version) { - version = parsedMetadata.version; - } - - const bytes = base64ToBytes(parsedMetadata.data); - return new SecretMetadata(bytes, { + return new SecretMetadata(data, { timestamp: parsedMetadata.timestamp, type, version, @@ -172,10 +186,10 @@ export class SecretMetadata implements ISecretMetadata { * * @returns The sorted secret metadata array. */ - static sort( - data: SecretMetadata[], + static sort( + data: SecretMetadata[], order: 'asc' | 'desc' = 'asc', - ): SecretMetadata[] { + ): SecretMetadata[] { return data.sort((a, b) => { if (order === 'asc') { return a.timestamp - b.timestamp; @@ -184,7 +198,7 @@ export class SecretMetadata implements ISecretMetadata { }); } - get data() { + get data(): DataType { return this.#data; } @@ -206,13 +220,16 @@ export class SecretMetadata implements ISecretMetadata { * @returns The serialized SecretMetadata value in bytes. */ toBytes(): Uint8Array { - // encode the raw secret to base64 encoded string - // to create more compacted metadata - const b64Data = bytesToBase64(this.#data); + let _data: unknown = this.#data; + if (this.#data instanceof Uint8Array) { + // encode the raw secret to base64 encoded string + // to create more compacted metadata + _data = bytesToBase64(this.#data); + } // serialize the metadata to a JSON string const serializedMetadata = JSON.stringify({ - data: b64Data, + data: _data, timestamp: this.#timestamp, type: this.#type, version: this.#version, diff --git a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.ts b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.ts index e3f4aa3c2c5..281be8691ac 100644 --- a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.ts +++ b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.ts @@ -314,10 +314,11 @@ export class SeedlessOnboardingController extends BaseController< }); } - const secrets = SecretMetadata.parseSecretsFromMetadataStore(secretData); - return secrets - .filter((secret) => secret.type === SecretType.Mnemonic) - .map((secret) => secret.data); + const secrets = SecretMetadata.parseSecretsFromMetadataStore( + secretData, + SecretType.Mnemonic, + ); + return secrets.map((secret) => secret.data); } catch (error) { log('Error fetching seed phrase metadata', error); throw new Error( diff --git a/packages/seedless-onboarding-controller/src/types.ts b/packages/seedless-onboarding-controller/src/types.ts index 806f85d99f5..0fb2d6340a0 100644 --- a/packages/seedless-onboarding-controller/src/types.ts +++ b/packages/seedless-onboarding-controller/src/types.ts @@ -184,6 +184,8 @@ export type VaultData = { toprfAuthKeyPair: string; }; +export type SecretDataType = Uint8Array | string | number; + /** * The constructor options for the seed phrase metadata. */ From cda67647fa13a9ef8485f17e7359b7a5c865f288 Mon Sep 17 00:00:00 2001 From: lwin Date: Wed, 14 May 2025 12:20:24 +0800 Subject: [PATCH 6/6] test: updated tests --- .../src/SeedlessOnboardingController.test.ts | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts index 0db1fda280f..225ec21e37a 100644 --- a/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts +++ b/packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts @@ -2207,5 +2207,86 @@ describe('SeedlessOnboardingController', () => { sortedSeedPhraseMetadataDesc[1].timestamp, ); }); + + it('should be able to overwrite the default Generic DataType', () => { + const secret1 = new SecretMetadata('private-key-1', { + type: SecretType.PrivateKey, + }); + expect(secret1.data).toBe('private-key-1'); + expect(secret1.type).toBe(SecretType.PrivateKey); + expect(secret1.version).toBe(SecretMetadataVersion.V1); + + // should be able to convert to bytes + const secret1Bytes = secret1.toBytes(); + const parsedSecret1 = + SecretMetadata.fromRawMetadata(secret1Bytes); + expect(parsedSecret1.data).toBe('private-key-1'); + expect(parsedSecret1.type).toBe(SecretType.PrivateKey); + expect(parsedSecret1.version).toBe(SecretMetadataVersion.V1); + + const secret2 = new SecretMetadata(MOCK_SEED_PHRASE, { + type: SecretType.Mnemonic, + }); + expect(secret2.data).toStrictEqual(MOCK_SEED_PHRASE); + expect(secret2.type).toBe(SecretType.Mnemonic); + + const secret2Bytes = secret2.toBytes(); + const parsedSecret2 = + SecretMetadata.fromRawMetadata(secret2Bytes); + expect(parsedSecret2.data).toStrictEqual(MOCK_SEED_PHRASE); + expect(parsedSecret2.type).toBe(SecretType.Mnemonic); + }); + + it('should be able to parse the array of Mixed SecretMetadata', () => { + const MOCK_PRIVATE_KEY = 'private-key-1'; + const secret1 = new SecretMetadata(MOCK_PRIVATE_KEY, { + type: SecretType.PrivateKey, + }); + const secret2 = new SecretMetadata(MOCK_SEED_PHRASE, { + type: SecretType.Mnemonic, + }); + + const secrets = [secret1.toBytes(), secret2.toBytes()]; + + const parsedSecrets = + SecretMetadata.parseSecretsFromMetadataStore(secrets); + expect(parsedSecrets).toHaveLength(2); + expect(parsedSecrets[0].data).toBe(MOCK_PRIVATE_KEY); + expect(parsedSecrets[0].type).toBe(SecretType.PrivateKey); + expect(parsedSecrets[1].data).toStrictEqual(MOCK_SEED_PHRASE); + expect(parsedSecrets[1].type).toBe(SecretType.Mnemonic); + }); + + it('should be able to filter the array of SecretMetadata by type', () => { + const MOCK_PRIVATE_KEY = 'MOCK_PRIVATE_KEY'; + const secret1 = new SecretMetadata(MOCK_PRIVATE_KEY, { + type: SecretType.PrivateKey, + }); + const secret2 = new SecretMetadata(MOCK_SEED_PHRASE, { + type: SecretType.Mnemonic, + }); + const secret3 = new SecretMetadata(MOCK_SEED_PHRASE); + + const secrets = [secret1.toBytes(), secret2.toBytes(), secret3.toBytes()]; + + const mnemonicSecrets = SecretMetadata.parseSecretsFromMetadataStore( + secrets, + SecretType.Mnemonic, + ); + expect(mnemonicSecrets).toHaveLength(2); + expect(mnemonicSecrets[0].data).toStrictEqual(MOCK_SEED_PHRASE); + expect(mnemonicSecrets[0].type).toBe(SecretType.Mnemonic); + expect(mnemonicSecrets[1].data).toStrictEqual(MOCK_SEED_PHRASE); + expect(mnemonicSecrets[1].type).toBe(SecretType.Mnemonic); + + const privateKeySecrets = SecretMetadata.parseSecretsFromMetadataStore( + secrets, + SecretType.PrivateKey, + ); + + expect(privateKeySecrets).toHaveLength(1); + expect(privateKeySecrets[0].data).toBe(MOCK_PRIVATE_KEY); + expect(privateKeySecrets[0].type).toBe(SecretType.PrivateKey); + }); }); });