1 import type { PublicKeyReference } from '@proton/crypto';
2 import { captureMessage } from '@proton/shared/lib/helpers/sentry';
3 import type { ContactEmail } from '@proton/shared/lib/interfaces/contacts';
4 import type { GetVerificationPreferences } from '@proton/shared/lib/interfaces/hooks/GetVerificationPreferences';
5 import isTruthy from '@proton/utils/isTruthy';
6 import unique from '@proton/utils/unique';
8 import { canonicalizeInternalEmail } from '../helpers/email';
9 import type { CalendarEvent, CalendarEventData } from '../interfaces/calendar';
10 import type { SimpleMap } from '../interfaces/utils';
11 import { CALENDAR_CARD_TYPE } from './constants';
13 const { SIGNED, ENCRYPTED_AND_SIGNED } = CALENDAR_CARD_TYPE;
15 export const withNormalizedAuthor = (x: CalendarEventData) => ({
17 Author: canonicalizeInternalEmail(x.Author),
19 export const withNormalizedAuthors = (x: CalendarEventData[]) => {
23 return x.map(withNormalizedAuthor);
26 interface GetAuthorPublicKeysMap {
28 getVerificationPreferences: GetVerificationPreferences;
29 contactEmailsMap: SimpleMap<ContactEmail>;
32 export const getAuthorPublicKeysMap = async ({
34 getVerificationPreferences,
36 }: GetAuthorPublicKeysMap) => {
37 const publicKeysMap: SimpleMap<PublicKeyReference | PublicKeyReference[]> = {};
38 const authors = unique(
39 [...event.SharedEvents, ...event.CalendarEvents]
40 .map(({ Author, Type }) => {
41 if (![SIGNED, ENCRYPTED_AND_SIGNED].includes(Type)) {
42 // no need to fetch keys in this case
45 return canonicalizeInternalEmail(Author);
50 const promises = authors.map(async (author) => {
52 const { verifyingKeys } = await getVerificationPreferences({ email: author, contactEmailsMap });
53 publicKeysMap[author] = verifyingKeys;
54 } catch (error: any) {
55 // We're seeing too many unexpected offline errors in the GET /keys route.
56 // We log them to Sentry and ignore them here (no verification will take place in these cases)
57 const { ID, CalendarID } = event;
58 const errorMessage = error?.message || 'Unknown error';
59 captureMessage('Unexpected error verifying event signature', {
60 extra: { message: errorMessage, eventID: ID, calendarID: CalendarID },
64 await Promise.all(promises);