@metamask-previews/keyring-controller 22.0.2-preview-13f36eb8 → 22.0.2-preview-0013a1bd

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.
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  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");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- 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;
12
+ var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_encryptor, _KeyringController_cacheEncryptionKey, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_password, _KeyringController_encryptionKey, _KeyringController_qrKeyringStateListener, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _KeyringController_addQRKeyring, _KeyringController_subscribeToQRKeyringEvents, _KeyringController_unsubscribeFromQRKeyringsEvents, _KeyringController_createNewVaultWithKeyring, _KeyringController_updateCachedEncryptionKey, _KeyringController_verifySeedPhrase, _KeyringController_getUpdatedKeyrings, _KeyringController_getSerializedKeyrings, _KeyringController_getSessionState, _KeyringController_restoreSerializedKeyrings, _KeyringController_unlockKeyrings, _KeyringController_updateVault, _KeyringController_isNewEncryptionAvailable, _KeyringController_isEnvelopeEncryptionEnabled, _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;
13
13
  function $importDefault(module) {
14
14
  if (module?.__esModule) {
15
15
  return module.default;
@@ -145,6 +145,17 @@ function assertIsValidPassword(password) {
145
145
  throw new Error(KeyringControllerError.InvalidEmptyPassword);
146
146
  }
147
147
  }
148
+ /**
149
+ * Assert that the provided cacheEncryptionKey is true.
150
+ *
151
+ * @param cacheEncryptionKey - The cacheEncryptionKey to check.
152
+ * @throws If the cacheEncryptionKey is not true.
153
+ */
154
+ function assertIsCacheEncryptionKeyTrue(cacheEncryptionKey) {
155
+ if (!cacheEncryptionKey) {
156
+ throw new Error(KeyringControllerError.CacheEncryptionKeyDisabled);
157
+ }
158
+ }
148
159
  /**
149
160
  * Checks if the provided value is a serialized keyrings array.
150
161
  *
@@ -235,6 +246,7 @@ export class KeyringController extends BaseController {
235
246
  keyrings: { persist: false, anonymous: false },
236
247
  encryptionKey: { persist: false, anonymous: false },
237
248
  encryptionSalt: { persist: false, anonymous: false },
249
+ encryptedEncryptionKey: { persist: true, anonymous: false },
238
250
  },
239
251
  messenger,
240
252
  state: {
@@ -247,17 +259,24 @@ export class KeyringController extends BaseController {
247
259
  _KeyringController_vaultOperationMutex.set(this, new Mutex());
248
260
  _KeyringController_keyringBuilders.set(this, void 0);
249
261
  _KeyringController_encryptor.set(this, void 0);
262
+ _KeyringController_cacheEncryptionKey.set(this, void 0);
250
263
  _KeyringController_keyrings.set(this, void 0);
251
264
  _KeyringController_unsupportedKeyrings.set(this, void 0);
265
+ _KeyringController_password.set(this, void 0);
252
266
  _KeyringController_encryptionKey.set(this, void 0);
253
267
  _KeyringController_qrKeyringStateListener.set(this, void 0);
254
268
  __classPrivateFieldSet(this, _KeyringController_keyringBuilders, keyringBuilders
255
269
  ? keyringBuilders.concat(defaultKeyringBuilders)
256
270
  : defaultKeyringBuilders, "f");
257
- assertIsExportableKeyEncryptor(encryptor);
258
271
  __classPrivateFieldSet(this, _KeyringController_encryptor, encryptor, "f");
259
272
  __classPrivateFieldSet(this, _KeyringController_keyrings, [], "f");
260
273
  __classPrivateFieldSet(this, _KeyringController_unsupportedKeyrings, [], "f");
274
+ // This option allows the controller to cache an exported key
275
+ // for use in decrypting and encrypting data without password
276
+ __classPrivateFieldSet(this, _KeyringController_cacheEncryptionKey, Boolean(options.cacheEncryptionKey), "f");
277
+ if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
278
+ assertIsExportableKeyEncryptor(encryptor);
279
+ }
261
280
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_registerMessageHandlers).call(this);
262
281
  }
263
282
  /**
@@ -327,9 +346,11 @@ export class KeyringController extends BaseController {
327
346
  * @param password - Password to unlock keychain.
328
347
  * @param seed - A BIP39-compliant seed phrase as Uint8Array,
329
348
  * either as a string or an array of UTF-8 bytes that represent the string.
349
+ * @param encryptionKey - Optional encryption key to encrypt the new vault. If
350
+ * set, envelope encryption will be used.
330
351
  * @returns Promise resolving when the operation ends successfully.
331
352
  */
332
- async createNewVaultAndRestore(password, seed) {
353
+ async createNewVaultAndRestore(password, seed, encryptionKey) {
333
354
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
334
355
  assertIsValidPassword(password);
335
356
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createNewVaultWithKeyring).call(this, password, {
@@ -338,25 +359,28 @@ export class KeyringController extends BaseController {
338
359
  mnemonic: seed,
339
360
  numberOfAccounts: 1,
340
361
  },
341
- });
362
+ }, encryptionKey);
342
363
  });
