Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / shared / lib / keys / import / importKeysProcessV2.ts
blob583305c68dee9aa47742403707e39e71e8605973
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';
6 import {
7     type ActiveKeyWithVersion,
8     type Address,
9     type Api,
10     type DecryptedKey,
11     type KeyTransparencyVerify,
12     isActiveKeyV6,
13 } from '../../interfaces';
14 import { generateAddressKeyTokens } from '../addressKeys';
15 import {
16     getActiveAddressKeys,
17     getActiveKeyObject,
18     getNormalizedActiveAddressKeys,
19     getPrimaryFlag,
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 {
28     api: Api;
29     keyImportRecords: KeyImportData[];
30     onImport: OnKeyImportCallback;
31     keyPassword: string;
32     address: Address;
33     addressKeys: DecryptedKey[];
34     userKey: PrivateKeyReference;
35     keyTransparencyVerify: KeyTransparencyVerify;
38 const importKeysProcessV2 = async ({
39     api,
40     keyImportRecords,
41     onImport,
42     address,
43     addressKeys,
44     userKey,
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(
52         keyImportRecords,
53         activeKeysList,
54         inactiveKeys
55     );
57     existingKeys.forEach((keyImportRecord) => {
58         onImport(keyImportRecord.id, new Error('Key already active'));
59     });
61     let mutableActiveKeys = activeKeys;
63     for (const keyImportRecord of keysToImport) {
64         try {
65             const { privateKey } = keyImportRecord;
67             const { token, encryptedToken, signature } = await generateAddressKeyTokens(userKey);
68             const privateKeyArmored = await CryptoProxy.exportPrivateKey({
69                 privateKey,
70                 passphrase: token,
71             });
73             const newActiveKey = (await getActiveKeyObject(
74                 privateKey as PrivateKeyReferenceV4 | PrivateKeyReferenceV6,
75                 {
76                     ID: 'tmp',
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),
80                 }
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(
87                 updatedActiveKeys,
88                 address,
89                 keyTransparencyVerify
90             );
92             const { Key } = await api(
93                 createAddressKeyRouteV2({
94                     AddressID: address.ID,
95                     Primary: newActiveKey.primary,
96                     PrivateKey: privateKeyArmored,
97                     SignedKeyList,
98                     Signature: signature,
99                     Token: encryptedToken,
100                 })
101             );
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');
111         } catch (e: any) {
112             onImport(keyImportRecord.id, e);
113         }
114     }
116     await reactivateAddressKeysV2({
117         api,
118         address,
119         activeKeys: mutableActiveKeys,
120         userKey,
121         keysToReactivate,
122         onReactivation: onImport,
123         keyTransparencyVerify,
124     });
127 export default importKeysProcessV2;