@metamask-previews/keyring-controller 24.0.0-preview-e983f054 → 24.0.0-preview-e958bbad

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_cacheEncryptionKey, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_password, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _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;
12
+ var _KeyringController_instances, _KeyringController_controllerOperationMutex, _KeyringController_vaultOperationMutex, _KeyringController_keyringBuilders, _KeyringController_encryptor, _KeyringController_keyrings, _KeyringController_unsupportedKeyrings, _KeyringController_encryptionKey, _KeyringController_registerMessageHandlers, _KeyringController_getKeyringById, _KeyringController_getKeyringByIdOrDefault, _KeyringController_getKeyringMetadata, _KeyringController_getKeyringBuilderForType, _KeyringController_createNewVaultWithKeyring, _KeyringController_deriveEncryptionKey, _KeyringController_setEncryptionKey, _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;
13
13
  function $importDefault(module) {
14
14
  if (module?.__esModule) {
15
15
  return module.default;
@@ -18,7 +18,6 @@ function $importDefault(module) {
18
18
  }
19
19
  import { isValidPrivate, getBinarySize } from "@ethereumjs/util";
20
20
  import { BaseController } from "@metamask/base-controller";
21
- import * as encryptorUtils from "@metamask/browser-passworder";
22
21
  import { HdKeyring } from "@metamask/eth-hd-keyring";
23
22
  import { normalize as ethNormalize } from "@metamask/eth-sig-util";
24
23
  import SimpleKeyring from "@metamask/eth-simple-keyring";
@@ -28,7 +27,7 @@ import $Wallet from "ethereumjs-wallet";
28
27
  const { thirdparty: importers } = $Wallet;
29
28
  const Wallet = $importDefault($Wallet);
30
29
  import $lodash from "lodash";
31
- const { isEqual } = $lodash;
30
+ const { cloneDeep, isEqual } = $lodash;
32
31
  // When generating a ULID within the same millisecond, monotonicFactory provides some guarantees regarding sort order.
33
32
  import { ulid } from "ulid";
34
33
  import { KeyringControllerError } from "./constants.mjs";
@@ -113,23 +112,6 @@ function assertHasUint8ArrayMnemonic(keyring) {
113
112
  throw new Error("Can't get mnemonic bytes from keyring");
114
113
  }
115
114
  }
116
- /**
117
- * Assert that the provided encryptor supports
118
- * encryption and encryption key export.
119
- *
120
- * @param encryptor - The encryptor to check.
121
- * @throws If the encryptor does not support key encryption.
122
- */
123
- function assertIsExportableKeyEncryptor(encryptor) {
124
- if (!('importKey' in encryptor &&
125
- typeof encryptor.importKey === 'function' &&
126
- 'decryptWithKey' in encryptor &&
127
- typeof encryptor.decryptWithKey === 'function' &&
128
- 'encryptWithKey' in encryptor &&
129
- typeof encryptor.encryptWithKey === 'function')) {
130
- throw new Error(KeyringControllerError.UnsupportedEncryptionKeyExport);
131
- }
132
- }
133
115
  /**
134
116
  * Assert that the provided password is a valid non-empty string.
135
117
  *
@@ -231,12 +213,11 @@ export class KeyringController extends BaseController {
231
213
  * @param options - Initial options used to configure this controller
232
214
  * @param options.encryptor - An optional object for defining encryption schemes.
233
215
  * @param options.keyringBuilders - Set a new name for account.
234
- * @param options.cacheEncryptionKey - Whether to cache or not encryption key.
235
216
  * @param options.messenger - A restricted messenger.
236
217
  * @param options.state - Initial state to set on this controller.
237
218
  */
238
219
  constructor(options) {
239
- const { encryptor = encryptorUtils, keyringBuilders, messenger, state, } = options;
220
+ const { encryptor, keyringBuilders, messenger, state } = options;
240
221
  super({
241
222
  name,
242
223
  metadata: {
@@ -282,22 +263,15 @@ export class KeyringController extends BaseController {
282
263
  _KeyringController_vaultOperationMutex.set(this, new Mutex());
283
264
  _KeyringController_keyringBuilders.set(this, void 0);
284
265
  _KeyringController_encryptor.set(this, void 0);
285
- _KeyringController_cacheEncryptionKey.set(this, void 0);
286
266
  _KeyringController_keyrings.set(this, void 0);
287
267
  _KeyringController_unsupportedKeyrings.set(this, void 0);
288
- _KeyringController_password.set(this, void 0);
268
+ _KeyringController_encryptionKey.set(this, void 0);
289
269
  __classPrivateFieldSet(this, _KeyringController_keyringBuilders, keyringBuilders
290
270
  ? keyringBuilders.concat(defaultKeyringBuilders)
291
271
  : defaultKeyringBuilders, "f");
292
272
  __classPrivateFieldSet(this, _KeyringController_encryptor, encryptor, "f");
293
273
  __classPrivateFieldSet(this, _KeyringController_keyrings, [], "f");
294
274
  __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
- }
301
275
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_registerMessageHandlers).call(this);
302
276
  }
303
277
  /**
@@ -668,7 +642,7 @@ export class KeyringController extends BaseController {
668
642
  async setLocked() {
669
643
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
670
644
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
671
- __classPrivateFieldSet(this, _KeyringController_password, undefined, "f");
645
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, undefined, "f");
672
646
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
673
647
  this.update((state) => {
674
648
  state.isUnlocked = false;
@@ -850,22 +824,11 @@ export class KeyringController extends BaseController {
850
824
  */
851
825
  changePassword(password) {
852
826
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
853
- // If the password is the same, do nothing.
854
- if (__classPrivateFieldGet(this, _KeyringController_password, "f") === password) {
855
- return Promise.resolve();
856
- }
857
827
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
858
828
  assertIsValidPassword(password);
859
- __classPrivateFieldSet(this, _KeyringController_password, password, "f");
860
- // We need to clear encryption key and salt from state
861
- // to force the controller to re-encrypt the vault using
862
- // the new password.
863
- if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
864
- this.update((state) => {
865
- delete state.encryptionKey;
866
- delete state.encryptionSalt;
867
- });
868
- }
829
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password, {
830
+ ignoreExistingVault: true,
831
+ });
869
832
  });
