@metamask-previews/seedless-onboarding-controller 5.0.0-preview-8c66598b → 5.0.0-preview-e98a6769

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 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 new public method, `checkIsSeedlessOnboardingUserAuthenticated` to validate the controller authenticate tokens state. ([#6998](https://github.com/MetaMask/core/pull/6998))
13
+
14
+ ### Changed
15
+
16
+ - Refactor `refreshAuthTokens` method, separately catch refreshJWTToken and authenticate errors. ([#6998](https://github.com/MetaMask/core/pull/6998))
17
+ - Bump `@metamask/toprf-secure-backup` package to `0.9.0`. ([#6998](https://github.com/MetaMask/core/pull/6998))
18
+
19
+ ### Fixed
20
+
21
+ - Fixed `Invalid Access Token` error during rehydration. ([#6998](https://github.com/MetaMask/core/pull/6998))
22
+
10
23
  ## [5.0.0]
11
24
 
12
25
  ### Changed
@@ -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_renewRefreshToken, _SeedlessOnboardingController_passwordOutdatedCacheTTL, _SeedlessOnboardingController_isUnlocked, _SeedlessOnboardingController_cachedDecryptedVaultData, _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_decryptAndParseVaultData, _SeedlessOnboardingController_withPersistedSecretMetadataBackupsState, _SeedlessOnboardingController_filterDupesAndUpdateSocialBackupsMetadata, _SeedlessOnboardingController_createNewVaultWithAuthData, _SeedlessOnboardingController_updateVault, _SeedlessOnboardingController_withControllerLock, _SeedlessOnboardingController_withVaultLock, _SeedlessOnboardingController_parseVaultData, _SeedlessOnboardingController_assertIsUnlocked, _SeedlessOnboardingController_assertIsAuthenticatedUser, _SeedlessOnboardingController_assertIsSRPBackedUpUser, _SeedlessOnboardingController_assertPasswordInSync, _SeedlessOnboardingController_resetPasswordOutdatedCache, _SeedlessOnboardingController_addRefreshTokenToRevokeList, _SeedlessOnboardingController_isTokenExpiredError, _SeedlessOnboardingController_isMaxKeyChainLengthError, _SeedlessOnboardingController_executeWithTokenRefresh;
13
+ var _SeedlessOnboardingController_instances, _SeedlessOnboardingController_vaultEncryptor, _SeedlessOnboardingController_controllerOperationMutex, _SeedlessOnboardingController_vaultOperationMutex, _SeedlessOnboardingController_refreshJWTToken, _SeedlessOnboardingController_revokeRefreshToken, _SeedlessOnboardingController_renewRefreshToken, _SeedlessOnboardingController_passwordOutdatedCacheTTL, _SeedlessOnboardingController_isUnlocked, _SeedlessOnboardingController_cachedDecryptedVaultData, _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_decryptAndParseVaultData, _SeedlessOnboardingController_withPersistedSecretMetadataBackupsState, _SeedlessOnboardingController_filterDupesAndUpdateSocialBackupsMetadata, _SeedlessOnboardingController_createNewVaultWithAuthData, _SeedlessOnboardingController_updateVault, _SeedlessOnboardingController_withControllerLock, _SeedlessOnboardingController_withVaultLock, _SeedlessOnboardingController_parseVaultData, _SeedlessOnboardingController_assertIsUnlocked, _SeedlessOnboardingController_assertIsAuthenticatedUser, _SeedlessOnboardingController_assertIsSRPBackedUpUser, _SeedlessOnboardingController_assertPasswordInSync, _SeedlessOnboardingController_resetPasswordOutdatedCache, _SeedlessOnboardingController_addRefreshTokenToRevokeList, _SeedlessOnboardingController_isAuthTokenError, _SeedlessOnboardingController_isMaxKeyChainLengthError, _SeedlessOnboardingController_executeWithTokenRefresh;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.SeedlessOnboardingController = exports.getInitialSeedlessOnboardingControllerStateWithDefaults = void 0;
16
16
  const auth_network_utils_1 = require("@metamask/auth-network-utils");
@@ -297,14 +297,10 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
297
297
  state.authConnection = authConnection;
298
298
  state.socialLoginEmail = socialLoginEmail;
299
299
  state.metadataAccessToken = metadataAccessToken;
300
+ state.refreshToken = refreshToken;
301
+ // Temporarily store revoke token & access token in state for later vault creation
302
+ state.revokeToken = revokeToken;
300
303
  state.accessToken = accessToken;
301
- if (refreshToken) {
302
- state.refreshToken = refreshToken;
303
- }
304
- if (revokeToken) {
305
- // Temporarily store revoke token in state for later vault creation
306
- state.revokeToken = revokeToken;
307
- }
308
304
  // we will check if the controller state is properly set with the authenticated user info
309
305
  // before setting the isSeedlessOnboardingUserAuthenticated to true
310
306
  (0, assertions_1.assertIsSeedlessOnboardingUserAuthenticated)(state);
@@ -406,26 +402,26 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
406
402
  */
407
403
  async fetchAllSecretData(password) {
408
404
  return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_withControllerLock).call(this, async () => {
409
- // assert that the user is authenticated before fetching the secret data
410
- __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
411
- let encKey;
412
- let pwEncKey;
413
- let authKeyPair;
414
- if (password) {
415
- const recoverEncKeyResult = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverEncKey).call(this, password);
416
- encKey = recoverEncKeyResult.encKey;
417
- pwEncKey = recoverEncKeyResult.pwEncKey;
418
- authKeyPair = recoverEncKeyResult.authKeyPair;
419
- }
420
- else {
421
- __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsUnlocked).call(this);
422
- // verify the password and unlock the vault
423
- const keysFromVault = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_unlockVaultAndGetVaultData).call(this);
424
- encKey = keysFromVault.toprfEncryptionKey;
425
- pwEncKey = keysFromVault.toprfPwEncryptionKey;
426
- authKeyPair = keysFromVault.toprfAuthKeyPair;
427
- }
428
- const performFetch = async () => {
405
+ return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_executeWithTokenRefresh).call(this, async () => {
406
+ // assert that the user is authenticated before fetching the secret data
407
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
408
+ let encKey;
409
+ let pwEncKey;
410
+ let authKeyPair;
411
+ if (password) {
412
+ const recoverEncKeyResult = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_recoverEncKey).call(this, password);
413
+ encKey = recoverEncKeyResult.encKey;
414
+ pwEncKey = recoverEncKeyResult.pwEncKey;
415
+ authKeyPair = recoverEncKeyResult.authKeyPair;
416
+ }
417
+ else {
418
+ __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsUnlocked).call(this);
419
+ // verify the password and unlock the vault
420
+ const keysFromVault = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_unlockVaultAndGetVaultData).call(this);
421
+ encKey = keysFromVault.toprfEncryptionKey;
422
+ pwEncKey = keysFromVault.toprfPwEncryptionKey;
423
+ authKeyPair = keysFromVault.toprfAuthKeyPair;
424
+ }
429
425
  const secrets = await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_fetchAllSecretDataFromMetadataStore).call(this, encKey, authKeyPair);
430
426
  if (password) {
431
427
  // if password is provided, we need to create a new vault with the auth data. (supposedly the user is trying to rehydrate the wallet)
@@ -437,8 +433,7 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
437
433
  });
438
434
  }
439
435
  return secrets;
440
- };
441
- return await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_executeWithTokenRefresh).call(this, performFetch, 'fetchAllSecretData');
436
+ }, 'fetchAllSecretData');
442
437
  });
