@metamask-previews/keyring-controller 22.1.0-preview-7b919d75 → 22.1.0-preview-982a3250

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,25 +7,12 @@ 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 optional `SupportedKeyDerivationOptions` type parameter to the `ExportableKeyEncryptor` type ([#5963](https://github.com/MetaMask/core/pull/5963))
13
- - This type parameter allows specifying the key derivation options supported by the injected encryptor.
14
-
15
10
  ### Changed
16
11
 
17
- - **BREAKING:** The `KeyringController` constructor now requires an encryptor supporting the `keyFromPassword`, `exportKey` and `generateSalt` methods ([#5963](https://github.com/MetaMask/core/pull/5963))
18
12
  - Bump `@metamask/keyring-api` from `^18.0.0` to `^19.0.0` ([#6146](https://github.com/MetaMask/core/pull/6146))
19
13
  - Bump `@metamask/keyring-internal-api` from `^6.2.0` to `^7.0.0` ([#6146](https://github.com/MetaMask/core/pull/6146))
20
14
  - Bump `@metamask/utils` from `^11.2.0` to `^11.4.2` ([#6054](https://github.com/MetaMask/core/pull/6054))
21
15
 
22
- ### Removed
23
-
24
- - **BREAKING:** The `cacheEncryptionKey` parameter has been removed from the `KeyringController` constructor options ([#5963](https://github.com/MetaMask/core/pull/5963))
25
- - This parameter was previously used to enable encryption key in-memory caching, but it is no longer needed as the controller now always uses the latest encryption key.
26
- - **BREAKING:** The `submitEncryptionKey` method does not accept an `encryptionSalt` argument anymore ([#5963](https://github.com/MetaMask/core/pull/5963))
27
- - The encryption salt is now always taken from the vault.
28
-
29
16
  ## [22.1.0]
30
17
 
31
18
  ### Added
@@ -36,7 +36,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
36
36
  var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
38
  };
39
- var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_encryptor, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_encryptionKey, _KeyringController_qrKeyringStateListener, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _KeyringController_addQRKeyring, _KeyringController_subscribeToQRKeyringEvents, _KeyringController_unsubscribeFromQRKeyringsEvents, _KeyringController_createNewVaultWithKeyring, _KeyringController_deriveEncryptionKey, _KeyringController_useEncryptionKey, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_getSessionState, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_isNewEncryptionAvailable, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_createKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_removeEmptyKeyrings, _KeyringController_assertNoDuplicateAccounts, _KeyringController_setUnlocked, _KeyringController_assertIsUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
39
+ var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_password, _KeyringController_qrKeyringStateListener, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _KeyringController_addQRKeyring, _KeyringController_subscribeToQRKeyringEvents, _KeyringController_unsubscribeFromQRKeyringsEvents, _KeyringController_createNewVaultWithKeyring, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_getSessionState, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_isNewEncryptionAvailable, _KeyringController_getAccountsFromKeyrings, _KeyringController_createKeyringWithFirstAccount, _KeyringController_newKeyring, _KeyringController_createKeyring, _KeyringController_clearKeyrings, _KeyringController_restoreKeyring, _KeyringController_destroyKeyring, _KeyringController_removeEmptyKeyrings, _KeyringController_assertNoDuplicateAccounts, _KeyringController_setUnlocked, _KeyringController_assertIsUnlocked, _KeyringController_persistOrRollback, _KeyringController_withRollback, _KeyringController_assertControllerMutexIsLocked, _KeyringController_withControllerLock, _KeyringController_withVaultLock;
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.KeyringController = exports.getDefaultKeyringState = exports.keyringBuilderFactory = exports.SignTypedDataVersion = exports.AccountImportStrategy = exports.isCustodyKeyring = exports.KeyringTypes = void 0;
42
42
  const util_1 = require("@ethereumjs/util");
@@ -255,6 +255,7 @@ class KeyringController extends base_controller_1.BaseController {
255
255
  * @param options - Initial options used to configure this controller
256
256
  * @param options.encryptor - An optional object for defining encryption schemes.
257
257
  * @param options.keyringBuilders - Set a new name for account.
258
+ * @param options.cacheEncryptionKey - Whether to cache or not encryption key.
258
259
  * @param options.messenger - A restricted messenger.
259
260
  * @param options.state - Initial state to set on this controller.
260
261
  */
@@ -280,17 +281,23 @@ class KeyringController extends base_controller_1.BaseController {
280
281
  _KeyringController_vaultOperationMutex.set(this, new async_mutex_1.Mutex());
281
282
  _KeyringController_keyringBuilders.set(this, void 0);
282
283
  _KeyringController_encryptor.set(this, void 0);
284
+ _KeyringController_cacheEncryptionKey.set(this, void 0);
283
285
  _KeyringController_keyrings.set(this, void 0);
284
286
  _KeyringController_unsupportedKeyrings.set(this, void 0);
285
- _KeyringController_encryptionKey.set(this, void 0);
287
+ _KeyringController_password.set(this, void 0);
286
288
  _KeyringController_qrKeyringStateListener.set(this, void 0);
287
289
  __classPrivateFieldSet(this, _KeyringController_keyringBuilders, keyringBuilders
288
290
  ? keyringBuilders.concat(defaultKeyringBuilders)
289
291
  : defaultKeyringBuilders, "f");
290
- assertIsExportableKeyEncryptor(encryptor);
291
292
  __classPrivateFieldSet(this, _KeyringController_encryptor, encryptor, "f");
292
293
  __classPrivateFieldSet(this, _KeyringController_keyrings, [], "f");
293
294
  __classPrivateFieldSet(this, _KeyringController_unsupportedKeyrings, [], "f");
295
+ // This option allows the controller to cache an exported key
296
+ // for use in decrypting and encrypting data without password
297
+ __classPrivateFieldSet(this, _KeyringController_cacheEncryptionKey, Boolean(options.cacheEncryptionKey), "f");
298
+ if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
299
+ assertIsExportableKeyEncryptor(encryptor);
300
+ }
294
301
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_registerMessageHandlers).call(this);
295
302
  }
296
303
  /**
@@ -665,7 +672,7 @@ class KeyringController extends base_controller_1.BaseController {
665
672
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
666
673
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
667
674
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unsubscribeFromQRKeyringsEvents).call(this);
668
- __classPrivateFieldSet(this, _KeyringController_encryptionKey, undefined, "f");
675
+ __classPrivateFieldSet(this, _KeyringController_password, undefined, "f");
669
676
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
670
677
  this.update((state) => {
671
678
  state.isUnlocked = false;
@@ -847,9 +854,22 @@ class KeyringController extends base_controller_1.BaseController {
847
854
  */
848
855
  changePassword(password) {
849
856
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
857
+ // If the password is the same, do nothing.
858
+ if (__classPrivateFieldGet(this, _KeyringController_password, "f") === password) {
859
+ return Promise.resolve();
860
+ }
850
861
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
851
862
  assertIsValidPassword(password);
852
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password);
863
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
864
+ // We need to clear encryption key and salt from state
865
+ // to force the controller to re-encrypt the vault using
866
+ // the new password.
867
+ if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
868
+ this.update((state) => {
869
+ delete state.encryptionKey;
870
+ delete state.encryptionSalt;
871
+ });
872
+ }
853
873
  });
854
874
  }
855
875
  /**
@@ -863,10 +883,7 @@ class KeyringController extends base_controller_1.BaseController {
863
883
  */
864
884
  async submitEncryptionKey(encryptionKey, encryptionSalt) {
865
885
  const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
866
- const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, {
867
- exportedEncryptionKey: encryptionKey,
868
- encryptionKeySalt: encryptionSalt,
869
- });
886
+ const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, undefined, encryptionKey, encryptionSalt);
870
887
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
871
888
  return result;
872
889
  });
@@ -893,8 +910,9 @@ class KeyringController extends base_controller_1.BaseController {
893
910
  async exportEncryptionKey() {
894
911
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
895
912
  return await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async () => {
896
- assertIsEncryptionKeySet(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.exported);
897
- return __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").exported;
913
+ const { encryptionKey } = this.state;
914
+ assertIsEncryptionKeySet(encryptionKey);
915
+ return encryptionKey;
898
916
  });
899
917
  }
900
918
  /**
@@ -906,7 +924,7 @@ class KeyringController extends base_controller_1.BaseController {
906
924
  */
907
925
  async submitPassword(password) {
908
926
  const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
909
- const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, { password });
927
+ const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, password);
910
928
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
911
929
  return result;
912
930
  });
@@ -916,12 +934,6 @@ class KeyringController extends base_controller_1.BaseController {
916
934
  // can attempt to upgrade the vault.
917
935
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
918
936
  if (newMetadata || __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_isNewEncryptionAvailable).call(this)) {
919
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password, {
920
- // If the vault is being upgraded, we want to ignore the metadata
921
- // that is already in the vault, so we can effectively
922
- // re-encrypt the vault with the new encryption config.
923
- useVaultKeyMetadata: false,
924
- });
925
937
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateVault).call(this);
926
938
  }