870
833
  }
871
834
  /**
@@ -874,12 +837,15 @@ export class KeyringController extends BaseController {
874
837
  * consistency with the vault salt.
875
838
  *
876
839
  * @param encryptionKey - Key to unlock the keychain.
877
- * @param encryptionSalt - Optional salt to unlock the keychain.
840
+ * @param keyDerivationSalt - Optional salt to unlock the keychain.
878
841
  * @returns Promise resolving when the operation completes.
879
842
  */
880
- async submitEncryptionKey(encryptionKey, encryptionSalt) {
843
+ async submitEncryptionKey(encryptionKey, keyDerivationSalt) {
881
844
  const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
882
- const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, undefined, encryptionKey, encryptionSalt);
845
+ const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, {
846
+ encryptionKey,
847
+ keyDerivationSalt,
848
+ });
883
849
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
884
850
  return result;
885
851
  });
@@ -906,9 +872,8 @@ export class KeyringController extends BaseController {
906
872
  async exportEncryptionKey() {
907
873
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
908
874
  return await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async () => {
909
- const { encryptionKey } = this.state;
910
- assertIsEncryptionKeySet(encryptionKey);
911
- return encryptionKey;
875
+ assertIsEncryptionKeySet(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.serialized);
876
+ return __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").serialized;
912
877
  });
913
878
  }
914
879
  /**
@@ -920,7 +885,7 @@ export class KeyringController extends BaseController {
920
885
  */
921
886
  async submitPassword(password) {
922
887
  const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
923
- const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, password);
888
+ const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, { password });
924
889
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
925
890
  return result;
926
891
  });
@@ -930,6 +895,12 @@ export class KeyringController extends BaseController {
930
895
  // can attempt to upgrade the vault.
931
896
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
932
897
  if (newMetadata || __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_isNewEncryptionAvailable).call(this)) {
898
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password, {
899
+ // If the vault is being upgraded, we want to ignore the metadata
900
+ // that is already in the vault, so we can effectively
901
+ // re-encrypt the vault with the new encryption config.
902
+ ignoreExistingVault: true,
903
+ });
933
904
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateVault).call(this);
934
905
  }
935
906
  });
@@ -991,7 +962,7 @@ export class KeyringController extends BaseController {
991
962
  return keyring.type;
992
963
  }
993
964
  }
994
- _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_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
965
+ _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_instances = new WeakSet(), _KeyringController_registerMessageHandlers = function _KeyringController_registerMessageHandlers() {
995
966
  this.messenger.registerActionHandler(`${name}:signMessage`, this.signMessage.bind(this));
996
967
  this.messenger.registerActionHandler(`${name}:signEip7702Authorization`, this.signEip7702Authorization.bind(this));
997
968
  this.messenger.registerActionHandler(`${name}:signPersonalMessage`, this.signPersonalMessage.bind(this));
@@ -1050,10 +1021,70 @@ async function _KeyringController_createNewVaultWithKeyring(password, keyring) {
1050
1021
  delete state.encryptionKey;
1051
1022
  delete state.encryptionSalt;
1052
1023
  });