343
364
  }
344
365
  /**
345
366
  * Create a new vault and primary keyring.
346
367
  *
347
- * This only works if keyrings are empty. If there is a pre-existing unlocked vault, calling this will have no effect.
348
- * If there is a pre-existing locked vault, it will be replaced.
368
+ * This only works if keyrings are empty. If there is a pre-existing unlocked
369
+ * vault, calling this will have no effect. If there is a pre-existing locked
370
+ * vault, it will be replaced.
349
371
  *
350
372
  * @param password - Password to unlock the new vault.
373
+ * @param encryptionKey - Optional encryption key to encrypt the new vault. If
374
+ * set, envelope encryption will be used.
351
375
  * @returns Promise resolving when the operation ends successfully.
352
376
  */
353
- async createNewVaultAndKeychain(password) {
377
+ async createNewVaultAndKeychain(password, encryptionKey) {
354
378
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
355
379
  const accounts = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getAccountsFromKeyrings).call(this);
356
380
  if (!accounts.length) {
357
381
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createNewVaultWithKeyring).call(this, password, {
358
382
  type: KeyringTypes.hd,
359
- });
383
+ }, encryptionKey);
360
384
  }
361
385
  });
362
386
  }
@@ -385,7 +409,16 @@ export class KeyringController extends BaseController {
385
409
  if (!this.state.vault) {
386
410
  throw new Error(KeyringControllerError.VaultError);
387
411
  }
388
- await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decrypt(password, this.state.vault);
412
+ if (this.state.encryptedEncryptionKey) {
413
+ // Envelope encryption mode.
414
+ assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
415
+ const decryptedEncryptionKey = (await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decrypt(password, this.state.encryptedEncryptionKey));
416
+ const importedKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(decryptedEncryptionKey);
417
+ await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(importedKey, this.state.vault);
418
+ }
419
+ else {
420
+ await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decrypt(password, this.state.vault);
421
+ }
389
422
  }
390
423
  /**
391
424
  * Returns the status of the vault.
@@ -574,7 +607,7 @@ export class KeyringController extends BaseController {
574
607
  try {
575
608
  wallet = importers.fromEtherWallet(input, password);
576
609
  }
577
- catch (e) {
610
+ catch {
578
611
  wallet = wallet || (await Wallet.fromV3(input, password, true));
579
612
  }
580
613
  privateKey = bytesToHex(wallet.getPrivateKey());
@@ -632,6 +665,7 @@ export class KeyringController extends BaseController {
632
665
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
633
666
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
634
667
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unsubscribeFromQRKeyringsEvents).call(this);
668
+ __classPrivateFieldSet(this, _KeyringController_password, undefined, "f");
635
669
  __classPrivateFieldSet(this, _KeyringController_encryptionKey, undefined, "f");
636
670
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
637
671
  this.update((state) => {
@@ -813,10 +847,33 @@ export class KeyringController extends BaseController {
813
847
  * @returns Promise resolving when the operation completes.
814
848
  */
