@metamask-previews/keyring-controller 24.0.0-preview-684a40c0 → 24.0.0-preview-2e88eaea

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,26 @@ 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 `EncryptionKey` and `SupportedKeyDerivationOptions` type parameters to the `KeyringController`, `ExportableKeyEncryptor` and `KeyringControllerOptions` types ([#5963](https://github.com/MetaMask/core/pull/5963))
13
+ - This type parameter allows specifying the key derivation options supported by the injected encryptor, defaulting to `@metamask/browser-passworder` types.
14
+
15
+ ### Changed
16
+
17
+ - **BREAKING:** The `KeyringController` constructor options now require an encryptor ([#5963](https://github.com/MetaMask/core/pull/5963))
18
+ - The `encryptor` constructor option was previously optional and defaulted to an instance of `@metamask/browser-passworder`.
19
+ - **BREAKING:** The `GenericEncryptor` and `ExportableKeyEncryptor` types have been merged into a single `Encryptor` type ([#5963](https://github.com/MetaMask/core/pull/5963))
20
+
21
+ ### Removed
22
+
23
+ - **BREAKING:** The `cacheEncryptionKey` parameter has been removed from the `KeyringController` constructor options ([#5963](https://github.com/MetaMask/core/pull/5963))
24
+ - 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.
25
+
26
+ ### Fixed
27
+
28
+ - Fixed incorrect type for `decryptWithKey` method of `ExportableKeyEncryptor` ([#5963](https://github.com/MetaMask/core/pull/5963))
29
+
10
30
  ## [24.0.0]
11
31
 
12
32
  ### Changed
@@ -36,12 +36,11 @@ 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_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;
39
+ 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;
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");
43
43
  const base_controller_1 = require("@metamask/base-controller");
44
- const encryptorUtils = __importStar(require("@metamask/browser-passworder"));
45
44
  const eth_hd_keyring_1 = require("@metamask/eth-hd-keyring");
46
45
  const eth_sig_util_1 = require("@metamask/eth-sig-util");
47
46
  const eth_simple_keyring_1 = __importDefault(require("@metamask/eth-simple-keyring"));
@@ -136,23 +135,6 @@ function assertHasUint8ArrayMnemonic(keyring) {
136
135
  throw new Error("Can't get mnemonic bytes from keyring");
137
136
  }
138
137
  }
139
- /**
140
- * Assert that the provided encryptor supports
141
- * encryption and encryption key export.
142
- *
143
- * @param encryptor - The encryptor to check.
144
- * @throws If the encryptor does not support key encryption.
145
- */
146
- function assertIsExportableKeyEncryptor(encryptor) {
147
- if (!('importKey' in encryptor &&
148
- typeof encryptor.importKey === 'function' &&
149
- 'decryptWithKey' in encryptor &&
150
- typeof encryptor.decryptWithKey === 'function' &&
151
- 'encryptWithKey' in encryptor &&
152
- typeof encryptor.encryptWithKey === 'function')) {
153
- throw new Error(constants_1.KeyringControllerError.UnsupportedEncryptionKeyExport);
154
- }
155
- }
156
138
  /**
157
139
  * Assert that the provided password is a valid non-empty string.
158
140
  *
@@ -254,12 +236,11 @@ class KeyringController extends base_controller_1.BaseController {
254
236
  * @param options - Initial options used to configure this controller
255
237
  * @param options.encryptor - An optional object for defining encryption schemes.
256
238
  * @param options.keyringBuilders - Set a new name for account.
257
- * @param options.cacheEncryptionKey - Whether to cache or not encryption key.
258
239
  * @param options.messenger - A restricted messenger.
259
240
  * @param options.state - Initial state to set on this controller.
260
241
  */
261
242
  constructor(options) {
262
- const { encryptor = encryptorUtils, keyringBuilders, messenger, state, } = options;
243
+ const { encryptor, keyringBuilders, messenger, state } = options;
263
244
  super({
264
245
  name,
265
246
  metadata: {
@@ -305,22 +286,15 @@ class KeyringController extends base_controller_1.BaseController {
305
286
  _KeyringController_vaultOperationMutex.set(this, new async_mutex_1.Mutex());
306
287
  _KeyringController_keyringBuilders.set(this, void 0);
307
288
  _KeyringController_encryptor.set(this, void 0);
308
- _KeyringController_cacheEncryptionKey.set(this, void 0);
309
289
  _KeyringController_keyrings.set(this, void 0);
310
290
  _KeyringController_unsupportedKeyrings.set(this, void 0);
311
- _KeyringController_password.set(this, void 0);
291
+ _KeyringController_encryptionKey.set(this, void 0);
312
292
  __classPrivateFieldSet(this, _KeyringController_keyringBuilders, keyringBuilders
313
293
  ? keyringBuilders.concat(defaultKeyringBuilders)
314
294
  : defaultKeyringBuilders, "f");
315
295
  __classPrivateFieldSet(this, _KeyringController_encryptor, encryptor, "f");
316
296
  __classPrivateFieldSet(this, _KeyringController_keyrings, [], "f");
317
297
  __classPrivateFieldSet(this, _KeyringController_unsupportedKeyrings, [], "f");
318
- // This option allows the controller to cache an exported key
319
- // for use in decrypting and encrypting data without password
320
- __classPrivateFieldSet(this, _KeyringController_cacheEncryptionKey, Boolean(options.cacheEncryptionKey), "f");
321
- if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
322
- assertIsExportableKeyEncryptor(encryptor);
323
- }
324
298
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_registerMessageHandlers).call(this);
325
299
  }
326
300
  /**
@@ -691,7 +665,7 @@ class KeyringController extends base_controller_1.BaseController {
691
665
  async setLocked() {
692
666
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
693
667
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
694
- __classPrivateFieldSet(this, _KeyringController_password, undefined, "f");
668
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, undefined, "f");
695
669
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
696
670
  this.update((state) => {
697
671
  state.isUnlocked = false;
@@ -873,22 +847,11 @@ class KeyringController extends base_controller_1.BaseController {
873
847
  */
874
848
  changePassword(password) {
875
849
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
876
- // If the password is the same, do nothing.
877
- if (__classPrivateFieldGet(this, _KeyringController_password, "f") === password) {
878
- return Promise.resolve();
879
- }
880
850
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_persistOrRollback).call(this, async () => {
881
851
  assertIsValidPassword(password);
882
- __classPrivateFieldSet(this, _KeyringController_password, password, "f");
883
- // We need to clear encryption key and salt from state
884
- // to force the controller to re-encrypt the vault using
885
- // the new password.
886
- if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
887
- this.update((state) => {
888
- delete state.encryptionKey;
889
- delete state.encryptionSalt;
890
- });
891
- }
852
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password, {
853
+ useVaultKeyMetadata: false,
854
+ });
892
855
  });
893
856
  }
894
857
  /**
@@ -897,12 +860,15 @@ class KeyringController extends base_controller_1.BaseController {
897
860
  * consistency with the vault salt.
898
861
  *
899
862
  * @param encryptionKey - Key to unlock the keychain.
900
- * @param encryptionSalt - Optional salt to unlock the keychain.
863
+ * @param keyDerivationSalt - Optional salt to unlock the keychain.
901
864
  * @returns Promise resolving when the operation completes.
902
865
  */
903
- async submitEncryptionKey(encryptionKey, encryptionSalt) {
866
+ async submitEncryptionKey(encryptionKey, keyDerivationSalt) {
904
867
  const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
905
- const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, undefined, encryptionKey, encryptionSalt);
868
+ const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, {
869
+ encryptionKey,
870
+ keyDerivationSalt,
871
+ });
906
872
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
907
873
  return result;
908
874
  });
@@ -929,9 +895,8 @@ class KeyringController extends base_controller_1.BaseController {
929
895
  async exportEncryptionKey() {
930
896
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertIsUnlocked).call(this);
931
897
  return await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async () => {
932
- const { encryptionKey } = this.state;
933
- assertIsEncryptionKeySet(encryptionKey);
934
- return encryptionKey;
898
+ assertIsEncryptionKeySet(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.serialized);
899
+ return __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").serialized;
935
900
  });
936
901
  }
937
902
  /**
@@ -943,7 +908,7 @@ class KeyringController extends base_controller_1.BaseController {
943
908
  */
944
909
  async submitPassword(password) {
945
910
  const { newMetadata } = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
946
- const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, password);
911
+ const result = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_unlockKeyrings).call(this, { password });
947
912
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
948
913
  return result;
949
914
  });
@@ -953,6 +918,12 @@ class KeyringController extends base_controller_1.BaseController {
953
918
  // can attempt to upgrade the vault.
954
919
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withRollback).call(this, async () => {
955
920
  if (newMetadata || __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_isNewEncryptionAvailable).call(this)) {
921
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password, {
922
+ // If the vault is being upgraded, we want to ignore the metadata
923
+ // that is already in the vault, so we can effectively
924
+ // re-encrypt the vault with the new encryption config.
925
+ useVaultKeyMetadata: false,
926
+ });
956
927
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_updateVault).call(this);
957
928
  }
958
929
  });
