Merge branch 'feat/inda-383-daily-stat' into 'main'
[ProtonMail-WebClient.git] / packages / shared / lib / keys / add / addAddressKeyHelper.ts
blob71971688492cc3c852d1f3f690613720f6caa2ef
1 import { createAddressKeyRoute, createAddressKeyRouteV2 } from '../../api/keys';
2 import { DEFAULT_KEYGEN_TYPE, KEYGEN_CONFIGS } from '../../constants';
3 import {
4     type ActiveKeyWithVersion,
5     type ActiveAddressKeysByVersion,
6     type ActiveKey,
7     type Address,
8     type Api,
9     type KeyGenConfig,
10     type KeyGenConfigV6,
11     type KeyPair,
12     type KeyTransparencyVerify,
13     isActiveKeyV6,
14 } from '../../interfaces';
15 import { generateAddressKey, getNewAddressKeyToken } from '../addressKeys';
16 import { getActiveKeyObject, getNormalizedActiveAddressKeys } from '../getActiveKeys';
17 import { getDefaultKeyFlags } from '../keyFlags';
18 import { getSignedKeyListWithDeferredPublish } from '../signedKeyList';
20 interface CreateAddressKeyLegacyArguments {
21     api: Api;
22     keyGenConfig?: KeyGenConfig; // no v6 key support for non-migrated users
23     address: Address;
24     passphrase: string;
25     activeKeys: ActiveAddressKeysByVersion;
26     keyTransparencyVerify: KeyTransparencyVerify;
27     addressForwardingID?: string;
30 export const removePrimary = <T extends ActiveKey>(activeKey: T): T => {
31     if (activeKey.primary) {
32         return {
33             ...activeKey,
34             primary: 0,
35         };
36     }
37     return activeKey;
40 export const createAddressKeyLegacy = async ({
41     api,
42     address,
43     keyGenConfig = KEYGEN_CONFIGS[DEFAULT_KEYGEN_TYPE],
44     passphrase,
45     activeKeys,
46     keyTransparencyVerify,
47     addressForwardingID: AddressForwardingID,
48 }: CreateAddressKeyLegacyArguments) => {
49     const { privateKey, privateKeyArmored } = await generateAddressKey({
50         email: address.Email,
51         passphrase,
52         keyGenConfig,
53     });
54     const newActiveKey = await getActiveKeyObject(privateKey, {
55         ID: 'tmp',
56         primary: 1,
57         flags: getDefaultKeyFlags(address),
58     });
59     // no v6 keys allowed with non-migrated keys
60     const updatedActiveKeys = getNormalizedActiveAddressKeys(address, {
61         v4: [newActiveKey, ...activeKeys.v4.map(removePrimary)],
62         v6: [],
63     });
64     const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
65         updatedActiveKeys,
66         address,
67         keyTransparencyVerify
68     );
69     const { Key } = await api(
70         createAddressKeyRoute({
71             AddressID: address.ID,
72             Primary: newActiveKey.primary,
73             PrivateKey: privateKeyArmored,
74             SignedKeyList,
75             AddressForwardingID,
76         })
77     );
78     await onSKLPublishSuccess();
79     newActiveKey.ID = Key.ID;
81     const formerActiveKeys = activeKeys;
82     return [newActiveKey, updatedActiveKeys, formerActiveKeys] as const;
85 interface CreateAddressKeyV2Arguments {
86     api: Api;
87     userKeys: KeyPair[];
88     keyGenConfig?: KeyGenConfig | KeyGenConfigV6;
89     address: Address;
90     activeKeys: ActiveAddressKeysByVersion;
91     keyTransparencyVerify: KeyTransparencyVerify;
94 /**
95  * Generates either a v4 or v6 address key based on `keyGenConfig`.
96  * NB: if a v6 key is requested, this does not take care of also generating a v4 one.
97  */
98 export const createAddressKeyV2 = async ({
99     api,
100     userKeys,
101     keyGenConfig = KEYGEN_CONFIGS[DEFAULT_KEYGEN_TYPE],
102     address,
103     activeKeys,
104     keyTransparencyVerify,
105 }: CreateAddressKeyV2Arguments) => {
106     const { token, encryptedToken, signature } = await getNewAddressKeyToken({ address, userKeys });
108     const { privateKey, privateKeyArmored } = await generateAddressKey({
109         // also typeof keyGenConfig
110         email: address.Email,
111         passphrase: token,
112         keyGenConfig,
113     });
114     const newActiveKey = (await getActiveKeyObject(privateKey, {
115         ID: 'tmp',
116         primary: 1,
117         flags: getDefaultKeyFlags(address),
118     })) as ActiveKeyWithVersion;
120     const toNormalize = isActiveKeyV6(newActiveKey)
121         ? { v4: [...activeKeys.v4], v6: [newActiveKey, ...activeKeys.v6.map(removePrimary)] }
122         : { v4: [newActiveKey, ...activeKeys.v4.map(removePrimary)], v6: [...activeKeys.v6] };
124     const updatedActiveKeys = getNormalizedActiveAddressKeys(address, toNormalize);
126     const [SignedKeyList, onSKLPublishSuccess] = await getSignedKeyListWithDeferredPublish(
127         updatedActiveKeys,
128         address,
129         keyTransparencyVerify
130     );
131     const { Key } = await api(
132         createAddressKeyRouteV2({
133             AddressID: address.ID,
134             Primary: newActiveKey.primary,
135             PrivateKey: privateKeyArmored,
136             SignedKeyList,
137             Signature: signature,
138             Token: encryptedToken,
139         })
140     );
141     // Only once the SKL is successfully posted we add it to the KT commit state.
142     await onSKLPublishSuccess();
143     newActiveKey.ID = Key.ID;
145     const formerActiveKeys = activeKeys;
146     return [newActiveKey, updatedActiveKeys, formerActiveKeys] as const;