@metamask-previews/seedless-onboarding-controller 2.4.0-preview-defa214d → 2.4.0-preview-fed19434

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 (40) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/SeedlessOnboardingController.cjs +133 -70
  3. package/dist/SeedlessOnboardingController.cjs.map +1 -1
  4. package/dist/SeedlessOnboardingController.d.cts +7 -14
  5. package/dist/SeedlessOnboardingController.d.cts.map +1 -1
  6. package/dist/SeedlessOnboardingController.d.mts +7 -14
  7. package/dist/SeedlessOnboardingController.d.mts.map +1 -1
  8. package/dist/SeedlessOnboardingController.mjs +134 -71
  9. package/dist/SeedlessOnboardingController.mjs.map +1 -1
  10. package/dist/assertions.cjs +16 -1
  11. package/dist/assertions.cjs.map +1 -1
  12. package/dist/assertions.d.cts +7 -0
  13. package/dist/assertions.d.cts.map +1 -1
  14. package/dist/assertions.d.mts +7 -0
  15. package/dist/assertions.d.mts.map +1 -1
  16. package/dist/assertions.mjs +14 -0
  17. package/dist/assertions.mjs.map +1 -1
  18. package/dist/constants.cjs +3 -1
  19. package/dist/constants.cjs.map +1 -1
  20. package/dist/constants.d.cts +4 -2
  21. package/dist/constants.d.cts.map +1 -1
  22. package/dist/constants.d.mts +4 -2
  23. package/dist/constants.d.mts.map +1 -1
  24. package/dist/constants.mjs +3 -1
  25. package/dist/constants.mjs.map +1 -1
  26. package/dist/index.cjs +3 -1
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +1 -0
  29. package/dist/index.d.cts.map +1 -1
  30. package/dist/index.d.mts +1 -0
  31. package/dist/index.d.mts.map +1 -1
  32. package/dist/index.mjs +1 -0
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/types.cjs.map +1 -1
  35. package/dist/types.d.cts +6 -0
  36. package/dist/types.d.cts.map +1 -1
  37. package/dist/types.d.mts +6 -0
  38. package/dist/types.d.mts.map +1 -1
  39. package/dist/types.mjs.map +1 -1
  40. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Added an optional parameter, `passwordOutdatedCacheTTL` to the constructor params and exported `SecretMetadata` class from the controller.([#6169](https://github.com/MetaMask/core/pull/6169))
13
+
14
+ ### Changed
15
+
16
+ - Renamed public method `submitGlobalPassword` to `submitGlobalPasswordAndSync`. ([#6180](https://github.com/MetaMask/core/pull/6180))
17
+
18
+ ### Removed
19
+
20
+ - Removed `syncLatestGlobalPassword` from the Controller. ([#6180](https://github.com/MetaMask/core/pull/6180))
21
+ - Moved the vault syncing to the `submitGlobalPassword` method
22
+
10
23
  ## [2.4.0]
11
24
 
12
25
  ### Fixed
@@ -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_refreshJWTToken, _SeedlessOnboardingController_revokeRefreshToken, _SeedlessOnboardingController_isUnlocked, _SeedlessOnboardingController_submitGlobalPassword, _SeedlessOnboardingController_getAccessToken, _SeedlessOnboardingController_setUnlocked, _SeedlessOnboardingController_persistOprfKey, _SeedlessOnboardingController_persistAuthPubKey, _SeedlessOnboardingController_storeKeyringEncryptionKey, _SeedlessOnboardingController_loadKeyringEncryptionKey, _SeedlessOnboardingController_loadSeedlessEncryptionKey, _SeedlessOnboardingController_recoverAuthPubKey, _SeedlessOnboardingController_recoverEncKey, _SeedlessOnboardingController_fetchAllSecretDataFromMetadataStore, _SeedlessOnboardingController_changeEncryptionKey, _SeedlessOnboardingController_encryptAndStoreSecretData, _SeedlessOnboardingController_unlockVaultAndGetVaultData, _SeedlessOnboardingController_withPersistedSecretMetadataBackupsState, _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_revokeRefreshTokenAndUpdateState, _SeedlessOnboardingController_isTokenExpiredError, _SeedlessOnboardingController_isMaxKeyChainLengthError, _SeedlessOnboardingController_executeWithTokenRefresh;
13
+ var _SeedlessOnboardingController_instances, _SeedlessOnboardingController_vaultEncryptor, _SeedlessOnboardingController_controllerOperationMutex, _SeedlessOnboardingController_vaultOperationMutex, _SeedlessOnboardingController_refreshJWTToken, _SeedlessOnboardingController_revokeRefreshToken, _SeedlessOnboardingController_isUnlocked, _SeedlessOnboardingController_passwordOutdatedCacheTTL, _SeedlessOnboardingController_submitGlobalPasswordAndSync, _SeedlessOnboardingController_getAccessToken, _SeedlessOnboardingController_setUnlocked, _SeedlessOnboardingController_persistOprfKey, _SeedlessOnboardingController_persistAuthPubKey, _SeedlessOnboardingController_storeKeyringEncryptionKey, _SeedlessOnboardingController_loadKeyringEncryptionKey, _SeedlessOnboardingController_loadSeedlessEncryptionKey, _SeedlessOnboardingController_recoverAuthPubKey, _SeedlessOnboardingController_recoverEncKey, _SeedlessOnboardingController_fetchAllSecretDataFromMetadataStore, _SeedlessOnboardingController_changeEncryptionKey, _SeedlessOnboardingController_encryptAndStoreSecretData, _SeedlessOnboardingController_unlockVaultAndGetVaultData, _SeedlessOnboardingController_withPersistedSecretMetadataBackupsState, _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_revokeRefreshTokenAndUpdateState, _SeedlessOnboardingController_isTokenExpiredError, _SeedlessOnboardingController_isMaxKeyChainLengthError, _SeedlessOnboardingController_executeWithTokenRefresh;
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");
@@ -136,8 +136,9 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
136
136
  * @param options.network - The network to be used for the Seedless Onboarding flow.
137
137
  * @param options.refreshJWTToken - A function to get a new jwt token using refresh token.
138
138
  * @param options.revokeRefreshToken - A function to revoke the refresh token.
139
+ * @param options.passwordOutdatedCacheTTL - The TTL of the password outdated cache in milliseconds.,
139
140
  */
140
- constructor({ messenger, state, encryptor, toprfKeyDeriver, network = constants_1.Web3AuthNetwork.Mainnet, refreshJWTToken, revokeRefreshToken, }) {
141
+ constructor({ messenger, state, encryptor, toprfKeyDeriver, network = constants_1.Web3AuthNetwork.Mainnet, refreshJWTToken, revokeRefreshToken, passwordOutdatedCacheTTL = constants_1.PASSWORD_OUTDATED_CACHE_TTL_MS, }) {
141
142
  super({
142
143
  name: constants_1.controllerName,
143
144
  metadata: seedlessOnboardingMetadata,
@@ -159,6 +160,12 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
159
160
  * The controller lock is synchronized with the keyring lock.
160
161
  */
161
162
  _SeedlessOnboardingController_isUnlocked.set(this, false);
163
+ /**
164
+ * The TTL of the password outdated cache in milliseconds.
165
+ */
166
+ _SeedlessOnboardingController_passwordOutdatedCacheTTL.set(this, void 0);
167
+ (0, assertions_1.assertIsPasswordOutdatedCacheValid)(passwordOutdatedCacheTTL);
168
+ __classPrivateFieldSet(this, _SeedlessOnboardingController_passwordOutdatedCacheTTL, passwordOutdatedCacheTTL, "f");
162
169
  __classPrivateFieldSet(this, _SeedlessOnboardingController_vaultEncryptor, encryptor, "f");
163
170
  this.toprfClient = new toprf_secure_backup_1.ToprfSecureBackup({
164
171
  network,
@@ -391,7 +398,7 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
391
398
  await this.verifyVaultPassword(oldPassword, {
392
399
  skipLock: true, // skip lock since we already have the lock
393
400
  });
394
- await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertPasswordInSync).call(this, {
401
+ const { latestKeyIndex } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertPasswordInSync).call(this, {
395
402
  skipCache: true,
396
403
  skipLock: true, // skip lock since we already have the lock
397
404
  });
@@ -405,6 +412,7 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
405
412
  const { encKey: newEncKey, pwEncKey: newPwEncKey, authKeyPair: newAuthKeyPair, } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_changeEncryptionKey).call(this, {
406
413
  oldPassword,
407
414
  newPassword,
415
+ latestKeyIndex,
408
416
  });
409
417
  // update and encrypt the vault with new password
410
418
  await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_createNewVaultWithAuthData).call(this, {
@@ -487,14 +495,26 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
487
495
  return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_withControllerLock).call(this, async () => {
488
496
  const { toprfEncryptionKey, toprfPwEncryptionKey, toprfAuthKeyPair, revokeToken, } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_unlockVaultAndGetVaultData).call(this, password);
489
497
  __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_setUnlocked).call(this);
498
+ await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_createNewVaultWithAuthData).call(this, {
499
+ password,
500
+ rawToprfEncryptionKey: toprfEncryptionKey,
501
+ rawToprfPwEncryptionKey: toprfPwEncryptionKey,
502
+ rawToprfAuthKeyPair: toprfAuthKeyPair,
503
+ });
490
504
  if (revokeToken) {
491
- await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_revokeRefreshTokenAndUpdateState).call(this, revokeToken);
492
- // re-creating vault to persist the new revoke token
493
- await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_createNewVaultWithAuthData).call(this, {
494
- password,
495
- rawToprfEncryptionKey: toprfEncryptionKey,
496
- rawToprfPwEncryptionKey: toprfPwEncryptionKey,
497
- rawToprfAuthKeyPair: toprfAuthKeyPair,
505
+ // this call is not critical for unlocking, so we can do it in the background without await.
506
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_revokeRefreshTokenAndUpdateState).call(this, revokeToken)
507
+ .then(() => {
508
+ // re-creating vault to persist the new revoke token
509
+ return __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_createNewVaultWithAuthData).call(this, {
510
+ password,
511
+ rawToprfEncryptionKey: toprfEncryptionKey,
512
+ rawToprfPwEncryptionKey: toprfPwEncryptionKey,
513
+ rawToprfAuthKeyPair: toprfAuthKeyPair,
514
+ });
515
+ })
516
+ .catch((error) => {
517
+ log('Error revoking refresh token', error);
498
518
  });
499
519
  }
500
520
  });
@@ -513,33 +533,6 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
513
533
  });
514
534
  __classPrivateFieldSet(this, _SeedlessOnboardingController_isUnlocked, false, "f");
515
535
  }
516
- /**
517
- * Sync the latest global password to the controller.
518
- * reset vault with latest globalPassword,
519
- * persist the latest global password authPubKey
520
- *
521
- * @param params - The parameters for syncing the latest global password.
522
- * @param params.globalPassword - The latest global password.
523
- * @returns A promise that resolves to the success of the operation.
524
- */
525
- async syncLatestGlobalPassword({ globalPassword, }) {
526
- return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_withControllerLock).call(this, async () => {
527
- __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsUnlocked).call(this);
528
- const doSyncPassword = async () => {
529
- // update vault with latest globalPassword
530
- const { encKey, pwEncKey, authKeyPair } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverEncKey).call(this, globalPassword);
531
- // update and encrypt the vault with new password
532
- await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_createNewVaultWithAuthData).call(this, {
533
- password: globalPassword,
534
- rawToprfEncryptionKey: encKey,
535
- rawToprfPwEncryptionKey: pwEncKey,
536
- rawToprfAuthKeyPair: authKeyPair,
537
- });
538
- __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_resetPasswordOutdatedCache).call(this);
539
- };
540
- return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_executeWithTokenRefresh).call(this, doSyncPassword, 'syncLatestGlobalPassword');
541
- });
542
- }
543
536
  /**
544
537
  * @description Unlock the controller with the latest global password.
545
538
  *
@@ -548,22 +541,24 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
548
541
  * @param params.globalPassword - The latest global password.
549
542
  * @returns A promise that resolves to the success of the operation.
550
543
  */