@@ -1015,7 +986,7 @@ class KeyringController extends base_controller_1.BaseController {
1015
986
  }
1016
987
  }
1017
988
  exports.KeyringController = KeyringController;
1018
- _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() {
989
+ _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() {
1019
990
  this.messenger.registerActionHandler(`${name}:signMessage`, this.signMessage.bind(this));
1020
991
  this.messenger.registerActionHandler(`${name}:signEip7702Authorization`, this.signEip7702Authorization.bind(this));
1021
992
  this.messenger.registerActionHandler(`${name}:signPersonalMessage`, this.signPersonalMessage.bind(this));
@@ -1074,10 +1045,64 @@ async function _KeyringController_createNewVaultWithKeyring(password, keyring) {
1074
1045
  delete state.encryptionKey;
1075
1046
  delete state.encryptionSalt;
1076
1047
  });
1077
- __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1048
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, password);
1078
1049
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_clearKeyrings).call(this);
1079
1050
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_createKeyringWithFirstAccount).call(this, keyring.type, keyring.opts);
1080
1051
  __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setUnlocked).call(this);
1052
+ }, _KeyringController_deriveEncryptionKey =
1053
+ /**
1054
+ * Derive the vault encryption key from the provided password, and
1055
+ * assign it to the instance variable for later use with cryptographic
1056
+ * functions.
1057
+ *
1058
+ * When the controller has a vault in its state, the key is derived
1059
+ * using the salt from the vault. If the vault is empty, a new salt
1060
+ * is generated and used to derive the key.
1061
+ *
1062
+ * @param password - The password to use for decryption or derivation.
1063
+ * @param options - Options for the key derivation.
1064
+ * @param options.useVaultKeyMetadata - Whether to use the vault key metadata
1065
+ */
1066
+ async function _KeyringController_deriveEncryptionKey(password, options = {
1067
+ useVaultKeyMetadata: true,
1068
+ }) {
1069
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1070
+ const { vault } = this.state;
1071
+ if (typeof password !== 'string') {
1072
+ throw new TypeError(constants_1.KeyringControllerError.WrongPasswordType);
1073
+ }
1074
+ let serializedEncryptionKey, salt;
1075
+ if (vault && options.useVaultKeyMetadata) {
1076
+ // The `decryptWithDetail` method is being used here instead of
1077
+ // `keyFromPassword` + `exportKey` to let the encryptor handle
1078
+ // any legacy encryption formats and metadata that might be
1079
+ // present (or absent) in the vault.
1080
+ const { exportedKeyString, salt: existingSalt } = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithDetail(password, vault);
1081
+ serializedEncryptionKey = exportedKeyString;
1082
+ salt = existingSalt;
1083
+ }
1084
+ else {
1085
+ salt = __classPrivateFieldGet(this, _KeyringController_encryptor, "f").generateSalt();
1086
+ serializedEncryptionKey = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").exportKey(await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").keyFromPassword(password, salt, true));
1087
+ }
1088
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, {
1089
+ salt,
1090
+ serialized: serializedEncryptionKey,
1091
+ }, "f");
1092
+ }, _KeyringController_setEncryptionKey = function _KeyringController_setEncryptionKey(encryptionKey, keyDerivationSalt) {
1093
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertControllerMutexIsLocked).call(this);
1094
+ if (typeof encryptionKey !== 'string' ||
1095
+ typeof keyDerivationSalt !== 'string') {
1096
+ throw new TypeError(constants_1.KeyringControllerError.WrongEncryptionKeyType);
1097
+ }
1098
+ const { vault } = this.state;
1099
+ if (vault && JSON.parse(vault).salt !== keyDerivationSalt) {
1100
+ throw new Error(constants_1.KeyringControllerError.ExpiredCredentials);
1101
+ }
1102
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, {
1103
+ salt: keyDerivationSalt,
1104
+ serialized: encryptionKey,
1105
+ }, "f");
1081
1106
  }, _KeyringController_verifySeedPhrase =