927
939
  });
@@ -1176,7 +1188,7 @@ class KeyringController extends base_controller_1.BaseController {
1176
1188
  }
1177
1189
  }
1178
1190
  exports.KeyringController = KeyringController;
1179
- _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_encryptionKey = new WeakMap(), _KeyringController_qrKeyringStateListener = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
1191
+ _KeyringController_controllerOperationMutex = new WeakMap(), _KeyringController_vaultOperationMutex = new WeakMap(), _KeyringController_keyringBuilders = new WeakMap(), _KeyringController_encryptor = new WeakMap(), _KeyringController_cacheEncryptionKey = new WeakMap(), _KeyringController_keyrings = new WeakMap(), _KeyringController_unsupportedKeyrings = new WeakMap(), _KeyringController_password = new WeakMap(), _KeyringController_qrKeyringStateListener = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
1180
1192
  this.messagingSystem.registerActionHandler(`${name}:signMessage`, this.signMessage.bind(this));
1181
1193
  this.messagingSystem.registerActionHandler(`${name}:signEip7702Authorization`, this.signEip7702Authorization.bind(this));
1182
1194
  this.messagingSystem.registerActionHandler(`${name}:signPersonalMessage`, this.signPersonalMessage.bind(this));
@@ -1256,60 +1268,10 @@ async function _KeyringController_createNewVaultWithKeyring(password, keyring) {
1256
1268
  delete state.encryptionKey;
1257
1269
  delete state.encryptionSalt;
1258
1270
  });