1053
- __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1024
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password, {
1025
+ ignoreExistingVault: true,
1026
+ });
1054
1027
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
1055
1028
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyringWithFirstAccount).call(this, keyring.type, keyring.opts);
1056
1029
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
1030
+ }, _KeyringController_deriveEncryptionKey =
1031
+ /**
1032
+ * Derive the vault encryption key from the provided password, and
1033
+ * assign it to the instance variable for later use with cryptographic
1034
+ * functions.
1035
+ *
1036
+ * When the controller has a vault in its state, the key is derived
1037
+ * using the salt from the vault. If the vault is empty, a new salt
1038
+ * is generated and used to derive the key.
1039
+ *
1040
+ * If `options.ignoreExistingVault` is set to `false`, the existing
1041
+ * vault is completely ignored: the new key won't be able to decrypt
1042
+ * the existing vault, and should be used to re-encrypt it.
1043
+ *
1044
+ * @param password - The password to use for decryption or derivation.
1045
+ * @param options - Options for the key derivation.
1046
+ * @param options.ignoreExistingVault - Whether to use the existing vault salt and key metadata
1047
+ */
1048
+ async function _KeyringController_deriveEncryptionKey(password, options = {
1049
+ ignoreExistingVault: false,
1050
+ }) {
1051
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1052
+ const { vault } = this.state;
1053
+ if (typeof password !== 'string') {
1054
+ throw new TypeError(KeyringControllerError.WrongPasswordType);
1055
+ }
1056
+ let serializedEncryptionKey, salt;
1057
+ if (vault && !options.ignoreExistingVault) {
1058
+ // The `decryptWithDetail` method is being used here instead of
1059
+ // `keyFromPassword` + `exportKey` to let the encryptor handle
1060
+ // any legacy encryption formats and metadata that might be
1061
+ // present (or absent) in the vault.
1062
+ const { exportedKeyString, salt: existingSalt } = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithDetail(password, vault);
1063
+ serializedEncryptionKey = exportedKeyString;
1064
+ salt = existingSalt;
1065
+ }
1066
+ else {
1067
+ salt = __classPrivateFieldGet(this, _KeyringController_encryptor, "f").generateSalt();
1068
+ serializedEncryptionKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").exportKey(await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").keyFromPassword(password, salt, true));
1069
+ }
1070
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, {
1071
+ salt,
1072
+ serialized: serializedEncryptionKey,
1073
+ }, "f");
1074
+ }, _KeyringController_setEncryptionKey = function _KeyringController_setEncryptionKey(encryptionKey, keyDerivationSalt) {
1075
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1076
+ if (typeof encryptionKey !== 'string' ||
1077
+ typeof keyDerivationSalt !== 'string') {
1078
+ throw new TypeError(KeyringControllerError.WrongEncryptionKeyType);
1079
+ }
1080
+ const { vault } = this.state;
1081
+ if (vault && JSON.parse(vault).salt !== keyDerivationSalt) {
1082
+ throw new Error(KeyringControllerError.ExpiredCredentials);
1083
+ }
1084
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, {
1085
+ salt: keyDerivationSalt,
1086
+ serialized: encryptionKey,
1087
+ }, "f");
1057
1088
  }, _KeyringController_verifySeedPhrase =
1058
1089
  /**
1059
1090
  * Internal non-exclusive method to verify the seed phrase.
@@ -1134,7 +1165,7 @@ async function _KeyringController_getSerializedKeyrings({ includeUnsupported } =
1134
1165
  return serializedKeyrings;
1135
1166
  }, _KeyringController_getSessionState =
1136
1167
  /**
1137
- * Get a snapshot of session data held by class variables.
1168
+ * Get a snapshot of session data held by instance variables.
1138
1169
  *
1139
1170
  * @returns An object with serialized keyrings, keyrings metadata,
1140
1171
  * and the user password.
@@ -1142,7 +1173,7 @@ async function _KeyringController_getSerializedKeyrings({ includeUnsupported } =
1142
1173
  async function _KeyringController_getSessionState() {
1143
1174
  return {
1144
1175
  keyrings: await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this),
1145
- password: __classPrivateFieldGet(this, _KeyringController_password, "f"),
1176
+ encryptionKey: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"),
1146
1177
  };
1147
1178
  }, _KeyringController_restoreSerializedKeyrings =
1148
1179
  /**
@@ -1171,54 +1202,27 @@ async function _KeyringController_restoreSerializedKeyrings(serializedKeyrings)
1171
1202
  * Unlock Keyrings, decrypting the vault and deserializing all
1172
1203
  * keyrings contained in it, using a password or an encryption key with salt.
1173
1204
  *
1174
- * @param password - The keyring controller password.
1175
- * @param encryptionKey - An exported key string to unlock keyrings with.
1176
- * @param encryptionSalt - The salt used to encrypt the vault.
1205
+ * @param credentials - The credentials to unlock the keyrings.
1177
1206
  * @returns A promise resolving to the deserialized keyrings array.
1178
1207
  */
