@metamask-previews/seedless-onboarding-controller 10.0.2-preview-1ec310ea7 → 10.0.3-preview-bdb5ec714
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.
- package/CHANGELOG.md +10 -1
- package/dist/SecretMetadata.cjs +2 -15
- package/dist/SecretMetadata.cjs.map +1 -1
- package/dist/SecretMetadata.d.cts +1 -3
- package/dist/SecretMetadata.d.cts.map +1 -1
- package/dist/SecretMetadata.d.mts +1 -3
- package/dist/SecretMetadata.d.mts.map +1 -1
- package/dist/SecretMetadata.mjs +3 -16
- package/dist/SecretMetadata.mjs.map +1 -1
- package/dist/SeedlessOnboardingController.cjs +17 -8
- package/dist/SeedlessOnboardingController.cjs.map +1 -1
- package/dist/SeedlessOnboardingController.d.cts.map +1 -1
- package/dist/SeedlessOnboardingController.d.mts.map +1 -1
- package/dist/SeedlessOnboardingController.mjs +17 -8
- package/dist/SeedlessOnboardingController.mjs.map +1 -1
- package/dist/utils.cjs +1 -44
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +0 -24
- package/dist/utils.d.cts.map +1 -1
- package/dist/utils.d.mts +0 -24
- package/dist/utils.d.mts.map +1 -1
- package/dist/utils.mjs +0 -41
- package/dist/utils.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,10 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [10.0.3]
|
|
11
|
+
|
|
10
12
|
### Changed
|
|
11
13
|
|
|
12
14
|
- Bump `@metamask/utils` from `^11.9.0` to `^11.11.0` ([#9074](https://github.com/MetaMask/core/pull/9074))
|
|
13
15
|
- Bump `@metamask/keyring-controller` from `^27.0.0` to `^27.1.0` ([#9129](https://github.com/MetaMask/core/pull/9129))
|
|
16
|
+
- `SecretMetadata.compare` no longer uses `createdAt` (server-stamped TIMEUUID) for ordering; sort priority is now `PrimarySrp` tag first, then client-side timestamp ([#9247](https://github.com/MetaMask/core/pull/9247))
|
|
17
|
+
- The password change flow passes a `transformDataItems` callback to `changeEncKey` so sorting happens inside the metadata lock, preventing data loss from concurrent writes ([#9247](https://github.com/MetaMask/core/pull/9247))
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Fix `InvalidPrimarySecretDataType` crash caused by `changeEncKey` re-inserting items without sorting, causing the server to stamp `createdAt` in arbitrary order on password change ([#9247](https://github.com/MetaMask/core/pull/9247))
|
|
14
22
|
|
|
15
23
|
## [10.0.2]
|
|
16
24
|
|
|
@@ -400,7 +408,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
400
408
|
- `checkIsPasswordOutdated`: Check if the password is current device is outdated, i.e. user changed password in another device.
|
|
401
409
|
- `clearState`: Reset the state of the controller to the defaults.
|
|
402
410
|
|
|
403
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/seedless-onboarding-controller@10.0.
|
|
411
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/seedless-onboarding-controller@10.0.3...HEAD
|
|
412
|
+
[10.0.3]: https://github.com/MetaMask/core/compare/@metamask/seedless-onboarding-controller@10.0.2...@metamask/seedless-onboarding-controller@10.0.3
|
|
404
413
|
[10.0.2]: https://github.com/MetaMask/core/compare/@metamask/seedless-onboarding-controller@10.0.1...@metamask/seedless-onboarding-controller@10.0.2
|
|
405
414
|
[10.0.1]: https://github.com/MetaMask/core/compare/@metamask/seedless-onboarding-controller@10.0.0...@metamask/seedless-onboarding-controller@10.0.1
|
|
406
415
|
[10.0.0]: https://github.com/MetaMask/core/compare/@metamask/seedless-onboarding-controller@9.1.0...@metamask/seedless-onboarding-controller@10.0.0
|
package/dist/SecretMetadata.cjs
CHANGED
|
@@ -104,9 +104,7 @@ class SecretMetadata {
|
|
|
104
104
|
*
|
|
105
105
|
* Ordering priority:
|
|
106
106
|
* 1. PrimarySrp always comes first (regardless of order direction)
|
|
107
|
-
* 2.
|
|
108
|
-
* 3. Legacy items (null createdAt) are considered older
|
|
109
|
-
* 4. Fall back to client-side timestamp
|
|
107
|
+
* 2. Fall back to client-side timestamp
|
|
110
108
|
*
|
|
111
109
|
* @param a - The first SecretMetadata instance.
|
|
112
110
|
* @param b - The second SecretMetadata instance.
|
|
@@ -126,18 +124,7 @@ class SecretMetadata {
|
|
|
126
124
|
if (bIsPrimary) {
|
|
127
125
|
return 1;
|
|
128
126
|
}
|
|
129
|
-
//
|
|
130
|
-
if (a.createdAt && b.createdAt) {
|
|
131
|
-
return (0, utils_2.compareTimeuuid)(a.createdAt, b.createdAt, order);
|
|
132
|
-
}
|
|
133
|
-
// Handle mixed createdAt: legacy items (null) are older
|
|
134
|
-
if (!a.createdAt && b.createdAt) {
|
|
135
|
-
return order === 'asc' ? -1 : 1; // a (legacy/older) comes before b in asc
|
|
136
|
-
}
|
|
137
|
-
if (a.createdAt && !b.createdAt) {
|
|
138
|
-
return order === 'asc' ? 1 : -1; // b (legacy/older) comes before a in asc
|
|
139
|
-
}
|
|
140
|
-
// Both null: fall back to client-side timestamp
|
|
127
|
+
// Fall back to client-side timestamp
|
|
141
128
|
return SecretMetadata.compareByTimestamp(a, b, order);
|
|
142
129
|
}
|
|
143
130
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecretMetadata.cjs","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SecretDataItemOutput } from '@metamask/toprf-secure-backup';\nimport { EncAccountDataType } from '@metamask/toprf-secure-backup';\nimport {\n base64ToBytes,\n bytesToBase64,\n stringToBytes,\n bytesToString,\n} from '@metamask/utils';\n\nimport {\n SeedlessOnboardingControllerErrorMessage,\n SecretType,\n} from './constants';\nimport type { SecretDataType } from './types';\nimport { compareTimeuuid, getSecretTypeFromDataType } from './utils';\n\ntype ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {\n data: DataType;\n timestamp: number;\n type: SecretType;\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 */\n\n/**\n * Options for SecretMetadata constructor.\n *\n * New clients: provide V2 fields (`dataType`, `createdAt`, etc).\n * Reading V1 data: `timestamp` and `type` come from encrypted JSON.\n */\ntype SecretMetadataOptions = {\n // V1 fields (from encrypted JSON payload, for backward compat)\n timestamp?: number;\n type?: SecretType;\n\n // Storage-level metadata from the metadata store (not encrypted).\n itemId?: string;\n dataType?: EncAccountDataType;\n createdAt?: string;\n /**\n * The storage-level version from the SDK ('v1' or 'v2').\n * - 'v1': Legacy items created before dataType was introduced\n * - 'v2': Items with dataType set (either new or migrated)\n */\n storageVersion?: SecretDataItemOutput['version'];\n};\n\nexport class SecretMetadata<\n DataType extends SecretDataType = Uint8Array,\n> implements ISecretMetadata<DataType> {\n readonly #data: DataType;\n\n readonly #timestamp: number;\n\n readonly #type: SecretType;\n\n // Storage-level metadata (not encrypted)\n readonly #itemId?: string;\n\n readonly #dataType?: EncAccountDataType;\n\n readonly #createdAt?: string;\n\n readonly #storageVersion?: SecretDataItemOutput['version'];\n\n /**\n * @param data - The secret data.\n * @param options - Optional metadata. New clients should provide `dataType`.\n */\n constructor(data: DataType, options?: SecretMetadataOptions) {\n this.#data = data;\n this.#timestamp = options?.timestamp ?? Date.now();\n this.#itemId = options?.itemId;\n this.#dataType = options?.dataType;\n this.#createdAt = options?.createdAt;\n this.#storageVersion = options?.storageVersion;\n\n // Derive type from dataType (new clients), or use provided type (V1 compat)\n if (options?.dataType === undefined || options?.dataType === null) {\n this.#type = options?.type ?? SecretType.Mnemonic;\n } else {\n this.#type = getSecretTypeFromDataType(options.dataType);\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 and create the SecretMetadata instance from the raw metadata bytes.\n *\n * @param rawMetadata - The raw metadata.\n * @param storageMetadata - Storage-level metadata from the metadata store.\n * @returns The parsed secret metadata.\n */\n static fromRawMetadata<DataType extends SecretDataType>(\n rawMetadata: Uint8Array,\n storageMetadata: Omit<SecretMetadataOptions, 'timestamp' | 'type'>,\n ): SecretMetadata<DataType> {\n const serializedMetadata = bytesToString(rawMetadata);\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n SecretMetadata.assertIsValidSecretMetadataJson<DataType>(parsedMetadata);\n\n const type = parsedMetadata.type ?? SecretType.Mnemonic;\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 ...storageMetadata,\n });\n }\n\n /**\n * Compare two SecretMetadata instances by timestamp.\n *\n * @param a - The first SecretMetadata instance.\n * @param b - The second SecretMetadata instance.\n * @param order - The sort order. Default is 'asc'.\n * @returns A negative number if a < b, positive if a > b, zero if equal.\n */\n static compareByTimestamp<DataType extends SecretDataType = SecretDataType>(\n a: SecretMetadata<DataType>,\n b: SecretMetadata<DataType>,\n order: 'asc' | 'desc' = 'asc',\n ): number {\n return order === 'asc'\n ? a.timestamp - b.timestamp\n : b.timestamp - a.timestamp;\n }\n\n /**\n * Compare two SecretMetadata instances for ordering.\n *\n * Ordering priority:\n * 1. PrimarySrp always comes first (regardless of order direction)\n * 2. Server-side createdAt (TIMEUUID) if both have it\n * 3. Legacy items (null createdAt) are considered older\n * 4. Fall back to client-side timestamp\n *\n * @param a - The first SecretMetadata instance.\n * @param b - The second SecretMetadata instance.\n * @param order - The sort order. Default is 'asc'.\n * @returns A negative number if a < b, positive if a > b, zero if equal.\n */\n static compare<DataType extends SecretDataType = SecretDataType>(\n a: SecretMetadata<DataType>,\n b: SecretMetadata<DataType>,\n order: 'asc' | 'desc' = 'asc',\n ): number {\n // PrimarySrp always comes first (regardless of order direction)\n const aIsPrimary = a.dataType === EncAccountDataType.PrimarySrp;\n const bIsPrimary = b.dataType === EncAccountDataType.PrimarySrp;\n if (aIsPrimary && bIsPrimary) {\n return 0; // Both PrimarySrp: treat as equal (handles data corruption gracefully)\n }\n if (aIsPrimary) {\n return -1;\n }\n if (bIsPrimary) {\n return 1;\n }\n // Use server-side createdAt if available (TIMEUUID requires timestamp extraction)\n if (a.createdAt && b.createdAt) {\n return compareTimeuuid(a.createdAt, b.createdAt, order);\n }\n // Handle mixed createdAt: legacy items (null) are older\n if (!a.createdAt && b.createdAt) {\n return order === 'asc' ? -1 : 1; // a (legacy/older) comes before b in asc\n }\n if (a.createdAt && !b.createdAt) {\n return order === 'asc' ? 1 : -1; // b (legacy/older) comes before a in asc\n }\n // Both null: fall back to client-side timestamp\n return SecretMetadata.compareByTimestamp(a, b, order);\n }\n\n /**\n * Check if a SecretMetadata instance matches the given type.\n *\n * @param secret - The SecretMetadata instance to check.\n * @param type - The type to match against.\n * @returns True if the secret matches the type.\n */\n static matchesType<DataType extends SecretDataType = SecretDataType>(\n secret: SecretMetadata<DataType>,\n type: SecretType,\n ): boolean {\n return secret.type === type;\n }\n\n get data(): DataType {\n return this.#data;\n }\n\n get timestamp(): number {\n return this.#timestamp;\n }\n\n get type(): SecretType {\n return this.#type;\n }\n\n get itemId(): string | undefined {\n return this.#itemId;\n }\n\n get dataType(): EncAccountDataType | undefined {\n return this.#dataType;\n }\n\n get createdAt(): string | undefined {\n return this.#createdAt;\n }\n\n /**\n * The storage-level version from the SDK ('v1' or 'v2').\n *\n * @returns The storage-level version.\n */\n get storageVersion(): SecretDataItemOutput['version'] | undefined {\n return this.#storageVersion;\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 });\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":"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","sourcesContent":["import type { SecretDataItemOutput } from '@metamask/toprf-secure-backup';\nimport { EncAccountDataType } from '@metamask/toprf-secure-backup';\nimport {\n base64ToBytes,\n bytesToBase64,\n stringToBytes,\n bytesToString,\n} from '@metamask/utils';\n\nimport {\n SeedlessOnboardingControllerErrorMessage,\n SecretType,\n} from './constants';\nimport type { SecretDataType } from './types';\nimport { getSecretTypeFromDataType } from './utils';\n\ntype ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {\n data: DataType;\n timestamp: number;\n type: SecretType;\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 */\n\n/**\n * Options for SecretMetadata constructor.\n *\n * New clients: provide V2 fields (`dataType`, `createdAt`, etc).\n * Reading V1 data: `timestamp` and `type` come from encrypted JSON.\n */\ntype SecretMetadataOptions = {\n // V1 fields (from encrypted JSON payload, for backward compat)\n timestamp?: number;\n type?: SecretType;\n\n // Storage-level metadata from the metadata store (not encrypted).\n itemId?: string;\n dataType?: EncAccountDataType;\n createdAt?: string;\n /**\n * The storage-level version from the SDK ('v1' or 'v2').\n * - 'v1': Legacy items created before dataType was introduced\n * - 'v2': Items with dataType set (either new or migrated)\n */\n storageVersion?: SecretDataItemOutput['version'];\n};\n\nexport class SecretMetadata<\n DataType extends SecretDataType = Uint8Array,\n> implements ISecretMetadata<DataType> {\n readonly #data: DataType;\n\n readonly #timestamp: number;\n\n readonly #type: SecretType;\n\n // Storage-level metadata (not encrypted)\n readonly #itemId?: string;\n\n readonly #dataType?: EncAccountDataType;\n\n readonly #createdAt?: string;\n\n readonly #storageVersion?: SecretDataItemOutput['version'];\n\n /**\n * @param data - The secret data.\n * @param options - Optional metadata. New clients should provide `dataType`.\n */\n constructor(data: DataType, options?: SecretMetadataOptions) {\n this.#data = data;\n this.#timestamp = options?.timestamp ?? Date.now();\n this.#itemId = options?.itemId;\n this.#dataType = options?.dataType;\n this.#createdAt = options?.createdAt;\n this.#storageVersion = options?.storageVersion;\n\n // Derive type from dataType (new clients), or use provided type (V1 compat)\n if (options?.dataType === undefined || options?.dataType === null) {\n this.#type = options?.type ?? SecretType.Mnemonic;\n } else {\n this.#type = getSecretTypeFromDataType(options.dataType);\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 and create the SecretMetadata instance from the raw metadata bytes.\n *\n * @param rawMetadata - The raw metadata.\n * @param storageMetadata - Storage-level metadata from the metadata store.\n * @returns The parsed secret metadata.\n */\n static fromRawMetadata<DataType extends SecretDataType>(\n rawMetadata: Uint8Array,\n storageMetadata: Omit<SecretMetadataOptions, 'timestamp' | 'type'>,\n ): SecretMetadata<DataType> {\n const serializedMetadata = bytesToString(rawMetadata);\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n SecretMetadata.assertIsValidSecretMetadataJson<DataType>(parsedMetadata);\n\n const type = parsedMetadata.type ?? SecretType.Mnemonic;\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 ...storageMetadata,\n });\n }\n\n /**\n * Compare two SecretMetadata instances by timestamp.\n *\n * @param a - The first SecretMetadata instance.\n * @param b - The second SecretMetadata instance.\n * @param order - The sort order. Default is 'asc'.\n * @returns A negative number if a < b, positive if a > b, zero if equal.\n */\n static compareByTimestamp<DataType extends SecretDataType = SecretDataType>(\n a: SecretMetadata<DataType>,\n b: SecretMetadata<DataType>,\n order: 'asc' | 'desc' = 'asc',\n ): number {\n return order === 'asc'\n ? a.timestamp - b.timestamp\n : b.timestamp - a.timestamp;\n }\n\n /**\n * Compare two SecretMetadata instances for ordering.\n *\n * Ordering priority:\n * 1. PrimarySrp always comes first (regardless of order direction)\n * 2. Fall back to client-side timestamp\n *\n * @param a - The first SecretMetadata instance.\n * @param b - The second SecretMetadata instance.\n * @param order - The sort order. Default is 'asc'.\n * @returns A negative number if a < b, positive if a > b, zero if equal.\n */\n static compare<DataType extends SecretDataType = SecretDataType>(\n a: SecretMetadata<DataType>,\n b: SecretMetadata<DataType>,\n order: 'asc' | 'desc' = 'asc',\n ): number {\n // PrimarySrp always comes first (regardless of order direction)\n const aIsPrimary = a.dataType === EncAccountDataType.PrimarySrp;\n const bIsPrimary = b.dataType === EncAccountDataType.PrimarySrp;\n if (aIsPrimary && bIsPrimary) {\n return 0; // Both PrimarySrp: treat as equal (handles data corruption gracefully)\n }\n if (aIsPrimary) {\n return -1;\n }\n if (bIsPrimary) {\n return 1;\n }\n // Fall back to client-side timestamp\n return SecretMetadata.compareByTimestamp(a, b, order);\n }\n\n /**\n * Check if a SecretMetadata instance matches the given type.\n *\n * @param secret - The SecretMetadata instance to check.\n * @param type - The type to match against.\n * @returns True if the secret matches the type.\n */\n static matchesType<DataType extends SecretDataType = SecretDataType>(\n secret: SecretMetadata<DataType>,\n type: SecretType,\n ): boolean {\n return secret.type === type;\n }\n\n get data(): DataType {\n return this.#data;\n }\n\n get timestamp(): number {\n return this.#timestamp;\n }\n\n get type(): SecretType {\n return this.#type;\n }\n\n get itemId(): string | undefined {\n return this.#itemId;\n }\n\n get dataType(): EncAccountDataType | undefined {\n return this.#dataType;\n }\n\n get createdAt(): string | undefined {\n return this.#createdAt;\n }\n\n /**\n * The storage-level version from the SDK ('v1' or 'v2').\n *\n * @returns The storage-level version.\n */\n get storageVersion(): SecretDataItemOutput['version'] | undefined {\n return this.#storageVersion;\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 });\n\n // convert the serialized metadata to bytes(Uint8Array)\n return stringToBytes(serializedMetadata);\n }\n}\n"]}
|
|
@@ -81,9 +81,7 @@ export declare class SecretMetadata<DataType extends SecretDataType = Uint8Array
|
|
|
81
81
|
*
|
|
82
82
|
* Ordering priority:
|
|
83
83
|
* 1. PrimarySrp always comes first (regardless of order direction)
|
|
84
|
-
* 2.
|
|
85
|
-
* 3. Legacy items (null createdAt) are considered older
|
|
86
|
-
* 4. Fall back to client-side timestamp
|
|
84
|
+
* 2. Fall back to client-side timestamp
|
|
87
85
|
*
|
|
88
86
|
* @param a - The first SecretMetadata instance.
|
|
89
87
|
* @param b - The second SecretMetadata instance.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecretMetadata.d.cts","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sCAAsC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,sCAAsC;AAQnE,OAAO,EAEL,UAAU,EACX,wBAAoB;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAgB;AAG9C,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,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;AAEH;;;;;GAKG;AACH,KAAK,qBAAqB,GAAG;IAE3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAGlB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC,SAAS,CAAC,CAAC;CAClD,CAAC;AAEF,qBAAa,cAAc,CACzB,QAAQ,SAAS,cAAc,GAAG,UAAU,CAC5C,YAAW,eAAe,CAAC,QAAQ,CAAC;;IAgBpC;;;OAGG;gBACS,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,qBAAqB;IAgB3D;;;;;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;;;;;;OAMG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,SAAS,cAAc,EACpD,WAAW,EAAE,UAAU,EACvB,eAAe,EAAE,IAAI,CAAC,qBAAqB,EAAE,WAAW,GAAG,MAAM,CAAC,GACjE,cAAc,CAAC,QAAQ,CAAC;IAsB3B;;;;;;;OAOG;IACH,MAAM,CAAC,kBAAkB,CAAC,QAAQ,SAAS,cAAc,GAAG,cAAc,EACxE,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,EAC3B,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,EAC3B,KAAK,GAAE,KAAK,GAAG,MAAc,GAC5B,MAAM;IAMT
|
|
1
|
+
{"version":3,"file":"SecretMetadata.d.cts","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -81,9 +81,7 @@ export declare class SecretMetadata<DataType extends SecretDataType = Uint8Array
|
|
|
81
81
|
*
|
|
82
82
|
* Ordering priority:
|
|
83
83
|
* 1. PrimarySrp always comes first (regardless of order direction)
|
|
84
|
-
* 2.
|
|
85
|
-
* 3. Legacy items (null createdAt) are considered older
|
|
86
|
-
* 4. Fall back to client-side timestamp
|
|
84
|
+
* 2. Fall back to client-side timestamp
|
|
87
85
|
*
|
|
88
86
|
* @param a - The first SecretMetadata instance.
|
|
89
87
|
* @param b - The second SecretMetadata instance.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecretMetadata.d.mts","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sCAAsC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,sCAAsC;AAQnE,OAAO,EAEL,UAAU,EACX,wBAAoB;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAgB;AAG9C,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,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;AAEH;;;;;GAKG;AACH,KAAK,qBAAqB,GAAG;IAE3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAGlB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC,SAAS,CAAC,CAAC;CAClD,CAAC;AAEF,qBAAa,cAAc,CACzB,QAAQ,SAAS,cAAc,GAAG,UAAU,CAC5C,YAAW,eAAe,CAAC,QAAQ,CAAC;;IAgBpC;;;OAGG;gBACS,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,qBAAqB;IAgB3D;;;;;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;;;;;;OAMG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,SAAS,cAAc,EACpD,WAAW,EAAE,UAAU,EACvB,eAAe,EAAE,IAAI,CAAC,qBAAqB,EAAE,WAAW,GAAG,MAAM,CAAC,GACjE,cAAc,CAAC,QAAQ,CAAC;IAsB3B;;;;;;;OAOG;IACH,MAAM,CAAC,kBAAkB,CAAC,QAAQ,SAAS,cAAc,GAAG,cAAc,EACxE,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,EAC3B,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,EAC3B,KAAK,GAAE,KAAK,GAAG,MAAc,GAC5B,MAAM;IAMT
|
|
1
|
+
{"version":3,"file":"SecretMetadata.d.mts","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"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"}
|
package/dist/SecretMetadata.mjs
CHANGED
|
@@ -13,7 +13,7 @@ var _SecretMetadata_data, _SecretMetadata_timestamp, _SecretMetadata_type, _Secr
|
|
|
13
13
|
import { EncAccountDataType } from "@metamask/toprf-secure-backup";
|
|
14
14
|
import { base64ToBytes, bytesToBase64, stringToBytes, bytesToString } from "@metamask/utils";
|
|
15
15
|
import { SeedlessOnboardingControllerErrorMessage, SecretType } from "./constants.mjs";
|
|
16
|
-
import {
|
|
16
|
+
import { getSecretTypeFromDataType } from "./utils.mjs";
|
|
17
17
|
export class SecretMetadata {
|
|
18
18
|
/**
|
|
19
19
|
* @param data - The secret data.
|
|
@@ -101,9 +101,7 @@ export class SecretMetadata {
|
|
|
101
101
|
*
|
|
102
102
|
* Ordering priority:
|
|
103
103
|
* 1. PrimarySrp always comes first (regardless of order direction)
|
|
104
|
-
* 2.
|
|
105
|
-
* 3. Legacy items (null createdAt) are considered older
|
|
106
|
-
* 4. Fall back to client-side timestamp
|
|
104
|
+
* 2. Fall back to client-side timestamp
|
|
107
105
|
*
|
|
108
106
|
* @param a - The first SecretMetadata instance.
|
|
109
107
|
* @param b - The second SecretMetadata instance.
|
|
@@ -123,18 +121,7 @@ export class SecretMetadata {
|
|
|
123
121
|
if (bIsPrimary) {
|
|
124
122
|
return 1;
|
|
125
123
|
}
|
|
126
|
-
//
|
|
127
|
-
if (a.createdAt && b.createdAt) {
|
|
128
|
-
return compareTimeuuid(a.createdAt, b.createdAt, order);
|
|
129
|
-
}
|
|
130
|
-
// Handle mixed createdAt: legacy items (null) are older
|
|
131
|
-
if (!a.createdAt && b.createdAt) {
|
|
132
|
-
return order === 'asc' ? -1 : 1; // a (legacy/older) comes before b in asc
|
|
133
|
-
}
|
|
134
|
-
if (a.createdAt && !b.createdAt) {
|
|
135
|
-
return order === 'asc' ? 1 : -1; // b (legacy/older) comes before a in asc
|
|
136
|
-
}
|
|
137
|
-
// Both null: fall back to client-side timestamp
|
|
124
|
+
// Fall back to client-side timestamp
|
|
138
125
|
return SecretMetadata.compareByTimestamp(a, b, order);
|
|
139
126
|
}
|
|
140
127
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecretMetadata.mjs","sourceRoot":"","sources":["../src/SecretMetadata.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SecretDataItemOutput } from '@metamask/toprf-secure-backup';\nimport { EncAccountDataType } from '@metamask/toprf-secure-backup';\nimport {\n base64ToBytes,\n bytesToBase64,\n stringToBytes,\n bytesToString,\n} from '@metamask/utils';\n\nimport {\n SeedlessOnboardingControllerErrorMessage,\n SecretType,\n} from './constants';\nimport type { SecretDataType } from './types';\nimport { compareTimeuuid, getSecretTypeFromDataType } from './utils';\n\ntype ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {\n data: DataType;\n timestamp: number;\n type: SecretType;\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 */\n\n/**\n * Options for SecretMetadata constructor.\n *\n * New clients: provide V2 fields (`dataType`, `createdAt`, etc).\n * Reading V1 data: `timestamp` and `type` come from encrypted JSON.\n */\ntype SecretMetadataOptions = {\n // V1 fields (from encrypted JSON payload, for backward compat)\n timestamp?: number;\n type?: SecretType;\n\n // Storage-level metadata from the metadata store (not encrypted).\n itemId?: string;\n dataType?: EncAccountDataType;\n createdAt?: string;\n /**\n * The storage-level version from the SDK ('v1' or 'v2').\n * - 'v1': Legacy items created before dataType was introduced\n * - 'v2': Items with dataType set (either new or migrated)\n */\n storageVersion?: SecretDataItemOutput['version'];\n};\n\nexport class SecretMetadata<\n DataType extends SecretDataType = Uint8Array,\n> implements ISecretMetadata<DataType> {\n readonly #data: DataType;\n\n readonly #timestamp: number;\n\n readonly #type: SecretType;\n\n // Storage-level metadata (not encrypted)\n readonly #itemId?: string;\n\n readonly #dataType?: EncAccountDataType;\n\n readonly #createdAt?: string;\n\n readonly #storageVersion?: SecretDataItemOutput['version'];\n\n /**\n * @param data - The secret data.\n * @param options - Optional metadata. New clients should provide `dataType`.\n */\n constructor(data: DataType, options?: SecretMetadataOptions) {\n this.#data = data;\n this.#timestamp = options?.timestamp ?? Date.now();\n this.#itemId = options?.itemId;\n this.#dataType = options?.dataType;\n this.#createdAt = options?.createdAt;\n this.#storageVersion = options?.storageVersion;\n\n // Derive type from dataType (new clients), or use provided type (V1 compat)\n if (options?.dataType === undefined || options?.dataType === null) {\n this.#type = options?.type ?? SecretType.Mnemonic;\n } else {\n this.#type = getSecretTypeFromDataType(options.dataType);\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 and create the SecretMetadata instance from the raw metadata bytes.\n *\n * @param rawMetadata - The raw metadata.\n * @param storageMetadata - Storage-level metadata from the metadata store.\n * @returns The parsed secret metadata.\n */\n static fromRawMetadata<DataType extends SecretDataType>(\n rawMetadata: Uint8Array,\n storageMetadata: Omit<SecretMetadataOptions, 'timestamp' | 'type'>,\n ): SecretMetadata<DataType> {\n const serializedMetadata = bytesToString(rawMetadata);\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n SecretMetadata.assertIsValidSecretMetadataJson<DataType>(parsedMetadata);\n\n const type = parsedMetadata.type ?? SecretType.Mnemonic;\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 ...storageMetadata,\n });\n }\n\n /**\n * Compare two SecretMetadata instances by timestamp.\n *\n * @param a - The first SecretMetadata instance.\n * @param b - The second SecretMetadata instance.\n * @param order - The sort order. Default is 'asc'.\n * @returns A negative number if a < b, positive if a > b, zero if equal.\n */\n static compareByTimestamp<DataType extends SecretDataType = SecretDataType>(\n a: SecretMetadata<DataType>,\n b: SecretMetadata<DataType>,\n order: 'asc' | 'desc' = 'asc',\n ): number {\n return order === 'asc'\n ? a.timestamp - b.timestamp\n : b.timestamp - a.timestamp;\n }\n\n /**\n * Compare two SecretMetadata instances for ordering.\n *\n * Ordering priority:\n * 1. PrimarySrp always comes first (regardless of order direction)\n * 2. Server-side createdAt (TIMEUUID) if both have it\n * 3. Legacy items (null createdAt) are considered older\n * 4. Fall back to client-side timestamp\n *\n * @param a - The first SecretMetadata instance.\n * @param b - The second SecretMetadata instance.\n * @param order - The sort order. Default is 'asc'.\n * @returns A negative number if a < b, positive if a > b, zero if equal.\n */\n static compare<DataType extends SecretDataType = SecretDataType>(\n a: SecretMetadata<DataType>,\n b: SecretMetadata<DataType>,\n order: 'asc' | 'desc' = 'asc',\n ): number {\n // PrimarySrp always comes first (regardless of order direction)\n const aIsPrimary = a.dataType === EncAccountDataType.PrimarySrp;\n const bIsPrimary = b.dataType === EncAccountDataType.PrimarySrp;\n if (aIsPrimary && bIsPrimary) {\n return 0; // Both PrimarySrp: treat as equal (handles data corruption gracefully)\n }\n if (aIsPrimary) {\n return -1;\n }\n if (bIsPrimary) {\n return 1;\n }\n // Use server-side createdAt if available (TIMEUUID requires timestamp extraction)\n if (a.createdAt && b.createdAt) {\n return compareTimeuuid(a.createdAt, b.createdAt, order);\n }\n // Handle mixed createdAt: legacy items (null) are older\n if (!a.createdAt && b.createdAt) {\n return order === 'asc' ? -1 : 1; // a (legacy/older) comes before b in asc\n }\n if (a.createdAt && !b.createdAt) {\n return order === 'asc' ? 1 : -1; // b (legacy/older) comes before a in asc\n }\n // Both null: fall back to client-side timestamp\n return SecretMetadata.compareByTimestamp(a, b, order);\n }\n\n /**\n * Check if a SecretMetadata instance matches the given type.\n *\n * @param secret - The SecretMetadata instance to check.\n * @param type - The type to match against.\n * @returns True if the secret matches the type.\n */\n static matchesType<DataType extends SecretDataType = SecretDataType>(\n secret: SecretMetadata<DataType>,\n type: SecretType,\n ): boolean {\n return secret.type === type;\n }\n\n get data(): DataType {\n return this.#data;\n }\n\n get timestamp(): number {\n return this.#timestamp;\n }\n\n get type(): SecretType {\n return this.#type;\n }\n\n get itemId(): string | undefined {\n return this.#itemId;\n }\n\n get dataType(): EncAccountDataType | undefined {\n return this.#dataType;\n }\n\n get createdAt(): string | undefined {\n return this.#createdAt;\n }\n\n /**\n * The storage-level version from the SDK ('v1' or 'v2').\n *\n * @returns The storage-level version.\n */\n get storageVersion(): SecretDataItemOutput['version'] | undefined {\n return this.#storageVersion;\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 });\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 type { SecretDataItemOutput } from '@metamask/toprf-secure-backup';\nimport { EncAccountDataType } from '@metamask/toprf-secure-backup';\nimport {\n base64ToBytes,\n bytesToBase64,\n stringToBytes,\n bytesToString,\n} from '@metamask/utils';\n\nimport {\n SeedlessOnboardingControllerErrorMessage,\n SecretType,\n} from './constants';\nimport type { SecretDataType } from './types';\nimport { getSecretTypeFromDataType } from './utils';\n\ntype ISecretMetadata<DataType extends SecretDataType = Uint8Array> = {\n data: DataType;\n timestamp: number;\n type: SecretType;\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 */\n\n/**\n * Options for SecretMetadata constructor.\n *\n * New clients: provide V2 fields (`dataType`, `createdAt`, etc).\n * Reading V1 data: `timestamp` and `type` come from encrypted JSON.\n */\ntype SecretMetadataOptions = {\n // V1 fields (from encrypted JSON payload, for backward compat)\n timestamp?: number;\n type?: SecretType;\n\n // Storage-level metadata from the metadata store (not encrypted).\n itemId?: string;\n dataType?: EncAccountDataType;\n createdAt?: string;\n /**\n * The storage-level version from the SDK ('v1' or 'v2').\n * - 'v1': Legacy items created before dataType was introduced\n * - 'v2': Items with dataType set (either new or migrated)\n */\n storageVersion?: SecretDataItemOutput['version'];\n};\n\nexport class SecretMetadata<\n DataType extends SecretDataType = Uint8Array,\n> implements ISecretMetadata<DataType> {\n readonly #data: DataType;\n\n readonly #timestamp: number;\n\n readonly #type: SecretType;\n\n // Storage-level metadata (not encrypted)\n readonly #itemId?: string;\n\n readonly #dataType?: EncAccountDataType;\n\n readonly #createdAt?: string;\n\n readonly #storageVersion?: SecretDataItemOutput['version'];\n\n /**\n * @param data - The secret data.\n * @param options - Optional metadata. New clients should provide `dataType`.\n */\n constructor(data: DataType, options?: SecretMetadataOptions) {\n this.#data = data;\n this.#timestamp = options?.timestamp ?? Date.now();\n this.#itemId = options?.itemId;\n this.#dataType = options?.dataType;\n this.#createdAt = options?.createdAt;\n this.#storageVersion = options?.storageVersion;\n\n // Derive type from dataType (new clients), or use provided type (V1 compat)\n if (options?.dataType === undefined || options?.dataType === null) {\n this.#type = options?.type ?? SecretType.Mnemonic;\n } else {\n this.#type = getSecretTypeFromDataType(options.dataType);\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 and create the SecretMetadata instance from the raw metadata bytes.\n *\n * @param rawMetadata - The raw metadata.\n * @param storageMetadata - Storage-level metadata from the metadata store.\n * @returns The parsed secret metadata.\n */\n static fromRawMetadata<DataType extends SecretDataType>(\n rawMetadata: Uint8Array,\n storageMetadata: Omit<SecretMetadataOptions, 'timestamp' | 'type'>,\n ): SecretMetadata<DataType> {\n const serializedMetadata = bytesToString(rawMetadata);\n const parsedMetadata = JSON.parse(serializedMetadata);\n\n SecretMetadata.assertIsValidSecretMetadataJson<DataType>(parsedMetadata);\n\n const type = parsedMetadata.type ?? SecretType.Mnemonic;\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 ...storageMetadata,\n });\n }\n\n /**\n * Compare two SecretMetadata instances by timestamp.\n *\n * @param a - The first SecretMetadata instance.\n * @param b - The second SecretMetadata instance.\n * @param order - The sort order. Default is 'asc'.\n * @returns A negative number if a < b, positive if a > b, zero if equal.\n */\n static compareByTimestamp<DataType extends SecretDataType = SecretDataType>(\n a: SecretMetadata<DataType>,\n b: SecretMetadata<DataType>,\n order: 'asc' | 'desc' = 'asc',\n ): number {\n return order === 'asc'\n ? a.timestamp - b.timestamp\n : b.timestamp - a.timestamp;\n }\n\n /**\n * Compare two SecretMetadata instances for ordering.\n *\n * Ordering priority:\n * 1. PrimarySrp always comes first (regardless of order direction)\n * 2. Fall back to client-side timestamp\n *\n * @param a - The first SecretMetadata instance.\n * @param b - The second SecretMetadata instance.\n * @param order - The sort order. Default is 'asc'.\n * @returns A negative number if a < b, positive if a > b, zero if equal.\n */\n static compare<DataType extends SecretDataType = SecretDataType>(\n a: SecretMetadata<DataType>,\n b: SecretMetadata<DataType>,\n order: 'asc' | 'desc' = 'asc',\n ): number {\n // PrimarySrp always comes first (regardless of order direction)\n const aIsPrimary = a.dataType === EncAccountDataType.PrimarySrp;\n const bIsPrimary = b.dataType === EncAccountDataType.PrimarySrp;\n if (aIsPrimary && bIsPrimary) {\n return 0; // Both PrimarySrp: treat as equal (handles data corruption gracefully)\n }\n if (aIsPrimary) {\n return -1;\n }\n if (bIsPrimary) {\n return 1;\n }\n // Fall back to client-side timestamp\n return SecretMetadata.compareByTimestamp(a, b, order);\n }\n\n /**\n * Check if a SecretMetadata instance matches the given type.\n *\n * @param secret - The SecretMetadata instance to check.\n * @param type - The type to match against.\n * @returns True if the secret matches the type.\n */\n static matchesType<DataType extends SecretDataType = SecretDataType>(\n secret: SecretMetadata<DataType>,\n type: SecretType,\n ): boolean {\n return secret.type === type;\n }\n\n get data(): DataType {\n return this.#data;\n }\n\n get timestamp(): number {\n return this.#timestamp;\n }\n\n get type(): SecretType {\n return this.#type;\n }\n\n get itemId(): string | undefined {\n return this.#itemId;\n }\n\n get dataType(): EncAccountDataType | undefined {\n return this.#dataType;\n }\n\n get createdAt(): string | undefined {\n return this.#createdAt;\n }\n\n /**\n * The storage-level version from the SDK ('v1' or 'v2').\n *\n * @returns The storage-level version.\n */\n get storageVersion(): SecretDataItemOutput['version'] | undefined {\n return this.#storageVersion;\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 });\n\n // convert the serialized metadata to bytes(Uint8Array)\n return stringToBytes(serializedMetadata);\n }\n}\n"]}
|
|
@@ -1323,17 +1323,19 @@ async function _SeedlessOnboardingController_recoverEncKey(password) {
|
|
|
1323
1323
|
createdAt: item.createdAt,
|
|
1324
1324
|
storageVersion: item.version,
|
|
1325
1325
|
}));
|
|
1326
|
-
// Sort: PrimarySrp first, then by
|
|
1326
|
+
// Sort: PrimarySrp first, then by client timestamp (oldest first)
|
|
1327
1327
|
results.sort((a, b) => SecretMetadata_1.SecretMetadata.compare(a, b, 'asc'));
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
const isMnemonic = SecretMetadata_1.SecretMetadata.matchesType(firstItem, constants_1.SecretType.Mnemonic);
|
|
1334
|
-
if (!isDataTypePrimary || !isMnemonic) {
|
|
1328
|
+
const primaryIndex = results.findIndex((result) => SecretMetadata_1.SecretMetadata.matchesType(result, constants_1.SecretType.Mnemonic) &&
|
|
1329
|
+
(result.dataType === undefined ||
|
|
1330
|
+
result.dataType === null ||
|
|
1331
|
+
result.dataType === toprf_secure_backup_1.EncAccountDataType.PrimarySrp));
|
|
1332
|
+
if (primaryIndex === -1) {
|
|
1335
1333
|
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.InvalidPrimarySecretDataType);
|
|
1336
1334
|
}
|
|
1335
|
+
if (primaryIndex !== 0) {
|
|
1336
|
+
const [primary] = results.splice(primaryIndex, 1);
|
|
1337
|
+
results.unshift(primary);
|
|
1338
|
+
}
|
|
1337
1339
|
return results;
|
|
1338
1340
|
}
|
|
1339
1341
|
throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.NoSecretDataFound);
|
|
@@ -1379,6 +1381,13 @@ async function _SeedlessOnboardingController_changeEncryptionKey({ oldPassword,
|
|
|
1379
1381
|
oldAuthKeyPair: authKeyPair,
|
|
1380
1382
|
newKeyShareIndex: globalKeyIndex,
|
|
1381
1383
|
newPassword,
|
|
1384
|
+
transformDataItems: (items) => items
|
|
1385
|
+
.sort((a, b) => SecretMetadata_1.SecretMetadata.compare(SecretMetadata_1.SecretMetadata.fromRawMetadata(a.data, { dataType: a.dataType }), SecretMetadata_1.SecretMetadata.fromRawMetadata(b.data, { dataType: b.dataType }), 'asc'))
|
|
1386
|
+
.map(({ data, dataType, version }) => ({
|
|
1387
|
+
data,
|
|
1388
|
+
dataType,
|
|
1389
|
+
version: dataType === undefined ? 'v1' : version,
|
|
1390
|
+
})),
|
|
1382
1391
|
});
|
|
1383
1392
|
return result;
|
|
1384
1393
|
}, _SeedlessOnboardingController_encryptAndStoreSecretData =
|