1259
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password);
1271
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1260
1272
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
1261
1273
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyringWithFirstAccount).call(this, keyring.type, keyring.opts);
1262
1274
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
1263
- }, _KeyringController_deriveEncryptionKey =
1264
- /**
1265
- * Derive the vault encryption key from the provided password, and
1266
- * assign it to the instance variable for later use with cryptographic
1267
- * functions.
1268
- *
1269
- * When the controller has a vault in its state, the key is derived
1270
- * using the salt from the vault. If the vault is empty, a new salt
1271
- * is generated and used to derive the key.
1272
- *
1273
- * @param password - The password to use for decryption or derivation.
1274
- * @param options - Options for the key derivation.
1275
- * @param options.useVaultKeyMetadata - Whether to use the vault key metadata
1276
- */
1277
- async function _KeyringController_deriveEncryptionKey(password, options = {
1278
- useVaultKeyMetadata: true,
1279
- }) {
1280
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1281
- const { vault } = this.state;
1282
- if (typeof password !== 'string') {
1283
- throw new TypeError(constants_1.KeyringControllerError.WrongPasswordType);
1284
- }
1285
- let salt, keyMetadata;
1286
- if (vault && options.useVaultKeyMetadata) {
1287
- const parsedVault = JSON.parse(vault);
1288
- salt = parsedVault.salt;
1289
- keyMetadata = parsedVault.keyMetadata;
1290
- }
1291
- else {
1292
- salt = __classPrivateFieldGet(this, _KeyringController_encryptor, "f").generateSalt();
1293
- }
1294
- const exportedEncryptionKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").exportKey(await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").keyFromPassword(password, salt, true, keyMetadata));
1295
- __classPrivateFieldSet(this, _KeyringController_encryptionKey, {
1296
- salt,
1297
- exported: exportedEncryptionKey,
1298
- }, "f");
1299
- }, _KeyringController_useEncryptionKey = function _KeyringController_useEncryptionKey(encryptionKey, encryptionSalt) {
1300
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1301
- if (typeof encryptionKey !== 'string' ||
1302
- typeof encryptionSalt !== 'string') {
1303
- throw new TypeError(constants_1.KeyringControllerError.WrongEncryptionKeyType);
1304
- }
1305
- const { vault } = this.state;
1306
- if (vault && JSON.parse(vault).salt !== encryptionSalt) {
1307
- throw new Error(constants_1.KeyringControllerError.ExpiredCredentials);
1308
- }
1309
- __classPrivateFieldSet(this, _KeyringController_encryptionKey, {
1310
- salt: encryptionSalt,
1311
- exported: encryptionKey,
1312
- }, "f");
1313
1275
  }, _KeyringController_verifySeedPhrase =