1179
- async function _KeyringController_unlockKeyrings(password, encryptionKey, encryptionSalt) {
1208
+ async function _KeyringController_unlockKeyrings(credentials) {
1180
1209
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
1181
- const encryptedVault = this.state.vault;
1182
- if (!encryptedVault) {
1210
+ if (!this.state.vault) {
1183
1211
  throw new Error(KeyringControllerError.VaultError);
1184
1212
  }
1185
- let vault;
1186
- const updatedState = {};
1187
- if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
1188
- assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
1189
- if (password) {
1190
- const result = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithDetail(password, encryptedVault);
1191
- vault = result.vault;
1192
- __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1193
- updatedState.encryptionKey = result.exportedKeyString;
1194
- updatedState.encryptionSalt = result.salt;
1195
- }
1196
- else {
1197
- const parsedEncryptedVault = JSON.parse(encryptedVault);
1198
- if (encryptionSalt && encryptionSalt !== parsedEncryptedVault.salt) {
1199
- throw new Error(KeyringControllerError.ExpiredCredentials);
1200
- }
1201
- else {
1202
- encryptionSalt = parsedEncryptedVault.salt;
1203
- }
1204
- if (typeof encryptionKey !== 'string') {
1205
- throw new TypeError(KeyringControllerError.WrongPasswordType);
1206
- }
1207
- const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1208
- vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(key, parsedEncryptedVault);
1209
- // This call is required on the first call because encryptionKey
1210
- // is not yet inside the memStore
1211
- updatedState.encryptionKey = encryptionKey;
1212
- updatedState.encryptionSalt = encryptionSalt;
1213
- }
1213
+ const parsedEncryptedVault = JSON.parse(this.state.vault);
1214
+ if ('password' in credentials) {
1215
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, credentials.password);
1214
1216
  }
1215
1217
  else {
1216
- if (typeof password !== 'string') {
1217
- throw new TypeError(KeyringControllerError.WrongPasswordType);
1218
- }
1219
- vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decrypt(password, encryptedVault);
1220
- __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1218
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setEncryptionKey).call(this, credentials.encryptionKey, credentials.keyDerivationSalt || parsedEncryptedVault.salt);
1221
1219
  }
1220
+ const encryptionKey = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.serialized;
1221
+ if (!encryptionKey) {
1222
+ throw new Error(KeyringControllerError.MissingCredentials);
1223
+ }
1224
+ const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1225
+ const vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(key, parsedEncryptedVault);
1222
1226
  if (!isSerializedKeyringsArray(vault)) {
1223
1227
  throw new Error(KeyringControllerError.VaultDataError);
1224
1228
  }
@@ -1226,10 +1230,8 @@ async function _KeyringController_unlockKeyrings(password, encryptionKey, encryp
1226
1230
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1227
1231
  this.update((state) => {
1228
1232
  state.keyrings = updatedKeyrings;
1229
- if (updatedState.encryptionKey || updatedState.encryptionSalt) {
1230
- state.encryptionKey = updatedState.encryptionKey;
1231
- state.encryptionSalt = updatedState.encryptionSalt;
1232
- }
1233
+ state.encryptionKey = encryptionKey;
1234
+ state.encryptionSalt = parsedEncryptedVault.salt;
1233
1235
  });
1234
1236
  return { keyrings, newMetadata };
1235
1237
  });
