Use same lock values as mobile clients
[ProtonMail-WebClient.git] / packages / shared / lib / calendar / crypto / keys / helpers.ts
blob926df8c9ec4d9e2c70ce466f877f045f1c2f900c
1 import { c } from 'ttag';
3 import isTruthy from '@proton/utils/isTruthy';
4 import noop from '@proton/utils/noop';
6 import { hasBit } from '../../../helpers/bitset';
7 import { uint8ArrayToBase64String } from '../../../helpers/encoding';
8 import type { Address, DecryptedKey } from '../../../interfaces';
9 import type {
10     CalendarEvent,
11     CalendarMember,
12     CalendarSetupData,
13     CreateOrResetCalendarPayload,
14     DecryptedCalendarKey,
15 } from '../../../interfaces/calendar';
16 import { CalendarKeyFlags } from '../../../interfaces/calendar';
17 import type { GetAddressKeys } from '../../../interfaces/hooks/GetAddressKeys';
18 import type { GetCalendarKeys } from '../../../interfaces/hooks/GetCalendarKeys';
19 import { getPrimaryKey, splitKeys } from '../../../keys';
20 import { toSessionKey } from '../../../keys/sessionKey';
21 import { getIsAutoAddedInvite } from '../../apiModels';
22 import { readSessionKeys } from '../../deserialize';
24 export const getPrimaryCalendarKey = (calendarKeys: DecryptedCalendarKey[]) => {
25     const primaryKey = calendarKeys.find(({ Key: { Flags } }) => hasBit(Flags, CalendarKeyFlags.PRIMARY));
26     if (!primaryKey) {
27         throw new Error('Calendar primary key not found');
28     }
29     return primaryKey;
32 export const getCalendarEventDecryptionKeys = async ({
33     calendarEvent,
34     addressKeys,
35     calendarKeys,
36     getAddressKeys,
37     getCalendarKeys,
38 }: {
39     calendarEvent: CalendarEvent;
40     addressKeys?: DecryptedKey[];
41     calendarKeys?: DecryptedCalendarKey[];
42     getAddressKeys?: GetAddressKeys;
43     getCalendarKeys?: GetCalendarKeys;
44 }) => {
45     const { CalendarID } = calendarEvent;
46     if (getIsAutoAddedInvite(calendarEvent)) {
47         if (!addressKeys && !getAddressKeys) {
48             return;
49         }
50         return splitKeys(addressKeys || (await getAddressKeys?.(calendarEvent.AddressID))).privateKeys;
51     }
52     if (!calendarKeys && !getCalendarKeys) {
53         return;
54     }
55     return splitKeys(calendarKeys || (await getCalendarKeys?.(CalendarID))).privateKeys;
58 export const getCreationKeys = async ({
59     calendarEvent,
60     newAddressKeys,
61     oldAddressKeys,
62     newCalendarKeys,
63     oldCalendarKeys,
64     decryptedSharedKeyPacket,
65 }: {
66     calendarEvent?: CalendarEvent;
67     newAddressKeys: DecryptedKey[];
68     oldAddressKeys?: DecryptedKey[];
69     newCalendarKeys: DecryptedCalendarKey[];
70     oldCalendarKeys?: DecryptedCalendarKey[];
71     decryptedSharedKeyPacket?: string;
72 }) => {
73     const primaryAddressKey = getPrimaryKey(newAddressKeys);
74     const primaryPrivateAddressKey = primaryAddressKey ? primaryAddressKey.privateKey : undefined;
75     if (!primaryPrivateAddressKey) {
76         throw new Error(c('Error').t`Address primary private key not found`);
77     }
78     const { publicKey: primaryPublicCalendarKey } = getPrimaryCalendarKey(newCalendarKeys);
80     if (!calendarEvent) {
81         return {
82             publicKey: primaryPublicCalendarKey,
83             privateKey: primaryPrivateAddressKey,
84             sharedSessionKey: decryptedSharedKeyPacket ? toSessionKey(decryptedSharedKeyPacket) : undefined,
85         };
86     }
88     const privateKeys = await getCalendarEventDecryptionKeys({
89         calendarEvent,
90         addressKeys: oldAddressKeys,
91         calendarKeys: oldCalendarKeys || newCalendarKeys,
92     });
94     const [sharedSessionKey, calendarSessionKey] = await readSessionKeys({
95         calendarEvent,
96         privateKeys,
97         decryptedSharedKeyPacket,
98     });
100     return {
101         publicKey: primaryPublicCalendarKey,
102         privateKey: primaryPrivateAddressKey,
103         sharedSessionKey,
104         calendarSessionKey,
105     };
108 export const getSharedSessionKey = async ({
109     calendarEvent,
110     calendarKeys,
111     getAddressKeys,
112     getCalendarKeys,
113 }: {
114     calendarEvent: CalendarEvent;
115     calendarKeys?: DecryptedCalendarKey[];
116     getAddressKeys?: GetAddressKeys;
117     getCalendarKeys?: GetCalendarKeys;
118 }) => {
119     try {
120         // we need to decrypt the sharedKeyPacket in Event to obtain the decrypted session key
121         const privateKeys = calendarKeys
122             ? splitKeys(calendarKeys).privateKeys
123             : await getCalendarEventDecryptionKeys({ calendarEvent, getAddressKeys, getCalendarKeys });
124         if (!privateKeys) {
125             return;
126         }
127         const [sessionKey] = await readSessionKeys({ calendarEvent, privateKeys });
129         return sessionKey;
130     } catch (e: any) {
131         noop();
132     }
135 export const getBase64SharedSessionKey = async ({
136     calendarEvent,
137     calendarKeys,
138     getAddressKeys,
139     getCalendarKeys,
140 }: {
141     calendarEvent: CalendarEvent;
142     calendarKeys?: DecryptedCalendarKey[];
143     getAddressKeys?: GetAddressKeys;
144     getCalendarKeys?: GetCalendarKeys;
145 }) => {
146     const sessionKey = await getSharedSessionKey({ calendarEvent, calendarKeys, getAddressKeys, getCalendarKeys });
148     return sessionKey ? uint8ArrayToBase64String(sessionKey.data) : undefined;
151 export const getAddressesMembersMap = (Members: CalendarMember[], Addresses: Address[]) => {
152     return Members.reduce<{ [key: string]: Address }>((acc, Member) => {
153         const Address = Addresses.find(({ Email }) => Email === Member.Email);
154         if (!Address) {
155             return acc;
156         }
157         acc[Member.ID] = Address;
158         return acc;
159     }, {});
162 export const isCalendarSetupData = (
163     payload: CreateOrResetCalendarPayload | CalendarSetupData
164 ): payload is CalendarSetupData => isTruthy(payload.Passphrase.KeyPacket);