815
849
  changePassword(password) {
850
+ return this.changePasswordAndEncryptionKey(password);
851
+ }
852
+ /**
853
+ * Changes the password and encryption key used to encrypt the vault.
854
+ *
855
+ * @param password - The new password.
856
+ * @param encryptionKey - The new encryption key. If omitted, the encryption
857
+ * key will not be changed.
858
+ * @returns Promise resolving when the operation completes.
859
+ */
860
+ changePasswordAndEncryptionKey(password, encryptionKey) {
816
861
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
817
862
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
818
863
  assertIsValidPassword(password);
819
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password);
864
+ // Update password.
865
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
866
+ // Update encryption key.
867
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateCachedEncryptionKey).call(this, encryptionKey);
868
+ // We need to clear encryption key and salt from state
869
+ // to force the controller to re-encrypt the vault using
870
+ // the new password.
871
+ if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
872
+ this.update((state) => {
873
+ delete state.encryptionKey;
874
+ delete state.encryptionSalt;
875
+ });
876
+ }
820
877
  });
821
878
  }
822
879
  /**
@@ -824,13 +881,12 @@ export class KeyringController extends BaseController {
824
881
  * using the given encryption key and salt.
825
882
  *
826
883
  * @param encryptionKey - Key to unlock the keychain.
884
+ * @param encryptionSalt - Salt to unlock the keychain.
827
885
  * @returns Promise resolving when the operation completes.
828
886
  */
829
- async submitEncryptionKey(encryptionKey) {
887
+ async submitEncryptionKey(encryptionKey, encryptionSalt) {
830
888
  const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
831
- const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, {
832
- exportedEncryptionKey: encryptionKey,
833
- });
889
+ const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, undefined, encryptionKey, encryptionSalt);
834
890
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
835
891
  return result;
836
892
  });
@@ -858,7 +914,7 @@ export class KeyringController extends BaseController {
858
914
  */
859
915
  async submitPassword(password) {
860
916
  const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
861
- const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, { password });
917
+ const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, password);
862
918
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
863
919
  return result;
864
920
  });
@@ -868,12 +924,6 @@ export class KeyringController extends BaseController {
868
924
  // can attempt to upgrade the vault.
869
925
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
870
926
  if (newMetadata || __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_isNewEncryptionAvailable).call(this)) {
871
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password, {
872
- // If the vault is being upgraded, we want to ignore the metadata
873
- // that is already in the vault, so we can effectively
874
- // re-encrypt the vault with the new encryption config.
875
- ignoreVaultKeyMetadata: true,
876
- });
877
927
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateVault).call(this);
878
928
  }
879
929
  });
@@ -1127,7 +1177,7 @@ export class KeyringController extends BaseController {
1127
1177
  });
1128
1178
  }
1129
1179
  }