@@ -1237,57 +1239,36 @@ async function _KeyringController_unlockKeyrings(password, encryptionKey, encryp
1237
1239
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
1238
1240
  // Ensure no duplicate accounts are persisted.
1239
1241
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertNoDuplicateAccounts).call(this);
1240
- const { encryptionKey, encryptionSalt, vault } = this.state;
1241
- // READ THIS CAREFULLY:
1242
- // We do check if the vault is still considered up-to-date, if not, we would not re-use the
1243
- // cached key and we will re-generate a new one (based on the password).
1244
- //
1245
- // This helps doing seamless updates of the vault. Useful in case we change some cryptographic
1246
- // parameters to the KDF.
1247
- const useCachedKey = encryptionKey && vault && __classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated?.(vault);
1248
- if (!__classPrivateFieldGet(this, _KeyringController_password, "f") && !encryptionKey) {
1242
+ if (!__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")) {
1249
1243
  throw new Error(KeyringControllerError.MissingCredentials);
1250
1244
  }
1251
1245
  const serializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1252
1246
  if (!serializedKeyrings.some((keyring) => keyring.type === KeyringTypes.hd)) {
1253
1247
  throw new Error(KeyringControllerError.NoHdKeyring);
1254
1248
  }
1255
- const updatedState = {};
1256
- if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
1257
- assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
1258
- if (useCachedKey) {
1259
- const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1260
- const vaultJSON = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(key, serializedKeyrings);
1261
- vaultJSON.salt = encryptionSalt;
1262
- updatedState.vault = JSON.stringify(vaultJSON);
1263
- }
1264
- else if (__classPrivateFieldGet(this, _KeyringController_password, "f")) {
1265
- const { vault: newVault, exportedKeyString } = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithDetail(__classPrivateFieldGet(this, _KeyringController_password, "f"), serializedKeyrings);
1266
- updatedState.vault = newVault;
1267
- updatedState.encryptionKey = exportedKeyString;
1268
- }
1269
- }
1270
- else {
1271
- assertIsValidPassword(__classPrivateFieldGet(this, _KeyringController_password, "f"));
1272
- updatedState.vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encrypt(__classPrivateFieldGet(this, _KeyringController_password, "f"), serializedKeyrings);
1273
- }
1274
- if (!updatedState.vault) {
1275
- throw new Error(KeyringControllerError.MissingVaultData);
1276
- }
1249
+ const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").serialized);
1250
+ const encryptedVault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(key, serializedKeyrings);
1251
+ // We need to include the salt used to derive
1252
+ // the encryption key, to be able to derive it
1253
+ // from password again.
1254
+ encryptedVault.salt = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt;
1255
+ const updatedState = {
1256
+ vault: JSON.stringify(encryptedVault),
1257
+ encryptionKey: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").serialized,
1258
+ encryptionSalt: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt,
1259
+ };
1277
1260
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1278
1261
  this.update((state) => {
1279
1262
  state.vault = updatedState.vault;
1280
1263
  state.keyrings = updatedKeyrings;
1281
- if (updatedState.encryptionKey) {
1282
- state.encryptionKey = updatedState.encryptionKey;
1283
- state.encryptionSalt = JSON.parse(updatedState.vault).salt;
1284
- }
1264
+ state.encryptionKey = updatedState.encryptionKey;
1265
+ state.encryptionSalt = updatedState.encryptionSalt;
1285
1266
  });
1286
1267
  return true;
1287
1268
  });
1288
1269
  }, _KeyringController_isNewEncryptionAvailable = function _KeyringController_isNewEncryptionAvailable() {
1289
1270
  const { vault } = this.state;
1290
- if (!vault || !__classPrivateFieldGet(this, _KeyringController_password, "f") || !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated) {
1271
+ if (!vault || !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated) {
1291
1272
  return false;
1292
1273
  }
1293
1274
  return !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated(vault);
@@ -1521,13 +1502,13 @@ async function _KeyringController_persistOrRollback(callback) {
1521
1502
  async function _KeyringController_withRollback(callback) {
1522
1503
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async ({ releaseLock }) => {
1523
1504
  const currentSerializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1524
- const currentPassword = __classPrivateFieldGet(this, _KeyringController_password, "f");
1505
+ const currentEncryptionKey = cloneDeep(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"));
1525
1506
  try {
1526
1507
  return await callback({ releaseLock });
1527
1508
  }
1528
1509
  catch (e) {
1529
- // Keyrings and password are restored to their previous state
1530
- __classPrivateFieldSet(this, _KeyringController_password, currentPassword, "f");
1510
+ // Keyrings and encryption credentials are restored to their previous state
1511
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, currentEncryptionKey, "f");
1531
1512
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreSerializedKeyrings).call(this, currentSerializedKeyrings);
1532
1513
  throw e;
1533
1514
  }