1082
1107
  /**
1083
1108
  * Internal non-exclusive method to verify the seed phrase.
@@ -1158,7 +1183,7 @@ async function _KeyringController_getSerializedKeyrings({ includeUnsupported } =
1158
1183
  return serializedKeyrings;
1159
1184
  }, _KeyringController_getSessionState =
1160
1185
  /**
1161
- * Get a snapshot of session data held by class variables.
1186
+ * Get a snapshot of session data held by instance variables.
1162
1187
  *
1163
1188
  * @returns An object with serialized keyrings, keyrings metadata,
1164
1189
  * and the user password.
@@ -1166,7 +1191,7 @@ async function _KeyringController_getSerializedKeyrings({ includeUnsupported } =
1166
1191
  async function _KeyringController_getSessionState() {
1167
1192
  return {
1168
1193
  keyrings: await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this),
1169
- password: __classPrivateFieldGet(this, _KeyringController_password, "f"),
1194
+ encryptionKey: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"),
1170
1195
  };
1171
1196
  }, _KeyringController_restoreSerializedKeyrings =
1172
1197
  /**
@@ -1195,54 +1220,27 @@ async function _KeyringController_restoreSerializedKeyrings(serializedKeyrings)
1195
1220
  * Unlock Keyrings, decrypting the vault and deserializing all
1196
1221
  * keyrings contained in it, using a password or an encryption key with salt.
1197
1222
  *
1198
- * @param password - The keyring controller password.
1199
- * @param encryptionKey - An exported key string to unlock keyrings with.
1200
- * @param encryptionSalt - The salt used to encrypt the vault.
1223
+ * @param credentials - The credentials to unlock the keyrings.
1201
1224
  * @returns A promise resolving to the deserialized keyrings array.
1202
1225
  */
