1 import type { PrivateKeyReference } from '@proton/crypto';
2 import { CryptoProxy } from '@proton/crypto';
4 import type { Address as tsAddress, User as tsUser } from '../../lib/interfaces';
5 import { getDecryptedAddressKeysHelper, getDecryptedUserKeysHelper } from '../../lib/keys';
6 import { upgradeV2KeysHelper } from '../../lib/keys/upgradeKeysV2';
7 import { Modulus } from '../authentication/login.data';
8 import { getAddressKey, getUserKey } from './keyDataHelper';
10 const DEFAULT_EMAIL = 'test@test.com';
11 const DEFAULT_KEYPASSWORD = '1';
13 const getKey = async (email = DEFAULT_EMAIL, keyPassword = DEFAULT_KEYPASSWORD) => {
14 const privateKey = await CryptoProxy.generateKey({
15 userIDs: [{ name: email, email }],
20 privateKeyArmored: await CryptoProxy.exportPrivateKey({
22 passphrase: keyPassword,
27 describe('upgrade keys v2', () => {
28 describe('do v2 upgrade', () => {
29 it('should upgrade v2 keys', async () => {
30 const keyPassword = DEFAULT_KEYPASSWORD;
31 const [userKey1, userKey2] = await Promise.all([
32 getUserKey('a', keyPassword, 2),
33 getUserKey('b', keyPassword, 2),
36 Keys: [userKey1.Key, userKey2.Key],
38 const keys = await Promise.all([
39 getAddressKey('c', userKey1.key.privateKey, 'test@test.com', 2),
40 getAddressKey('d', userKey1.key.privateKey, 'test@test.com', 2),
41 getAddressKey('e', userKey2.key.privateKey, 'test2@test.com', 2),
46 Email: 'test@test.com',
47 Keys: [keys[0].Key, keys[1].Key],
50 Email: 'test2@test.com',
54 const api = jasmine.createSpy('api').and.returnValues(Promise.resolve({ Modulus }), Promise.resolve());
55 const newKeyPassword = await upgradeV2KeysHelper({
58 loginPassword: keyPassword,
60 clearKeyPassword: keyPassword,
61 isOnePasswordMode: true,
63 preAuthKTVerify: () => async () => {},
64 keyMigrationKTVerifier: async () => {},
66 if (!newKeyPassword) {
67 throw new Error('Missing new password');
69 expect(api.calls.all().length).toBe(2);
70 const newKeysArgs = api.calls.all()[1].args[0];
71 const decryptedUserKeys = await getDecryptedUserKeysHelper(
72 { ...User, Keys: newKeysArgs.data.UserKeys },
75 const decryptedAddressesKeys = await getDecryptedAddressKeysHelper(
76 newKeysArgs.data.AddressKeys,
81 expect(decryptedUserKeys.every((key) => key.privateKey.isPrivate())).toBe(true);
82 expect(decryptedUserKeys.length).toBe(2 as any);
83 expect(decryptedAddressesKeys.every((key) => key.privateKey.isPrivate())).toBe(true);
84 expect(decryptedAddressesKeys.length).toBe(3 as any);
85 expect(newKeysArgs).toEqual({
86 url: 'core/v4/keys/private/upgrade',
88 data: jasmine.objectContaining({
89 KeySalt: jasmine.any(String),
90 Auth: jasmine.any(Object),
91 UserKeys: jasmine.any(Array),
92 AddressKeys: jasmine.any(Array),
93 SignedKeyLists: jasmine.any(Object),
96 expect(newKeyPassword).toEqual(jasmine.any(String));
100 describe('do legacy upgrade', () => {
101 it('should upgrade v2 keys', async () => {
102 const keyPassword = DEFAULT_KEYPASSWORD;
103 const [userKey1, userKey2, addressKey1, addressKey2, addressKey3] = await Promise.all([
114 PrivateKey: userKey1.privateKeyArmored,
119 PrivateKey: userKey2.privateKeyArmored,
126 Email: 'test@test.com',
130 PrivateKey: addressKey1.privateKeyArmored,
135 PrivateKey: addressKey2.privateKeyArmored,
141 Email: 'test2@test.com',
145 PrivateKey: addressKey3.privateKeyArmored,
151 const api = jasmine.createSpy('api').and.returnValues(Promise.resolve({ Modulus }), Promise.resolve());
152 const newKeyPassword = await upgradeV2KeysHelper({
154 addresses: Addresses,
155 loginPassword: keyPassword,
157 clearKeyPassword: keyPassword,
158 isOnePasswordMode: true,
160 preAuthKTVerify: () => async () => {},
161 keyMigrationKTVerifier: async () => {},
163 if (!newKeyPassword) {
164 throw new Error('Missing new password');
166 expect(api.calls.all().length).toBe(2);
167 const newKeysArgs = api.calls.all()[1].args[0];
168 const decryptedKeys: PrivateKeyReference[] = await Promise.all(
169 newKeysArgs.data.Keys.map(({ PrivateKey }: any) => {
170 return CryptoProxy.importPrivateKey({ armoredKey: PrivateKey, passphrase: newKeyPassword });
173 expect(decryptedKeys.every((key) => key.isPrivate())).toBe(true);
174 expect(decryptedKeys.length).toBe(5);
175 expect(newKeysArgs.data.Keys[0].PrivateKey);
176 expect(newKeysArgs).toEqual({
177 url: 'core/v4/keys/private/upgrade',
179 data: jasmine.objectContaining({
180 KeySalt: jasmine.any(String),
181 Auth: jasmine.any(Object),
182 Keys: jasmine.any(Array),
185 expect(newKeyPassword).toEqual(jasmine.any(String));
188 it('should upgrade v2 keys in two password mode', async () => {
189 const keyPassword = DEFAULT_KEYPASSWORD;
190 const [userKey1, userKey2, addressKey1, addressKey2] = await Promise.all([
200 PrivateKey: userKey1.privateKeyArmored,
205 PrivateKey: userKey2.privateKeyArmored,
212 Email: 'test@test.com',
216 PrivateKey: addressKey1.privateKeyArmored,
221 PrivateKey: addressKey2.privateKeyArmored,
227 const api = jasmine.createSpy('api').and.returnValues(Promise.resolve());
228 const newKeyPassword = await upgradeV2KeysHelper({
230 addresses: Addresses,
231 loginPassword: '123',
233 clearKeyPassword: keyPassword,
234 isOnePasswordMode: false,
236 preAuthKTVerify: () => async () => {},
237 keyMigrationKTVerifier: async () => {},
239 expect(api.calls.all().length).toBe(1);
240 if (!newKeyPassword) {
241 throw new Error('Missing password');
243 const newKeysArgs = api.calls.all()[0].args[0];
244 const decryptedKeys: PrivateKeyReference[] = await Promise.all(
245 newKeysArgs.data.Keys.map(({ PrivateKey }: any) => {
246 return CryptoProxy.importPrivateKey({ armoredKey: PrivateKey, passphrase: newKeyPassword });
249 expect(decryptedKeys.length).toBe(4);
250 expect(decryptedKeys.every((key) => key.isPrivate())).toBe(true);
251 expect(newKeysArgs.data.Keys[0].PrivateKey);
252 expect(newKeysArgs).toEqual({
253 url: 'core/v4/keys/private/upgrade',
255 data: jasmine.objectContaining({
256 KeySalt: jasmine.any(String),
257 Keys: jasmine.any(Array),
260 expect(newKeyPassword).toEqual(jasmine.any(String));
263 it('should upgrade v2 and v3 keys mixed', async () => {
264 const keyPassword = DEFAULT_KEYPASSWORD;
265 const [userKey1, userKey2, addressKey1, addressKey2] = await Promise.all([
275 PrivateKey: userKey1.privateKeyArmored,
280 PrivateKey: userKey2.privateKeyArmored,
287 Email: 'test@test.com',
291 PrivateKey: addressKey1.privateKeyArmored,
296 PrivateKey: addressKey2.privateKeyArmored,
302 const api = jasmine.createSpy('api').and.returnValues(Promise.resolve());
303 const newKeyPassword = await upgradeV2KeysHelper({
305 addresses: Addresses,
306 loginPassword: '123',
308 clearKeyPassword: keyPassword,
309 isOnePasswordMode: false,
311 preAuthKTVerify: () => async () => {},
312 keyMigrationKTVerifier: async () => {},
314 if (!newKeyPassword) {
315 throw new Error('Missing password');
317 expect(api.calls.all().length).toBe(1);
318 const newKeysArgs = api.calls.all()[0].args[0];
319 const decryptedKeys: PrivateKeyReference[] = await Promise.all(
320 newKeysArgs.data.Keys.map(({ PrivateKey }: any) => {
321 return CryptoProxy.importPrivateKey({ armoredKey: PrivateKey, passphrase: newKeyPassword });
324 expect(decryptedKeys.length).toBe(4);
325 expect(decryptedKeys.every((key) => key.isPrivate())).toBe(true);
326 expect(newKeysArgs.data.Keys[0].PrivateKey);
327 expect(newKeysArgs).toEqual({
328 url: 'core/v4/keys/private/upgrade',
330 data: jasmine.objectContaining({
331 KeySalt: jasmine.any(String),
332 Keys: jasmine.any(Array),
335 expect(newKeyPassword).toEqual(jasmine.any(String));
339 describe('do not upgrade', () => {
340 it('should not upgrade if the v2 keys cannot be decrypted', async () => {
341 const email = 'test@test.com';
342 const keyPassword = '1';
343 const [userKey1, addressKey1, addressKey2] = await Promise.all([
346 getKey('test@test.com', '123'),
352 PrivateKey: userKey1.privateKeyArmored,
363 PrivateKey: addressKey1.privateKeyArmored,
368 PrivateKey: addressKey2.privateKeyArmored,
374 const api = jasmine.createSpy('api').and.returnValues(Promise.resolve());
375 const newKeyPassword = await upgradeV2KeysHelper({
377 addresses: Addresses,
378 loginPassword: keyPassword,
380 clearKeyPassword: keyPassword,
381 isOnePasswordMode: false,
383 preAuthKTVerify: () => async () => {},
384 keyMigrationKTVerifier: async () => {},
386 expect(api.calls.all().length).toBe(0);
387 expect(newKeyPassword).toBeUndefined();
390 it('should not upgrade if there are no v2 keys', async () => {
391 const email = 'test@test.com';
392 const keyPassword = '1';
393 const [userKey1, addressKey1, addressKey2] = await Promise.all([getKey(), getKey(), getKey()]);
398 PrivateKey: userKey1.privateKeyArmored,
409 PrivateKey: addressKey1.privateKeyArmored,
414 PrivateKey: addressKey2.privateKeyArmored,
420 const api = jasmine.createSpy('api').and.returnValues(Promise.resolve({ Modulus }), Promise.resolve());
421 const newKeyPassword = await upgradeV2KeysHelper({
423 addresses: Addresses,
424 loginPassword: keyPassword,
426 clearKeyPassword: keyPassword,
427 isOnePasswordMode: true,
429 preAuthKTVerify: () => async () => {},
430 keyMigrationKTVerifier: async () => {},
432 expect(api.calls.all().length).toBe(0);
433 expect(newKeyPassword).toBeUndefined();