443
438
  }
444
439
  /**
@@ -676,6 +671,21 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
676
671
  ? await doCheckIsPasswordExpired()
677
672
  : await __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_withControllerLock).call(this, doCheckIsPasswordExpired), 'checkIsPasswordOutdated');
678
673
  }
674
+ /**
675
+ * Check if the user is authenticated with the seedless onboarding flow by checking the token values in the state.
676
+ *
677
+ * @returns True if the user is authenticated, false otherwise.
678
+ */
679
+ async checkIsSeedlessOnboardingUserAuthenticated() {
680
+ try {
681
+ (0, assertions_1.assertIsSeedlessOnboardingUserAuthenticated)(this.state);
682
+ // if accessToken is missing, the user needs to authenticate again
683
+ return Boolean(this.state.accessToken) && Boolean(this.state.revokeToken);
684
+ }
685
+ catch {
686
+ return false;
687
+ }
688
+ }
679
689
  /**
680
690
  * Clears the current state of the SeedlessOnboardingController.
681
691
  */
@@ -715,12 +725,15 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
715
725
  */
716
726
  async refreshAuthTokens() {
717
727
  __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_assertIsAuthenticatedUser).call(this, this.state);
718
- const { refreshToken } = this.state;
728
+ const { refreshToken, revokeToken } = this.state;
729
+ const res = await __classPrivateFieldGet(this, _SeedlessOnboardingController_refreshJWTToken, "f").call(this, {
730
+ connection: this.state.authConnection,
731
+ refreshToken,
732
+ }).catch((error) => {
733
+ log('Error refreshing JWT tokens', error);
734
+ throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.FailedToRefreshJWTTokens);
735
+ });
719
736
  try {
720
- const res = await __classPrivateFieldGet(this, _SeedlessOnboardingController_refreshJWTToken, "f").call(this, {
721
- connection: this.state.authConnection,
722
- refreshToken,
723
- });
724
737
  const { idTokens, accessToken, metadataAccessToken } = res;
725
738
  // re-authenticate with the new id tokens to set new node auth tokens
726
739
  await this.authenticate({
@@ -731,6 +744,8 @@ class SeedlessOnboardingController extends base_controller_1.BaseController {
731
744
  authConnectionId: this.state.authConnectionId,
732
745
  groupedAuthConnectionId: this.state.groupedAuthConnectionId,
733
746
  userId: this.state.userId,
747
+ refreshToken,
748
+ revokeToken,
734
749
  skipLock: true,
735
750
  });
736
751
  }
@@ -912,7 +927,7 @@ async function _SeedlessOnboardingController_submitGlobalPassword({ targetAuthPu
912
927
  __classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_setUnlocked).call(this);
913
928
  }
914
929
  catch (error) {
915
- if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isTokenExpiredError).call(this, error)) {
930
+ if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isAuthTokenError).call(this, error)) {
916
931
  throw error;
917
932
  }