1203
- async function _KeyringController_unlockKeyrings(password, encryptionKey, encryptionSalt) {
1226
+ async function _KeyringController_unlockKeyrings(credentials) {
1204
1227
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
1205
- const encryptedVault = this.state.vault;
1206
- if (!encryptedVault) {
1228
+ if (!this.state.vault) {
1207
1229
  throw new Error(constants_1.KeyringControllerError.VaultError);
1208
1230
  }
1209
- let vault;
1210
- const updatedState = {};
1211
- if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
1212
- assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
1213
- if (password) {
1214
- const result = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithDetail(password, encryptedVault);
1215
- vault = result.vault;
1216
- __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1217
- updatedState.encryptionKey = result.exportedKeyString;
1218
- updatedState.encryptionSalt = result.salt;
1219
- }
1220
- else {
1221
- const parsedEncryptedVault = JSON.parse(encryptedVault);
1222
- if (encryptionSalt && encryptionSalt !== parsedEncryptedVault.salt) {
1223
- throw new Error(constants_1.KeyringControllerError.ExpiredCredentials);
1224
- }
1225
- else {
1226
- encryptionSalt = parsedEncryptedVault.salt;
1227
- }
1228
- if (typeof encryptionKey !== 'string') {
1229
- throw new TypeError(constants_1.KeyringControllerError.WrongPasswordType);
1230
- }
1231
- const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1232
- vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(key, parsedEncryptedVault);
1233
- // This call is required on the first call because encryptionKey
1234
- // is not yet inside the memStore
1235
- updatedState.encryptionKey = encryptionKey;
1236
- updatedState.encryptionSalt = encryptionSalt;
1237
- }
1231
+ const parsedEncryptedVault = JSON.parse(this.state.vault);
1232
+ if ('password' in credentials) {
1233
+ await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_deriveEncryptionKey).call(this, credentials.password);
1238
1234
  }
1239
1235
  else {
1240
- if (typeof password !== 'string') {
1241
- throw new TypeError(constants_1.KeyringControllerError.WrongPasswordType);
1242
- }
1243
- vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decrypt(password, encryptedVault);
1244
- __classPrivateFieldSet(this, _KeyringController_password, password, "f");
1236
+ __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_setEncryptionKey).call(this, credentials.encryptionKey, credentials.keyDerivationSalt || parsedEncryptedVault.salt);
1245
1237
  }
1238
+ const encryptionKey = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")?.serialized;
1239
+ if (!encryptionKey) {
1240
+ throw new Error(constants_1.KeyringControllerError.MissingCredentials);
1241
+ }
1242
+ const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1243
+ const vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").decryptWithKey(key, parsedEncryptedVault);
1246
1244
  if (!isSerializedKeyringsArray(vault)) {
1247
1245
  throw new Error(constants_1.KeyringControllerError.VaultDataError);
1248
1246
  }
@@ -1250,10 +1248,8 @@ async function _KeyringController_unlockKeyrings(password, encryptionKey, encryp
1250
1248
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1251
1249
  this.update((state) => {
1252
1250
  state.keyrings = updatedKeyrings;
1253
- if (updatedState.encryptionKey || updatedState.encryptionSalt) {
1254
- state.encryptionKey = updatedState.encryptionKey;
1255
- state.encryptionSalt = updatedState.encryptionSalt;
1256
- }
1251
+ state.encryptionKey = encryptionKey;
1252
+ state.encryptionSalt = parsedEncryptedVault.salt;
1257
1253
  });
1258
1254
  return { keyrings, newMetadata };
1259
1255
  });
