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({
13 passphrase: newKeyPassword,
17 PrivateKey: privateKeyArmored,
21 export const getEncryptedArmoredOrganizationKey = async (
22 organizationKey: PrivateKeyReference | undefined,
23 newKeyPassword: string
25 if (!organizationKey) {
28 return CryptoProxy.exportPrivateKey({ privateKey: organizationKey, passphrase: newKeyPassword });
31 export const getArmoredPrivateUserKeys = async (keys: DecryptedKey[], keyPassword: string) => {
32 if (keys.length === 0) {
35 const armoredKeys = await Promise.all(
37 return getEncryptedArmoredUserKey(key, keyPassword).catch(noop);
40 const result = armoredKeys.filter(isTruthy);
42 if (result.length === 0) {
43 const decryptedError = new Error('No decrypted keys exist');
44 decryptedError.name = 'NoDecryptedKeys';
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);
65 const result = armoredKeys.filter(isTruthy);
67 if (result.length === 0) {
68 const decryptedError = new Error('No decrypted keys exist');
69 decryptedError.name = 'NoDecryptedKeys';
76 interface AddressesKeys {
81 export const getArmoredPrivateAddressesKeys = async (addressesWithKeysList: AddressesKeys[], keyPassword: string) => {
82 const result = await Promise.all(
83 addressesWithKeysList.map(({ address, keys }) => {
87 return getArmoredPrivateAddressKeys(keys, address, keyPassword);
90 return result.flat().filter(isTruthy);
93 export const getUpdateKeysPayload = async (
94 addressesKeys: AddressesKeys[],
95 userKeys: DecryptedKey[],
96 organizationKey: PrivateKeyReference | undefined,
99 forceMigratedAddressKeys?: boolean
101 const hasMigratedAddressKeys = forceMigratedAddressKeys
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),
111 return hasMigratedAddressKeys
113 UserKeys: armoredUserKeys,
115 OrganizationKey: armoredOrganizationKey,
118 Keys: [...armoredUserKeys, ...armoredAddressesKeys],
120 OrganizationKey: armoredOrganizationKey,