1314
1276
  /**
1315
1277
  * Internal non-exclusive method to verify the seed phrase.
@@ -1390,7 +1352,7 @@ async function _KeyringController_getSerializedKeyrings({ includeUnsupported } =
1390
1352
  return serializedKeyrings;
1391
1353
  }, _KeyringController_getSessionState =
1392
1354
  /**
1393
- * Get a snapshot of session data held by instance variables.
1355
+ * Get a snapshot of session data held by class variables.
1394
1356
  *
1395
1357
  * @returns An object with serialized keyrings, keyrings metadata,
1396
1358
  * and the user password.
@@ -1398,7 +1360,7 @@ async function _KeyringController_getSerializedKeyrings({ includeUnsupported } =
1398
1360
  async function _KeyringController_getSessionState() {
1399
1361
  return {
1400
1362
  keyrings: await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this),
1401
- encryptionKey: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"),
1363
+ password: __classPrivateFieldGet(this, _KeyringController_password, "f"),
1402
1364
  };
1403
1365
  }, _KeyringController_restoreSerializedKeyrings =
1404
1366
  /**
@@ -1427,27 +1389,54 @@ async function _KeyringController_restoreSerializedKeyrings(serializedKeyrings)
1427
1389
  * Unlock Keyrings, decrypting the vault and deserializing all
1428
1390
  * keyrings contained in it, using a password or an encryption key with salt.
1429
1391
  *
1430
- * @param credentials - The credentials to unlock the keyrings.
1392
+ * @param password - The keyring controller password.
1393
+ * @param encryptionKey - An exported key string to unlock keyrings with.
1394
+ * @param encryptionSalt - The salt used to encrypt the vault.
1431
1395
  * @returns A promise resolving to the deserialized keyrings array.
1432
1396
  */
