Use same lock values as mobile clients
[ProtonMail-WebClient.git] / packages / shared / lib / keys / changePassword.ts
blob78b27617b0f31ea0c20ce0226a2f50df82239fcd
1 import type { PrivateKeyReference } from '@proton/crypto';
2 import { CryptoProxy } from '@proton/crypto';
3 import isTruthy from '@proton/utils/isTruthy';
4 import noop from '@proton/utils/noop';
6 import type { DecryptedKey, Address as tsAddress } from '../interfaces';
7 import { getEncryptedArmoredAddressKey } from './addressKeys';
8 import { getHasMigratedAddressKeys } from './keyMigration';
10 const getEncryptedArmoredUserKey = async ({ ID, privateKey }: DecryptedKey, newKeyPassword: string) => {
11     const privateKeyArmored = await CryptoProxy.exportPrivateKey({
12         privateKey,
13         passphrase: newKeyPassword,
14     });
15     return {
16         ID,
17         PrivateKey: privateKeyArmored,
18     };
21 export const getEncryptedArmoredOrganizationKey = async (
22     organizationKey: PrivateKeyReference | undefined,
23     newKeyPassword: string
24 ) => {
25     if (!organizationKey) {
26         return;
27     }
28     return CryptoProxy.exportPrivateKey({ privateKey: organizationKey, passphrase: newKeyPassword });
31 export const getArmoredPrivateUserKeys = async (keys: DecryptedKey[], keyPassword: string) => {
32     if (keys.length === 0) {
33         return [];
34     }
35     const armoredKeys = await Promise.all(
36         keys.map((key) => {
37             return getEncryptedArmoredUserKey(key, keyPassword).catch(noop);
38         })
39     );
40     const result = armoredKeys.filter(isTruthy);
42     if (result.length === 0) {
43         const decryptedError = new Error('No decrypted keys exist');
44         decryptedError.name = 'NoDecryptedKeys';
45         throw decryptedError;
46     }
48     return result;
51 export const getArmoredPrivateAddressKeys = async (keys: DecryptedKey[], address: tsAddress, keyPassword: string) => {
52     const armoredKeys = await Promise.all(
53         keys.map(async ({ ID, privateKey }) => {
54             const PrivateKey = await getEncryptedArmoredAddressKey(privateKey, address.Email, keyPassword).catch(noop);
55             if (!PrivateKey) {
56                 return;
57             }
58             return {
59                 ID,
60                 PrivateKey,
61             };
62         })
63     );
65     const result = armoredKeys.filter(isTruthy);
67     if (result.length === 0) {
68         const decryptedError = new Error('No decrypted keys exist');
69         decryptedError.name = 'NoDecryptedKeys';
70         throw decryptedError;
71     }
73     return result;
76 interface AddressesKeys {
77     address: tsAddress;
78     keys: DecryptedKey[];
81 export const getArmoredPrivateAddressesKeys = async (addressesWithKeysList: AddressesKeys[], keyPassword: string) => {
82     const result = await Promise.all(
83         addressesWithKeysList.map(({ address, keys }) => {
84             if (!keys.length) {
85                 return;
86             }
87             return getArmoredPrivateAddressKeys(keys, address, keyPassword);
88         })
89     );
90     return result.flat().filter(isTruthy);
93 export const getUpdateKeysPayload = async (
94     addressesKeys: AddressesKeys[],
95     userKeys: DecryptedKey[],
96     organizationKey: PrivateKeyReference | undefined,
97     keyPassword: string,
98     keySalt: string,
99     forceMigratedAddressKeys?: boolean
100 ) => {
101     const hasMigratedAddressKeys = forceMigratedAddressKeys
102         ? true
103         : getHasMigratedAddressKeys(addressesKeys.map(({ address }) => address));
105     const [armoredUserKeys, armoredAddressesKeys, armoredOrganizationKey] = await Promise.all([
106         getArmoredPrivateUserKeys(userKeys, keyPassword),
107         hasMigratedAddressKeys ? [] : getArmoredPrivateAddressesKeys(addressesKeys, keyPassword),
108         getEncryptedArmoredOrganizationKey(organizationKey, keyPassword),
109     ]);
111     return hasMigratedAddressKeys
112         ? {
113               UserKeys: armoredUserKeys,
114               KeySalt: keySalt,
115               OrganizationKey: armoredOrganizationKey,
116           }
117         : {
118               Keys: [...armoredUserKeys, ...armoredAddressesKeys],
119               KeySalt: keySalt,
120               OrganizationKey: armoredOrganizationKey,
121           };