@metamask-previews/seedless-onboarding-controller 0.0.0-preview-e9f8bc88 → 1.0.0-preview-39fa8d37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +24 -19
  2. package/dist/SecretMetadata.cjs.map +1 -1
  3. package/dist/SecretMetadata.d.cts +4 -0
  4. package/dist/SecretMetadata.d.cts.map +1 -1
  5. package/dist/SecretMetadata.d.mts +4 -0
  6. package/dist/SecretMetadata.d.mts.map +1 -1
  7. package/dist/SecretMetadata.mjs.map +1 -1
  8. package/dist/SeedlessOnboardingController.cjs +65 -25
  9. package/dist/SeedlessOnboardingController.cjs.map +1 -1
  10. package/dist/SeedlessOnboardingController.d.cts +2 -1
  11. package/dist/SeedlessOnboardingController.d.cts.map +1 -1
  12. package/dist/SeedlessOnboardingController.d.mts +2 -1
  13. package/dist/SeedlessOnboardingController.d.mts.map +1 -1
  14. package/dist/SeedlessOnboardingController.mjs +66 -26
  15. package/dist/SeedlessOnboardingController.mjs.map +1 -1
  16. package/dist/constants.cjs +1 -1
  17. package/dist/constants.cjs.map +1 -1
  18. package/dist/constants.d.cts.map +1 -1
  19. package/dist/constants.d.mts.map +1 -1
  20. package/dist/constants.mjs +1 -1
  21. package/dist/constants.mjs.map +1 -1
  22. package/dist/errors.cjs +31 -7
  23. package/dist/errors.cjs.map +1 -1
  24. package/dist/errors.d.cts +5 -4
  25. package/dist/errors.d.cts.map +1 -1
  26. package/dist/errors.d.mts +5 -4
  27. package/dist/errors.d.mts.map +1 -1
  28. package/dist/errors.mjs +31 -7
  29. package/dist/errors.mjs.map +1 -1
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +1 -1
  32. package/dist/index.d.cts.map +1 -1
  33. package/dist/index.d.mts +1 -1
  34. package/dist/index.d.mts.map +1 -1
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/types.cjs.map +1 -1
  37. package/dist/types.d.cts +50 -0
  38. package/dist/types.d.cts.map +1 -1
  39. package/dist/types.d.mts +50 -0
  40. package/dist/types.d.mts.map +1 -1
  41. package/dist/types.mjs.map +1 -1
  42. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -7,25 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.0.0]
11
+
10
12
  ### Added
11
13
 