1433
- async function _KeyringController_unlockKeyrings(credentials) {
1397
+ async function _KeyringController_unlockKeyrings(password, encryptionKey, encryptionSalt) {
1434
1398
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
1435
- if (!this.state.vault) {
1399
+ const encryptedVault = this.state.vault;
1400
+ if (!encryptedVault) {
1436
1401
  throw new Error(constants_1.KeyringControllerError.VaultError);
1437
1402
  }
1438
- const parsedEncryptedVault = JSON.parse(this.state.vault);
1439
- if ('password' in credentials) {
1440
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, credentials.password);
1403
+ let vault;
1404
+ const updatedState = {};
1405
+ if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
1406
+ assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
1407
+ if (password) {
1408
+ const result = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithDetail(password, encryptedVault);
1409
+ vault = result.vault;
1410
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1411
+ updatedState.encryptionKey = result.exportedKeyString;
1412
+ updatedState.encryptionSalt = result.salt;
1413
+ }
1414
+ else {
1415
+ const parsedEncryptedVault = JSON.parse(encryptedVault);
1416
+ if (encryptionSalt && encryptionSalt !== parsedEncryptedVault.salt) {
1417
+ throw new Error(constants_1.KeyringControllerError.ExpiredCredentials);
1418
+ }
1419
+ else {
1420
+ encryptionSalt = parsedEncryptedVault.salt;
1421
+ }
1422
+ if (typeof encryptionKey !== 'string') {
1423
+ throw new TypeError(constants_1.KeyringControllerError.WrongPasswordType);
1424
+ }
1425
+ const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1426
+ vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(key, parsedEncryptedVault);
1427
+ // This call is required on the first call because encryptionKey
1428
+ // is not yet inside the memStore
1429
+ updatedState.encryptionKey = encryptionKey;
1430
+ updatedState.encryptionSalt = encryptionSalt;
1431
+ }
1441
1432
  }
1442
1433
  else {
1443
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_useEncryptionKey).call(this, credentials.exportedEncryptionKey, credentials.encryptionKeySalt || parsedEncryptedVault.salt);
1444
- }
1445
- const encryptionKey = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.exported;
1446
- if (!encryptionKey) {
1447
- throw new Error(constants_1.KeyringControllerError.MissingCredentials);
1434
+ if (typeof password !== 'string') {
1435
+ throw new TypeError(constants_1.KeyringControllerError.WrongPasswordType);
1436
+ }
1437
+ vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decrypt(password, encryptedVault);
1438
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1448
1439
  }
1449
- const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1450
- const vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(key, parsedEncryptedVault);
1451
1440
  if (!isSerializedKeyringsArray(vault)) {
1452
1441
  throw new Error(constants_1.KeyringControllerError.VaultDataError);
1453
1442
  }
@@ -1455,8 +1444,10 @@ async function _KeyringController_unlockKeyrings(credentials) {
1455
1444
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1456
1445
  this.update((state) => {
1457
1446
  state.keyrings = updatedKeyrings;
1458
- state.encryptionKey = encryptionKey;
1459
- state.encryptionSalt = parsedEncryptedVault.salt;
1447
+ if (updatedState.encryptionKey || updatedState.encryptionSalt) {
1448
+ state.encryptionKey = updatedState.encryptionKey;
1449
+ state.encryptionSalt = updatedState.encryptionSalt;
1450
+ }
1460
1451
  });
1461
1452
  return { keyrings, newMetadata };
1462
1453
  });
