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;
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.
20 const getPublicKeysEmailHelperWithKT = async ({
23 includeInternalKeysWithE2EEDisabledForMail,
25 verifyOutboundPublicKeys,
30 internalKeysOnly: boolean;
31 includeInternalKeysWithE2EEDisabledForMail: boolean;
33 verifyOutboundPublicKeys: VerifyOutboundPublicKeys | null;
36 }): Promise<ApiKeysConfig> => {
46 } = await getAndVerifyApiKeys({
50 verifyOutboundPublicKeys,
51 skipVerificationOfExternalDomains: !includeInternalKeysWithE2EEDisabledForMail, // as we know we are in a Mail context
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) {
68 publicKeys: addressKeysForMailEncryption,
69 ktVerificationResult: addressKTResult,
70 RecipientType: RECIPIENT_TYPES.TYPE_INTERNAL,
72 isInternalWithDisabledE2EEForMail: false,
75 } else if (intendedForMailEncryption && hasDisabledE2EEForMail && hasValidProtonMX) {
76 // All keys are disabled for E2EE in mail, hence the recipient may be treated as external
79 RecipientType: RECIPIENT_TYPES.TYPE_EXTERNAL,
81 isInternalWithDisabledE2EEForMail: true,
82 ktVerificationResult: {
83 status: getFailedOrUnVerified(
84 addressKTResult?.status === KT_VERIFICATION_STATUS.VERIFICATION_FAILED
89 } else if (!intendedForMailEncryption && (addressKeysForMailEncryption.length > 0 || hasValidProtonMX)) {
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
95 isInternalWithDisabledE2EEForMail: hasDisabledE2EEForMail, // unused, could also be set to undefined
98 } // else, the recipient is believed external, and no address keys are returned
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);
112 publicKeys: mailCapableUnverifiedInternalKeys,
113 ktVerificationResult: { status, keysChangedRecently },
114 RecipientType: RECIPIENT_TYPES.TYPE_INTERNAL,
116 isInternalWithDisabledE2EEForMail: false,
122 // Then we check if there are internal catchall keys
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;
131 publicKeys: mailCapableCatchAllKeys,
132 ktVerificationResult,
133 RecipientType: RECIPIENT_TYPES.TYPE_INTERNAL,
135 isInternalWithDisabledE2EEForMail: false,
141 const ktVerificationResult = {
142 status: getFailedOrUnVerified(verificationFailed),
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];
152 publicKeys: [firstUnverifiedKey],
153 ktVerificationResult,
154 RecipientType: RECIPIENT_TYPES.TYPE_EXTERNAL,
156 isInternalWithDisabledE2EEForMail: false,
163 RecipientType: RECIPIENT_TYPES.TYPE_EXTERNAL,
164 ktVerificationResult,
166 isInternalWithDisabledE2EEForMail: false,
169 } catch (error: any) {
170 const { data = {} } = error;
171 if (data.Code === KEY_GET_DOMAIN_EXTERNAL) {
172 // It's an external recipient
175 RecipientType: RECIPIENT_TYPES.TYPE_EXTERNAL,
177 isInternalWithDisabledE2EEForMail: false,
180 if (EMAIL_ERRORS.includes(data.Code)) {
183 Errors: [data.Error],
190 export default getPublicKeysEmailHelperWithKT;