1130
- _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() {
1180
+ _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_encryptionKey = new WeakMap(), _KeyringController_qrKeyringStateListener = new WeakMap(), _KeyringController_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
1131
1181
  this.messagingSystem.registerActionHandler(`${name}:signMessage`, this.signMessage.bind(this));
1132
1182
  this.messagingSystem.registerActionHandler(`${name}:signEip7702Authorization`, this.signEip7702Authorization.bind(this));
1133
1183
  this.messagingSystem.registerActionHandler(`${name}:signPersonalMessage`, this.signPersonalMessage.bind(this));
@@ -1196,9 +1246,10 @@ async function _KeyringController_addQRKeyring() {
1196
1246
  * @param keyring - A object containing the params to instantiate a new keyring.
1197
1247
  * @param keyring.type - The keyring type.
1198
1248
  * @param keyring.opts - Optional parameters required to instantiate the keyring.
1249
+ * @param encryptionKey - Optional encryption key to encrypt the vault.
1199
1250
  * @returns A promise that resolves to the state.
1200
1251
  */
1201
- async function _KeyringController_createNewVaultWithKeyring(password, keyring) {
1252
+ async function _KeyringController_createNewVaultWithKeyring(password, keyring, encryptionKey) {
1202
1253
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1203
1254
  if (typeof password !== 'string') {
1204
1255
  throw new TypeError(KeyringControllerError.WrongPasswordType);
@@ -1207,56 +1258,21 @@ async function _KeyringController_createNewVaultWithKeyring(password, keyring) {
1207
1258
  delete state.encryptionKey;
1208
1259
  delete state.encryptionSalt;
1209
1260
  });
1210
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password);
1261
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1262
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateCachedEncryptionKey).call(this, encryptionKey);
1211
1263
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
1212
1264
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyringWithFirstAccount).call(this, keyring.type, keyring.opts);
1213
1265
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
1214
- }, _KeyringController_deriveEncryptionKey =
1215
- /**
1216
- * Derive the vault encryption key from the provided password, and
1217
- * assign it to the class variable for later use with cryptographic
1218
- * functions.
1219
- *
1220
- * When the controller has a vault in its state, the key is derived
1221
- * using the salt from the vault. If the vault is empty, a new salt
1222
- * is generated and used to derive the key.
1223
- *
1224
- * @param password - The password to use for decryption or derivation.
1225
- * @param options - Options for the key derivation.
1226
- * @param options.ignoreVaultKeyMetadata - Whether to ignore the vault key metadata
1227
- */
1228
- async function _KeyringController_deriveEncryptionKey(password, options = {
1229
- ignoreVaultKeyMetadata: false,
1230
- }) {
1231
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1232
- const { vault } = this.state;
1233
- if (typeof password !== 'string') {
1234
- throw new TypeError(KeyringControllerError.WrongPasswordType);
1235
- }
1236
- let salt, keyMetadata;
1237
- if (vault && !options.ignoreVaultKeyMetadata) {
1238
- const parsedVault = JSON.parse(vault);
1239
- salt = parsedVault.salt;
1240
- keyMetadata = parsedVault.keyMetadata;
1266
+ }, _KeyringController_updateCachedEncryptionKey = function _KeyringController_updateCachedEncryptionKey(encryptionKey) {
1267
+ if (!encryptionKey && this.state.encryptedEncryptionKey) {
1268
+ // If no encryption key is provided and we are in envelope encryption
1269
+ // mode, use the cached encryption key. This case occurs when we call
1270
+ // change password without providing a new encryption key.
1271
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, this.state.encryptionKey, "f");
1241
1272
  }
1242
1273
  else {
1243
- salt = __classPrivateFieldGet(this, _KeyringController_encryptor, "f").generateSalt();
1274
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, encryptionKey, "f");
1244
1275
  }
1245
- const exportedEncryptionKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").exportKey(await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").keyFromPassword(password, salt, true, keyMetadata));
1246
- __classPrivateFieldSet(this, _KeyringController_encryptionKey, {
1247
- salt,
1248
- exported: exportedEncryptionKey,
1249
- }, "f");
1250
- }, _KeyringController_useEncryptionKey = function _KeyringController_useEncryptionKey(encryptionKey, encryptionSalt) {
1251
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1252
- if (typeof encryptionKey !== 'string' ||
1253
- typeof encryptionSalt !== 'string') {
1254
- throw new TypeError(KeyringControllerError.WrongEncryptionKeyType);
1255
- }
1256
- __classPrivateFieldSet(this, _KeyringController_encryptionKey, {
1257
- salt: encryptionSalt,
1258
- exported: encryptionKey,
1259
- }, "f");
1260
1276
  }, _KeyringController_verifySeedPhrase =
1261
1277
  /**
1262
1278
  * Internal non-exclusive method to verify the seed phrase.
@@ -1345,6 +1361,7 @@ async function _KeyringController_getSerializedKeyrings({ includeUnsupported } =
1345
1361
  async function _KeyringController_getSessionState() {
1346
1362
  return {
1347
1363
  keyrings: await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this),
1364
+ password: __classPrivateFieldGet(this, _KeyringController_password, "f"),
1348
1365
  encryptionKey: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"),
1349
1366
  };
1350
1367
  }, _KeyringController_restoreSerializedKeyrings =
@@ -1374,28 +1391,63 @@ async function _KeyringController_restoreSerializedKeyrings(serializedKeyrings)
1374
1391
  * Unlock Keyrings, decrypting the vault and deserializing all
1375
1392
  * keyrings contained in it, using a password or an encryption key with salt.
1376
1393
  *
1377
- * @param credentials - The credentials to unlock the keyrings.
1394
+ * @param password - The keyring controller password.
1395
+ * @param encryptionKey - An exported key string to unlock keyrings with.
1396
+ * @param encryptionSalt - The salt used to encrypt the vault.
1378
1397
  * @returns A promise resolving to the deserialized keyrings array.
1379
1398
  */