@@ -1261,57 +1257,36 @@ async function _KeyringController_unlockKeyrings(password, encryptionKey, encryp
1261
1257
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withVaultLock).call(this, async () => {
1262
1258
  // Ensure no duplicate accounts are persisted.
1263
1259
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_assertNoDuplicateAccounts).call(this);
1264
- const { encryptionKey, encryptionSalt, vault } = this.state;
1265
- // READ THIS CAREFULLY:
1266
- // We do check if the vault is still considered up-to-date, if not, we would not re-use the
1267
- // cached key and we will re-generate a new one (based on the password).
1268
- //
1269
- // This helps doing seamless updates of the vault. Useful in case we change some cryptographic
1270
- // parameters to the KDF.
1271
- const useCachedKey = encryptionKey && vault && __classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated?.(vault);
1272
- if (!__classPrivateFieldGet(this, _KeyringController_password, "f") && !encryptionKey) {
1260
+ if (!__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f")) {
1273
1261
  throw new Error(constants_1.KeyringControllerError.MissingCredentials);
1274
1262
  }
1275
1263
  const serializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1276
1264
  if (!serializedKeyrings.some((keyring) => keyring.type === KeyringTypes.hd)) {
1277
1265
  throw new Error(constants_1.KeyringControllerError.NoHdKeyring);
1278
1266
  }
1279
- const updatedState = {};
1280
- if (__classPrivateFieldGet(this, _KeyringController_cacheEncryptionKey, "f")) {
1281
- assertIsExportableKeyEncryptor(__classPrivateFieldGet(this, _KeyringController_encryptor, "f"));
1282
- if (useCachedKey) {
1283
- const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(encryptionKey);
1284
- const vaultJSON = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(key, serializedKeyrings);
1285
- vaultJSON.salt = encryptionSalt;
1286
- updatedState.vault = JSON.stringify(vaultJSON);
1287
- }
1288
- else if (__classPrivateFieldGet(this, _KeyringController_password, "f")) {
1289
- const { vault: newVault, exportedKeyString } = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithDetail(__classPrivateFieldGet(this, _KeyringController_password, "f"), serializedKeyrings);
1290
- updatedState.vault = newVault;
1291
- updatedState.encryptionKey = exportedKeyString;
1292
- }
1293
- }
1294
- else {
1295
- assertIsValidPassword(__classPrivateFieldGet(this, _KeyringController_password, "f"));
1296
- updatedState.vault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encrypt(__classPrivateFieldGet(this, _KeyringController_password, "f"), serializedKeyrings);
1297
- }
1298
- if (!updatedState.vault) {
1299
- throw new Error(constants_1.KeyringControllerError.MissingVaultData);
1300
- }
1267
+ const key = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").importKey(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").serialized);
1268
+ const encryptedVault = await __classPrivateFieldGet(this, _KeyringController_encryptor, "f").encryptWithKey(key, serializedKeyrings);
1269
+ // We need to include the salt used to derive
1270
+ // the encryption key, to be able to derive it
1271
+ // from password again.
1272
+ encryptedVault.salt = __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt;
1273
+ const updatedState = {
1274
+ vault: JSON.stringify(encryptedVault),
1275
+ encryptionKey: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").serialized,
1276
+ encryptionSalt: __classPrivateFieldGet(this, _KeyringController_encryptionKey, "f").salt,
1277
+ };
1301
1278
  const updatedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getUpdatedKeyrings).call(this);