551
- async submitGlobalPassword({ globalPassword, maxKeyChainLength = 5, }) {
544
+ async submitGlobalPasswordAndSync({ globalPassword, maxKeyChainLength = 5, }) {
552
545
  return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_withControllerLock).call(this, async () => {
553
546
  return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_executeWithTokenRefresh).call(this, async () => {
554
547
  const currentDeviceAuthPubKey = __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverAuthPubKey).call(this);
555
- await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_submitGlobalPassword).call(this, {
548
+ await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_submitGlobalPasswordAndSync).call(this, {
556
549
  targetAuthPubKey: currentDeviceAuthPubKey,
557
550
  globalPassword,
558
551
  maxKeyChainLength,
559
552
  });
560
- }, 'submitGlobalPassword');
553
+ }, 'submitGlobalPasswordAndSync');
561
554
  });
562
555
  }
563
556
  /**
564
557
  * @description Check if the current password is outdated compare to the global password.
565
558
  *
566
559
  * @param options - Optional options object.
560
+ * @param options.globalAuthPubKey - The global auth public key to compare with the current auth public key.
561
+ * If not provided, the global auth public key will be fetched from the backend.
567
562
  * @param options.skipCache - If true, bypass the cache and force a fresh check.
568
563
  * @param options.skipLock - Whether to skip the lock acquisition. (to prevent deadlock in case the caller already acquired the lock)
569
564
  * @returns A promise that resolves to true if the password is outdated, false otherwise.
@@ -578,19 +573,28 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
578
573
  const now = Date.now();
579
574
  const isCacheValid = passwordOutdatedCache &&
580
575
  now - passwordOutdatedCache.timestamp <
581
- constants_1.PASSWORD_OUTDATED_CACHE_TTL_MS;
576
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_passwordOutdatedCacheTTL, "f");
582
577
  if (isCacheValid) {
583
578
  return passwordOutdatedCache.isExpiredPwd;
584
579
  }
585
580
  }
586
581
  const { nodeAuthTokens, authConnectionId, groupedAuthConnectionId, userId, } = this.state;
587
582
  const currentDeviceAuthPubKey = __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverAuthPubKey).call(this);
588
- const { authPubKey: globalAuthPubKey } = await this.toprfClient.fetchAuthPubKey({
589
- nodeAuthTokens,
590
- authConnectionId,
591
- groupedAuthConnectionId,
592
- userId,
593
- });
583
+ let globalAuthPubKey = options?.globalAuthPubKey;
584
+ if (!globalAuthPubKey) {
585
+ const { authPubKey } = await this.toprfClient
586
+ .fetchAuthPubKey({
587
+ nodeAuthTokens,
588
+ authConnectionId,
589
+ groupedAuthConnectionId,
590
+ userId,
591
+ })
592
+ .catch((error) => {
593
+ log('Error fetching auth pub key', error);
594
+ throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.FailedToFetchAuthPubKey);
595
+ });
596
+ globalAuthPubKey = authPubKey;
597
+ }
594
598
  // use noble lib to deserialize and compare curve point
595
599
  const isExpiredPwd = !secp256k1_1.secp256k1.ProjectivePoint.fromHex(currentDeviceAuthPubKey).equals(secp256k1_1.secp256k1.ProjectivePoint.fromHex(globalAuthPubKey));
596
600
  // Cache the result in state
@@ -720,7 +724,7 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
720
724
  }
721
725
  }
722
726
  exports.SeedlessOnboardingController = SeedlessOnboardingController;
723
- _SeedlessOnboardingController_vaultEncryptor = new WeakMap(), _SeedlessOnboardingController_controllerOperationMutex = new WeakMap(), _SeedlessOnboardingController_vaultOperationMutex = new WeakMap(), _SeedlessOnboardingController_refreshJWTToken = new WeakMap(), _SeedlessOnboardingController_revokeRefreshToken = new WeakMap(), _SeedlessOnboardingController_isUnlocked = new WeakMap(), _SeedlessOnboardingController_instances = new WeakSet(), _SeedlessOnboardingController_submitGlobalPassword =
727
+ _SeedlessOnboardingController_vaultEncryptor = new WeakMap(), _SeedlessOnboardingController_controllerOperationMutex = new WeakMap(), _SeedlessOnboardingController_vaultOperationMutex = new WeakMap(), _SeedlessOnboardingController_refreshJWTToken = new WeakMap(), _SeedlessOnboardingController_revokeRefreshToken = new WeakMap(), _SeedlessOnboardingController_isUnlocked = new WeakMap(), _SeedlessOnboardingController_passwordOutdatedCacheTTL = new WeakMap(), _SeedlessOnboardingController_instances = new WeakSet(), _SeedlessOnboardingController_submitGlobalPasswordAndSync =
724
728
  /**
725
729
  * @description Submit the global password to the controller, verify the
726
730
  * password validity and unlock the controller.
@@ -733,32 +737,52 @@ _SeedlessOnboardingController_vaultEncryptor = new WeakMap(), _SeedlessOnboardin
733
737
  * @returns A promise that resolves to the keyring encryption key
734
738
  * corresponding to the current authPubKey in state.
735
739
  */