1380
- async function _KeyringController_unlockKeyrings(credentials) {
1399
+ async function _KeyringController_unlockKeyrings(password, encryptionKey, encryptionSalt) {
1381
1400
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
1382
- if (!this.state.vault) {
1401
+ const { vault: encryptedVault, encryptedEncryptionKey } = this.state;
1402
+ if (!encryptedVault) {
1383
1403
  throw new Error(KeyringControllerError.VaultError);
1384
1404
  }
1385
- const parsedEncryptedVault = JSON.parse(this.state.vault);
1386
- if ('password' in credentials) {
1387
- await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, credentials.password);
1405
+ let vault;
1406
+ const updatedState = {};
1407
+ if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
1408
+ assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
1409
+ if (password) {
1410
+ if (encryptedEncryptionKey) {
1411
+ const decryptedEncryptionKey = (await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decrypt(password, encryptedEncryptionKey));
1412
+ const importedKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(decryptedEncryptionKey);
1413
+ vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(importedKey, encryptedVault);
1414
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1415
+ updatedState.encryptionKey = decryptedEncryptionKey;
1416
+ }
1417
+ else {
1418
+ const result = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithDetail(password, encryptedVault);
1419
+ vault = result.vault;
1420
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1421
+ updatedState.encryptionKey = result.exportedKeyString;
1422
+ updatedState.encryptionSalt = result.salt;
1423
+ }
1424
+ }
1425
+ else {
1426
+ const parsedEncryptedVault = JSON.parse(encryptedVault);
1427
+ if (encryptionSalt !== parsedEncryptedVault.salt) {
1428
+ throw new Error(KeyringControllerError.ExpiredCredentials);
1429
+ }
1430
+ if (typeof encryptionKey !== 'string') {
1431
+ throw new TypeError(KeyringControllerError.WrongPasswordType);
1432
+ }
1433
+ const importedKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1434
+ vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(importedKey, parsedEncryptedVault);
1435
+ // This call is required on the first call because encryptionKey
1436
+ // is not yet inside the memStore
1437
+ updatedState.encryptionKey = encryptionKey;
1438
+ // we can safely assume that encryptionSalt is defined here
1439
+ // because we compare it with the salt from the vault
1440
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1441
+ updatedState.encryptionSalt = encryptionSalt;
1442
+ }
1388
1443
  }
1389
1444
  else {
1390
- const { exportedEncryptionKey } = credentials;
1391
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_useEncryptionKey).call(this, exportedEncryptionKey, parsedEncryptedVault.salt);
1392
- }
1393
- const encryptionKey = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.exported;
1394
- if (!encryptionKey) {
1395
- throw new Error(KeyringControllerError.MissingCredentials);
1445
+ if (typeof password !== 'string') {
1446
+ throw new TypeError(KeyringControllerError.WrongPasswordType);
1447
+ }
1448
+ vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decrypt(password, encryptedVault);
1449
+ __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1396
1450
  }
1397
- const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1398
- const vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(key, parsedEncryptedVault);
1399
1451
  if (!isSerializedKeyringsArray(vault)) {
1400
1452
  throw new Error(KeyringControllerError.VaultDataError);
1401
1453
  }
@@ -1403,8 +1455,10 @@ async function _KeyringController_unlockKeyrings(credentials) {
1403
1455
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1404
1456
  this.update((state) => {
1405
1457
  state.keyrings = updatedKeyrings;
1406
- state.encryptionKey = encryptionKey;
1407
- state.encryptionSalt = parsedEncryptedVault.salt;
1458
+ if (updatedState.encryptionKey || updatedState.encryptionSalt) {
1459
+ state.encryptionKey = updatedState.encryptionKey;
1460
+ state.encryptionSalt = updatedState.encryptionSalt;
1461
+ }
1408
1462
  });
1409
1463
  return { keyrings, newMetadata };
1410
1464
  });