1302
1279
  this.update((state) => {
1303
1280
  state.vault = updatedState.vault;
1304
1281
  state.keyrings = updatedKeyrings;
1305
- if (updatedState.encryptionKey) {
1306
- state.encryptionKey = updatedState.encryptionKey;
1307
- state.encryptionSalt = JSON.parse(updatedState.vault).salt;
1308
- }
1282
+ state.encryptionKey = updatedState.encryptionKey;
1283
+ state.encryptionSalt = updatedState.encryptionSalt;
1309
1284
  });
1310
1285
  return true;
1311
1286
  });
1312
1287
  }, _KeyringController_isNewEncryptionAvailable = function _KeyringController_isNewEncryptionAvailable() {
1313
1288
  const { vault } = this.state;
1314
- if (!vault || !__classPrivateFieldGet(this, _KeyringController_password, "f") || !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated) {
1289
+ if (!vault || !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated) {
1315
1290
  return false;
1316
1291
  }
1317
1292
  return !__classPrivateFieldGet(this, _KeyringController_encryptor, "f").isVaultUpdated(vault);
@@ -1545,13 +1520,13 @@ async function _KeyringController_persistOrRollback(callback) {
1545
1520
  async function _KeyringController_withRollback(callback) {
1546
1521
  return __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_withControllerLock).call(this, async ({ releaseLock }) => {
1547
1522
  const currentSerializedKeyrings = await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_getSerializedKeyrings).call(this);
1548
- const currentPassword = __classPrivateFieldGet(this, _KeyringController_password, "f");
1523
+ const currentEncryptionKey = (0, lodash_1.cloneDeep)(__classPrivateFieldGet(this, _KeyringController_encryptionKey, "f"));
1549
1524
  try {
1550
1525
  return await callback({ releaseLock });
1551
1526
  }
1552
1527
  catch (e) {
1553
- // Keyrings and password are restored to their previous state
1554
- __classPrivateFieldSet(this, _KeyringController_password, currentPassword, "f");
1528
+ // Keyrings and encryption credentials are restored to their previous state
1529
+ __classPrivateFieldSet(this, _KeyringController_encryptionKey, currentEncryptionKey, "f");
1555
1530
  await __classPrivateFieldGet(this, _KeyringController_instances, "m", _KeyringController_restoreSerializedKeyrings).call(this, currentSerializedKeyrings);
1556
1531
  throw e;
1557
1532
  }