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';
12 } from '@proton/key-transparency';
17 KeyTransparencyCommit,
18 KeyTransparencyVerify,
21 } from '@proton/shared/lib/interfaces';
22 import { KeyTransparencyActivation } from '@proton/shared/lib/interfaces';
24 interface CreatedSKL {
27 signedKeyList: SignedKeyList;
28 creationTimestamp: number;
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
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) {
48 createdSKLs.current.push({
50 revision: address.SignedKeyList?.Revision,
52 creationTimestamp: +serverTime(),
58 const keyTransparencyCommit: KeyTransparencyCommit = useCallback(async (userKeys: DecryptedKey[]) => {
60 const ktActivation = await getKTActivation();
61 if (ktActivation === KeyTransparencyActivation.DISABLED) {
65 if (!createdSKLs.current.length) {
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,
85 creationTimestamp: savedSKL.creationTimestamp,
86 expectedMinEpochID: correspondingSKL.ExpectedMinEpochID,
87 revision: correspondingSKL.Revision,
88 email: savedSKL.address.Email,
89 data: savedSKL.signedKeyList.Data,
91 await commitSKLToLS(ktBlob, privateKeys, ktLSAPI, user.ID, savedSKL.address.ID);
93 createdSKLs.current = [];
94 } catch (error: any) {
95 ktSentryReportError(error, { context: 'KeyTransparencyCommit' });
100 keyTransparencyVerify,
101 keyTransparencyCommit,
105 export default useKTVerifier;