@@ -1412,41 +1466,84 @@ async function _KeyringController_unlockKeyrings(credentials) {
1412
1466
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
1413
1467
  // Ensure no duplicate accounts are persisted.
1414
1468
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertNoDuplicateAccounts).call(this);
1415
- if (!__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")) {
1469
+ const { encryptionKey, encryptionSalt, vault } = this.state;
1470
+ // READ THIS CAREFULLY:
1471
+ // We do check if the vault is still considered up-to-date, if not, we would not re-use the
1472
+ // cached key and we will re-generate a new one (based on the password).
1473
+ //
1474
+ // This helps doing seamless updates of the vault. Useful in case we change some cryptographic
1475
+ // parameters to the KDF.
1476
+ const useCachedKey = encryptionKey && vault && __classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated?.(vault);
1477
+ if (!__classPrivateFieldGet(this, _KeyringController_password, "f") && !encryptionKey) {
1416
1478
  throw new Error(KeyringControllerError.MissingCredentials);
1417
1479
  }
1418
1480
  const serializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1419
1481
  if (!serializedKeyrings.some((keyring) => keyring.type === KeyringTypes.hd)) {
1420
1482
  throw new Error(KeyringControllerError.NoHdKeyring);
1421
1483
  }
1422
- const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").exported);
1423
- const encryptedVault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(key, serializedKeyrings);
1424
- if (__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt) {
1425
- // We need to include the salt used to derive
1426
- // the encryption key, to be able to derive it
1427
- // from password again.
1428
- encryptedVault.salt = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt;
1484
+ const updatedState = {};
1485
+ if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
1486
+ assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
1487
+ if (useCachedKey) {
1488
+ const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1489
+ const vaultJSON = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(key, serializedKeyrings);
1490
+ vaultJSON.salt = encryptionSalt;
1491
+ updatedState.vault = JSON.stringify(vaultJSON);
1492
+ }
1493
+ else if (__classPrivateFieldGet(this, _KeyringController_password, "f")) {
1494
+ if (__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")) {
1495
+ // Update cached key.
1496
+ updatedState.encryptionKey = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f");
1497
+ // Encrypt key and update encrypted key.
1498
+ const encryptedEncryptionKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encrypt(__classPrivateFieldGet(this, _KeyringController_password, "f"), __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"));
1499
+ updatedState.encryptedEncryptionKey = encryptedEncryptionKey;
1500
+ // Encrypt and update vault.
1501
+ const importedKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"));
1502
+ const vaultJSON = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(importedKey, serializedKeyrings);
1503
+ // Note that we don't need to explicitly append the salt to the
1504
+ // vault here as it's already stored as part of the encrypted
1505
+ // encryption key.
1506
+ updatedState.vault = JSON.stringify(vaultJSON);
1507
+ }
1508
+ else {
1509
+ const { vault: newVault, exportedKeyString } = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithDetail(__classPrivateFieldGet(this, _KeyringController_password, "f"), serializedKeyrings);
1510
+ updatedState.vault = newVault;
1511
+ updatedState.encryptionKey = exportedKeyString;
1512
+ }
1513
+ }
1514
+ }
1515
+ else {
1516
+ assertIsValidPassword(__classPrivateFieldGet(this, _KeyringController_password, "f"));
1517
+ updatedState.vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encrypt(__classPrivateFieldGet(this, _KeyringController_password, "f"), serializedKeyrings);
1518
+ }
1519
+ if (__classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_isEnvelopeEncryptionEnabled).call(this)) {
1520
+ assertIsCacheEncryptionKeyTrue(__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f"));
1521
+ }
1522
+ if (!updatedState.vault) {
1523
+ throw new Error(KeyringControllerError.MissingVaultData);
1429
1524
  }
1430
- const updatedState = {
1431
- vault: JSON.stringify(encryptedVault),
1432
- encryptionKey: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").exported,
1433
- encryptionSalt: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt,
1434
- };
1435
1525
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1436
1526
  this.update((state) => {
1437
1527
  state.vault = updatedState.vault;
1438
1528
  state.keyrings = updatedKeyrings;
1439
- state.encryptionKey = updatedState.encryptionKey;
1440
- state.encryptionSalt = updatedState.encryptionSalt;
1529
+ if (updatedState.encryptionKey) {
1530
+ state.encryptionKey = updatedState.encryptionKey;
1531
+ state.encryptionSalt = JSON.parse(updatedState.vault).salt;
1532
+ }
1533
+ if (updatedState.encryptedEncryptionKey) {
1534
+ state.encryptedEncryptionKey = updatedState.encryptedEncryptionKey;
1535
+ }
1441
1536
  });
1442
1537
  return true;
1443
1538
  });
