Skip to content

Commit 9399e4f

Browse files
committed
update tests
1 parent 6650cb7 commit 9399e4f

File tree

1 file changed

+91
-13
lines changed

1 file changed

+91
-13
lines changed

packages/seedless-onboarding-controller/src/SeedlessOnboardingController.test.ts

Lines changed: 91 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ import {
2626
stringToBytes,
2727
bigIntToHex,
2828
} from '@metamask/utils';
29+
import { gcm } from '@noble/ciphers/aes';
30+
import { utf8ToBytes } from '@noble/ciphers/utils';
31+
import { managedNonce } from '@noble/ciphers/webcrypto';
2932
import type { webcrypto } from 'node:crypto';
3033

3134
import {
@@ -91,6 +94,7 @@ const MOCK_NODE_AUTH_TOKENS = [
9194
];
9295

9396
const MOCK_KEYRING_ID = 'mock-keyring-id';
97+
const MOCK_KEYRING_ENCRYPTION_KEY = 'mock-keyring-encryption-key';
9498
const MOCK_SEED_PHRASE = stringToBytes(
9599
'horror pink muffin canal young photo magnet runway start elder patch until',
96100
);
@@ -396,11 +400,17 @@ async function createMockVault(
396400
const { vault: encryptedMockVault, exportedKeyString } =
397401
await encryptor.encryptWithDetail(MOCK_PASSWORD, serializedKeyData);
398402

403+
const aes = managedNonce(gcm)(encKey);
404+
const encryptedKeyringEncryptionKey = aes.encrypt(
405+
utf8ToBytes(MOCK_KEYRING_ENCRYPTION_KEY),
406+
);
407+
399408
return {
400409
encryptedMockVault,
401410
vaultEncryptionKey: exportedKeyString,
402411
vaultEncryptionSalt: JSON.parse(encryptedMockVault).salt,
403412
revokeToken: mockRevokeToken,
413+
encryptedKeyringEncryptionKey,
404414
};
405415
}
406416

@@ -445,6 +455,7 @@ async function decryptVault(vault: string, password: string) {
445455
* @param options.vault - The mock vault data.
446456
* @param options.vaultEncryptionKey - The mock vault encryption key.
447457
* @param options.vaultEncryptionSalt - The mock vault encryption salt.
458+
* @param options.encryptedKeyringEncryptionKey - The mock encrypted keyring encryption key.
448459
* @returns The initial controller state with the mock authenticated user.
449460
*/
450461
function getMockInitialControllerState(options?: {
@@ -455,6 +466,7 @@ function getMockInitialControllerState(options?: {
455466
vault?: string;
456467
vaultEncryptionKey?: string;
457468
vaultEncryptionSalt?: string;
469+
encryptedKeyringEncryptionKey?: string;
458470
}): Partial<SeedlessOnboardingControllerState> {
459471
const state = getDefaultSeedlessOnboardingControllerState();
460472

@@ -486,6 +498,10 @@ function getMockInitialControllerState(options?: {
486498
state.authPubKey = options.authPubKey ?? MOCK_AUTH_PUB_KEY;
487499
}
488500

501+
if (options?.encryptedKeyringEncryptionKey) {
502+
state.encryptedKeyringEncryptionKey = options.encryptedKeyringEncryptionKey;
503+
}
504+
489505
return state;
490506
}
491507

@@ -2942,11 +2958,11 @@ describe('SeedlessOnboardingController', () => {
29422958
});
29432959
});
29442960

2945-
describe('recoverCurrentDevicePassword', () => {
2961+
describe('recoverKeyringEncryptionKey', () => {
29462962
const GLOBAL_PASSWORD = 'global-password';
29472963
const RECOVERED_PASSWORD = 'recovered-password';
29482964

2949-
it('should recover the password for the current device', async () => {
2965+
it('should store and recover keyring encryption key', async () => {
29502966
await withController(
29512967
{
29522968
state: getMockInitialControllerState({
@@ -2955,6 +2971,19 @@ describe('SeedlessOnboardingController', () => {
29552971
}),
29562972
},
29572973
async ({ controller, toprfClient }) => {
2974+
// Setup and store keyring encryption key.
2975+
await mockCreateToprfKeyAndBackupSeedPhrase(
2976+
toprfClient,
2977+
controller,
2978+
RECOVERED_PASSWORD,
2979+
MOCK_SEED_PHRASE,
2980+
MOCK_KEYRING_ID,
2981+
);
2982+
2983+
await controller.storeKeyringEncryptionKey(
2984+
MOCK_KEYRING_ENCRYPTION_KEY,
2985+
);
2986+
29582987
// Mock recoverEncKey for the global password
29592988
const mockToprfEncryptor = createMockToprfEncryptor();
29602989
const encKey = mockToprfEncryptor.deriveEncKey(GLOBAL_PASSWORD);
@@ -2968,29 +2997,72 @@ describe('SeedlessOnboardingController', () => {
29682997
});
29692998

29702999
// Mock toprfClient.recoverPassword
3000+
const recoveredEncKey =
3001+
mockToprfEncryptor.deriveEncKey(RECOVERED_PASSWORD);
29713002
jest.spyOn(toprfClient, 'recoverPassword').mockResolvedValueOnce({
2972-
password: RECOVERED_PASSWORD,
3003+
password: bytesToBase64(recoveredEncKey),
29733004
});
29743005

2975-
const result = await controller.recoverCurrentDevicePassword({
3006+
const result = await controller.recoverKeyringEncryptionKey({
29763007
globalPassword: GLOBAL_PASSWORD,
29773008
});
29783009

2979-
expect(result).toStrictEqual({ password: RECOVERED_PASSWORD });
3010+
expect(result).toStrictEqual({
3011+
keyringEncryptionKey: MOCK_KEYRING_ENCRYPTION_KEY,
3012+
});
29803013
expect(toprfClient.recoverEncKey).toHaveBeenCalled();
29813014
expect(toprfClient.recoverPassword).toHaveBeenCalled();
29823015
},
29833016
);
29843017
});
29853018

3019+
it('should throw if encryptedKeyringEncryptionKey not set', async () => {
3020+
await withController(
3021+
{
3022+
state: getMockInitialControllerState({
3023+
withMockAuthenticatedUser: true,
3024+
withMockAuthPubKey: true,
3025+
}),
3026+
},
3027+
async ({ controller, toprfClient }) => {
3028+
// Mock recoverEncKey for the global password
3029+
const mockToprfEncryptor = createMockToprfEncryptor();
3030+
const encKey = mockToprfEncryptor.deriveEncKey(GLOBAL_PASSWORD);
3031+
const authKeyPair =
3032+
mockToprfEncryptor.deriveAuthKeyPair(GLOBAL_PASSWORD);
3033+
jest.spyOn(toprfClient, 'recoverEncKey').mockResolvedValueOnce({
3034+
encKey,
3035+
authKeyPair,
3036+
rateLimitResetResult: Promise.resolve(),
3037+
keyShareIndex: 1,
3038+
});
3039+
3040+
// Mock toprfClient.recoverPassword
3041+
const recoveredEncKey =
3042+
mockToprfEncryptor.deriveEncKey(RECOVERED_PASSWORD);
3043+
jest.spyOn(toprfClient, 'recoverPassword').mockResolvedValueOnce({
3044+
password: bytesToBase64(recoveredEncKey),
3045+
});
3046+
3047+
await expect(
3048+
controller.recoverKeyringEncryptionKey({
3049+
globalPassword: GLOBAL_PASSWORD,
3050+
}),
3051+
).rejects.toThrow(
3052+
SeedlessOnboardingControllerErrorMessage.CouldNotRecoverPassword,
3053+
);
3054+
},
3055+
);
3056+
});
3057+
29863058
it('should throw SRPNotBackedUpError if no authPubKey in state', async () => {
29873059
await withController(
29883060
{
29893061
state: getMockInitialControllerState({}),
29903062
},
29913063
async ({ controller }) => {
29923064
await expect(
2993-
controller.recoverCurrentDevicePassword({
3065+
controller.recoverKeyringEncryptionKey({
29943066
globalPassword: GLOBAL_PASSWORD,
29953067
}),
29963068
).rejects.toThrow(
@@ -3019,7 +3091,7 @@ describe('SeedlessOnboardingController', () => {
30193091
);
30203092

30213093
await expect(
3022-
controller.recoverCurrentDevicePassword({
3094+
controller.recoverKeyringEncryptionKey({
30233095
globalPassword: GLOBAL_PASSWORD,
30243096
}),
30253097
).rejects.toStrictEqual(
@@ -3061,7 +3133,7 @@ describe('SeedlessOnboardingController', () => {
30613133
);
30623134

30633135
await expect(
3064-
controller.recoverCurrentDevicePassword({
3136+
controller.recoverKeyringEncryptionKey({
30653137
globalPassword: GLOBAL_PASSWORD,
30663138
}),
30673139
).rejects.toStrictEqual(
@@ -3098,7 +3170,7 @@ describe('SeedlessOnboardingController', () => {
30983170
.mockRejectedValueOnce(new Error('Unknown error'));
30993171

31003172
await expect(
3101-
controller.recoverCurrentDevicePassword({
3173+
controller.recoverKeyringEncryptionKey({
31023174
globalPassword: GLOBAL_PASSWORD,
31033175
}),
31043176
).rejects.toStrictEqual(
@@ -3995,7 +4067,7 @@ describe('SeedlessOnboardingController', () => {
39954067
});
39964068
});
39974069

3998-
describe('recoverCurrentDevicePassword with token refresh', () => {
4070+
describe('recoverKeyringEncryptionKey with token refresh', () => {
39994071
// const OLD_PASSWORD = 'old-mock-password';
40004072
// const GLOBAL_PASSWORD = 'new-global-password';
40014073
let MOCK_VAULT: string;
@@ -4004,6 +4076,7 @@ describe('SeedlessOnboardingController', () => {
40044076
let INITIAL_AUTH_PUB_KEY: string;
40054077
let initialAuthKeyPair: KeyPair; // Store initial keypair for vault creation
40064078
let initialEncKey: Uint8Array; // Store initial encKey for vault creation
4079+
let initialEncryptedKeyringEncryptionKey: Uint8Array; // Store initial encKey for vault creation
40074080

40084081
// Generate initial keys and vault state before tests run
40094082
beforeAll(async () => {
@@ -4023,9 +4096,11 @@ describe('SeedlessOnboardingController', () => {
40234096
MOCK_VAULT = mockResult.encryptedMockVault;
40244097
MOCK_VAULT_ENCRYPTION_KEY = mockResult.vaultEncryptionKey;
40254098
MOCK_VAULT_ENCRYPTION_SALT = mockResult.vaultEncryptionSalt;
4099+
initialEncryptedKeyringEncryptionKey =
4100+
mockResult.encryptedKeyringEncryptionKey;
40264101
});
40274102

4028-
it('should retry recoverCurrentDevicePassword after refreshing expired tokens', async () => {
4103+
it('should retry recoverKeyringEncryptionKey after refreshing expired tokens', async () => {
40294104
await withController(
40304105
{
40314106
state: getMockInitialControllerState({
@@ -4034,6 +4109,9 @@ describe('SeedlessOnboardingController', () => {
40344109
vault: MOCK_VAULT,
40354110
vaultEncryptionKey: MOCK_VAULT_ENCRYPTION_KEY,
40364111
vaultEncryptionSalt: MOCK_VAULT_ENCRYPTION_SALT,
4112+
encryptedKeyringEncryptionKey: bytesToBase64(
4113+
initialEncryptedKeyringEncryptionKey,
4114+
),
40374115
}),
40384116
},
40394117
async ({ controller, toprfClient, mockRefreshJWTToken }) => {
@@ -4055,7 +4133,7 @@ describe('SeedlessOnboardingController', () => {
40554133
);
40564134
})
40574135
.mockResolvedValueOnce({
4058-
password: MOCK_PASSWORD,
4136+
password: bytesToBase64(initialEncKey),
40594137
});
40604138

40614139
// Mock authenticate for token refresh
@@ -4064,7 +4142,7 @@ describe('SeedlessOnboardingController', () => {
40644142
isNewUser: false,
40654143
});
40664144

4067-
await controller.recoverCurrentDevicePassword({
4145+
await controller.recoverKeyringEncryptionKey({
40684146
globalPassword: MOCK_PASSWORD,
40694147
});
40704148

0 commit comments

Comments
 (0)