736
- async function _SeedlessOnboardingController_submitGlobalPassword({ targetAuthPubKey, globalPassword, maxKeyChainLength, }) {
737
- const { pwEncKey: curPwEncKey, authKeyPair: curAuthKeyPair } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverEncKey).call(this, globalPassword);
740
+ async function _SeedlessOnboardingController_submitGlobalPasswordAndSync({ targetAuthPubKey, globalPassword, maxKeyChainLength, }) {
741
+ const { pwEncKey: latestPwEncKey, authKeyPair: latestAuthKeyPair, encKey: latestEncKey, } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverEncKey).call(this, globalPassword);
738
742
  try {
739
- // Recover vault encryption key.
740
- const res = await this.toprfClient.recoverPwEncKey({
743
+ // Recover current device's vault encryption key with the latest global password
744
+ const { pwEncKey: currentDevicePwEncKey } = await this.toprfClient.recoverPwEncKey({
741
745
  targetAuthPubKey,
742
- curPwEncKey,
743
- curAuthKeyPair,
746
+ curPwEncKey: latestPwEncKey,
747
+ curAuthKeyPair: latestAuthKeyPair,
744
748
  maxPwChainLength: maxKeyChainLength,
745
749
  });
746
- const { pwEncKey } = res;
747
- const vaultKey = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_loadSeedlessEncryptionKey).call(this, pwEncKey);
748
- // Unlock the controller
749
- const { revokeToken, toprfEncryptionKey, toprfPwEncryptionKey, toprfAuthKeyPair, } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_unlockVaultAndGetVaultData).call(this, undefined, vaultKey);
750
+ // recover the vault encryption key and keyring encryption key with the current device's pwEncKey
751
+ const [vaultKey, keyringEncryptionKey] = await Promise.all([
752
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_loadSeedlessEncryptionKey).call(this, currentDevicePwEncKey),
753
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_loadKeyringEncryptionKey).call(this, currentDevicePwEncKey),
754
+ ]);
755
+ // Unlock the controller and vault
756
+ const { revokeToken } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_unlockVaultAndGetVaultData).call(this, undefined, vaultKey);
750
757
  __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_setUnlocked).call(this);
