1 import { serverTime } from '@proton/crypto';
2 import { commitSKLToLS, fetchSignedKeyLists, ktSentryReport, ktSentryReportError } from '@proton/key-transparency';
4 import type { Address, DecryptedKey, PreAuthKTVerifier, PreAuthKTVerify, SignedKeyList } from '../interfaces';
5 import { KeyTransparencyActivation } from '../interfaces';
6 import { getDefaultKTLS } from './defaults';
9 * Return a KT verifier for when getSignedKeyList is called before apps are properly mounted,
10 * e.g. signup or login, such that self audit couldn't have run and user keys are not directly accessible
12 const createPreAuthKTVerifier = (ktActivation: KeyTransparencyActivation): PreAuthKTVerifier => {
13 interface CreatedSKL {
16 userKeys: DecryptedKey[];
17 signedKeyList: SignedKeyList;
18 creationTimestamp: number;
21 var createdSKLs: CreatedSKL[] = [];
23 const ktLSAPI = getDefaultKTLS();
25 const preAuthKTVerify: PreAuthKTVerify = (userKeys: DecryptedKey[]) => async (address, signedKeyList) => {
26 if (ktActivation === KeyTransparencyActivation.DISABLED) {
31 revision: address.SignedKeyList?.Revision,
34 creationTimestamp: +serverTime(),
38 const preAuthKTCommit: PreAuthKTVerifier['preAuthKTCommit'] = async (userID, api) => {
40 if (ktActivation === KeyTransparencyActivation.DISABLED) {
44 if (!createdSKLs.length) {
48 for (const savedSKL of createdSKLs) {
49 const allSKLs = await fetchSignedKeyLists(api, savedSKL.revision ?? 0, savedSKL.address.Email);
50 const correspondingSKL = allSKLs.find((skl) => savedSKL.signedKeyList.Data == skl.Data);
51 if (!correspondingSKL || !correspondingSKL.Revision || !correspondingSKL.ExpectedMinEpochID) {
52 ktSentryReport('Could not find new SKL revision and expectedMinEpochID', {
53 email: savedSKL.address.Email,
57 const privateKeys = savedSKL.userKeys.map(({ privateKey }) => privateKey);
59 creationTimestamp: savedSKL.creationTimestamp,
60 expectedMinEpochID: correspondingSKL.ExpectedMinEpochID,
61 revision: correspondingSKL.Revision,
62 email: savedSKL.address.Email,
63 data: savedSKL.signedKeyList.Data,
65 await commitSKLToLS(ktBlob, privateKeys, ktLSAPI, userID, savedSKL.address.ID);
68 } catch (error: any) {
69 ktSentryReportError(error, { context: 'preAuthKTCommit' });
79 export default createPreAuthKTVerifier;