918
933
  if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isMaxKeyChainLengthError).call(this, error)) {
@@ -968,7 +983,7 @@ async function _SeedlessOnboardingController_persistOprfKey(oprfKey, authPubKey)
968
983
  });
969
984
  }
970
985
  catch (error) {
971
- if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isTokenExpiredError).call(this, error)) {
986
+ if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isAuthTokenError).call(this, error)) {
972
987
  throw error;
973
988
  }
974
989
  log('Error persisting local encryption key', error);
@@ -1046,7 +1061,7 @@ async function _SeedlessOnboardingController_recoverEncKey(password) {
1046
1061
  }
1047
1062
  catch (error) {
1048
1063
  // throw token expired error for token refresh handler
1049
- if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isTokenExpiredError).call(this, error)) {
1064
+ if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isAuthTokenError).call(this, error)) {
1050
1065
  throw error;
1051
1066
  }
1052
1067
  throw errors_1.RecoveryError.getInstance(error);
@@ -1062,7 +1077,7 @@ async function _SeedlessOnboardingController_recoverEncKey(password) {
1062
1077
  }
1063
1078
  catch (error) {
1064
1079
  log('Error fetching secret data', error);
1065
- if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isTokenExpiredError).call(this, error)) {
1080
+ if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isAuthTokenError).call(this, error)) {
1066
1081
  throw error;
1067
1082
  }
1068
1083
  throw new Error(constants_1.SeedlessOnboardingControllerErrorMessage.FailedToFetchSecretMetadata);
@@ -1166,7 +1181,7 @@ async function _SeedlessOnboardingController_encryptAndStoreSecretData(params) {
1166
1181
  });
1167
1182
  }
1168
1183
  catch (error) {
1169
- if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isTokenExpiredError).call(this, error)) {
1184
+ if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isAuthTokenError).call(this, error)) {
1170
1185
  throw error;
1171
1186
  }
1172
1187
  log('Error encrypting and storing secret data backup', error);
@@ -1475,10 +1490,13 @@ async function _SeedlessOnboardingController_assertPasswordInSync(options) {
1475
1490
  { refreshToken, revokeToken },
1476
1491
  ];
1477
1492
  });
1478
- }, _SeedlessOnboardingController_isTokenExpiredError = function _SeedlessOnboardingController_isTokenExpiredError(error) {
1493
+ }, _SeedlessOnboardingController_isAuthTokenError = function _SeedlessOnboardingController_isAuthTokenError(error) {
1479
1494
  if (error instanceof toprf_secure_backup_1.TOPRFError) {
1495
+ return (
1480
1496
  // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
1481
- return error.code === toprf_secure_backup_1.TOPRFErrorCode.AuthTokenExpired;
1497
+ error.code === toprf_secure_backup_1.TOPRFErrorCode.AuthTokenExpired ||
1498
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
1499
+ error.code === toprf_secure_backup_1.TOPRFErrorCode.InvalidAuthToken);
1482
1500
  }
1483
1501
  return false;
1484
1502
  }, _SeedlessOnboardingController_isMaxKeyChainLengthError = function _SeedlessOnboardingController_isMaxKeyChainLengthError(error) {
@@ -1521,7 +1539,7 @@ async function _SeedlessOnboardingController_executeWithTokenRefresh(operation,
1521
1539
  }
1522
1540
  catch (error) {
1523
1541
  // Check if this is a token expiration error
1524
- if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isTokenExpiredError).call(this, error)) {
1542
+ if (__classPrivateFieldGet(this, _SeedlessOnboardingController_instances, "m", _SeedlessOnboardingController_isAuthTokenError).call(this, error)) {
1525
1543
  log(`Token expired during ${operationName}, attempting to refresh tokens`, error);
1526
1544
  try {
1527
1545
  // Refresh the tokens