758
+ await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_createNewVaultWithAuthData).call(this, {
759
+ password: globalPassword,
760
+ rawToprfEncryptionKey: latestEncKey,
761
+ rawToprfPwEncryptionKey: latestPwEncKey,
762
+ rawToprfAuthKeyPair: latestAuthKeyPair,
763
+ });
751
764
  if (revokeToken) {
752
- // revoke and recyle refresh token after unlock to keep refresh token fresh, avoid malicious use of leaked refresh token
753
- await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_revokeRefreshTokenAndUpdateState).call(this, revokeToken);
754
- // re-creating vault to persist the new revoke token
755
- await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_createNewVaultWithAuthData).call(this, {
756
- password: globalPassword,
757
- rawToprfEncryptionKey: toprfEncryptionKey,
758
- rawToprfPwEncryptionKey: toprfPwEncryptionKey,
759
- rawToprfAuthKeyPair: toprfAuthKeyPair,
765
+ // // revoke and recyle refresh token after unlock to keep refresh token fresh, avoid malicious use of leaked refresh token
766
+ // // this call is not critical for unlocking, so we can do it in the background without await.
767
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_revokeRefreshTokenAndUpdateState).call(this, revokeToken)
768
+ .then(() => {
769
+ // re-creating vault to persist the new revoke token.
770
+ // TODO: Optimize this function such that updates to vault wont require re-creating the vault.
771
+ return __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_createNewVaultWithAuthData).call(this, {
772
+ password: globalPassword,
773
+ rawToprfEncryptionKey: latestEncKey,
774
+ rawToprfPwEncryptionKey: latestPwEncKey,
775
+ rawToprfAuthKeyPair: latestAuthKeyPair,
776
+ });
777
+ })
778
+ .catch((error) => {
779
+ log('Error revoking refresh token', error);
760
780
  });
