Skip to content

Commit 7c89a87

Browse files
test(KeyringController): mock encryptor upgrade (#5943)
## Explanation For testing envelope encryption (#5940), we need a more versatile mock encryptor. (I.e., one that can handle multiple ciphertexts at the same time.) Hence, here we upgrade the mock encryptor as a preparation for #5490. ## References <!-- Are there any issues that this pull request is tied to? Are there other links that reviewers should consult to understand these changes better? Are there client or consumer pull requests to adopt any breaking changes? For example: * Fixes #12345 * Related to #67890 --> ## Changelog <!-- THIS SECTION IS NO LONGER NEEDED. The process for updating changelogs has changed. Please consult the "Updating changelogs" section of the Contributing doc for more. --> ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs), highlighting breaking changes as necessary - [x] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes
1 parent bc8c0dd commit 7c89a87

File tree

2 files changed

+166
-110
lines changed

2 files changed

+166
-110
lines changed

packages/keyring-controller/src/KeyringController.test.ts

Lines changed: 80 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ import {
3737
keyringBuilderFactory,
3838
} from './KeyringController';
3939
import MockEncryptor, {
40+
DECRYPTION_ERROR,
4041
MOCK_ENCRYPTION_KEY,
42+
SALT,
4143
} from '../tests/mocks/mockEncryptor';
4244
import { MockErc4337Keyring } from '../tests/mocks/mockErc4337Keyring';
4345
import { MockKeyring } from '../tests/mocks/mockKeyring';
@@ -67,6 +69,8 @@ const uint8ArraySeed = new Uint8Array(
6769
const privateKey =
6870
'1e4e6a4c0c077f4ae8ddfbf372918e61dd0fb4a4cfa592cb16e7546d505e68fc';
6971
const password = 'password123';
72+
const freshVault =
73+
'{"data":"{\\"tag\\":{\\"key\\":{\\"password\\":\\"password123\\",\\"salt\\":\\"salt\\"},\\"iv\\":\\"iv\\"},\\"value\\":[{\\"type\\":\\"HD Key Tree\\",\\"data\\":{\\"mnemonic\\":[119,97,114,114,105,111,114,32,108,97,110,103,117,97,103,101,32,106,111,107,101,32,98,111,110,117,115,32,117,110,102,97,105,114,32,97,114,116,105,115,116,32,107,97,110,103,97,114,111,111,32,99,105,114,99,108,101,32,101,120,112,97,110,100,32,104,111,112,101,32,109,105,100,100,108,101,32,103,97,117,103,101],\\"numberOfAccounts\\":1,\\"hdPath\\":\\"m/44\'/60\'/0\'/0\\"},\\"metadata\\":{\\"id\\":\\"01JXEFM7DAX2VJ0YFR4ESNY3GQ\\",\\"name\\":\\"\\"}}]}","iv":"iv","salt":"salt"}';
7074

7175
const commonConfig = { chain: Chain.Goerli, hardfork: Hardfork.Berlin };
7276

@@ -553,15 +557,13 @@ describe('KeyringController', () => {
553557
await withController(
554558
{ cacheEncryptionKey },
555559
async ({ controller, initialState }) => {
556-
const initialVault = controller.state.vault;
557560
const initialKeyrings = controller.state.keyrings;
558561
await controller.createNewVaultAndRestore(
559562
password,
560563
uint8ArraySeed,
561564
);
562565
expect(controller.state).not.toBe(initialState);
563566
expect(controller.state.vault).toBeDefined();
564-
expect(controller.state.vault).toStrictEqual(initialVault);
565567
expect(controller.state.keyrings).toHaveLength(
566568
initialKeyrings.length,
567569
);
@@ -577,7 +579,7 @@ describe('KeyringController', () => {
577579
await withController(
578580
{ cacheEncryptionKey },
579581
async ({ controller, encryptor }) => {
580-
const encryptSpy = jest.spyOn(encryptor, 'encrypt');
582+
const encryptSpy = jest.spyOn(encryptor, 'encryptWithKey');
581583
const serializedKeyring = await controller.withKeyring(
582584
{ type: 'HD Key Tree' },
583585
async ({ keyring }) => keyring.serialize(),
@@ -590,7 +592,8 @@ describe('KeyringController', () => {
590592
currentSeedWord,
591593
);
592594

593-
expect(encryptSpy).toHaveBeenCalledWith(password, [
595+
const key = JSON.parse(MOCK_ENCRYPTION_KEY);
596+
expect(encryptSpy).toHaveBeenCalledWith(key, [
594597
{
595598
data: serializedKeyring,
596599
type: 'HD Key Tree',
@@ -1302,7 +1305,15 @@ describe('KeyringController', () => {
13021305
},
13031306
],
13041307
};
1305-
expect(controller.state).toStrictEqual(modifiedState);
1308+
const modifiedStateWithoutVault = {
1309+
...modifiedState,
1310+
vault: undefined,
1311+
};
1312+
const stateWithoutVault = {
1313+
...controller.state,
1314+
vault: undefined,
1315+
};
1316+
expect(stateWithoutVault).toStrictEqual(modifiedStateWithoutVault);
13061317
expect(importedAccountAddress).toBe(address);
13071318
});
13081319
});
@@ -1381,7 +1392,15 @@ describe('KeyringController', () => {
13811392
},
13821393
],
13831394
};
1384-
expect(controller.state).toStrictEqual(modifiedState);
1395+
const modifiedStateWithoutVault = {
1396+
...modifiedState,
1397+
vault: undefined,
1398+
};
1399+
const stateWithoutVault = {
1400+
...controller.state,
1401+
vault: undefined,
1402+
};
1403+
expect(stateWithoutVault).toStrictEqual(modifiedStateWithoutVault);
13851404
expect(importedAccountAddress).toBe(address);
13861405
});
13871406
});
@@ -2678,10 +2697,10 @@ describe('KeyringController', () => {
26782697
{
26792698
cacheEncryptionKey,
26802699
skipVaultCreation: true,
2681-
state: { vault: 'my vault' },
2700+
state: { vault: freshVault },
26822701
},
26832702
async ({ controller, encryptor }) => {
2684-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
2703+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
26852704
{
26862705
type: 'UnsupportedKeyring',
26872706
data: '0x1234',
@@ -2700,10 +2719,10 @@ describe('KeyringController', () => {
27002719
{
27012720
cacheEncryptionKey,
27022721
skipVaultCreation: true,
2703-
state: { vault: 'my vault' },
2722+
state: { vault: freshVault },
27042723
},
27052724
async ({ controller, encryptor }) => {
2706-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
2725+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
27072726
{
27082727
foo: 'bar',
27092728
},
@@ -2733,11 +2752,11 @@ describe('KeyringController', () => {
27332752
await withController(
27342753
{
27352754
cacheEncryptionKey,
2736-
state: { vault: 'my vault' },
2755+
state: { vault: freshVault },
27372756
skipVaultCreation: true,
27382757
},
27392758
async ({ controller, encryptor }) => {
2740-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
2759+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
27412760
{
27422761
type: KeyringTypes.hd,
27432762
data: {
@@ -2776,7 +2795,7 @@ describe('KeyringController', () => {
27762795
{
27772796
cacheEncryptionKey: true,
27782797
state: {
2779-
vault: 'my vault',
2798+
vault: freshVault,
27802799
},
27812800
skipVaultCreation: true,
27822801
},
@@ -2787,9 +2806,8 @@ describe('KeyringController', () => {
27872806
);
27882807
jest
27892808
.spyOn(encryptor, 'importKey')
2790-
// @ts-expect-error we are assigning a mock value
27912809
.mockResolvedValue('imported key');
2792-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
2810+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
27932811
{
27942812
type: KeyringTypes.hd,
27952813
data: {
@@ -2840,7 +2858,7 @@ describe('KeyringController', () => {
28402858
{
28412859
cacheEncryptionKey: false,
28422860
state: {
2843-
vault: 'my vault',
2861+
vault: freshVault,
28442862
},
28452863
skipVaultCreation: true,
28462864
},
@@ -2895,14 +2913,14 @@ describe('KeyringController', () => {
28952913
{
28962914
skipVaultCreation: true,
28972915
cacheEncryptionKey,
2898-
state: { vault: 'my vault' },
2916+
state: { vault: freshVault },
28992917
keyringBuilders: [keyringBuilderFactory(MockKeyring)],
29002918
},
29012919
async ({ controller, encryptor, messenger }) => {
29022920
const unlockListener = jest.fn();
29032921
messenger.subscribe('KeyringController:unlock', unlockListener);
29042922
jest.spyOn(encryptor, 'isVaultUpdated').mockReturnValue(false);
2905-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
2923+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
29062924
{
29072925
type: KeyringTypes.hd,
29082926
data: {},
@@ -2926,12 +2944,12 @@ describe('KeyringController', () => {
29262944
{
29272945
skipVaultCreation: true,
29282946
cacheEncryptionKey,
2929-
state: { vault: 'my vault' },
2947+
state: { vault: freshVault },
29302948
},
29312949
async ({ controller, encryptor }) => {
29322950
jest.spyOn(encryptor, 'isVaultUpdated').mockReturnValue(false);
29332951
jest.spyOn(encryptor, 'encrypt').mockRejectedValue(new Error());
2934-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
2952+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
29352953
{
29362954
type: KeyringTypes.hd,
29372955
data: {
@@ -2955,13 +2973,13 @@ describe('KeyringController', () => {
29552973
{
29562974
skipVaultCreation: true,
29572975
cacheEncryptionKey,
2958-
state: { vault: 'my vault' },
2976+
state: { vault: freshVault },
29592977
keyringBuilders: [keyringBuilderFactory(MockKeyring)],
29602978
},
29612979
async ({ controller, encryptor, messenger }) => {
29622980
const unlockListener = jest.fn();
29632981
messenger.subscribe('KeyringController:unlock', unlockListener);
2964-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
2982+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
29652983
{
29662984
type: KeyringTypes.hd,
29672985
data: {},
@@ -2986,12 +3004,12 @@ describe('KeyringController', () => {
29863004
{
29873005
skipVaultCreation: true,
29883006
cacheEncryptionKey,
2989-
state: { vault: 'my vault' },
3007+
state: { vault: freshVault },
29903008
},
29913009
async ({ controller, encryptor }) => {
29923010
jest.spyOn(encryptor, 'isVaultUpdated').mockReturnValue(false);
2993-
const encryptSpy = jest.spyOn(encryptor, 'encrypt');
2994-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
3011+
const encryptSpy = jest.spyOn(encryptor, 'encryptWithKey');
3012+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
29953013
{
29963014
type: KeyringTypes.hd,
29973015
data: {
@@ -3013,12 +3031,12 @@ describe('KeyringController', () => {
30133031
{
30143032
skipVaultCreation: true,
30153033
cacheEncryptionKey,
3016-
state: { vault: 'my vault' },
3034+
state: { vault: freshVault },
30173035
},
30183036
async ({ controller, encryptor }) => {
30193037
jest.spyOn(encryptor, 'isVaultUpdated').mockReturnValue(true);
30203038
const encryptSpy = jest.spyOn(encryptor, 'encrypt');
3021-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
3039+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
30223040
{
30233041
type: KeyringTypes.hd,
30243042
data: {
@@ -3027,6 +3045,10 @@ describe('KeyringController', () => {
30273045
},
30283046
]);
30293047

3048+
// TODO actually this does trigger re-encryption. The catch is
3049+
// that this test is run with cacheEncryptionKey enabled, so
3050+
// `encryptWithKey` is being used instead of `encrypt`. Hence,
3051+
// the spy on `encrypt` doesn't trigger.
30303052
await controller.submitPassword(password);
30313053

30323054
expect(encryptSpy).not.toHaveBeenCalled();
@@ -3040,7 +3062,7 @@ describe('KeyringController', () => {
30403062
{
30413063
skipVaultCreation: true,
30423064
cacheEncryptionKey,
3043-
state: { vault: 'my vault' },
3065+
state: { vault: freshVault },
30443066
},
30453067
async ({ controller, encryptor }) => {
30463068
jest.spyOn(encryptor, 'isVaultUpdated').mockReturnValue(false);
@@ -3066,7 +3088,7 @@ describe('KeyringController', () => {
30663088
{
30673089
skipVaultCreation: true,
30683090
cacheEncryptionKey,
3069-
state: { vault: 'my vault' },
3091+
state: { vault: freshVault },
30703092
},
30713093
async ({ controller, encryptor }) => {
30723094
jest.spyOn(encryptor, 'isVaultUpdated').mockReturnValue(true);
@@ -3119,14 +3141,19 @@ describe('KeyringController', () => {
31193141
it('should throw error when using the wrong password', async () => {
31203142
await withController(
31213143
{
3122-
skipVaultCreation: true,
31233144
cacheEncryptionKey,
3124-
state: { vault: 'my vault' },
3145+
skipVaultCreation: true,
3146+
state: {
3147+
vault: freshVault,
3148+
// @ts-expect-error we want to force the controller to have an
3149+
// encryption salt equal to the one in the vault
3150+
encryptionSalt: SALT,
3151+
},
31253152
},
31263153
async ({ controller }) => {
31273154
await expect(
31283155
controller.submitPassword('wrong password'),
3129-
).rejects.toThrow('Incorrect password.');
3156+
).rejects.toThrow(DECRYPTION_ERROR);
31303157
},
31313158
);
31323159
});
@@ -3154,14 +3181,14 @@ describe('KeyringController', () => {
31543181
cacheEncryptionKey: true,
31553182
skipVaultCreation: true,
31563183
state: {
3157-
vault: JSON.stringify({ data: '0x123', salt: 'my salt' }),
3184+
vault: freshVault,
31583185
// @ts-expect-error we want to force the controller to have an
31593186
// encryption salt equal to the one in the vault
3160-
encryptionSalt: 'my salt',
3187+
encryptionSalt: SALT,
31613188
},
31623189
},
31633190
async ({ controller, initialState, encryptor }) => {
3164-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
3191+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
31653192
{
31663193
type: 'UnsupportedKeyring',
31673194
data: '0x1234',
@@ -3188,19 +3215,15 @@ describe('KeyringController', () => {
31883215
cacheEncryptionKey: true,
31893216
skipVaultCreation: true,
31903217
state: {
3191-
vault: JSON.stringify({ data: '0x123', salt: 'my salt' }),
3218+
vault: freshVault,
31923219
// @ts-expect-error we want to force the controller to have an
31933220
// encryption salt equal to the one in the vault
3194-
encryptionSalt: 'my salt',
3221+
encryptionSalt: SALT,
31953222
},
31963223
},
31973224
async ({ controller, initialState, encryptor }) => {
31983225
const encryptWithKeySpy = jest.spyOn(encryptor, 'encryptWithKey');
3199-
jest
3200-
.spyOn(encryptor, 'importKey')
3201-
// @ts-expect-error we are assigning a mock value
3202-
.mockResolvedValue('imported key');
3203-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
3226+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
32043227
{
32053228
type: KeyringTypes.hd,
32063229
data: '0x123',
@@ -3213,18 +3236,21 @@ describe('KeyringController', () => {
32133236
);
32143237

32153238
expect(controller.state.isUnlocked).toBe(true);
3216-
expect(encryptWithKeySpy).toHaveBeenCalledWith('imported key', [
3217-
{
3218-
type: KeyringTypes.hd,
3219-
data: {
3220-
accounts: ['0x123'],
3221-
},
3222-
metadata: {
3223-
id: expect.any(String),
3224-
name: '',
3239+
expect(encryptWithKeySpy).toHaveBeenCalledWith(
3240+
JSON.parse(MOCK_ENCRYPTION_KEY),
3241+
[
3242+
{
3243+
type: KeyringTypes.hd,
3244+
data: {
3245+
accounts: ['0x123'],
3246+
},
3247+
metadata: {
3248+
id: expect.any(String),
3249+
name: '',
3250+
},
32253251
},
3226-
},
3227-
]);
3252+
],
3253+
);
32283254
},
32293255
);
32303256
});
@@ -3233,7 +3259,7 @@ describe('KeyringController', () => {
32333259
await withController(
32343260
{ cacheEncryptionKey: true },
32353261
async ({ controller, initialState, encryptor }) => {
3236-
jest.spyOn(encryptor, 'decrypt').mockResolvedValueOnce([
3262+
jest.spyOn(encryptor, 'decryptWithKey').mockResolvedValueOnce([
32373263
{
32383264
foo: 'bar',
32393265
},

0 commit comments

Comments
 (0)