Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / components / hooks / useGetEncryptionPreferences.ts
blobd8b873454983b042b8895c7b010ac7b320d4c427
1 import { useCallback } from 'react';
3 import { useGetAddressKeys } from '@proton/account/addressKeys/hooks';
4 import { useGetAddresses } from '@proton/account/addresses/hooks';
5 import { useGetUserKeys } from '@proton/account/userKeys/hooks';
6 import { useGetMailSettings } from '@proton/mail/mailSettings/hooks';
7 import getPublicKeysVcardHelper from '@proton/shared/lib/api/helpers/getPublicKeysVcardHelper';
8 import { MINUTE, RECIPIENT_TYPES } from '@proton/shared/lib/constants';
9 import { getSelfSendAddresses } from '@proton/shared/lib/helpers/address';
10 import { canonicalizeEmail, canonicalizeInternalEmail } from '@proton/shared/lib/helpers/email';
11 import type { ApiKeysConfig, PinnedKeysConfig, SelfSend } from '@proton/shared/lib/interfaces';
12 import { KT_VERIFICATION_STATUS } from '@proton/shared/lib/interfaces';
13 import type { GetEncryptionPreferences } from '@proton/shared/lib/interfaces/hooks/GetEncryptionPreferences';
14 import { getKeyHasFlagsToEncrypt } from '@proton/shared/lib/keys';
15 import { getActiveKeys } from '@proton/shared/lib/keys/getActiveKeys';
16 import { splitKeys } from '@proton/shared/lib/keys/keys';
17 import { getContactPublicKeyModel, getKeyEncryptionCapableStatus } from '@proton/shared/lib/keys/publicKeys';
18 import extractEncryptionPreferences from '@proton/shared/lib/mail/encryptionPreferences';
20 import useApi from './useApi';
21 import useCache from './useCache';
22 import { getPromiseValue } from './useCachedModelResult';
23 import useGetPublicKeysForInbox from './useGetPublicKeysForInbox';
25 export const CACHE_KEY = 'ENCRYPTION_PREFERENCES';
27 const DEFAULT_LIFETIME = 5 * MINUTE;
29 /**
30  * Given an email address and the user mail settings, return the encryption preferences for sending to that email.
31  * The logic for how those preferences are determined is laid out in the
32  * Confluence document 'Encryption preferences for outgoing email'.
33  * NB: the current logic does not handle internal address keys belonging to external accounts, since these keys are not used by Inbox.
34  */
35 const useGetEncryptionPreferences = () => {
36     const api = useApi();
37     const cache = useCache();
38     const getAddresses = useGetAddresses();
39     const getUserKeys = useGetUserKeys();
40     const getAddressKeys = useGetAddressKeys();
41     const getPublicKeysForInbox = useGetPublicKeysForInbox();
42     const getMailSettings = useGetMailSettings();
44     const getEncryptionPreferences = useCallback<GetEncryptionPreferences>(
45         async ({ email, lifetime, contactEmailsMap, intendedForEmail = true }) => {
46             const [addresses, mailSettings] = await Promise.all([getAddresses(), getMailSettings()]);
47             const canonicalEmail = canonicalizeInternalEmail(email);
48             const selfAddress = getSelfSendAddresses(addresses).find(
49                 ({ Email }) => canonicalizeInternalEmail(Email) === canonicalEmail
50             );
51             let selfSend: SelfSend | undefined;
52             let apiKeysConfig: ApiKeysConfig;
53             let pinnedKeysConfig: PinnedKeysConfig;
54             if (selfAddress) {
55                 // we do not trust the public keys in ownAddress (they will be deprecated in the API response soon anyway)
56                 const selfAddressKeys = await getAddressKeys(selfAddress.ID);
57                 const primaryAddressKey = (
58                     await getActiveKeys(selfAddress, selfAddress.SignedKeyList, selfAddress.Keys, selfAddressKeys)
59                 )[0];
60                 const selfPublicKey = primaryAddressKey?.publicKey;
61                 const canEncrypt = selfPublicKey ? await getKeyEncryptionCapableStatus(selfPublicKey) : undefined;
62                 const canSend = canEncrypt && getKeyHasFlagsToEncrypt(primaryAddressKey.flags);
63                 selfSend = { address: selfAddress, publicKey: selfPublicKey, canSend };
64                 // For own addresses, we use the decrypted keys in selfSend and do not fetch any data from the API
65                 apiKeysConfig = {
66                     publicKeys: [],
67                     RecipientType: RECIPIENT_TYPES.TYPE_INTERNAL,
68                     ktVerificationResult: { status: KT_VERIFICATION_STATUS.VERIFIED_KEYS },
69                 };
70                 pinnedKeysConfig = { pinnedKeys: [], isContact: false };
71             } else {
72                 const { publicKeys } = splitKeys(await getUserKeys());
73                 apiKeysConfig = await getPublicKeysForInbox({
74                     email,
75                     internalKeysOnly: intendedForEmail === false,
76                     includeInternalKeysWithE2EEDisabledForMail: intendedForEmail === false,
77                     lifetime,
78                     noCache: !lifetime,
79                 });
80                 const isInternal = apiKeysConfig.RecipientType === RECIPIENT_TYPES.TYPE_INTERNAL;
81                 pinnedKeysConfig = await getPublicKeysVcardHelper(api, email, publicKeys, isInternal, contactEmailsMap);
82             }
83             const publicKeyModel = await getContactPublicKeyModel({
84                 emailAddress: email,
85                 apiKeysConfig,
86                 pinnedKeysConfig,
87             });
88             return extractEncryptionPreferences(publicKeyModel, mailSettings, selfSend);
89         },
90         [api, getAddressKeys, getAddresses, getPublicKeysForInbox, getMailSettings]
91     );
93     return useCallback<GetEncryptionPreferences>(
94         ({ email, lifetime = DEFAULT_LIFETIME, contactEmailsMap, intendedForEmail }) => {
95             if (!cache.has(CACHE_KEY)) {
96                 cache.set(CACHE_KEY, new Map());
97             }
98             const subCache = cache.get(CACHE_KEY);
99             // By normalizing email here, we consider that it could not exist different encryption preferences
100             // For 2 addresses identical but for the cases.
101             // If a provider does different one day, this would have to evolve.
102             const canonicalEmail = canonicalizeEmail(email);
103             const miss = () =>
104                 getEncryptionPreferences({
105                     email: canonicalEmail,
106                     intendedForEmail,
107                     lifetime,
108                     contactEmailsMap,
109                 });
110             return getPromiseValue(subCache, canonicalEmail, miss, lifetime);
111         },
112         [cache, getEncryptionPreferences]
113     );
116 export default useGetEncryptionPreferences;