1444
1539
  }, _KeyringController_isNewEncryptionAvailable = function _KeyringController_isNewEncryptionAvailable() {
1445
1540
  const { vault } = this.state;
1446
- if (!vault || !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated) {
1541
+ if (!vault || !__classPrivateFieldGet(this, _KeyringController_password, "f") || !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated) {
1447
1542
  return false;
1448
1543
  }
1449
1544
  return !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated(vault);
1545
+ }, _KeyringController_isEnvelopeEncryptionEnabled = function _KeyringController_isEnvelopeEncryptionEnabled() {
1546
+ return this.state.encryptedEncryptionKey || __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f");
1450
1547
  }, _KeyringController_getAccountsFromKeyrings =
1451
1548
  /**
1452
1549
  * Retrieves all the accounts from keyrings instances
@@ -1531,7 +1628,8 @@ async function _KeyringController_createKeyring(type, data) {
1531
1628
  if (keyring.init) {
1532
1629
  await keyring.init();
1533
1630
  }
1534
- if (type === KeyringTypes.hd && (!isObject(data) || !data.mnemonic)) {
1631
+ if (type === KeyringTypes.hd &&
1632
+ (!isObject(data) || !data.mnemonic)) {
1535
1633
  if (!keyring.generateRandomMnemonic) {
1536
1634
  throw new Error(KeyringControllerError.UnsupportedGenerateRandomMnemonic);
1537
1635
  }
@@ -1653,11 +1751,16 @@ async function _KeyringController_assertNoDuplicateAccounts(additionalKeyrings =
1653
1751
  }
1654
1752
  }, _KeyringController_persistOrRollback =
1655
1753
  /**
1656
- * Execute the given function after acquiring the controller lock
1657
- * and save the vault to state after it (only if needed), or rollback to their
1658
- * previous state in case of error.
1754
+ * Execute the given function after acquiring the controller lock and save the
1755
+ * vault to state after it (only if needed), or rollback to their previous
1756
+ * state in case of error.
1757
+ *
1758
+ * ATTENTION: The callback must **not** alter `controller.state`. Any state
1759
+ * change performed by the callback will not be rolled back on error.
1659
1760
  *
1660
- * @param callback - The function to execute.
1761
+ * @param callback - The function to execute. This callback must **not** alter
1762
+ * `controller.state`. Any state change performed by the callback will not be
1763
+ * rolled back on error.
1661
1764
  * @returns The result of the function.
1662
1765
  */
1663
1766
  async function _KeyringController_persistOrRollback(callback) {
@@ -1682,16 +1785,15 @@ async function _KeyringController_persistOrRollback(callback) {
1682
1785
  async function _KeyringController_withRollback(callback) {
1683
1786
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async ({ releaseLock }) => {
1684
1787
  const currentSerializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1685
- const currentEncryptionKey = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.exported;
1686
- const currentEncryptionSalt = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.salt;
1788
+ const currentPassword = __classPrivateFieldGet(this, _KeyringController_password, "f");
1789
+ const currentEncryptionKey = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f");
1687
1790
  try {
1688
1791
  return await callback({ releaseLock });
1689
1792
  }
1690
1793
  catch (e) {
1691
- // Keyrings and encryption credentials are restored to their previous state
1692
- if (currentEncryptionKey && currentEncryptionSalt) {
1693
- __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_useEncryptionKey).call(this, currentEncryptionKey, currentEncryptionSalt);
1694
- }
1794
+ // Previous state is restored.
1795
+ __classPrivateFieldSet(this, _KeyringController_password, currentPassword, "f");
1796
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, currentEncryptionKey, "f");
1695
1797
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreSerializedKeyrings).call(this, currentSerializedKeyrings);
1696
1798
  throw e;
1697
1799
  }