12
- - Initial implementation of the seedless onboarding controller. ([#5874](https://github.com/MetaMask/core/pull/5874))
13
- - Authenticate OAuth user using the seedless onboarding flow and determine if the user is already registered or not
14
- - Create a new Toprf key and backup seed phrase
15
- - Add a new seed phrase backup to the metadata store
16
- - Add array of new seed phrase backups to the metadata store in batch (useful in multi-srp flow)
17
- - Fetch seed phrase metadata from the metadata store
18
- - Update the password of the seedless onboarding flow
19
- - Support multi SRP sync using social login. ([#5875](https://github.com/MetaMask/core/pull/5875))
20
- - Update Metadata to support multiple types of secrets (SRP, PrivateKey).
21
- - Add `Controller Lock` which will sync with `Keyring Lock`.
22
- - Updated `VaultEncryptor` type in constructor args and is compulsory to provided relevant encryptor to constructor.
23
- - Added new non-persisted states, `encryptionKey` and `encryptionSalt` to decrypt the vault when password is not available.
24
- - Update `password` param in `fetchAllSeedPhrases` method to optional. If password is not provided, `cached EncryptionKey` will be used.
25
- - Password sync features implementation. ([#5877](https://github.com/MetaMask/core/pull/5877))
26
- - checkIsPasswordOutdated to check current password is outdated compare to global password
27
- - Add password outdated check to add SRPs / change password
28
- - recover old password using latest global password
29
- - sync latest global password to reset vault to use latest password and persist latest auth pubkey
14
+ - Initial release of the seedless onboarding controller ([#5874](https://github.com/MetaMask/core/pull/5874), [#5875](https://github.com/MetaMask/core/pull/5875), [#5880](https://github.com/MetaMask/core/pull/5880))
15
+ - This controller allows MM extension and mobile users to login with google, apple accounts. This controller communicates with web3auth nodes + relies on toprf sdk (unreleased) to perform CRU operations related to backing up srps.
16
+ - The controller contains the following methods:
17
+ - `authenticate`: Authenticate OAuth user, generate Valid Authentication Token to interact with TOPRF Services and determine if the user has already registered or not.
18
+ - `createToprfKeyAndBackupSeedPhrase`: Create a new TOPRF encryption key using given password, encrypt the Seed Phrase and store the encrypted data in the metadata store.
19
+ - `addNewSeedPhraseBackup`: Add and encrypt a new seed phrase backup to the metadata store without create a new TOPRF encryption key.
20
+ - `fetchAllSeedPhrases`: Retrieve the encrypted backed-up Seed Phrases from the metadatastore and return decrypted Seed Phrases.
21
+ - `changePassword`: Update the password of the seedless onboarding flow
22
+ - `updateBackupMetadataState`: Update the backup metadata state of the controller.
23
+ - `verifyVaultPassword`: Verify the password validity by decrypting the vault
24
+ - `getSeedPhraseBackupHash`: Get the hash of the seed phrase backup for the given seed phrase from the state.
25
+ - `submitPassword`: Validate a password and unlock the controller.
26
+ - `setLocked`: Remove secrets from state and set the controller status to locked.
27
+ - `syncLatestGlobalPassword`: Sync the latest global password to the controller. This is useful for syncing the password change update across multiple devices.
28
+ - `recoverCurrentDevicePassword`:
29
+ - Recover the vault which is encrypted with the outdated password with the new password.
30
+ - This is useful when user wants to sync the current device without logging out.
31
+ - e.g. User enters the new password, decrypts the current vault (which was initially encrypted with old password) using the new password and recover the Key data.
32
+ - `checkIsPasswordOutdated`: Check if the password is current device is outdated, i.e. user changed password in another device.
33
+ - `clearState`: Reset the state of the controller to the defaults.
30
34
 
31
- [Unreleased]: https://github.com/MetaMask/core/
35
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/seedless-onboarding-controller@1.0.0...HEAD
36
+ [1.0.0]: https://github.com/MetaMask/core/releases/tag/@metamask/seedless-onboarding-controller@1.0.0
@@ -1 +1 @@
1
- {"version":3,"file":"SecretMetadata.cjs","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n base64ToBytes,\n bytesToBase64,\n stringToBytes,\n bytesToString,\n} from '@metamask/utils';\n\nimport {\n SeedlessOnboardingControllerErrorMessage,\n SecretType,\n SecretMetadataVersion,\n} from './constants';\nimport type { SecretDataType, SecretMetadataOptions } from './types';\n\ntype ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {\n data: DataType;\n timestamp: number;\n type: SecretType;\n version: SecretMetadataVersion;\n toBytes: () => Uint8Array;\n};\n\n// SecretMetadata type without the data and toBytes methods\n// in which the data is base64 encoded for more compacted metadata\ntype SecretMetadataJson<DataType extends SecretDataType> = Omit<\n ISecretMetadata<DataType>,\n 'data' | 'toBytes'\n> & {\n data: string; // base64 encoded string\n};\n\n/**\n * SecretMetadata is a class that adds metadata to the secret.\n *\n * It contains the secret and the timestamp when it was created.\n * It is used to store the secret in the metadata store.\n *\n * @example\n * ```ts\n * const secretMetadata = new SecretMetadata(secret);\n * ```\n */\nexport class SecretMetadata<DataType extends SecretDataType = Uint8Array>\n implements ISecretMetadata<DataType>\n{\n readonly #data: DataType;\n\n readonly #timestamp: number;\n\n readonly #type: SecretType;\n\n readonly #version: SecretMetadataVersion;\n\n /**\n * Create a new SecretMetadata instance.\n *\n * @param data - The secret to add metadata to.\n * @param options - The options for the secret metadata.\n * @param options.timestamp - The timestamp when the secret was created.\n * @param options.type - The type of the secret.\n */\n constructor(data: DataType, options?: Partial<SecretMetadataOptions>) {\n this.#data = data;\n this.#timestamp = options?.timestamp ?? Date.now();\n this.#type = options?.type ?? SecretType.Mnemonic;\n this.#version = options?.version ?? SecretMetadataVersion.V1;\n }\n\n /**\n * Create an Array of SecretMetadata instances from an array of secrets.\n *\n * To respect the order of the secrets, we add the index to the timestamp\n * so that the first secret backup will have the oldest timestamp\n * and the last secret backup will have the newest timestamp.\n *\n * @param data - The data to add metadata to.\n * @param data.value - The SeedPhrase/PrivateKey to add metadata to.\n * @param data.options - The options for the seed phrase metadata.\n * @returns The SecretMetadata instances.\n */\n static fromBatch<DataType extends SecretDataType = Uint8Array>(\n data: {\n value: DataType;\n options?: Partial<SecretMetadataOptions>;\n }[],\n ): SecretMetadata<DataType>[] {\n const timestamp = Date.now();\n return data.map((d, index) => {\n // To respect the order of the seed phrases, we add the index to the timestamp\n // so that the first seed phrase backup will have the oldest timestamp\n // and the last seed phrase backup will have the newest timestamp\n const backupCreatedAt = d.options?.timestamp ?? timestamp + index * 5;\n return new SecretMetadata(d.value, {\n timestamp: backupCreatedAt,\n type: d.options?.type,\n });\n });\n }\n\n /**\n * Assert that the provided value is a valid seed phrase metadata.\n *\n * @param value - The value to check.\n * @throws If the value is not a valid seed phrase metadata.\n */\n static assertIsValidSecretMetadataJson<\n DataType extends SecretDataType = Uint8Array,\n >(value: unknown): asserts value is SecretMetadataJson<DataType> {\n if (\n typeof value !== 'object' ||\n !value ||\n !('data' in value) ||\n typeof value.data !== 'string' ||\n !('timestamp' in value) ||\n typeof value.timestamp !== 'number'\n ) {\n throw new Error(\n SeedlessOnboardingControllerErrorMessage.InvalidSecretMetadata,\n );\n }\n }\n\n /**\n * Parse the SecretMetadata from the metadata store and return the array of SecretMetadata instances.\n *\n * This method also sorts the secrets by timestamp in ascending order, i.e. the oldest secret will be the first element in the array.\n *\n * @param secretMetadataArr - The array of SecretMetadata from the metadata store.\n * @param filterType - The type of the secret to filter.\n * @returns The array of SecretMetadata instances.\n */\n static parseSecretsFromMetadataStore<\n DataType extends SecretDataType = Uint8Array,\n >(\n secretMetadataArr: Uint8Array[],\n filterType?: SecretType,\n ): SecretMetadata<DataType>[] {\n const parsedSecertMetadata = secretMetadataArr.map((metadata) =>\n SecretMetadata.fromRawMetadata<DataType>(metadata),\n );\n\n const secrets = SecretMetadata.sort(parsedSecertMetadata);\n\n if (filterType) {\n return secrets.filter((secret) => secret.type === filterType);\n }\n\n return secrets;\n }\n\n /**\n * Parse and create the SecretMetadata instance from the raw metadata bytes.\n *\n * @param rawMetadata - The raw metadata.\n * @returns The parsed secret metadata.\n */\n static fromRawMetadata<DataType extends SecretDataType>(\n rawMetadata: Uint8Array,\n ): SecretMetadata<DataType> {\n const serializedMetadata = bytesToString(rawMetadata);\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n SecretMetadata.assertIsValidSecretMetadataJson<DataType>(parsedMetadata);\n\n // if the type is not provided, we default to Mnemonic for the backwards compatibility\n const type = parsedMetadata.type ?? SecretType.Mnemonic;\n const version = parsedMetadata.version ?? SecretMetadataVersion.V1;\n\n let data: DataType;\n try {\n data = base64ToBytes(parsedMetadata.data) as DataType;\n } catch {\n data = parsedMetadata.data as DataType;\n }\n\n return new SecretMetadata<DataType>(data, {\n timestamp: parsedMetadata.timestamp,\n type,\n version,\n });\n }\n\n /**\n * Sort the seed phrases by timestamp.\n *\n * @param data - The secret metadata array to sort.\n * @param order - The order to sort the seed phrases. Default is `desc`.\n *\n * @returns The sorted secret metadata array.\n */\n static sort<DataType extends SecretDataType = Uint8Array>(\n data: SecretMetadata<DataType>[],\n order: 'asc' | 'desc' = 'asc',\n ): SecretMetadata<DataType>[] {\n return data.sort((a, b) => {\n if (order === 'asc') {\n return a.timestamp - b.timestamp;\n }\n return b.timestamp - a.timestamp;\n });\n }\n\n get data(): DataType {\n return this.#data;\n }\n\n get timestamp() {\n return this.#timestamp;\n }\n\n get type() {\n return this.#type;\n }\n\n get version() {\n return this.#version;\n }\n\n /**\n * Serialize the secret metadata and convert it to a Uint8Array.\n *\n * @returns The serialized SecretMetadata value in bytes.\n */\n toBytes(): Uint8Array {\n let _data: unknown = this.#data;\n if (this.#data instanceof Uint8Array) {\n // encode the raw secret to base64 encoded string\n // to create more compacted metadata\n _data = bytesToBase64(this.#data);\n }\n\n // serialize the metadata to a JSON string\n const serializedMetadata = JSON.stringify({\n data: _data,\n timestamp: this.#timestamp,\n type: this.#type,\n version: this.#version,\n });\n\n // convert the serialized metadata to bytes(Uint8Array)\n return stringToBytes(serializedMetadata);\n }\n}\n"]}
1
+ {"version":3,"file":"SecretMetadata.cjs","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAKyB;AAEzB,+CAIqB;AAsBrB;;;;;;;;;;GAUG;AACH,MAAa,cAAc;IAWzB;;;;;;;OAOG;IACH,YAAY,IAAc,EAAE,OAAwC;QAhB3D,uCAAgB;QAEhB,4CAAmB;QAEnB,uCAAkB;QAElB,0CAAgC;QAWvC,uBAAA,IAAI,wBAAS,IAAI,MAAA,CAAC;QAClB,uBAAA,IAAI,6BAAc,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,MAAA,CAAC;QACnD,uBAAA,IAAI,wBAAS,OAAO,EAAE,IAAI,IAAI,sBAAU,CAAC,QAAQ,MAAA,CAAC;QAClD,uBAAA,IAAI,2BAAY,OAAO,EAAE,OAAO,IAAI,iCAAqB,CAAC,EAAE,MAAA,CAAC;IAC/D,CAAC;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,SAAS,CACd,IAGG;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE;YAC3B,8EAA8E;YAC9E,sEAAsE;YACtE,iEAAiE;YACjE,MAAM,eAAe,GAAG,CAAC,CAAC,OAAO,EAAE,SAAS,IAAI,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;YACtE,OAAO,IAAI,cAAc,CAAC,CAAC,CAAC,KAAK,EAAE;gBACjC,SAAS,EAAE,eAAe;gBAC1B,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI;aACtB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,+BAA+B,CAEpC,KAAc;QACd,IACE,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,KAAK;YACN,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;YAClB,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAC9B,CAAC,CAAC,WAAW,IAAI,KAAK,CAAC;YACvB,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,EACnC;YACA,MAAM,IAAI,KAAK,CACb,oDAAwC,CAAC,qBAAqB,CAC/D,CAAC;SACH;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,6BAA6B,CAGlC,iBAA+B,EAC/B,UAAuB;QAEvB,MAAM,oBAAoB,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC9D,cAAc,CAAC,eAAe,CAAW,QAAQ,CAAC,CACnD,CAAC;QAEF,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE1D,IAAI,UAAU,EAAE;YACd,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;SAC/D;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CACpB,WAAuB;QAEvB,MAAM,kBAAkB,GAAG,IAAA,qBAAa,EAAC,WAAW,CAAC,CAAC;QACtD,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAEtD,cAAc,CAAC,+BAA+B,CAAW,cAAc,CAAC,CAAC;QAEzE,sFAAsF;QACtF,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,IAAI,sBAAU,CAAC,QAAQ,CAAC;QACxD,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,IAAI,iCAAqB,CAAC,EAAE,CAAC;QAEnE,IAAI,IAAc,CAAC;QACnB,IAAI;YACF,IAAI,GAAG,IAAA,qBAAa,EAAC,cAAc,CAAC,IAAI,CAAa,CAAC;SACvD;QAAC,MAAM;YACN,IAAI,GAAG,cAAc,CAAC,IAAgB,CAAC;SACxC;QAED,OAAO,IAAI,cAAc,CAAW,IAAI,EAAE;YACxC,SAAS,EAAE,cAAc,CAAC,SAAS;YACnC,IAAI;YACJ,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CACT,IAAgC,EAChC,QAAwB,KAAK;QAE7B,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACxB,IAAI,KAAK,KAAK,KAAK,EAAE;gBACnB,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;aAClC;YACD,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI;QACN,OAAO,uBAAA,IAAI,4BAAM,CAAC;IACpB,CAAC;IAED,IAAI,SAAS;QACX,OAAO,uBAAA,IAAI,iCAAW,CAAC;IACzB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,uBAAA,IAAI,4BAAM,CAAC;IACpB,CAAC;IAED,IAAI,OAAO;QACT,OAAO,uBAAA,IAAI,+BAAS,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACH,OAAO;QACL,IAAI,KAAK,GAAY,uBAAA,IAAI,4BAAM,CAAC;QAChC,IAAI,uBAAA,IAAI,4BAAM,YAAY,UAAU,EAAE;YACpC,iDAAiD;YACjD,oCAAoC;YACpC,KAAK,GAAG,IAAA,qBAAa,EAAC,uBAAA,IAAI,4BAAM,CAAC,CAAC;SACnC;QAED,0CAA0C;QAC1C,MAAM,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC;YACxC,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,uBAAA,IAAI,iCAAW;YAC1B,IAAI,EAAE,uBAAA,IAAI,4BAAM;YAChB,OAAO,EAAE,uBAAA,IAAI,+BAAS;SACvB,CAAC,CAAC;QAEH,uDAAuD;QACvD,OAAO,IAAA,qBAAa,EAAC,kBAAkB,CAAC,CAAC;IAC3C,CAAC;CACF;AAxMD,wCAwMC","sourcesContent":["import {\n base64ToBytes,\n bytesToBase64,\n stringToBytes,\n bytesToString,\n} from '@metamask/utils';\n\nimport {\n SeedlessOnboardingControllerErrorMessage,\n SecretType,\n SecretMetadataVersion,\n} from './constants';\nimport type { SecretDataType, SecretMetadataOptions } from './types';\n\ntype ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {\n data: DataType;\n timestamp: number;\n type: SecretType;\n version: SecretMetadataVersion;\n toBytes: () => Uint8Array;\n};\n\n/**\n * SecretMetadata type without the data and toBytes methods\n * in which the data is base64 encoded for more compacted metadata\n */\ntype SecretMetadataJson<DataType extends SecretDataType> = Omit<\n ISecretMetadata<DataType>,\n 'data' | 'toBytes'\n> & {\n data: string; // base64 encoded string\n};\n\n/**\n * SecretMetadata is a class that adds metadata to the secret.\n *\n * It contains the secret and the timestamp when it was created.\n * It is used to store the secret in the metadata store.\n *\n * @example\n * ```ts\n * const secretMetadata = new SecretMetadata(secret);\n * ```\n */\nexport class SecretMetadata<DataType extends SecretDataType = Uint8Array>\n implements ISecretMetadata<DataType>\n{\n readonly #data: DataType;\n\n readonly #timestamp: number;\n\n readonly #type: SecretType;\n\n readonly #version: SecretMetadataVersion;\n\n /**\n * Create a new SecretMetadata instance.\n *\n * @param data - The secret to add metadata to.\n * @param options - The options for the secret metadata.\n * @param options.timestamp - The timestamp when the secret was created.\n * @param options.type - The type of the secret.\n */\n constructor(data: DataType, options?: Partial<SecretMetadataOptions>) {\n this.#data = data;\n this.#timestamp = options?.timestamp ?? Date.now();\n this.#type = options?.type ?? SecretType.Mnemonic;\n this.#version = options?.version ?? SecretMetadataVersion.V1;\n }\n\n /**\n * Create an Array of SecretMetadata instances from an array of secrets.\n *\n * To respect the order of the secrets, we add the index to the timestamp\n * so that the first secret backup will have the oldest timestamp\n * and the last secret backup will have the newest timestamp.\n *\n * @param data - The data to add metadata to.\n * @param data.value - The SeedPhrase/PrivateKey to add metadata to.\n * @param data.options - The options for the seed phrase metadata.\n * @returns The SecretMetadata instances.\n */\n static fromBatch<DataType extends SecretDataType = Uint8Array>(\n data: {\n value: DataType;\n options?: Partial<SecretMetadataOptions>;\n }[],\n ): SecretMetadata<DataType>[] {\n const timestamp = Date.now();\n return data.map((d, index) => {\n // To respect the order of the seed phrases, we add the index to the timestamp\n // so that the first seed phrase backup will have the oldest timestamp\n // and the last seed phrase backup will have the newest timestamp\n const backupCreatedAt = d.options?.timestamp ?? timestamp + index * 5;\n return new SecretMetadata(d.value, {\n timestamp: backupCreatedAt,\n type: d.options?.type,\n });\n });\n }\n\n /**\n * Assert that the provided value is a valid seed phrase metadata.\n *\n * @param value - The value to check.\n * @throws If the value is not a valid seed phrase metadata.\n */\n static assertIsValidSecretMetadataJson<\n DataType extends SecretDataType = Uint8Array,\n >(value: unknown): asserts value is SecretMetadataJson<DataType> {\n if (\n typeof value !== 'object' ||\n !value ||\n !('data' in value) ||\n typeof value.data !== 'string' ||\n !('timestamp' in value) ||\n typeof value.timestamp !== 'number'\n ) {\n throw new Error(\n SeedlessOnboardingControllerErrorMessage.InvalidSecretMetadata,\n );\n }\n }\n\n /**\n * Parse the SecretMetadata from the metadata store and return the array of SecretMetadata instances.\n *\n * This method also sorts the secrets by timestamp in ascending order, i.e. the oldest secret will be the first element in the array.\n *\n * @param secretMetadataArr - The array of SecretMetadata from the metadata store.\n * @param filterType - The type of the secret to filter.\n * @returns The array of SecretMetadata instances.\n */\n static parseSecretsFromMetadataStore<\n DataType extends SecretDataType = Uint8Array,\n >(\n secretMetadataArr: Uint8Array[],\n filterType?: SecretType,\n ): SecretMetadata<DataType>[] {\n const parsedSecertMetadata = secretMetadataArr.map((metadata) =>\n SecretMetadata.fromRawMetadata<DataType>(metadata),\n );\n\n const secrets = SecretMetadata.sort(parsedSecertMetadata);\n\n if (filterType) {\n return secrets.filter((secret) => secret.type === filterType);\n }\n\n return secrets;\n }\n\n /**\n * Parse and create the SecretMetadata instance from the raw metadata bytes.\n *\n * @param rawMetadata - The raw metadata.\n * @returns The parsed secret metadata.\n */\n static fromRawMetadata<DataType extends SecretDataType>(\n rawMetadata: Uint8Array,\n ): SecretMetadata<DataType> {\n const serializedMetadata = bytesToString(rawMetadata);\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n SecretMetadata.assertIsValidSecretMetadataJson<DataType>(parsedMetadata);\n\n // if the type is not provided, we default to Mnemonic for the backwards compatibility\n const type = parsedMetadata.type ?? SecretType.Mnemonic;\n const version = parsedMetadata.version ?? SecretMetadataVersion.V1;\n\n let data: DataType;\n try {\n data = base64ToBytes(parsedMetadata.data) as DataType;\n } catch {\n data = parsedMetadata.data as DataType;\n }\n\n return new SecretMetadata<DataType>(data, {\n timestamp: parsedMetadata.timestamp,\n type,\n version,\n });\n }\n\n /**\n * Sort the seed phrases by timestamp.\n *\n * @param data - The secret metadata array to sort.\n * @param order - The order to sort the seed phrases. Default is `desc`.\n *\n * @returns The sorted secret metadata array.\n */\n static sort<DataType extends SecretDataType = Uint8Array>(\n data: SecretMetadata<DataType>[],\n order: 'asc' | 'desc' = 'asc',\n ): SecretMetadata<DataType>[] {\n return data.sort((a, b) => {\n if (order === 'asc') {\n return a.timestamp - b.timestamp;\n }\n return b.timestamp - a.timestamp;\n });\n }\n\n get data(): DataType {\n return this.#data;\n }\n\n get timestamp() {\n return this.#timestamp;\n }\n\n get type() {\n return this.#type;\n }\n\n get version() {\n return this.#version;\n }\n\n /**\n * Serialize the secret metadata and convert it to a Uint8Array.\n *\n * @returns The serialized SecretMetadata value in bytes.\n */\n toBytes(): Uint8Array {\n let _data: unknown = this.#data;\n if (this.#data instanceof Uint8Array) {\n // encode the raw secret to base64 encoded string\n // to create more compacted metadata\n _data = bytesToBase64(this.#data);\n }\n\n // serialize the metadata to a JSON string\n const serializedMetadata = JSON.stringify({\n data: _data,\n timestamp: this.#timestamp,\n type: this.#type,\n version: this.#version,\n });\n\n // convert the serialized metadata to bytes(Uint8Array)\n return stringToBytes(serializedMetadata);\n }\n}\n"]}
@@ -7,6 +7,10 @@ type ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {
7
7
  version: SecretMetadataVersion;
8
8
  toBytes: () => Uint8Array;
9
9
  };
10
+ /**
11
+ * SecretMetadata type without the data and toBytes methods
12
+ * in which the data is base64 encoded for more compacted metadata
13
+ */
10
14
  type SecretMetadataJson<DataType extends SecretDataType> = Omit<ISecretMetadata<DataType>, 'data' | 'toBytes'> & {
11
15
  data: string;
12
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SecretMetadata.d.cts","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,UAAU,EACV,qBAAqB,EACtB,wBAAoB;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,oBAAgB;AAErE,KAAK,eAAe,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,IAAI;IACnE,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,MAAM,UAAU,CAAC;CAC3B,CAAC;AAIF,KAAK,kBAAkB,CAAC,QAAQ,SAAS,cAAc,IAAI,IAAI,CAC7D,eAAe,CAAC,QAAQ,CAAC,EACzB,MAAM,GAAG,SAAS,CACnB,GAAG;IACF,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,cAAc,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,CACtE,YAAW,eAAe,CAAC,QAAQ,CAAC;;IAUpC;;;;;;;OAOG;gBACS,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAOpE;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,SAAS,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAC3D,IAAI,EAAE;QACJ,KAAK,EAAE,QAAQ,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;KAC1C,EAAE,GACF,cAAc,CAAC,QAAQ,CAAC,EAAE;IAc7B;;;;;OAKG;IACH,MAAM,CAAC,+BAA+B,CACpC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAC5C,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,kBAAkB,CAAC,QAAQ,CAAC;IAehE;;;;;;;;OAQG;IACH,MAAM,CAAC,6BAA6B,CAClC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAE5C,iBAAiB,EAAE,UAAU,EAAE,EAC/B,UAAU,CAAC,EAAE,UAAU,GACtB,cAAc,CAAC,QAAQ,CAAC,EAAE;IAc7B;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,SAAS,cAAc,EACpD,WAAW,EAAE,UAAU,GACtB,cAAc,CAAC,QAAQ,CAAC;IAwB3B;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,EACtD,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,EAChC,KAAK,GAAE,KAAK,GAAG,MAAc,GAC5B,cAAc,CAAC,QAAQ,CAAC,EAAE;IAS7B,IAAI,IAAI,IAAI,QAAQ,CAEnB;IAED,IAAI,SAAS,WAEZ;IAED,IAAI,IAAI,eAEP;IAED,IAAI,OAAO,0BAEV;IAED;;;;OAIG;IACH,OAAO,IAAI,UAAU;CAmBtB"}
1
+ {"version":3,"file":"SecretMetadata.d.cts","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,UAAU,EACV,qBAAqB,EACtB,wBAAoB;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,oBAAgB;AAErE,KAAK,eAAe,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,IAAI;IACnE,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,MAAM,UAAU,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,KAAK,kBAAkB,CAAC,QAAQ,SAAS,cAAc,IAAI,IAAI,CAC7D,eAAe,CAAC,QAAQ,CAAC,EACzB,MAAM,GAAG,SAAS,CACnB,GAAG;IACF,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,cAAc,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,CACtE,YAAW,eAAe,CAAC,QAAQ,CAAC;;IAUpC;;;;;;;OAOG;gBACS,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAOpE;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,SAAS,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAC3D,IAAI,EAAE;QACJ,KAAK,EAAE,QAAQ,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;KAC1C,EAAE,GACF,cAAc,CAAC,QAAQ,CAAC,EAAE;IAc7B;;;;;OAKG;IACH,MAAM,CAAC,+BAA+B,CACpC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAC5C,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,kBAAkB,CAAC,QAAQ,CAAC;IAehE;;;;;;;;OAQG;IACH,MAAM,CAAC,6BAA6B,CAClC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAE5C,iBAAiB,EAAE,UAAU,EAAE,EAC/B,UAAU,CAAC,EAAE,UAAU,GACtB,cAAc,CAAC,QAAQ,CAAC,EAAE;IAc7B;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,SAAS,cAAc,EACpD,WAAW,EAAE,UAAU,GACtB,cAAc,CAAC,QAAQ,CAAC;IAwB3B;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,EACtD,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,EAChC,KAAK,GAAE,KAAK,GAAG,MAAc,GAC5B,cAAc,CAAC,QAAQ,CAAC,EAAE;IAS7B,IAAI,IAAI,IAAI,QAAQ,CAEnB;IAED,IAAI,SAAS,WAEZ;IAED,IAAI,IAAI,eAEP;IAED,IAAI,OAAO,0BAEV;IAED;;;;OAIG;IACH,OAAO,IAAI,UAAU;CAmBtB"}
@@ -7,6 +7,10 @@ type ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {
7
7
  version: SecretMetadataVersion;
8
8
  toBytes: () => Uint8Array;
9
9
  };
10
+ /**
11
+ * SecretMetadata type without the data and toBytes methods
12
+ * in which the data is base64 encoded for more compacted metadata
13
+ */
10
14
  type SecretMetadataJson<DataType extends SecretDataType> = Omit<ISecretMetadata<DataType>, 'data' | 'toBytes'> & {
11
15
  data: string;
12
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SecretMetadata.d.mts","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,UAAU,EACV,qBAAqB,EACtB,wBAAoB;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,oBAAgB;AAErE,KAAK,eAAe,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,IAAI;IACnE,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,MAAM,UAAU,CAAC;CAC3B,CAAC;AAIF,KAAK,kBAAkB,CAAC,QAAQ,SAAS,cAAc,IAAI,IAAI,CAC7D,eAAe,CAAC,QAAQ,CAAC,EACzB,MAAM,GAAG,SAAS,CACnB,GAAG;IACF,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,cAAc,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,CACtE,YAAW,eAAe,CAAC,QAAQ,CAAC;;IAUpC;;;;;;;OAOG;gBACS,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAOpE;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,SAAS,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAC3D,IAAI,EAAE;QACJ,KAAK,EAAE,QAAQ,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;KAC1C,EAAE,GACF,cAAc,CAAC,QAAQ,CAAC,EAAE;IAc7B;;;;;OAKG;IACH,MAAM,CAAC,+BAA+B,CACpC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAC5C,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,kBAAkB,CAAC,QAAQ,CAAC;IAehE;;;;;;;;OAQG;IACH,MAAM,CAAC,6BAA6B,CAClC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAE5C,iBAAiB,EAAE,UAAU,EAAE,EAC/B,UAAU,CAAC,EAAE,UAAU,GACtB,cAAc,CAAC,QAAQ,CAAC,EAAE;IAc7B;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,SAAS,cAAc,EACpD,WAAW,EAAE,UAAU,GACtB,cAAc,CAAC,QAAQ,CAAC;IAwB3B;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,EACtD,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,EAChC,KAAK,GAAE,KAAK,GAAG,MAAc,GAC5B,cAAc,CAAC,QAAQ,CAAC,EAAE;IAS7B,IAAI,IAAI,IAAI,QAAQ,CAEnB;IAED,IAAI,SAAS,WAEZ;IAED,IAAI,IAAI,eAEP;IAED,IAAI,OAAO,0BAEV;IAED;;;;OAIG;IACH,OAAO,IAAI,UAAU;CAmBtB"}
1
+ {"version":3,"file":"SecretMetadata.d.mts","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,UAAU,EACV,qBAAqB,EACtB,wBAAoB;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,oBAAgB;AAErE,KAAK,eAAe,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,IAAI;IACnE,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,MAAM,UAAU,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,KAAK,kBAAkB,CAAC,QAAQ,SAAS,cAAc,IAAI,IAAI,CAC7D,eAAe,CAAC,QAAQ,CAAC,EACzB,MAAM,GAAG,SAAS,CACnB,GAAG;IACF,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,cAAc,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,CACtE,YAAW,eAAe,CAAC,QAAQ,CAAC;;IAUpC;;;;;;;OAOG;gBACS,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAOpE;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,SAAS,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAC3D,IAAI,EAAE;QACJ,KAAK,EAAE,QAAQ,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;KAC1C,EAAE,GACF,cAAc,CAAC,QAAQ,CAAC,EAAE;IAc7B;;;;;OAKG;IACH,MAAM,CAAC,+BAA+B,CACpC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAC5C,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,kBAAkB,CAAC,QAAQ,CAAC;IAehE;;;;;;;;OAQG;IACH,MAAM,CAAC,6BAA6B,CAClC,QAAQ,SAAS,cAAc,GAAG,UAAU,EAE5C,iBAAiB,EAAE,UAAU,EAAE,EAC/B,UAAU,CAAC,EAAE,UAAU,GACtB,cAAc,CAAC,QAAQ,CAAC,EAAE;IAc7B;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,SAAS,cAAc,EACpD,WAAW,EAAE,UAAU,GACtB,cAAc,CAAC,QAAQ,CAAC;IAwB3B;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,CAAC,QAAQ,SAAS,cAAc,GAAG,UAAU,EACtD,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,EAChC,KAAK,GAAE,KAAK,GAAG,MAAc,GAC5B,cAAc,CAAC,QAAQ,CAAC,EAAE;IAS7B,IAAI,IAAI,IAAI,QAAQ,CAEnB;IAED,IAAI,SAAS,WAEZ;IAED,IAAI,IAAI,eAEP;IAED,IAAI,OAAO,0BAEV;IAED;;;;OAIG;IACH,OAAO,IAAI,UAAU;CAmBtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"SecretMetadata.mjs","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n base64ToBytes,\n bytesToBase64,\n stringToBytes,\n bytesToString,\n} from '@metamask/utils';\n\nimport {\n SeedlessOnboardingControllerErrorMessage,\n SecretType,\n SecretMetadataVersion,\n} from './constants';\nimport type { SecretDataType, SecretMetadataOptions } from './types';\n\ntype ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {\n data: DataType;\n timestamp: number;\n type: SecretType;\n version: SecretMetadataVersion;\n toBytes: () => Uint8Array;\n};\n\n// SecretMetadata type without the data and toBytes methods\n// in which the data is base64 encoded for more compacted metadata\ntype SecretMetadataJson<DataType extends SecretDataType> = Omit<\n ISecretMetadata<DataType>,\n 'data' | 'toBytes'\n> & {\n data: string; // base64 encoded string\n};\n\n/**\n * SecretMetadata is a class that adds metadata to the secret.\n *\n * It contains the secret and the timestamp when it was created.\n * It is used to store the secret in the metadata store.\n *\n * @example\n * ```ts\n * const secretMetadata = new SecretMetadata(secret);\n * ```\n */\nexport class SecretMetadata<DataType extends SecretDataType = Uint8Array>\n implements ISecretMetadata<DataType>\n{\n readonly #data: DataType;\n\n readonly #timestamp: number;\n\n readonly #type: SecretType;\n\n readonly #version: SecretMetadataVersion;\n\n /**\n * Create a new SecretMetadata instance.\n *\n * @param data - The secret to add metadata to.\n * @param options - The options for the secret metadata.\n * @param options.timestamp - The timestamp when the secret was created.\n * @param options.type - The type of the secret.\n */\n constructor(data: DataType, options?: Partial<SecretMetadataOptions>) {\n this.#data = data;\n this.#timestamp = options?.timestamp ?? Date.now();\n this.#type = options?.type ?? SecretType.Mnemonic;\n this.#version = options?.version ?? SecretMetadataVersion.V1;\n }\n\n /**\n * Create an Array of SecretMetadata instances from an array of secrets.\n *\n * To respect the order of the secrets, we add the index to the timestamp\n * so that the first secret backup will have the oldest timestamp\n * and the last secret backup will have the newest timestamp.\n *\n * @param data - The data to add metadata to.\n * @param data.value - The SeedPhrase/PrivateKey to add metadata to.\n * @param data.options - The options for the seed phrase metadata.\n * @returns The SecretMetadata instances.\n */\n static fromBatch<DataType extends SecretDataType = Uint8Array>(\n data: {\n value: DataType;\n options?: Partial<SecretMetadataOptions>;\n }[],\n ): SecretMetadata<DataType>[] {\n const timestamp = Date.now();\n return data.map((d, index) => {\n // To respect the order of the seed phrases, we add the index to the timestamp\n // so that the first seed phrase backup will have the oldest timestamp\n // and the last seed phrase backup will have the newest timestamp\n const backupCreatedAt = d.options?.timestamp ?? timestamp + index * 5;\n return new SecretMetadata(d.value, {\n timestamp: backupCreatedAt,\n type: d.options?.type,\n });\n });\n }\n\n /**\n * Assert that the provided value is a valid seed phrase metadata.\n *\n * @param value - The value to check.\n * @throws If the value is not a valid seed phrase metadata.\n */\n static assertIsValidSecretMetadataJson<\n DataType extends SecretDataType = Uint8Array,\n >(value: unknown): asserts value is SecretMetadataJson<DataType> {\n if (\n typeof value !== 'object' ||\n !value ||\n !('data' in value) ||\n typeof value.data !== 'string' ||\n !('timestamp' in value) ||\n typeof value.timestamp !== 'number'\n ) {\n throw new Error(\n SeedlessOnboardingControllerErrorMessage.InvalidSecretMetadata,\n );\n }\n }\n\n /**\n * Parse the SecretMetadata from the metadata store and return the array of SecretMetadata instances.\n *\n * This method also sorts the secrets by timestamp in ascending order, i.e. the oldest secret will be the first element in the array.\n *\n * @param secretMetadataArr - The array of SecretMetadata from the metadata store.\n * @param filterType - The type of the secret to filter.\n * @returns The array of SecretMetadata instances.\n */\n static parseSecretsFromMetadataStore<\n DataType extends SecretDataType = Uint8Array,\n >(\n secretMetadataArr: Uint8Array[],\n filterType?: SecretType,\n ): SecretMetadata<DataType>[] {\n const parsedSecertMetadata = secretMetadataArr.map((metadata) =>\n SecretMetadata.fromRawMetadata<DataType>(metadata),\n );\n\n const secrets = SecretMetadata.sort(parsedSecertMetadata);\n\n if (filterType) {\n return secrets.filter((secret) => secret.type === filterType);\n }\n\n return secrets;\n }\n\n /**\n * Parse and create the SecretMetadata instance from the raw metadata bytes.\n *\n * @param rawMetadata - The raw metadata.\n * @returns The parsed secret metadata.\n */\n static fromRawMetadata<DataType extends SecretDataType>(\n rawMetadata: Uint8Array,\n ): SecretMetadata<DataType> {\n const serializedMetadata = bytesToString(rawMetadata);\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n SecretMetadata.assertIsValidSecretMetadataJson<DataType>(parsedMetadata);\n\n // if the type is not provided, we default to Mnemonic for the backwards compatibility\n const type = parsedMetadata.type ?? SecretType.Mnemonic;\n const version = parsedMetadata.version ?? SecretMetadataVersion.V1;\n\n let data: DataType;\n try {\n data = base64ToBytes(parsedMetadata.data) as DataType;\n } catch {\n data = parsedMetadata.data as DataType;\n }\n\n return new SecretMetadata<DataType>(data, {\n timestamp: parsedMetadata.timestamp,\n type,\n version,\n });\n }\n\n /**\n * Sort the seed phrases by timestamp.\n *\n * @param data - The secret metadata array to sort.\n * @param order - The order to sort the seed phrases. Default is `desc`.\n *\n * @returns The sorted secret metadata array.\n */\n static sort<DataType extends SecretDataType = Uint8Array>(\n data: SecretMetadata<DataType>[],\n order: 'asc' | 'desc' = 'asc',\n ): SecretMetadata<DataType>[] {\n return data.sort((a, b) => {\n if (order === 'asc') {\n return a.timestamp - b.timestamp;\n }\n return b.timestamp - a.timestamp;\n });\n }\n\n get data(): DataType {\n return this.#data;\n }\n\n get timestamp() {\n return this.#timestamp;\n }\n\n get type() {\n return this.#type;\n }\n\n get version() {\n return this.#version;\n }\n\n /**\n * Serialize the secret metadata and convert it to a Uint8Array.\n *\n * @returns The serialized SecretMetadata value in bytes.\n */\n toBytes(): Uint8Array {\n let _data: unknown = this.#data;\n if (this.#data instanceof Uint8Array) {\n // encode the raw secret to base64 encoded string\n // to create more compacted metadata\n _data = bytesToBase64(this.#data);\n }\n\n // serialize the metadata to a JSON string\n const serializedMetadata = JSON.stringify({\n data: _data,\n timestamp: this.#timestamp,\n type: this.#type,\n version: this.#version,\n });\n\n // convert the serialized metadata to bytes(Uint8Array)\n return stringToBytes(serializedMetadata);\n }\n}\n"]}
1
+ {"version":3,"file":"SecretMetadata.mjs","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n base64ToBytes,\n bytesToBase64,\n stringToBytes,\n bytesToString,\n} from '@metamask/utils';\n\nimport {\n SeedlessOnboardingControllerErrorMessage,\n SecretType,\n SecretMetadataVersion,\n} from './constants';\nimport type { SecretDataType, SecretMetadataOptions } from './types';\n\ntype ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {\n data: DataType;\n timestamp: number;\n type: SecretType;\n version: SecretMetadataVersion;\n toBytes: () => Uint8Array;\n};\n\n/**\n * SecretMetadata type without the data and toBytes methods\n * in which the data is base64 encoded for more compacted metadata\n */\ntype SecretMetadataJson<DataType extends SecretDataType> = Omit<\n ISecretMetadata<DataType>,\n 'data' | 'toBytes'\n> & {\n data: string; // base64 encoded string\n};\n\n/**\n * SecretMetadata is a class that adds metadata to the secret.\n *\n * It contains the secret and the timestamp when it was created.\n * It is used to store the secret in the metadata store.\n *\n * @example\n * ```ts\n * const secretMetadata = new SecretMetadata(secret);\n * ```\n */\nexport class SecretMetadata<DataType extends SecretDataType = Uint8Array>\n implements ISecretMetadata<DataType>\n{\n readonly #data: DataType;\n\n readonly #timestamp: number;\n\n readonly #type: SecretType;\n\n readonly #version: SecretMetadataVersion;\n\n /**\n * Create a new SecretMetadata instance.\n *\n * @param data - The secret to add metadata to.\n * @param options - The options for the secret metadata.\n * @param options.timestamp - The timestamp when the secret was created.\n * @param options.type - The type of the secret.\n */\n constructor(data: DataType, options?: Partial<SecretMetadataOptions>) {\n this.#data = data;\n this.#timestamp = options?.timestamp ?? Date.now();\n this.#type = options?.type ?? SecretType.Mnemonic;\n this.#version = options?.version ?? SecretMetadataVersion.V1;\n }\n\n /**\n * Create an Array of SecretMetadata instances from an array of secrets.\n *\n * To respect the order of the secrets, we add the index to the timestamp\n * so that the first secret backup will have the oldest timestamp\n * and the last secret backup will have the newest timestamp.\n *\n * @param data - The data to add metadata to.\n * @param data.value - The SeedPhrase/PrivateKey to add metadata to.\n * @param data.options - The options for the seed phrase metadata.\n * @returns The SecretMetadata instances.\n */\n static fromBatch<DataType extends SecretDataType = Uint8Array>(\n data: {\n value: DataType;\n options?: Partial<SecretMetadataOptions>;\n }[],\n ): SecretMetadata<DataType>[] {\n const timestamp = Date.now();\n return data.map((d, index) => {\n // To respect the order of the seed phrases, we add the index to the timestamp\n // so that the first seed phrase backup will have the oldest timestamp\n // and the last seed phrase backup will have the newest timestamp\n const backupCreatedAt = d.options?.timestamp ?? timestamp + index * 5;\n return new SecretMetadata(d.value, {\n timestamp: backupCreatedAt,\n type: d.options?.type,\n });\n });\n }\n\n /**\n * Assert that the provided value is a valid seed phrase metadata.\n *\n * @param value - The value to check.\n * @throws If the value is not a valid seed phrase metadata.\n */\n static assertIsValidSecretMetadataJson<\n DataType extends SecretDataType = Uint8Array,\n >(value: unknown): asserts value is SecretMetadataJson<DataType> {\n if (\n typeof value !== 'object' ||\n !value ||\n !('data' in value) ||\n typeof value.data !== 'string' ||\n !('timestamp' in value) ||\n typeof value.timestamp !== 'number'\n ) {\n throw new Error(\n SeedlessOnboardingControllerErrorMessage.InvalidSecretMetadata,\n );\n }\n }\n\n /**\n * Parse the SecretMetadata from the metadata store and return the array of SecretMetadata instances.\n *\n * This method also sorts the secrets by timestamp in ascending order, i.e. the oldest secret will be the first element in the array.\n *\n * @param secretMetadataArr - The array of SecretMetadata from the metadata store.\n * @param filterType - The type of the secret to filter.\n * @returns The array of SecretMetadata instances.\n */\n static parseSecretsFromMetadataStore<\n DataType extends SecretDataType = Uint8Array,\n >(\n secretMetadataArr: Uint8Array[],\n filterType?: SecretType,\n ): SecretMetadata<DataType>[] {\n const parsedSecertMetadata = secretMetadataArr.map((metadata) =>\n SecretMetadata.fromRawMetadata<DataType>(metadata),\n );\n\n const secrets = SecretMetadata.sort(parsedSecertMetadata);\n\n if (filterType) {\n return secrets.filter((secret) => secret.type === filterType);\n }\n\n return secrets;\n }\n\n /**\n * Parse and create the SecretMetadata instance from the raw metadata bytes.\n *\n * @param rawMetadata - The raw metadata.\n * @returns The parsed secret metadata.\n */\n static fromRawMetadata<DataType extends SecretDataType>(\n rawMetadata: Uint8Array,\n ): SecretMetadata<DataType> {\n const serializedMetadata = bytesToString(rawMetadata);\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n SecretMetadata.assertIsValidSecretMetadataJson<DataType>(parsedMetadata);\n\n // if the type is not provided, we default to Mnemonic for the backwards compatibility\n const type = parsedMetadata.type ?? SecretType.Mnemonic;\n const version = parsedMetadata.version ?? SecretMetadataVersion.V1;\n\n let data: DataType;\n try {\n data = base64ToBytes(parsedMetadata.data) as DataType;\n } catch {\n data = parsedMetadata.data as DataType;\n }\n\n return new SecretMetadata<DataType>(data, {\n timestamp: parsedMetadata.timestamp,\n type,\n version,\n });\n }\n\n /**\n * Sort the seed phrases by timestamp.\n *\n * @param data - The secret metadata array to sort.\n * @param order - The order to sort the seed phrases. Default is `desc`.\n *\n * @returns The sorted secret metadata array.\n */\n static sort<DataType extends SecretDataType = Uint8Array>(\n data: SecretMetadata<DataType>[],\n order: 'asc' | 'desc' = 'asc',\n ): SecretMetadata<DataType>[] {\n return data.sort((a, b) => {\n if (order === 'asc') {\n return a.timestamp - b.timestamp;\n }\n return b.timestamp - a.timestamp;\n });\n }\n\n get data(): DataType {\n return this.#data;\n }\n\n get timestamp() {\n return this.#timestamp;\n }\n\n get type() {\n return this.#type;\n }\n\n get version() {\n return this.#version;\n }\n\n /**\n * Serialize the secret metadata and convert it to a Uint8Array.\n *\n * @returns The serialized SecretMetadata value in bytes.\n */\n toBytes(): Uint8Array {\n let _data: unknown = this.#data;\n if (this.#data instanceof Uint8Array) {\n // encode the raw secret to base64 encoded string\n // to create more compacted metadata\n _data = bytesToBase64(this.#data);\n }\n\n // serialize the metadata to a JSON string\n const serializedMetadata = JSON.stringify({\n data: _data,\n timestamp: this.#timestamp,\n type: this.#type,\n version: this.#version,\n });\n\n // convert the serialized metadata to bytes(Uint8Array)\n return stringToBytes(serializedMetadata);\n }\n}\n"]}
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _SeedlessOnboardingController_instances, _SeedlessOnboardingController_vaultEncryptor, _SeedlessOnboardingController_controllerOperationMutex, _SeedlessOnboardingController_vaultOperationMutex, _SeedlessOnboardingController_isUnlocked, _SeedlessOnboardingController_recoverPassword, _SeedlessOnboardingController_setUnlocked, _SeedlessOnboardingController_persistOprfKey, _SeedlessOnboardingController_persistAuthPubKey, _SeedlessOnboardingController_recoverAuthPubKey, _SeedlessOnboardingController_recoverEncKey, _SeedlessOnboardingController_changeEncryptionKey, _SeedlessOnboardingController_encryptAndStoreSeedPhraseBackup, _SeedlessOnboardingController_unlockVaultAndGetBackupEncKey, _SeedlessOnboardingController_withPersistedSeedPhraseBackupsState, _SeedlessOnboardingController_filterDupesAndUpdateSocialBackupsMetadata, _SeedlessOnboardingController_createNewVaultWithAuthData, _SeedlessOnboardingController_updateVault, _SeedlessOnboardingController_withControllerLock, _SeedlessOnboardingController_withVaultLock, _SeedlessOnboardingController_serializeKeyData, _SeedlessOnboardingController_parseVaultData, _SeedlessOnboardingController_assertIsUnlocked, _SeedlessOnboardingController_assertIsAuthenticatedUser, _SeedlessOnboardingController_assertIsSRPBackedUpUser, _SeedlessOnboardingController_assertPasswordInSync, _SeedlessOnboardingController_resetPasswordOutdatedCache, _SeedlessOnboardingController_assertIsValidVaultData;
13
+ var _SeedlessOnboardingController_instances, _SeedlessOnboardingController_vaultEncryptor, _SeedlessOnboardingController_controllerOperationMutex, _SeedlessOnboardingController_vaultOperationMutex, _SeedlessOnboardingController_isUnlocked, _SeedlessOnboardingController_recoverPassword, _SeedlessOnboardingController_setUnlocked, _SeedlessOnboardingController_persistOprfKey, _SeedlessOnboardingController_persistAuthPubKey, _SeedlessOnboardingController_recoverAuthPubKey, _SeedlessOnboardingController_recoverEncKey, _SeedlessOnboardingController_changeEncryptionKey, _SeedlessOnboardingController_encryptAndStoreSeedPhraseBackup, _SeedlessOnboardingController_unlockVaultAndGetBackupEncKey, _SeedlessOnboardingController_withPersistedSeedPhraseBackupsState, _SeedlessOnboardingController_filterDupesAndUpdateSocialBackupsMetadata, _SeedlessOnboardingController_createNewVaultWithAuthData, _SeedlessOnboardingController_updateVault, _SeedlessOnboardingController_withControllerLock, _SeedlessOnboardingController_withVaultLock, _SeedlessOnboardingController_serializeKeyData, _SeedlessOnboardingController_parseVaultData, _SeedlessOnboardingController_assertIsUnlocked, _SeedlessOnboardingController_assertIsAuthenticatedUser, _SeedlessOnboardingController_assertIsSRPBackedUpUser, _SeedlessOnboardingController_withRecoveryErrorHandler, _SeedlessOnboardingController_assertPasswordInSync, _SeedlessOnboardingController_resetPasswordOutdatedCache, _SeedlessOnboardingController_assertIsValidVaultData;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.SeedlessOnboardingController = exports.getDefaultSeedlessOnboardingControllerState = void 0;
16
16
  const auth_network_utils_1 = require("@metamask/auth-network-utils");
@@ -91,6 +91,10 @@ const seedlessOnboardingMetadata = {
91
91
  persist: true,
92
92
  anonymous: true,
93
93
  },
94
+ recoveryRatelimitCache: {
95
+ persist: true,
96
+ anonymous: true,
97
+ },
94
98
  };
95
99
  class SeedlessOnboardingController extends base_controller_1.BaseController {
96
100
  /**
@@ -100,9 +104,10 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
100
104
  * @param options.messenger - A restricted messenger.
101
105
  * @param options.state - Initial state to set on this controller.
102
106
  * @param options.encryptor - An optional encryptor to use for encrypting and decrypting seedless onboarding vault.
107
+ * @param options.toprfKeyDeriver - An optional key derivation interface for the TOPRF client.
103
108
  * @param options.network - The network to be used for the Seedless Onboarding flow.
104
109
  */
105
- constructor({ messenger, state, encryptor, network = constants_1.Web3AuthNetwork.Mainnet, }) {
110
+ constructor({ messenger, state, encryptor, toprfKeyDeriver, network = constants_1.Web3AuthNetwork.Mainnet, }) {
106
111
  super({
107
112
  name: constants_1.controllerName,
108
113
  metadata: seedlessOnboardingMetadata,
@@ -125,6 +130,7 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
125
130
  __classPrivateFieldSet(this, _SeedlessOnboardingController_vaultEncryptor, encryptor, "f");
126
131
  this.toprfClient = new toprf_secure_backup_1.ToprfSecureBackup({
127
132
  network,
133
+ keyDeriver: toprfKeyDeriver,
128
134
  });
129
135
  // setup subscriptions to the keyring lock event
130
136
  // when the keyring is locked (wallet is locked), the controller will be cleared of its credentials
@@ -153,17 +159,11 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
153
159
  return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_withControllerLock).call(this, async () => {
154
160
  try {
155
161
  const { idTokens, authConnectionId, groupedAuthConnectionId, userId, authConnection, socialLoginEmail, } = params;
156
- const hashedIdTokenHexes = idTokens.map((idToken) => {
157
- return (0, utils_1.remove0x)((0, auth_network_utils_1.keccak256AndHexify)((0, utils_1.stringToBytes)(idToken)));
158
- });
159
162
  const authenticationResult = await this.toprfClient.authenticate({
160
- authConnectionId: groupedAuthConnectionId || authConnectionId,
163
+ authConnectionId,
161
164
  userId,
162
- idTokens: hashedIdTokenHexes,
163
- groupedAuthConnectionParams: {
164
- authConnectionId,
165
- idTokens,
166
- },
165
+ idTokens,
166
+ groupedAuthConnectionId,
167
167
  });
168
168
  // update the state with the authenticated user info
169
169
  this.update((state) => {
@@ -196,7 +196,7 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
196
196
  __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
197
197
  return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_withControllerLock).call(this, async () => {
198
198
  // locally evaluate the encryption key from the password
199
- const { encKey, authKeyPair, oprfKey } = this.toprfClient.createLocalKey({
199
+ const { encKey, authKeyPair, oprfKey } = await this.toprfClient.createLocalKey({
200
200
  password,
201
201
  });
202
202
  // encrypt and store the seed phrase backup
@@ -487,7 +487,8 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
487
487
  const currentDeviceAuthPubKey = __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverAuthPubKey).call(this);
488
488
  const { authPubKey: globalAuthPubKey } = await this.toprfClient.fetchAuthPubKey({
489
489
  nodeAuthTokens,
490
- authConnectionId: groupedAuthConnectionId || authConnectionId,
490
+ authConnectionId,
491
+ groupedAuthConnectionId,
491
492
  userId,
492
493
  });
493
494
  // use noble lib to deserialize and compare curve point
@@ -547,12 +548,13 @@ async function _SeedlessOnboardingController_recoverPassword({ targetPwPubKey, g
547
548
  */
548
549
  async function _SeedlessOnboardingController_persistOprfKey(oprfKey, authPubKey) {
549
550
  __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
550
- const authConnectionId = this.state.groupedAuthConnectionId || this.state.authConnectionId;
551
+ const { authConnectionId, groupedAuthConnectionId, userId } = this.state;
551
552
  try {
552
553
  await this.toprfClient.persistLocalKey({
553
554
  nodeAuthTokens: this.state.nodeAuthTokens,
554
555
  authConnectionId,
555
- userId: this.state.userId,
556
+ groupedAuthConnectionId,
557
+ userId,
556
558
  oprfKey,
557
559
  authPubKey,
558
560
  });
@@ -578,20 +580,18 @@ async function _SeedlessOnboardingController_persistOprfKey(oprfKey, authPubKey)
578
580
  * @throws RecoveryError - If failed to recover the encryption key.
579
581
  */
580
582
  async function _SeedlessOnboardingController_recoverEncKey(password) {
581
- __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
582
- const authConnectionId = this.state.groupedAuthConnectionId || this.state.authConnectionId;
583
- try {
583
+ return __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_withRecoveryErrorHandler).call(this, async () => {
584
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
585
+ const { authConnectionId, groupedAuthConnectionId, userId } = this.state;
584
586
  const recoverEncKeyResult = await this.toprfClient.recoverEncKey({
585
587
  nodeAuthTokens: this.state.nodeAuthTokens,
586
588
  password,
587
589
  authConnectionId,
588
- userId: this.state.userId,
590
+ groupedAuthConnectionId,
591
+ userId,
589
592
  });
590
593
  return recoverEncKeyResult;
591
- }
592
- catch (error) {
593
- throw errors_1.RecoveryError.getInstance(error);
594
- }
594
+ });
595
595
  }, _SeedlessOnboardingController_changeEncryptionKey =
596
596
  /**
597
597
  * Update the encryption key with new password and update the Metadata Store with new encryption key.
@@ -602,12 +602,13 @@ async function _SeedlessOnboardingController_recoverEncKey(password) {
602
602
  */
603
603
  async function _SeedlessOnboardingController_changeEncryptionKey(newPassword, oldPassword) {
604
604
  __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
605
- const authConnectionId = this.state.groupedAuthConnectionId || this.state.authConnectionId;
605
+ const { authConnectionId, groupedAuthConnectionId, userId } = this.state;
606
606
  const { encKey, authKeyPair, keyShareIndex: newKeyShareIndex, } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverEncKey).call(this, oldPassword);
607
607
  return await this.toprfClient.changeEncKey({
608
608
  nodeAuthTokens: this.state.nodeAuthTokens,
609
609
  authConnectionId,
610
- userId: this.state.userId,
610
+ groupedAuthConnectionId,
611
+ userId,
611
612
  oldEncKey: encKey,
612
613
  oldAuthKeyPair: authKeyPair,
613
614
  newKeyShareIndex,
@@ -891,6 +892,45 @@ async function _SeedlessOnboardingController_withVaultLock(callback) {
891
892
  if (!this.state.authPubKey) {
892
893
  throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.SRPNotBackedUpError);
893
894
  }
895
+ }, _SeedlessOnboardingController_withRecoveryErrorHandler =
896
+ /**
897
+ * Handle the recovery error and update the recovery error data after executing the given callback.
898
+ *
899
+ * @param recoveryCallback - The callback recovery function to execute.
900
+ * @returns The result of the callback function.
901
+ */
902
+ async function _SeedlessOnboardingController_withRecoveryErrorHandler(recoveryCallback) {
903
+ const currentRecoveryAttempts = this.state.recoveryRatelimitCache?.numberOfAttempts || 0;
904
+ let updatedRecoveryAttempts = currentRecoveryAttempts + 1;
905
+ let updatedRemainingTime = this.state.recoveryRatelimitCache?.remainingTime || 0;
906
+ try {
907
+ const result = await recoveryCallback();
908
+ // reset the ratelimit error data
909
+ updatedRecoveryAttempts = 0;
910
+ updatedRemainingTime = 0;
911
+ return result;
912
+ }
913
+ catch (error) {
914
+ const recoveryError = errors_1.RecoveryError.getInstance(error, {
915
+ numberOfAttempts: updatedRecoveryAttempts,
916
+ remainingTime: updatedRemainingTime,
917
+ });
918
+ if (recoveryError.data?.numberOfAttempts) {
919
+ updatedRecoveryAttempts = recoveryError.data.numberOfAttempts;
920
+ }
921
+ if (recoveryError.data?.remainingTime) {
922
+ updatedRemainingTime = recoveryError.data.remainingTime;
923
+ }
924
+ throw recoveryError;
925
+ }
926
+ finally {
927
+ this.update((state) => {
928
+ state.recoveryRatelimitCache = {
929
+ numberOfAttempts: updatedRecoveryAttempts,
930
+ remainingTime: updatedRemainingTime,
931
+ };
932
+ });
933
+ }
894
934
  }, _SeedlessOnboardingController_assertPasswordInSync =
895
935
  /**
896
936
  * Assert that the password is in sync with the global password.