@@ -1464,36 +1455,57 @@ async function _KeyringController_unlockKeyrings(credentials) {
1464
1455
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
1465
1456
  // Ensure no duplicate accounts are persisted.
1466
1457
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertNoDuplicateAccounts).call(this);
1467
- if (!__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")) {
1458
+ const { encryptionKey, encryptionSalt, vault } = this.state;
1459
+ // READ THIS CAREFULLY:
1460
+ // We do check if the vault is still considered up-to-date, if not, we would not re-use the
1461
+ // cached key and we will re-generate a new one (based on the password).
1462
+ //
1463
+ // This helps doing seamless updates of the vault. Useful in case we change some cryptographic
1464
+ // parameters to the KDF.
1465
+ const useCachedKey = encryptionKey && vault && __classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated?.(vault);
1466
+ if (!__classPrivateFieldGet(this, _KeyringController_password, "f") && !encryptionKey) {
1468
1467
  throw new Error(constants_1.KeyringControllerError.MissingCredentials);
1469
1468
  }
1470
1469
  const serializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1471
1470
  if (!serializedKeyrings.some((keyring) => keyring.type === KeyringTypes.hd)) {
1472
1471
  throw new Error(constants_1.KeyringControllerError.NoHdKeyring);
1473
1472
  }
1474
- const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").exported);
1475
- const encryptedVault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(key, serializedKeyrings);
1476
- // We need to include the salt used to derive
1477
- // the encryption key, to be able to derive it
1478
- // from password again.
1479
- encryptedVault.salt = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt;
1480
- const updatedState = {
1481
- vault: JSON.stringify(encryptedVault),
1482
- encryptionKey: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").exported,
1483
- encryptionSalt: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt,
1484
- };
1473
+ const updatedState = {};
1474
+ if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
1475
+ assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
1476
+ if (useCachedKey) {
1477
+ const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1478
+ const vaultJSON = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(key, serializedKeyrings);
1479
+ vaultJSON.salt = encryptionSalt;
1480
+ updatedState.vault = JSON.stringify(vaultJSON);
1481
+ }
1482
+ else if (__classPrivateFieldGet(this, _KeyringController_password, "f")) {
1483
+ const { vault: newVault, exportedKeyString } = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithDetail(__classPrivateFieldGet(this, _KeyringController_password, "f"), serializedKeyrings);
1484
+ updatedState.vault = newVault;
1485
+ updatedState.encryptionKey = exportedKeyString;
1486
+ }
1487
+ }
1488
+ else {
1489
+ assertIsValidPassword(__classPrivateFieldGet(this, _KeyringController_password, "f"));
1490
+ updatedState.vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encrypt(__classPrivateFieldGet(this, _KeyringController_password, "f"), serializedKeyrings);
1491
+ }
1492
+ if (!updatedState.vault) {
1493
+ throw new Error(constants_1.KeyringControllerError.MissingVaultData);
1494
+ }
1485
1495
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1486
1496
  this.update((state) => {
1487
1497
  state.vault = updatedState.vault;
1488
1498
  state.keyrings = updatedKeyrings;
1489
- state.encryptionKey = updatedState.encryptionKey;
1490
- state.encryptionSalt = updatedState.encryptionSalt;
1499
+ if (updatedState.encryptionKey) {
1500
+ state.encryptionKey = updatedState.encryptionKey;
1501
+ state.encryptionSalt = JSON.parse(updatedState.vault).salt;
1502
+ }
1491
1503
  });
1492
1504
  return true;
1493
1505
  });
1494
1506
  }, _KeyringController_isNewEncryptionAvailable = function _KeyringController_isNewEncryptionAvailable() {
1495
1507
  const { vault } = this.state;
1496
- if (!vault || !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated) {
1508
+ if (!vault || !__classPrivateFieldGet(this, _KeyringController_password, "f") || !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated) {
1497
1509
  return false;
1498
1510
  }
1499
1511
  return !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated(vault);
@@ -1732,13 +1744,13 @@ async function _KeyringController_persistOrRollback(callback) {
1732
1744
  async function _KeyringController_withRollback(callback) {
1733
1745
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async ({ releaseLock }) => {
1734
1746
  const currentSerializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1735
- const currentEncryptionKey = (0, lodash_1.cloneDeep)(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"));
1747
+ const currentPassword = __classPrivateFieldGet(this, _KeyringController_password, "f");
1736
1748
  try {
1737
1749
  return await callback({ releaseLock });
1738
1750
  }
1739
1751
  catch (e) {
1740
- // Keyrings and encryption credentials are restored to their previous state
1741
- __classPrivateFieldSet(this, _KeyringController_encryptionKey, currentEncryptionKey, "f");
1752
+ // Keyrings and password are restored to their previous state
1753
+ __classPrivateFieldSet(this, _KeyringController_password, currentPassword, "f");
1742
1754
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreSerializedKeyrings).call(this, currentSerializedKeyrings);
1743
1755
  throw e;
1744
1756
  }