1 import { CryptoProxy } from '@proton/crypto';
2 import { activatePasswordlessKey } from '@proton/shared/lib/api/members';
5 getReplacedAddressKeyTokens,
6 reencryptOrganizationToken,
8 } from '@proton/shared/lib/keys';
9 import noop from '@proton/utils/noop';
11 import { createUserKeyRoute, replaceAddressTokens } from '../../api/keys';
12 import { DEFAULT_KEYGEN_TYPE, KEYGEN_CONFIGS } from '../../constants';
16 CachedOrganizationKey,
19 KeyTransparencyVerify,
21 } from '../../interfaces';
22 import { storeDeviceRecovery } from '../../recoveryFile/deviceRecovery';
23 import { getActiveKeys } from '../getActiveKeys';
24 import { getHasMigratedAddressKeys } from '../keyMigration';
25 import { generateUserKey } from '../userKeys';
26 import { createAddressKeyLegacy, createAddressKeyV2 } from './addAddressKeyHelper';
28 interface AddAddressKeysProcessArguments {
30 addressKeys: DecryptedKey[];
31 userKeys: DecryptedKey[];
34 keyGenConfig: KeyGenConfig;
36 keyTransparencyVerify: KeyTransparencyVerify;
39 export const addAddressKeysProcess = async ({
47 keyTransparencyVerify,
48 }: AddAddressKeysProcessArguments) => {
49 const hasMigratedAddressKeys = getHasMigratedAddressKeys(addresses);
51 const activeKeys = await getActiveKeys(address, address.SignedKeyList, address.Keys, addressKeys);
53 if (hasMigratedAddressKeys) {
54 return createAddressKeyV2({
60 keyTransparencyVerify,
64 return createAddressKeyLegacy({
68 passphrase: keyPassword,
70 keyTransparencyVerify,
74 interface AddUserKeysProcessArguments {
76 keyGenConfig?: KeyGenConfig;
78 userKeys: DecryptedKey[];
81 isDeviceRecoveryAvailable?: boolean;
82 isDeviceRecoveryEnabled?: boolean;
83 organizationKey?: CachedOrganizationKey;
86 export const addUserKeysProcess = async ({
88 keyGenConfig = KEYGEN_CONFIGS[DEFAULT_KEYGEN_TYPE],
94 isDeviceRecoveryAvailable,
95 isDeviceRecoveryEnabled,
96 }: AddUserKeysProcessArguments) => {
97 const { privateKey, privateKeyArmored } = await generateUserKey({
105 PrivateKey: privateKeyArmored,
109 const splitUserKeys = splitKeys(userKeys);
111 if (getHasMigratedAddressKeys(addresses)) {
112 const replacedResult = await getReplacedAddressKeyTokens({
113 privateKeys: splitUserKeys.privateKeys,
117 if (replacedResult.AddressKeyTokens.length) {
118 await api(replaceAddressTokens(replacedResult)).catch(/*ignore failures */ noop);
122 if (getIsPasswordless(organizationKey?.Key) && organizationKey?.privateKey) {
123 const result = await reencryptOrganizationToken({
124 Token: organizationKey.Key.Token,
125 encryptionKey: privateKey,
126 signingKey: privateKey,
127 decryptionKeys: splitUserKeys.privateKeys,
130 activatePasswordlessKey({
131 TokenKeyPacket: result.keyPacket,
132 Signature: result.signature,
134 ).catch(/*ignore failures */ noop);
137 // Store a new device recovery immediately to avoid having the storing trigger asynchronously which would cause red notification flashes
138 if (isDeviceRecoveryAvailable && isDeviceRecoveryEnabled) {
139 const publicKey = await CryptoProxy.importPublicKey({
140 binaryKey: await CryptoProxy.exportPublicKey({ key: privateKey, format: 'binary' }),
142 await storeDeviceRecovery({
145 userKeys: [{ ID: 'tmp-id', privateKey, publicKey }, ...userKeys],