Merge branch 'DRVDOC-1260' into 'main'
[ProtonMail-WebClient.git] / packages / components / containers / keyTransparency / useKTVerifier.ts
blob07209ba2a29816e993e844470061a36145340252
1 import { useCallback, useRef } from 'react';
3 import { useGetKTActivation } from '@proton/components/containers/keyTransparency/useKTActivation';
4 import useConfig from '@proton/components/hooks/useConfig';
5 import { serverTime } from '@proton/crypto';
6 import {
7     commitSKLToLS,
8     fetchSignedKeyLists,
9     getKTLocalStorage,
10     ktSentryReport,
11     ktSentryReportError,
12 } from '@proton/key-transparency';
13 import type {
14     Address,
15     Api,
16     DecryptedKey,
17     KeyTransparencyCommit,
18     KeyTransparencyVerify,
19     SignedKeyList,
20     UserModel,
21 } from '@proton/shared/lib/interfaces';
22 import { KeyTransparencyActivation } from '@proton/shared/lib/interfaces';
24 interface CreatedSKL {
25     address: Address;
26     revision?: number;
27     signedKeyList: SignedKeyList;
28     creationTimestamp: number;
31 /**
32  * Return a KT verifier for when the state exists, i.e. we are inside the apps
33  * and therefore self audit could run and the normal flow of verification can be performed
34  */
35 const useKTVerifier = (api: Api, getUser: () => Promise<UserModel>) => {
36     const { APP_NAME } = useConfig();
37     const getKTActivation = useGetKTActivation();
39     const createdSKLs = useRef<CreatedSKL[]>([]);
41     const keyTransparencyVerify: KeyTransparencyVerify = useCallback(
42         async (address: Address, signedKeyList: SignedKeyList) => {
43             const ktActivation = await getKTActivation();
44             if (ktActivation === KeyTransparencyActivation.DISABLED) {
45                 return;
46             }
48             createdSKLs.current.push({
49                 address,
50                 revision: address.SignedKeyList?.Revision,
51                 signedKeyList,
52                 creationTimestamp: +serverTime(),
53             });
54         },
55         []
56     );
58     const keyTransparencyCommit: KeyTransparencyCommit = useCallback(async (userKeys: DecryptedKey[]) => {
59         try {
60             const ktActivation = await getKTActivation();
61             if (ktActivation === KeyTransparencyActivation.DISABLED) {
62                 return;
63             }
65             if (!createdSKLs.current.length) {
66                 return;
67             }
69             const user = await getUser();
71             const privateKeys = userKeys.map(({ privateKey }) => privateKey);
73             const ktLSAPIPromise = getKTLocalStorage(APP_NAME);
74             const ktLSAPI = await ktLSAPIPromise;
75             for (const savedSKL of createdSKLs.current) {
76                 const allSKLs = await fetchSignedKeyLists(api, savedSKL?.revision ?? 0, savedSKL.address.Email);
77                 const correspondingSKL = allSKLs.find((skl) => savedSKL.signedKeyList.Data == skl.Data);
78                 if (!correspondingSKL || !correspondingSKL.Revision || !correspondingSKL.ExpectedMinEpochID) {
79                     ktSentryReport('Could not find new SKL revision and expectedMinEpochID', {
80                         email: savedSKL.address.Email,
81                     });
82                     return;
83                 }
84                 const ktBlob = {
85                     creationTimestamp: savedSKL.creationTimestamp,
86                     expectedMinEpochID: correspondingSKL.ExpectedMinEpochID,
87                     revision: correspondingSKL.Revision,
88                     email: savedSKL.address.Email,
89                     data: savedSKL.signedKeyList.Data,
90                 };
91                 await commitSKLToLS(ktBlob, privateKeys, ktLSAPI, user.ID, savedSKL.address.ID);
92             }
93             createdSKLs.current = [];
94         } catch (error: any) {
95             ktSentryReportError(error, { context: 'KeyTransparencyCommit' });
96         }
97     }, []);
99     return {
100         keyTransparencyVerify,
101         keyTransparencyCommit,
102     };
105 export default useKTVerifier;