Repository navigation
fix: fixed skipping metadata write on toprf creation retry #10419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a94659c
5dc8c1a
74fbd32
f2700a9
57804de
74942db
0d62b51
cfb1559
f54a681
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -646,21 +646,29 @@ export class SeedlessOnboardingController< | |
| // assert that the user is authenticated before creating the TOPRF key and backing up the seed phrase | ||
| this.#assertIsAuthenticatedUser(this.state); | ||
|
|
||
| if (this.state.vault) { | ||
| throw new Error( | ||
| SeedlessOnboardingControllerErrorMessage.VaultAlreadyExists, | ||
| ); | ||
| } | ||
|
|
||
| // locally evaluate the encryption key from the password | ||
| const { encKey, pwEncKey, authKeyPair, oprfKey } = | ||
| await this.toprfClient.createLocalKey({ | ||
| password, | ||
| }); | ||
| const performKeyCreationAndBackup = async (): Promise<void> => { | ||
| // encrypt and store the secret data | ||
| await this.#encryptAndStoreSecretData({ | ||
| const secretMetadata = await this.#encryptAndStoreSecretData({ | ||
| data: seedPhrase, | ||
| dataType: EncAccountDataType.PrimarySrp, | ||
| encKey, | ||
| authKeyPair, | ||
| options: { | ||
| keyringId, | ||
| }, | ||
| // Persist local backup state only after the full operation succeeds. | ||
| skipStatePersist: true, | ||
| }); | ||
|
|
||
| // store/persist the encryption key shares | ||
|
|
@@ -678,6 +686,13 @@ export class SeedlessOnboardingController< | |
|
|
||
| // Mark migration as complete since this new backup was created with the new data format (dataType) | ||
| this.#setMigrationVersion(SeedlessOnboardingMigrationVersion.V1); | ||
|
|
||
| // Persist local backup state after all operations succeed. | ||
| this.#filterDupesAndUpdateSocialBackupsMetadata({ | ||
| keyringId, | ||
| data: seedPhrase, | ||
| type: secretMetadata.type, | ||
| }); | ||
| }; | ||
|
|
||
| await this.#executeWithTokenRefresh( | ||
|
|
@@ -1744,8 +1759,10 @@ export class SeedlessOnboardingController< | |
| * @param params.authKeyPair - The authentication key pair to store. | ||
| * @param params.options - Optional options object. | ||
| * @param params.options.keyringId - The keyring id of the backup keyring (required for SRP types). | ||
| * @param params.skipStatePersist - Whether to persist the backup state after | ||
| * the remote metadata is stored. When true, the backup metadata is not persisted to the controller state. | ||
| * | ||
| * @returns A promise that resolves to the success of the operation. | ||
| * @returns A promise that resolves to the backup metadata. | ||
| */ | ||
| async #encryptAndStoreSecretData(params: { | ||
| data: Uint8Array; | ||
|
|
@@ -1755,16 +1772,24 @@ export class SeedlessOnboardingController< | |
| options?: { | ||
| keyringId?: string; | ||
| }; | ||
| }): Promise<void> { | ||
| const { options, data, encKey, authKeyPair, dataType } = params; | ||
| skipStatePersist?: boolean; | ||
| }): Promise<SecretMetadata> { | ||
| const { | ||
| options, | ||
| data, | ||
| encKey, | ||
| authKeyPair, | ||
| dataType, | ||
| skipStatePersist = false, | ||
| } = params; | ||
|
|
||
| const secretMetadata = new SecretMetadata(data, { dataType }); | ||
| const { type } = secretMetadata; | ||
|
|
||
| // before encrypting and create backup, we will check the state if the secret data is already backed up | ||
| const backupState = this.getSecretDataBackupState(data, type); | ||
| if (backupState) { | ||
| return; | ||
| return secretMetadata; | ||
| } | ||
|
|
||
| const secretData = secretMetadata.toBytes(); | ||
|
|
@@ -1777,7 +1802,9 @@ export class SeedlessOnboardingController< | |
| } | ||
|
|
||
| try { | ||
| await this.#withPersistedSecretMetadataBackupsState(async () => { | ||
| const persistMetadataFn = async (): Promise< | ||
| Omit<SocialBackupsMetadata, 'hash'> & { data: Uint8Array } | ||
| > => { | ||
| await this.toprfClient.addSecretDataItem({ | ||
| encKey, | ||
| secretData, | ||
|
|
@@ -1789,7 +1816,16 @@ export class SeedlessOnboardingController< | |
| data, | ||
| type, | ||
| }; | ||
|
Comment on lines
1804
to
1818
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When skipStatePersist: true, we call persistMetadataFn directly and skip #withPersistedSecretMetadataBackupsState entirely. Does that wrapper do anything beyond persisting state: locking, error normalization, cleanup? If so, we're silently skipping it.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| }); | ||
| }; | ||
|
|
||
| // Skip local persistence if `skipStatePersist` is true. | ||
| if (skipStatePersist) { | ||
| await persistMetadataFn(); | ||
| } else { | ||
| await this.#withPersistedSecretMetadataBackupsState(persistMetadataFn); | ||
| } | ||
|
|
||
| return secretMetadata; | ||
| } catch (error) { | ||
| if (this.#isAuthTokenError(error)) { | ||
| throw error; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing test for the exact bug scenario. This defers local state until after everything succeeds but there's no test that simulates: remote metadata writes → OPRF/vault creation fails → retry with a new TOPRF key → assert remote write happens again. That's the specific failure this fixes and it should have a dedicated test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addd here, 57804de