1 import type { PrivateKeyReference, PrivateKeyReferenceV4, PrivateKeyReferenceV6 } from '@proton/crypto';
2 import { CryptoProxy } from '@proton/crypto';
3 import { getDefaultKeyFlags } from '@proton/shared/lib/keys';
5 import { createAddressKeyRouteV2 } from '../../api/keys';
7 type ActiveKeyWithVersion,
11 type KeyTransparencyVerify,
13 } from '../../interfaces';
14 import { generateAddressKeyTokens } from '../addressKeys';
18 getNormalizedActiveAddressKeys,
20 } from '../getActiveKeys';
21 import { getInactiveKeys } from '../getInactiveKeys';
22 import { reactivateAddressKeysV2 } from '../reactivation/reactivateKeysProcessV2';
23 import { getSignedKeyListWithDeferredPublish } from '../signedKeyList';
24 import { getFilteredImportRecords } from './helper';
25 import type { KeyImportData, OnKeyImportCallback } from './interface';
27 export interface ImportKeysProcessV2Arguments {
29 keyImportRecords: KeyImportData[];
30 onImport: OnKeyImportCallback;
33 addressKeys: DecryptedKey[];
34 userKey: PrivateKeyReference;
35 keyTransparencyVerify: KeyTransparencyVerify;
38 const importKeysProcessV2 = async ({
45 keyTransparencyVerify,
46 }: ImportKeysProcessV2Arguments) => {
47 const activeKeys = await getActiveAddressKeys(address, address.SignedKeyList, address.Keys, addressKeys);
48 const activeKeysList = [...activeKeys.v4, ...activeKeys.v6];
49 const inactiveKeys = await getInactiveKeys(address.Keys, activeKeysList);
51 const [keysToReactivate, keysToImport, existingKeys] = getFilteredImportRecords(
57 existingKeys.forEach((keyImportRecord) => {
58 onImport(keyImportRecord.id, new Error('Key already active'));
61 let mutableActiveKeys = activeKeys;
63 for (const keyImportRecord of keysToImport) {
65 const { privateKey } = keyImportRecord;
67 const { token, encryptedToken, signature } = await generateAddressKeyTokens(userKey);
68 const privateKeyArmored = await CryptoProxy.exportPrivateKey({
73 const newActiveKey = (await getActiveKeyObject(
74 privateKey as PrivateKeyReferenceV4 | PrivateKeyReferenceV6,
77 // Do not set v6 as primary automatically (doing so would fail if forwarding is setup)
78 primary: privateKey.isPrivateKeyV6() ? 0 : getPrimaryFlag(mutableActiveKeys.v4),
79 flags: getDefaultKeyFlags(address),
81 )) as ActiveKeyWithVersion;
82 const toNormalize = isActiveKeyV6(newActiveKey)
83 ? { v4: [...mutableActiveKeys.v4], v6: [...mutableActiveKeys.v6, newActiveKey] }
84 : { v4: [...mutableActiveKeys.v4, newActiveKey], v6: [...mutableActiveKeys.v6] };
85 const updatedActiveKeys = getNormalizedActiveAddressKeys(address, toNormalize);
86 const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
92 const { Key } = await api(
93 createAddressKeyRouteV2({
94 AddressID: address.ID,
95 Primary: newActiveKey.primary,
96 PrivateKey: privateKeyArmored,
99 Token: encryptedToken,
102 // Only once the SKL is successfully posted we add it to the KT commit state.
103 await onSKLPublishSuccess();
105 // Mutably update the key with the latest value from the real ID.
106 newActiveKey.ID = Key.ID;
108 mutableActiveKeys = updatedActiveKeys;
110 onImport(keyImportRecord.id, 'ok');
112 onImport(keyImportRecord.id, e);
116 await reactivateAddressKeysV2({
119 activeKeys: mutableActiveKeys,
122 onReactivation: onImport,
123 keyTransparencyVerify,
127 export default importKeysProcessV2;