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';
13 CreateOrResetCalendarPayload,
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));
27 throw new Error('Calendar primary key not found');
32 export const getCalendarEventDecryptionKeys = async ({
39 calendarEvent: CalendarEvent;
40 addressKeys?: DecryptedKey[];
41 calendarKeys?: DecryptedCalendarKey[];
42 getAddressKeys?: GetAddressKeys;
43 getCalendarKeys?: GetCalendarKeys;
45 const { CalendarID } = calendarEvent;
46 if (getIsAutoAddedInvite(calendarEvent)) {
47 if (!addressKeys && !getAddressKeys) {
50 return splitKeys(addressKeys || (await getAddressKeys?.(calendarEvent.AddressID))).privateKeys;
52 if (!calendarKeys && !getCalendarKeys) {
55 return splitKeys(calendarKeys || (await getCalendarKeys?.(CalendarID))).privateKeys;
58 export const getCreationKeys = async ({
64 decryptedSharedKeyPacket,
66 calendarEvent?: CalendarEvent;
67 newAddressKeys: DecryptedKey[];
68 oldAddressKeys?: DecryptedKey[];
69 newCalendarKeys: DecryptedCalendarKey[];
70 oldCalendarKeys?: DecryptedCalendarKey[];
71 decryptedSharedKeyPacket?: string;
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`);
78 const { publicKey: primaryPublicCalendarKey } = getPrimaryCalendarKey(newCalendarKeys);
82 publicKey: primaryPublicCalendarKey,
83 privateKey: primaryPrivateAddressKey,
84 sharedSessionKey: decryptedSharedKeyPacket ? toSessionKey(decryptedSharedKeyPacket) : undefined,
88 const privateKeys = await getCalendarEventDecryptionKeys({
90 addressKeys: oldAddressKeys,
91 calendarKeys: oldCalendarKeys || newCalendarKeys,
94 const [sharedSessionKey, calendarSessionKey] = await readSessionKeys({
97 decryptedSharedKeyPacket,
101 publicKey: primaryPublicCalendarKey,
102 privateKey: primaryPrivateAddressKey,
108 export const getSharedSessionKey = async ({
114 calendarEvent: CalendarEvent;
115 calendarKeys?: DecryptedCalendarKey[];
116 getAddressKeys?: GetAddressKeys;
117 getCalendarKeys?: GetCalendarKeys;
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 });
127 const [sessionKey] = await readSessionKeys({ calendarEvent, privateKeys });
135 export const getBase64SharedSessionKey = async ({
141 calendarEvent: CalendarEvent;
142 calendarKeys?: DecryptedCalendarKey[];
143 getAddressKeys?: GetAddressKeys;
144 getCalendarKeys?: GetCalendarKeys;
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);
157 acc[Member.ID] = Address;
162 export const isCalendarSetupData = (
163 payload: CreateOrResetCalendarPayload | CalendarSetupData
164 ): payload is CalendarSetupData => isTruthy(payload.Passphrase.KeyPacket);