761
781
  }
782
+ // restore the current keyring encryption key with the new global password
783
+ await this.storeKeyringEncryptionKey(keyringEncryptionKey);
784
+ // reset the password outdated cache after successful global password submission and state sync
785
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_resetPasswordOutdatedCache).call(this);
762
786
  }
763
787
  catch (error) {
764
788
  if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isTokenExpiredError).call(this, error)) {
@@ -932,12 +956,31 @@ async function _SeedlessOnboardingController_recoverEncKey(password) {
932
956
  * @param params - The function parameters.
933
957
  * @param params.oldPassword - The old password to verify.
934
958
  * @param params.newPassword - The new password to update.
959
+ * @param params.latestKeyIndex - The key index of the latest key.
935
960
  * @returns A promise that resolves to new encryption key and authentication key pair.
936
961
  */
937
- async function _SeedlessOnboardingController_changeEncryptionKey({ oldPassword, newPassword, }) {
962
+ async function _SeedlessOnboardingController_changeEncryptionKey({ oldPassword, newPassword, latestKeyIndex, }) {
938
963
  __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
939
964
  const { authConnectionId, groupedAuthConnectionId, userId } = this.state;
940
- const { encKey, pwEncKey, authKeyPair, keyShareIndex: newKeyShareIndex, } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverEncKey).call(this, oldPassword);
965
+ let encKey;
966
+ let pwEncKey;
967
+ let authKeyPair;
968
+ let globalKeyIndex = latestKeyIndex;
969
+ if (!globalKeyIndex) {
970
+ ({
971
+ encKey,
972
+ pwEncKey,
973
+ authKeyPair,
974
+ keyShareIndex: globalKeyIndex,
975
+ } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverEncKey).call(this, oldPassword));
976
+ }
977
+ else {
978
+ ({
979
+ toprfEncryptionKey: encKey,
980
+ toprfPwEncryptionKey: pwEncKey,
981
+ toprfAuthKeyPair: authKeyPair,
982
+ } = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_unlockVaultAndGetVaultData).call(this, oldPassword));
983
+ }
941
984
  const result = await this.toprfClient.changeEncKey({
942
985
  nodeAuthTokens: this.state.nodeAuthTokens,
943
986
  authConnectionId,
@@ -946,7 +989,7 @@ async function _SeedlessOnboardingController_changeEncryptionKey({ oldPassword,
946
989
  oldEncKey: encKey,
947
990
  oldPwEncKey: pwEncKey,
948
991
  oldAuthKeyPair: authKeyPair,
949
- newKeyShareIndex,
992
+ newKeyShareIndex: globalKeyIndex,
950
993
  newPassword,
951
994
  });
952
995
  return result;
@@ -1288,13 +1331,33 @@ async function _SeedlessOnboardingController_withVaultLock(callback) {
1288
1331
  * @param options - The options for asserting the password is in sync.
1289
1332
  * @param options.skipCache - Whether to skip the cache check.
1290
1333
  * @param options.skipLock - Whether to skip the lock acquisition. (to prevent deadlock in case the caller already acquired the lock)
1334
+ * @returns The global auth public key and the latest key index.
1291
1335
  * @throws If the password is outdated.
1292
1336
  */
1293
1337
  async function _SeedlessOnboardingController_assertPasswordInSync(options) {
1294
- const isPasswordOutdated = await this.checkIsPasswordOutdated(options);
1338
+ const { nodeAuthTokens, authConnectionId, groupedAuthConnectionId, userId, } = this.state;
1339
+ if (!nodeAuthTokens || !authConnectionId || !userId) {
1340
+ throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.MissingAuthUserInfo);
1341
+ }
1342
+ const { authPubKey, keyIndex: latestKeyIndex } = await this.toprfClient
1343
+ .fetchAuthPubKey({
1344
+ nodeAuthTokens,
1345
+ authConnectionId,
1346
+ groupedAuthConnectionId,
1347
+ userId,
1348
+ })
1349
+ .catch((error) => {
1350
+ log('Error fetching auth pub key', error);
1351
+ throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.FailedToFetchAuthPubKey);
1352
+ });
1353
+ const isPasswordOutdated = await this.checkIsPasswordOutdated({
1354
+ ...options,
1355
+ globalAuthPubKey: authPubKey,
1356
+ });
1295
1357
  if (isPasswordOutdated) {
1296
1358
  throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.OutdatedPassword);
1297
1359
  }
1360
+ return { authPubKey, latestKeyIndex };
1298
1361
  }, _SeedlessOnboardingController_resetPasswordOutdatedCache = function _SeedlessOnboardingController_resetPasswordOutdatedCache() {
1299
1362
  this.update((state) => {
1300
1363
  delete state.passwordOutdatedCache;