Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / shared / lib / api / helpers / getPublicKeysEmailHelperWithKT.ts
blob8a1b20a190d03a8d5f365f65bad2db9efbcde06b
1 import { RECIPIENT_TYPES } from '../../constants';
2 import { API_CUSTOM_ERROR_CODES } from '../../errors';
3 import type { Api, ApiKeysConfig, VerifyOutboundPublicKeys } from '../../interfaces';
4 import { KT_VERIFICATION_STATUS } from '../../interfaces';
5 import { getExternalKeys, getInternalKeys, getMailCapableKeys, supportsMail } from '../../keys';
6 import { getAndVerifyApiKeys } from './getAndVerifyApiKeys';
8 const { KEY_GET_ADDRESS_MISSING, KEY_GET_DOMAIN_EXTERNAL, KEY_GET_INPUT_INVALID, KEY_GET_INVALID_KT } =
9     API_CUSTOM_ERROR_CODES;
10 const EMAIL_ERRORS = [KEY_GET_ADDRESS_MISSING, KEY_GET_DOMAIN_EXTERNAL, KEY_GET_INPUT_INVALID, KEY_GET_INVALID_KT];
12 const getFailedOrUnVerified = (failed: boolean) =>
13     failed ? KT_VERIFICATION_STATUS.VERIFICATION_FAILED : KT_VERIFICATION_STATUS.UNVERIFIED_KEYS;
15 /**
16  * This is an Inbox-specific helper, as it discards address keys from external addresses, which are not used by Inbox at the moment.
17  * If support for returning such keys is added, it's important to provide a way to distinguish them from Unverified keys (e.g. from WKD)
18  * which can also be present for external accounts.
19  */
20 const getPublicKeysEmailHelperWithKT = async ({
21     email,
22     internalKeysOnly,
23     includeInternalKeysWithE2EEDisabledForMail,
24     api,
25     verifyOutboundPublicKeys,
26     silence,
27     noCache,
28 }: {
29     email: string;
30     internalKeysOnly: boolean;
31     includeInternalKeysWithE2EEDisabledForMail: boolean;
32     api: Api;
33     verifyOutboundPublicKeys: VerifyOutboundPublicKeys | null;
34     silence?: boolean;
35     noCache?: boolean;
36 }): Promise<ApiKeysConfig> => {
37     try {
38         const {
39             addressKeys,
40             catchAllKeys,
41             unverifiedKeys,
42             addressKTResult,
43             catchAllKTResult,
44             hasValidProtonMX,
45             ...rest
46         } = await getAndVerifyApiKeys({
47             api,
48             email,
49             internalKeysOnly,
50             verifyOutboundPublicKeys,
51             skipVerificationOfExternalDomains: !includeInternalKeysWithE2EEDisabledForMail, // as we know we are in a Mail context
52             silence,
53             noCache,
54         });
56         // First we use verified internal address keys from internal recipients.
57         // Users with internal custom domains but with bad MX setup will not be properly identifiable if they also don't have address keys
58         // valid for mail encryption. For the current uses of this helper, this was deemed ok.
59         if (addressKeys.length > 0) {
60             const intendedForMailEncryption = !includeInternalKeysWithE2EEDisabledForMail;
61             // E2EE is disabled with external forwarding, as well as in some setups with custom addresses.
62             // unclear when/if it can happen that some keys have e2ee-disabled and some are not, but for now we cover the case.
63             const addressKeysForMailEncryption = addressKeys.filter((key) => supportsMail(key.flags));
64             const hasDisabledE2EEForMail = addressKeysForMailEncryption.length === 0;
66             if (intendedForMailEncryption && addressKeysForMailEncryption.length > 0) {
67                 return {
68                     publicKeys: addressKeysForMailEncryption,
69                     ktVerificationResult: addressKTResult,
70                     RecipientType: RECIPIENT_TYPES.TYPE_INTERNAL,
71                     isCatchAll: false,
72                     isInternalWithDisabledE2EEForMail: false,
73                     ...rest,
74                 };
75             } else if (intendedForMailEncryption && hasDisabledE2EEForMail && hasValidProtonMX) {
76                 // All keys are disabled for E2EE in mail, hence the recipient may be treated as external
77                 return {
78                     publicKeys: [],
79                     RecipientType: RECIPIENT_TYPES.TYPE_EXTERNAL,
80                     isCatchAll: false,
81                     isInternalWithDisabledE2EEForMail: true,
82                     ktVerificationResult: {
83                         status: getFailedOrUnVerified(
84                             addressKTResult?.status === KT_VERIFICATION_STATUS.VERIFICATION_FAILED
85                         ),
86                     },
87                     ...rest,
88                 };
89             } else if (!intendedForMailEncryption && (addressKeysForMailEncryption.length > 0 || hasValidProtonMX)) {
90                 return {
91                     publicKeys: addressKeys, // we checked `addressKeysForMailEncryption` to determine if the recipient is internal, but we return all keys as that's requested by the caller
92                     ktVerificationResult: addressKTResult,
93                     RecipientType: RECIPIENT_TYPES.TYPE_INTERNAL, // as e2ee-disabled flags are ignored, then from the perspective of the caller, this is an internal recipient
94                     isCatchAll: false,
95                     isInternalWithDisabledE2EEForMail: hasDisabledE2EEForMail, // unused, could also be set to undefined
96                     ...rest,
97                 };
98             } // else, the recipient is believed external, and no address keys are returned
99         }
101         const keysChangedRecently = !!addressKTResult?.keysChangedRecently || !!catchAllKTResult?.keysChangedRecently;
102         const verificationFailed =
103             addressKTResult?.status === KT_VERIFICATION_STATUS.VERIFICATION_FAILED ||
104             catchAllKTResult?.status === KT_VERIFICATION_STATUS.VERIFICATION_FAILED;
106         // Then we check if there are unverified internal address keys
107         if (unverifiedKeys) {
108             const mailCapableUnverifiedInternalKeys = getMailCapableKeys(getInternalKeys(unverifiedKeys));
109             if (mailCapableUnverifiedInternalKeys.length != 0) {
110                 const status = getFailedOrUnVerified(verificationFailed);
111                 return {
112                     publicKeys: mailCapableUnverifiedInternalKeys,
113                     ktVerificationResult: { status, keysChangedRecently },
114                     RecipientType: RECIPIENT_TYPES.TYPE_INTERNAL,
115                     isCatchAll: false,
116                     isInternalWithDisabledE2EEForMail: false,
117                     ...rest,
118                 };
119             }
120         }
122         // Then we check if there are internal catchall keys
123         if (catchAllKeys) {
124             const mailCapableCatchAllKeys = getMailCapableKeys(catchAllKeys);
125             if (mailCapableCatchAllKeys.length != 0) {
126                 const status = verificationFailed
127                     ? KT_VERIFICATION_STATUS.VERIFICATION_FAILED
128                     : catchAllKTResult?.status;
129                 const ktVerificationResult = catchAllKTResult ? { status: status!, keysChangedRecently } : undefined;
130                 return {
131                     publicKeys: mailCapableCatchAllKeys,
132                     ktVerificationResult,
133                     RecipientType: RECIPIENT_TYPES.TYPE_INTERNAL,
134                     isCatchAll: true,
135                     isInternalWithDisabledE2EEForMail: false,
136                     ...rest,
137                 };
138             }
139         }
141         const ktVerificationResult = {
142             status: getFailedOrUnVerified(verificationFailed),
143             keysChangedRecently,
144         };
146         // Finally we check if there are external unverified keys
147         if (unverifiedKeys) {
148             const mailCapableUnverifiedExternalKeys = getMailCapableKeys(getExternalKeys(unverifiedKeys));
149             if (mailCapableUnverifiedExternalKeys.length != 0) {
150                 const firstUnverifiedKey = mailCapableUnverifiedExternalKeys[0];
151                 return {
152                     publicKeys: [firstUnverifiedKey],
153                     ktVerificationResult,
154                     RecipientType: RECIPIENT_TYPES.TYPE_EXTERNAL,
155                     isCatchAll: false,
156                     isInternalWithDisabledE2EEForMail: false,
157                     ...rest,
158                 };
159             }
160         }
161         return {
162             publicKeys: [],
163             RecipientType: RECIPIENT_TYPES.TYPE_EXTERNAL,
164             ktVerificationResult,
165             isCatchAll: false,
166             isInternalWithDisabledE2EEForMail: false,
167             ...rest,
168         };
169     } catch (error: any) {
170         const { data = {} } = error;
171         if (data.Code === KEY_GET_DOMAIN_EXTERNAL) {
172             // It's an external recipient
173             return {
174                 publicKeys: [],
175                 RecipientType: RECIPIENT_TYPES.TYPE_EXTERNAL,
176                 isCatchAll: false,
177                 isInternalWithDisabledE2EEForMail: false,
178             };
179         }
180         if (EMAIL_ERRORS.includes(data.Code)) {
181             return {
182                 publicKeys: [],
183                 Errors: [data.Error],
184             };
185         }
186         throw error;
187     }
190 export default getPublicKeysEmailHelperWithKT;