Skip to content

Commit 3636a12

Browse files
committed
update tests
1 parent a0163c1 commit 3636a12

File tree

3 files changed

+105
-126
lines changed

3 files changed

+105
-126
lines changed

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

Lines changed: 82 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,54 +1417,6 @@ describe('SeedlessOnboardingController', () => {
14171417
);
14181418
});
14191419

1420-
it('should throw error if encryptionKey is missing', async () => {
1421-
await withController(
1422-
{
1423-
state: getMockInitialControllerState({
1424-
withMockAuthenticatedUser: true,
1425-
vault: MOCK_VAULT,
1426-
}),
1427-
},
1428-
async ({ controller, toprfClient, encryptor }) => {
1429-
mockcreateLocalKey(toprfClient, MOCK_PASSWORD);
1430-
1431-
// persist the local enc key
1432-
jest.spyOn(toprfClient, 'persistLocalKey').mockResolvedValueOnce();
1433-
// encrypt and store the secret data
1434-
handleMockSecretDataAdd();
1435-
1436-
jest.spyOn(encryptor, 'encryptWithDetail').mockResolvedValueOnce({
1437-
vault: MOCK_VAULT,
1438-
// @ts-expect-error intentional test case
1439-
exportedKeyString: undefined,
1440-
});
1441-
1442-
await controller.createToprfKeyAndBackupSeedPhrase(
1443-
MOCK_PASSWORD,
1444-
NEW_KEY_RING_1.seedPhrase,
1445-
NEW_KEY_RING_1.id,
1446-
);
1447-
1448-
mockFetchAuthPubKey(
1449-
toprfClient,
1450-
base64ToBytes(controller.state.authPubKey as string),
1451-
);
1452-
1453-
await expect(
1454-
controller.addNewSecretData(
1455-
NEW_KEY_RING_2.seedPhrase,
1456-
SecretType.Mnemonic,
1457-
{
1458-
keyringId: NEW_KEY_RING_2.id,
1459-
},
1460-
),
1461-
).rejects.toThrow(
1462-
SeedlessOnboardingControllerErrorMessage.MissingCredentials,
1463-
);
1464-
},
1465-
);
1466-
});
1467-
14681420
it('should throw error if encryptionSalt is different from the one in the vault', async () => {
14691421
await withController(
14701422
{
@@ -1506,54 +1458,6 @@ describe('SeedlessOnboardingController', () => {
15061458
);
15071459
});
15081460

1509-
it('should throw error if encryptionKey is of an unexpected type', async () => {
1510-
await withController(
1511-
{
1512-
state: getMockInitialControllerState({
1513-
withMockAuthenticatedUser: true,
1514-
vault: MOCK_VAULT,
1515-
}),
1516-
},
1517-
async ({ controller, toprfClient, encryptor }) => {
1518-
mockcreateLocalKey(toprfClient, MOCK_PASSWORD);
1519-
1520-
// persist the local enc key
1521-
jest.spyOn(toprfClient, 'persistLocalKey').mockResolvedValueOnce();
1522-
// encrypt and store the secret data
1523-
handleMockSecretDataAdd();
1524-
1525-
jest.spyOn(encryptor, 'encryptWithDetail').mockResolvedValueOnce({
1526-
vault: MOCK_VAULT,
1527-
// @ts-expect-error intentional test case
1528-
exportedKeyString: 123,
1529-
});
1530-
1531-
await controller.createToprfKeyAndBackupSeedPhrase(
1532-
MOCK_PASSWORD,
1533-
NEW_KEY_RING_1.seedPhrase,
1534-
NEW_KEY_RING_1.id,
1535-
);
1536-
1537-
mockFetchAuthPubKey(
1538-
toprfClient,
1539-
base64ToBytes(controller.state.authPubKey as string),
1540-
);
1541-
1542-
await expect(
1543-
controller.addNewSecretData(
1544-
NEW_KEY_RING_2.seedPhrase,
1545-
SecretType.Mnemonic,
1546-
{
1547-
keyringId: NEW_KEY_RING_2.id,
1548-
},
1549-
),
1550-
).rejects.toThrow(
1551-
SeedlessOnboardingControllerErrorMessage.WrongPasswordType,
1552-
);
1553-
},
1554-
);
1555-
});
1556-
15571461
it('should throw an error if vault unlocked has an unexpected shape', async () => {
15581462
await withController(
15591463
{
@@ -2984,7 +2888,7 @@ describe('SeedlessOnboardingController', () => {
29842888
});
29852889
});
29862890

2987-
describe('recoverKeyringEncryptionKey', () => {
2891+
describe('store and recover keyring encryption key', () => {
29882892
const GLOBAL_PASSWORD = 'global-password';
29892893
const RECOVERED_PASSWORD = 'recovered-password';
29902894

@@ -3029,19 +2933,56 @@ describe('SeedlessOnboardingController', () => {
30292933
password: bytesToBase64(recoveredEncKey),
30302934
});
30312935

3032-
const result = await controller.recoverKeyringEncryptionKey({
2936+
controller.setLocked();
2937+
2938+
await controller.submitGlobalPassword({
30332939
globalPassword: GLOBAL_PASSWORD,
30342940
});
30352941

3036-
expect(result).toStrictEqual({
3037-
keyringEncryptionKey: MOCK_KEYRING_ENCRYPTION_KEY,
3038-
});
2942+
const keyringEncryptionKey =
2943+
await controller.loadKeyringEncryptionKey();
2944+
2945+
expect(keyringEncryptionKey).toStrictEqual(
2946+
MOCK_KEYRING_ENCRYPTION_KEY,
2947+
);
30392948
expect(toprfClient.recoverEncKey).toHaveBeenCalled();
30402949
expect(toprfClient.recoverPassword).toHaveBeenCalled();
30412950
},
30422951
);
30432952
});
30442953

2954+
it('should throw if key not set', async () => {
2955+
await withController(
2956+
{
2957+
state: getMockInitialControllerState({
2958+
withMockAuthenticatedUser: true,
2959+
withMockAuthPubKey: true,
2960+
vault: 'mock-vault',
2961+
}),
2962+
},
2963+
async ({ controller, toprfClient }) => {
2964+
await expect(
2965+
controller.storeKeyringEncryptionKey(''),
2966+
).rejects.toThrow(
2967+
SeedlessOnboardingControllerErrorMessage.VaultEncryptionKeyUndefined,
2968+
);
2969+
2970+
// Setup and store keyring encryption key.
2971+
await mockCreateToprfKeyAndBackupSeedPhrase(
2972+
toprfClient,
2973+
controller,
2974+
RECOVERED_PASSWORD,
2975+
MOCK_SEED_PHRASE,
2976+
MOCK_KEYRING_ID,
2977+
);
2978+
2979+
await expect(controller.loadKeyringEncryptionKey()).rejects.toThrow(
2980+
SeedlessOnboardingControllerErrorMessage.EncryptedKeyringEncryptionKeyNotSet,
2981+
);
2982+
},
2983+
);
2984+
});
2985+
30452986
it('should store and load keyring encryption key', async () => {
30462987
await withController(
30472988
{
@@ -3158,13 +3099,18 @@ describe('SeedlessOnboardingController', () => {
31583099
password: bytesToBase64(recoveredEncKey),
31593100
});
31603101

3161-
const result = await controller.recoverKeyringEncryptionKey({
3102+
controller.setLocked();
3103+
3104+
await controller.submitGlobalPassword({
31623105
globalPassword: GLOBAL_PASSWORD,
31633106
});
31643107

3165-
expect(result).toStrictEqual({
3166-
keyringEncryptionKey: MOCK_KEYRING_ENCRYPTION_KEY,
3167-
});
3108+
const keyringEncryptionKey =
3109+
await controller.loadKeyringEncryptionKey();
3110+
3111+
expect(keyringEncryptionKey).toStrictEqual(
3112+
MOCK_KEYRING_ENCRYPTION_KEY,
3113+
);
31683114
},
31693115
);
31703116
});
@@ -3198,7 +3144,7 @@ describe('SeedlessOnboardingController', () => {
31983144
});
31993145

32003146
await expect(
3201-
controller.recoverKeyringEncryptionKey({
3147+
controller.submitGlobalPassword({
32023148
globalPassword: GLOBAL_PASSWORD,
32033149
}),
32043150
).rejects.toThrow(
@@ -3215,7 +3161,7 @@ describe('SeedlessOnboardingController', () => {
32153161
},
32163162
async ({ controller }) => {
32173163
await expect(
3218-
controller.recoverKeyringEncryptionKey({
3164+
controller.submitGlobalPassword({
32193165
globalPassword: GLOBAL_PASSWORD,
32203166
}),
32213167
).rejects.toThrow(
@@ -3244,7 +3190,7 @@ describe('SeedlessOnboardingController', () => {
32443190
);
32453191

32463192
await expect(
3247-
controller.recoverKeyringEncryptionKey({
3193+
controller.submitGlobalPassword({
32483194
globalPassword: GLOBAL_PASSWORD,
32493195
}),
32503196
).rejects.toStrictEqual(
@@ -3286,7 +3232,7 @@ describe('SeedlessOnboardingController', () => {
32863232
);
32873233

32883234
await expect(
3289-
controller.recoverKeyringEncryptionKey({
3235+
controller.submitGlobalPassword({
32903236
globalPassword: GLOBAL_PASSWORD,
32913237
}),
32923238
).rejects.toStrictEqual(
@@ -3323,7 +3269,7 @@ describe('SeedlessOnboardingController', () => {
33233269
.mockRejectedValueOnce(new Error('Unknown error'));
33243270

33253271
await expect(
3326-
controller.recoverKeyringEncryptionKey({
3272+
controller.submitGlobalPassword({
33273273
globalPassword: GLOBAL_PASSWORD,
33283274
}),
33293275
).rejects.toStrictEqual(
@@ -3405,6 +3351,29 @@ describe('SeedlessOnboardingController', () => {
34053351
// We still need verifyPassword to work conceptually, even if unlock is bypassed
34063352
// verifyPasswordSpy.mockResolvedValueOnce(); // Don't mock, let the real one run inside syncLatestGlobalPassword
34073353

3354+
controller.setLocked();
3355+
3356+
// Mock recoverEncKey for the global password
3357+
const encKey = mockToprfEncryptor.deriveEncKey(GLOBAL_PASSWORD);
3358+
const authKeyPair =
3359+
mockToprfEncryptor.deriveAuthKeyPair(GLOBAL_PASSWORD);
3360+
jest.spyOn(toprfClient, 'recoverEncKey').mockResolvedValueOnce({
3361+
encKey,
3362+
authKeyPair,
3363+
rateLimitResetResult: Promise.resolve(),
3364+
keyShareIndex: 1,
3365+
});
3366+
3367+
// Mock toprfClient.recoverPassword
3368+
const recoveredEncKey = mockToprfEncryptor.deriveEncKey(OLD_PASSWORD);
3369+
jest.spyOn(toprfClient, 'recoverPassword').mockResolvedValueOnce({
3370+
password: bytesToBase64(recoveredEncKey),
3371+
});
3372+
3373+
await controller.submitGlobalPassword({
3374+
globalPassword: GLOBAL_PASSWORD,
3375+
});
3376+
34083377
await controller.syncLatestGlobalPassword({
34093378
globalPassword: GLOBAL_PASSWORD,
34103379
});
@@ -4220,7 +4189,7 @@ describe('SeedlessOnboardingController', () => {
42204189
});
42214190
});
42224191

4223-
describe('recoverKeyringEncryptionKey with token refresh', () => {
4192+
describe('recover keyring encryption key with token refresh', () => {
42244193
// const OLD_PASSWORD = 'old-mock-password';
42254194
// const GLOBAL_PASSWORD = 'new-global-password';
42264195
let MOCK_VAULT: string;
@@ -4253,7 +4222,7 @@ describe('SeedlessOnboardingController', () => {
42534222
mockResult.encryptedKeyringEncryptionKey;
42544223
});
42554224

4256-
it('should retry recoverKeyringEncryptionKey after refreshing expired tokens', async () => {
4225+
it('should retry after refreshing expired tokens', async () => {
42574226
await withController(
42584227
{
42594228
state: getMockInitialControllerState({
@@ -4295,7 +4264,7 @@ describe('SeedlessOnboardingController', () => {
42954264
isNewUser: false,
42964265
});
42974266

4298-
await controller.recoverKeyringEncryptionKey({
4267+
await controller.submitGlobalPassword({
42994268
globalPassword: MOCK_PASSWORD,
43004269
});
43014270

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

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,12 +1123,6 @@ export class SeedlessOnboardingController<EncryptionKey> extends BaseController<
11231123
vaultEncryptionKey = encryptionKey;
11241124
}
11251125

1126-
if (!vaultEncryptionKey && !password) {
1127-
throw new Error(
1128-
SeedlessOnboardingControllerErrorMessage.MissingCredentials,
1129-
);
1130-
}
1131-
11321126
let decryptedVaultData: unknown;
11331127
const updatedState: Partial<SeedlessOnboardingControllerState> = {};
11341128

@@ -1145,20 +1139,19 @@ export class SeedlessOnboardingController<EncryptionKey> extends BaseController<
11451139
updatedState.vaultEncryptionKey = result.exportedKeyString;
11461140
updatedState.vaultEncryptionSalt = result.salt;
11471141
} else {
1142+
assertIsVaultEncryptionKeyDefined(vaultEncryptionKey);
1143+
11481144
const parsedEncryptedVault = JSON.parse(encryptedVault);
11491145

1150-
if (vaultEncryptionSalt !== parsedEncryptedVault.salt) {
1146+
if (
1147+
vaultEncryptionSalt &&
1148+
vaultEncryptionSalt !== parsedEncryptedVault.salt
1149+
) {
11511150
throw new Error(
11521151
SeedlessOnboardingControllerErrorMessage.ExpiredCredentials,
11531152
);
11541153
}
11551154

1156-
if (typeof vaultEncryptionKey !== 'string') {
1157-
throw new TypeError(
1158-
SeedlessOnboardingControllerErrorMessage.WrongPasswordType,
1159-
);
1160-
}
1161-
11621155
const key = await this.#vaultEncryptor.importKey(vaultEncryptionKey);
11631156
decryptedVaultData = await this.#vaultEncryptor.decryptWithKey(
11641157
key,
@@ -1831,3 +1824,19 @@ function assertIsEncryptedSeedlessEncryptionKeySet(
18311824
);
18321825
}
18331826
}
1827+
1828+
/**
1829+
* Assert that the provided vault encryption key is a valid non-empty string.
1830+
*
1831+
* @param vaultEncryptionKey - The vault encryption key to check.
1832+
* @throws If the vault encryption key is not a valid string.
1833+
*/
1834+
function assertIsVaultEncryptionKeyDefined(
1835+
vaultEncryptionKey: string | undefined
1836+
): asserts vaultEncryptionKey is string {
1837+
if (!vaultEncryptionKey) {
1838+
throw new Error(
1839+
SeedlessOnboardingControllerErrorMessage.VaultEncryptionKeyUndefined,
1840+
);
1841+
}
1842+
}

packages/seedless-onboarding-controller/src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,5 @@ export enum SeedlessOnboardingControllerErrorMessage {
5252
SRPNotBackedUpError = `${controllerName} - SRP not backed up`,
5353
EncryptedKeyringEncryptionKeyNotSet = `${controllerName} - Encrypted keyring encryption key is not set`,
5454
EncryptedSeedlessEncryptionKeyNotSet = `${controllerName} - Encrypted seedless encryption key is not set`,
55+
VaultEncryptionKeyUndefined = `${controllerName} - Vault encryption key is not available`,
5556
}

0 commit comments

Comments
 (0)