Page MenuHomePhabricator

D12838.diff
No OneTemporary

D12838.diff

diff --git a/desktop/src/main.js b/desktop/src/main.js
--- a/desktop/src/main.js
+++ b/desktop/src/main.js
@@ -306,12 +306,16 @@
const handleEncryptedNotification = (
encryptedPayload: string,
- keyserverID: string,
+ senderDeviceDescriptor:
+ | { +keyserverID: string }
+ | { +senderDeviceID: string },
+ type: string,
) => {
if (mainWindow) {
mainWindow.webContents.send('on-encrypted-notification', {
encryptedPayload,
- keyserverID,
+ senderDeviceDescriptor,
+ type,
});
}
};
diff --git a/desktop/src/push-notifications.js b/desktop/src/push-notifications.js
--- a/desktop/src/push-notifications.js
+++ b/desktop/src/push-notifications.js
@@ -131,29 +131,52 @@
handleClick: (threadID?: string) => void,
handleEncryptedNotification: (
encryptedPayload: string,
- keyserverID: string,
+ senderDeviceDescriptor:
+ | { +keyserverID: string }
+ | { +senderDeviceID: string },
+ type: string,
) => void,
) {
if (process.platform === 'darwin') {
pushNotifications.on('received-apns-notification', (event, userInfo) => {
- const { keyserverID, encryptedPayload } = userInfo;
+ const { keyserverID, senderDeviceID, encryptedPayload, type } = userInfo;
if (
typeof keyserverID === 'string' &&
- typeof encryptedPayload === 'string'
+ typeof encryptedPayload === 'string' &&
+ typeof type === 'string'
) {
- handleEncryptedNotification(encryptedPayload, keyserverID);
+ handleEncryptedNotification(encryptedPayload, { keyserverID }, type);
+ return;
+ }
+
+ if (
+ typeof senderDeviceID === 'string' &&
+ typeof encryptedPayload === 'string' &&
+ typeof type === 'string'
+ ) {
+ handleEncryptedNotification(encryptedPayload, { senderDeviceID }, type);
return;
}
showNewNotification(userInfo, handleClick);
});
} else if (process.platform === 'win32') {
windowsPushNotifEventEmitter.on('received-wns-notification', payload => {
- const { keyserverID, encryptedPayload } = payload;
+ const { keyserverID, senderDeviceID, encryptedPayload, type } = payload;
if (
typeof keyserverID === 'string' &&
- typeof encryptedPayload === 'string'
+ typeof encryptedPayload === 'string' &&
+ typeof type === 'string'
+ ) {
+ handleEncryptedNotification(encryptedPayload, { keyserverID }, type);
+ return;
+ }
+
+ if (
+ typeof senderDeviceID === 'string' &&
+ typeof encryptedPayload === 'string' &&
+ typeof type === 'string'
) {
- handleEncryptedNotification(encryptedPayload, keyserverID);
+ handleEncryptedNotification(encryptedPayload, { senderDeviceID }, type);
return;
}
showNewNotification(payload, handleClick);
diff --git a/lib/types/electron-types.js b/lib/types/electron-types.js
--- a/lib/types/electron-types.js
+++ b/lib/types/electron-types.js
@@ -1,5 +1,7 @@
// @flow
+import type { SenderDeviceDescriptor } from './notif-types';
+
type OnNavigateListener = ({
+canGoBack: boolean,
+canGoForward: boolean,
@@ -13,7 +15,8 @@
type OnEncryptedNotificationListener = (data: {
encryptedPayload: string,
- keyserverID?: string,
+ type: string,
+ senderDeviceDescriptor: SenderDeviceDescriptor,
}) => mixed;
export type ElectronBridge = {
diff --git a/web/push-notif/notif-crypto-utils.js b/web/push-notif/notif-crypto-utils.js
--- a/web/push-notif/notif-crypto-utils.js
+++ b/web/push-notif/notif-crypto-utils.js
@@ -14,12 +14,17 @@
import type {
PlainTextWebNotification,
EncryptedWebNotification,
+ SenderDeviceDescriptor,
} from 'lib/types/notif-types.js';
import { getCookieIDFromCookie } from 'lib/utils/cookie-utils.js';
import { getMessageForException } from 'lib/utils/errors.js';
import { promiseAll } from 'lib/utils/promises.js';
import { assertWithValidator } from 'lib/utils/validation-utils.js';
+import {
+ fetchAuthMetadata,
+ getNotifsInboundKeysForDeviceID,
+} from './services-client.js';
import {
type EncryptedData,
decryptData,
@@ -92,6 +97,16 @@
return data;
}
+async function deserializeEncryptedDataOptional<T>(
+ encryptedData: ?EncryptedData,
+ encryptionKey: ?CryptoKey,
+): Promise<?T> {
+ if (!encryptedData || !encryptionKey) {
+ return undefined;
+ }
+ return deserializeEncryptedData<T>(encryptedData, encryptionKey);
+}
+
async function serializeUnencryptedData<T>(
data: T,
encryptionKey: CryptoKey,
@@ -116,6 +131,15 @@
return await importJWKKey(((cryptoKey: any): SubtleCrypto$JsonWebKey));
}
+async function validateCryptoKeyOptional(
+ cryptoKey: ?CryptoKey | ?SubtleCrypto$JsonWebKey,
+): Promise<?CryptoKey> {
+ if (!cryptoKey) {
+ return undefined;
+ }
+ return validateCryptoKey(cryptoKey);
+}
+
async function getCryptoKeyPersistentForm(
cryptoKey: CryptoKey,
): Promise<CryptoKey | SubtleCrypto$JsonWebKey> {
@@ -128,6 +152,95 @@
return await exportKeyToJWK(cryptoKey);
}
+async function getNotifsAccountWithOlmData(
+ senderDeviceDescriptor: SenderDeviceDescriptor,
+): Promise<{
+ +encryptedOlmData: ?EncryptedData,
+ +encryptionKey: ?CryptoKey,
+ +olmDataKey: string,
+ +encryptionKeyDBLabel: string,
+ +encryptedOlmAccount: ?EncryptedData,
+ +accountEncryptionKey: ?CryptoKey,
+ +synchronizationValue: ?string,
+}> {
+ let olmDataKey;
+ let olmDataEncryptionKeyDBLabel;
+ const { keyserverID, senderDeviceID } = senderDeviceDescriptor;
+
+ if (keyserverID) {
+ const olmDBKeys = await getNotifsOlmSessionDBKeys(keyserverID);
+ const { olmDataKey: fetchedOlmDataKey, encryptionKeyDBKey } = olmDBKeys;
+ olmDataKey = fetchedOlmDataKey;
+ olmDataEncryptionKeyDBLabel = encryptionKeyDBKey;
+ } else {
+ invariant(
+ senderDeviceID,
+ 'keyserverID or SenderDeviceID must be present to decrypt a notif',
+ );
+ olmDataKey = getOlmDataKeyForDeviceID(senderDeviceID);
+ olmDataEncryptionKeyDBLabel =
+ getOlmEncryptionKeyDBLabelForDeviceID(senderDeviceID);
+ }
+
+ const queryResult = await localforage.getMultipleItems<{
+ notificationAccount: ?EncryptedData,
+ notificationAccountEncryptionKey: ?CryptoKey,
+ synchronizationValue: ?number,
+ [string]: ?EncryptedData | ?CryptoKey | ?SubtleCrypto$JsonWebKey,
+ }>(
+ [
+ INDEXED_DB_NOTIFS_ACCOUNT_KEY,
+ INDEXED_DB_NOTIFS_ACCOUNT_ENCRYPTION_KEY_DB_LABEL,
+ olmDataEncryptionKeyDBLabel,
+ olmDataKey,
+ ],
+ INDEXED_DB_NOTIFS_SYNC_KEY,
+ );
+
+ const {
+ values: {
+ notificationAccount,
+ notificationAccountEncryptionKey,
+ [olmDataKey]: maybeEncryptedOlmData,
+ [olmDataEncryptionKeyDBLabel]: maybeOlmDataEncryptionKey,
+ },
+ synchronizationValue,
+ } = queryResult;
+
+ if (!notificationAccount || !notificationAccountEncryptionKey) {
+ throw new Error(
+ 'Attempt to decrypt notification but olm account not initialized.',
+ );
+ }
+
+ const encryptedOlmData: ?EncryptedData = maybeEncryptedOlmData
+ ? assertWithValidator(maybeEncryptedOlmData, encryptedAESDataValidator)
+ : undefined;
+
+ const olmDataEncryptionKey: ?CryptoKey | ?SubtleCrypto$JsonWebKey =
+ maybeOlmDataEncryptionKey
+ ? assertWithValidator(
+ maybeOlmDataEncryptionKey,
+ extendedCryptoKeyValidator,
+ )
+ : undefined;
+
+ const [encryptionKey, accountEncryptionKey] = await Promise.all([
+ validateCryptoKeyOptional(olmDataEncryptionKey),
+ validateCryptoKey(notificationAccountEncryptionKey),
+ ]);
+
+ return {
+ encryptedOlmData,
+ encryptionKey,
+ encryptionKeyDBLabel: olmDataEncryptionKeyDBLabel,
+ encryptedOlmAccount: notificationAccount,
+ olmDataKey,
+ accountEncryptionKey,
+ synchronizationValue,
+ };
+}
+
async function persistNotifsAccountWithOlmData(input: {
+olmDataKey?: string,
+olmEncryptionKeyDBLabel?: string,
@@ -223,8 +336,14 @@
async function decryptWebNotification(
encryptedNotification: EncryptedWebNotification,
): Promise<PlainTextWebNotification | WebNotifDecryptionError> {
- const { id, keyserverID, encryptedPayload } = encryptedNotification;
- invariant(keyserverID, 'KeyserverID must be present to decrypt a notif');
+ const {
+ id,
+ encryptedPayload,
+ type: messageType,
+ ...rest
+ } = encryptedNotification;
+ const senderDeviceDescriptor: SenderDeviceDescriptor = rest;
+
const utilsData = await localforage.getItem<WebNotifsServiceUtilsData>(
WEB_NOTIFS_SERVICE_UTILS_KEY,
);
@@ -234,9 +353,11 @@
}
const { olmWasmPath, staffCanSee } = (utilsData: WebNotifsServiceUtilsData);
- let olmDBKeys;
+ let notifsAccountWithOlmData;
try {
- olmDBKeys = await getNotifsOlmSessionDBKeys(keyserverID);
+ notifsAccountWithOlmData = await getNotifsAccountWithOlmData(
+ senderDeviceDescriptor,
+ );
} catch (e) {
return {
id,
@@ -244,38 +365,109 @@
displayErrorMessage: staffCanSee,
};
}
- const { olmDataKey, encryptionKeyDBKey } = olmDBKeys;
- const [encryptedOlmData, encryptionKey] = await Promise.all([
- localforage.getItem<EncryptedData>(olmDataKey),
- retrieveEncryptionKey(encryptionKeyDBKey),
- ]);
- if (!encryptionKey || !encryptedOlmData) {
- return {
- id,
- error: 'Received encrypted notification but olm session was not created',
- displayErrorMessage: staffCanSee,
- };
- }
+ const {
+ encryptionKey,
+ encryptedOlmData,
+ olmDataKey,
+ encryptionKeyDBLabel: olmEncryptionKeyDBLabel,
+ accountEncryptionKey,
+ encryptedOlmAccount,
+ synchronizationValue,
+ } = notifsAccountWithOlmData;
try {
- await olm.init({ locateFile: () => olmWasmPath });
+ const [notificationsOlmData, accountWithPicklingKey] = await Promise.all([
+ deserializeEncryptedDataOptional<NotificationsOlmDataType>(
+ encryptedOlmData,
+ encryptionKey,
+ ),
+ deserializeEncryptedDataOptional<PickledOLMAccount>(
+ encryptedOlmAccount,
+ accountEncryptionKey,
+ ),
+ olm.init({ locateFile: () => olmWasmPath }),
+ ]);
- const decryptedNotification = await commonDecrypt<PlainTextWebNotification>(
- encryptedOlmData,
- olmDataKey,
- encryptionKey,
- encryptedPayload,
- );
+ let decryptedNotification;
+ let updatedOlmData;
+ let updatedNotifsAccount;
- const { unreadCount } = decryptedNotification;
+ const { senderDeviceID, keyserverID } = senderDeviceDescriptor;
- invariant(keyserverID, 'Keyserver ID must be set to update badge counts');
- await updateNotifsUnreadCountStorage({
- [keyserverID]: unreadCount,
- });
+ if (keyserverID) {
+ invariant(
+ notificationsOlmData && encryptionKey,
+ 'Received encrypted notification but keyserver olm session was not created',
+ );
+
+ const {
+ decryptedNotification: resultDecryptedNotification,
+ updatedOlmData: resultUpdatedOlmData,
+ } = await commonDecrypt<PlainTextWebNotification>(
+ notificationsOlmData,
+ encryptedPayload,
+ );
+
+ decryptedNotification = resultDecryptedNotification;
+ updatedOlmData = resultUpdatedOlmData;
+ const { unreadCount } = decryptedNotification;
+
+ invariant(keyserverID, 'Keyserver ID must be set to update badge counts');
+ await Promise.all([
+ persistNotifsAccountWithOlmData({
+ olmDataKey,
+ olmData: updatedOlmData,
+ olmEncryptionKeyDBLabel,
+ encryptionKey,
+ forceWrite: false,
+ synchronizationValue,
+ }),
+ updateNotifsUnreadCountStorage({
+ [keyserverID]: unreadCount,
+ }),
+ ]);
+
+ return { id, ...decryptedNotification };
+ } else {
+ invariant(
+ senderDeviceID,
+ 'keyserverID or SenderDeviceID must be present to decrypt a notif',
+ );
+ invariant(
+ accountWithPicklingKey,
+ 'Received encrypted notification but notifs olm account not created',
+ );
- return { id, ...decryptedNotification };
+ const {
+ decryptedNotification: resultDecryptedNotification,
+ updatedOlmData: resultUpdatedOlmData,
+ updatedNotifsAccount: resultUpdatedNotifsAccount,
+ } = await commonPeerDecrypt<PlainTextWebNotification>(
+ senderDeviceID,
+ notificationsOlmData,
+ accountWithPicklingKey,
+ messageType,
+ encryptedPayload,
+ );
+
+ decryptedNotification = resultDecryptedNotification;
+ updatedOlmData = resultUpdatedOlmData;
+ updatedNotifsAccount = resultUpdatedNotifsAccount;
+
+ await persistNotifsAccountWithOlmData({
+ accountWithPicklingKey: updatedNotifsAccount,
+ accountEncryptionKey,
+ encryptionKey,
+ olmData: updatedOlmData,
+ olmDataKey,
+ olmEncryptionKeyDBLabel,
+ synchronizationValue,
+ forceWrite: false,
+ });
+
+ return { id, ...decryptedNotification };
+ }
} catch (e) {
return {
id,
@@ -287,19 +479,16 @@
async function decryptDesktopNotification(
encryptedPayload: string,
+ messageType: string,
staffCanSee: boolean,
- keyserverID?: string,
+ senderDeviceDescriptor: SenderDeviceDescriptor,
): Promise<{ +[string]: mixed }> {
- let encryptedOlmData, encryptionKey, olmDataKey;
- try {
- const { olmDataKey: olmDataKeyValue, encryptionKeyDBKey } =
- await getNotifsOlmSessionDBKeys(keyserverID);
+ const { keyserverID, senderDeviceID } = senderDeviceDescriptor;
- olmDataKey = olmDataKeyValue;
-
- [encryptedOlmData, encryptionKey] = await Promise.all([
- localforage.getItem<EncryptedData>(olmDataKey),
- retrieveEncryptionKey(encryptionKeyDBKey),
+ let notifsAccountWithOlmData;
+ try {
+ [notifsAccountWithOlmData] = await Promise.all([
+ getNotifsAccountWithOlmData(senderDeviceDescriptor),
initOlm(),
]);
} catch (e) {
@@ -309,65 +498,126 @@
};
}
- if (!encryptionKey || !encryptedOlmData) {
- return {
- error: 'Received encrypted notification but olm session was not created',
- displayErrorMessage: staffCanSee,
- };
- }
+ const {
+ encryptionKey,
+ encryptedOlmData,
+ olmDataKey,
+ encryptionKeyDBLabel: olmEncryptionKeyDBLabel,
+ accountEncryptionKey,
+ encryptedOlmAccount,
+ synchronizationValue,
+ } = notifsAccountWithOlmData;
- let decryptedNotification;
try {
- decryptedNotification = await commonDecrypt<{ +[string]: mixed }>(
- encryptedOlmData,
- olmDataKey,
- encryptionKey,
- encryptedPayload,
- );
+ const [notificationsOlmData, accountWithPicklingKey] = await Promise.all([
+ deserializeEncryptedDataOptional<NotificationsOlmDataType>(
+ encryptedOlmData,
+ encryptionKey,
+ ),
+ deserializeEncryptedDataOptional<PickledOLMAccount>(
+ encryptedOlmAccount,
+ accountEncryptionKey,
+ ),
+ ]);
+
+ if (keyserverID) {
+ invariant(
+ notificationsOlmData && encryptionKey,
+ 'Received encrypted notification but keyserver olm session was not created',
+ );
+
+ const { decryptedNotification, updatedOlmData } = await commonDecrypt<{
+ +[string]: mixed,
+ }>(notificationsOlmData, encryptedPayload);
+
+ const updatedOlmDataPersistencePromise = persistNotifsAccountWithOlmData({
+ olmDataKey,
+ olmData: updatedOlmData,
+ olmEncryptionKeyDBLabel,
+ encryptionKey,
+ forceWrite: false,
+ synchronizationValue,
+ });
+
+ // iOS notifications require that unread count is set under
+ // `badge` key. Since MacOS notifications are created by the
+ // same function the unread count is also set under `badge` key
+ const { badge } = decryptedNotification;
+ if (typeof badge === 'number') {
+ await Promise.all([
+ updateNotifsUnreadCountStorage({ [(keyserverID: string)]: badge }),
+ updatedOlmDataPersistencePromise,
+ ]);
+ return decryptedNotification;
+ }
+
+ const { unreadCount } = decryptedNotification;
+ if (typeof unreadCount === 'number') {
+ await Promise.all([
+ updateNotifsUnreadCountStorage({
+ [(keyserverID: string)]: unreadCount,
+ }),
+ updatedOlmDataPersistencePromise,
+ ]);
+ }
+
+ return decryptedNotification;
+ } else {
+ invariant(
+ senderDeviceID,
+ 'keyserverID or SenderDeviceID must be present to decrypt a notif',
+ );
+
+ invariant(
+ accountWithPicklingKey,
+ 'Received encrypted notification but notifs olm account not created',
+ );
+
+ const { decryptedNotification, updatedOlmData, updatedNotifsAccount } =
+ await commonPeerDecrypt<{
+ +[string]: mixed,
+ }>(
+ senderDeviceID,
+ notificationsOlmData,
+ accountWithPicklingKey,
+ messageType,
+ encryptedPayload,
+ );
+
+ await persistNotifsAccountWithOlmData({
+ accountWithPicklingKey: updatedNotifsAccount,
+ accountEncryptionKey,
+ encryptionKey,
+ olmData: updatedOlmData,
+ olmDataKey,
+ olmEncryptionKeyDBLabel,
+ synchronizationValue,
+ forceWrite: false,
+ });
+
+ return decryptedNotification;
+ }
} catch (e) {
return {
error: e.message,
staffCanSee,
};
}
-
- if (!keyserverID) {
- return decryptedNotification;
- }
-
- // iOS notifications require that unread count is set under
- // `badge` key. Since MacOS notifications are created by the
- // same function the unread count is also set under `badge` key
- const { badge } = decryptedNotification;
- if (typeof badge === 'number') {
- await updateNotifsUnreadCountStorage({ [(keyserverID: string)]: badge });
- return decryptedNotification;
- }
-
- const { unreadCount } = decryptedNotification;
- if (typeof unreadCount === 'number') {
- await updateNotifsUnreadCountStorage({
- [(keyserverID: string)]: unreadCount,
- });
- }
- return decryptedNotification;
}
async function commonDecrypt<T>(
- encryptedOlmData: EncryptedData,
- olmDataKey: string,
- encryptionKey: CryptoKey,
+ notificationsOlmData: NotificationsOlmDataType,
encryptedPayload: string,
-): Promise<T> {
- const serializedOlmData = await decryptData(encryptedOlmData, encryptionKey);
+): Promise<{
+ +decryptedNotification: T,
+ +updatedOlmData: NotificationsOlmDataType,
+}> {
const {
mainSession,
picklingKey,
pendingSessionUpdate,
updateCreationTimestamp,
- }: NotificationsOlmDataType = JSON.parse(
- new TextDecoder().decode(serializedOlmData),
- );
+ } = notificationsOlmData;
let updatedOlmData: NotificationsOlmDataType;
let decryptedNotification: T;
@@ -410,14 +660,134 @@
};
}
- const updatedEncryptedSession = await encryptData(
- new TextEncoder().encode(JSON.stringify(updatedOlmData)),
- encryptionKey,
+ return { decryptedNotification, updatedOlmData };
+}
+
+async function commonPeerDecrypt<T>(
+ senderDeviceID: string,
+ notificationsOlmData: ?NotificationsOlmDataType,
+ notificationAccount: PickledOLMAccount,
+ messageType: string,
+ encryptedPayload: string,
+): Promise<{
+ +decryptedNotification: T,
+ +updatedOlmData?: NotificationsOlmDataType,
+ +updatedNotifsAccount?: PickledOLMAccount,
+}> {
+ if (
+ messageType !== olmEncryptedMessageTypes.PREKEY.toString() &&
+ messageType !== olmEncryptedMessageTypes.TEXT.toString()
+ ) {
+ throw new Error(
+ `Received message of invalid type from device: ${senderDeviceID}`,
+ );
+ }
+
+ let isSenderChainEmpty = true;
+ let hasReceivedMessage = false;
+ const sessionExists = !!notificationsOlmData;
+
+ if (notificationsOlmData) {
+ const session = new olm.Session();
+ session.unpickle(
+ notificationsOlmData.picklingKey,
+ notificationsOlmData.pendingSessionUpdate,
+ );
+
+ isSenderChainEmpty = session.is_sender_chain_empty();
+ hasReceivedMessage = session.has_received_message();
+ }
+
+ // regular message
+ const isRegularMessage =
+ !!notificationsOlmData &&
+ messageType === olmEncryptedMessageTypes.TEXT.toString();
+
+ const isRegularPrekeyMessage =
+ !!notificationsOlmData &&
+ messageType === olmEncryptedMessageTypes.PREKEY.toString() &&
+ isSenderChainEmpty &&
+ hasReceivedMessage;
+
+ if (!!notificationsOlmData && (isRegularMessage || isRegularPrekeyMessage)) {
+ return await commonDecrypt<T>(notificationsOlmData, encryptedPayload);
+ }
+
+ // At this point we either face race condition or session reset attempt or
+ // session initialization attempt. For each of this scenario new inbound
+ // session must be created in order to decrypt message
+ const authMetadata = await fetchAuthMetadata();
+ const notifInboundKeys = await getNotifsInboundKeysForDeviceID(
+ senderDeviceID,
+ authMetadata,
+ );
+
+ const account = new olm.Account();
+ const session = new olm.Session();
+
+ account.unpickle(
+ notificationAccount.picklingKey,
+ notificationAccount.pickledAccount,
);
- await localforage.setItem(olmDataKey, updatedEncryptedSession);
+ if (notifInboundKeys.error) {
+ throw new Error(notifInboundKeys.error);
+ }
+
+ invariant(
+ notifInboundKeys.curve25519,
+ 'curve25519 must be present in notifs inbound keys',
+ );
+
+ session.create_inbound_from(
+ account,
+ notifInboundKeys.curve25519,
+ encryptedPayload,
+ );
+
+ const decryptedNotification: T = JSON.parse(
+ session.decrypt(Number(messageType), encryptedPayload),
+ );
+
+ // session reset attempt or session initialization - handled the same
+ const sessionResetAttempt =
+ sessionExists && !isSenderChainEmpty && hasReceivedMessage;
+
+ // race condition
+ const raceCondition =
+ sessionExists && !isSenderChainEmpty && !hasReceivedMessage;
+ const { deviceID: ourDeviceID } = authMetadata;
+ invariant(ourDeviceID, 'Session creation attempt but no device id');
+
+ const thisDeviceWinsRaceCondition = ourDeviceID > senderDeviceID;
+
+ if (
+ !sessionExists ||
+ sessionResetAttempt ||
+ (raceCondition && !thisDeviceWinsRaceCondition)
+ ) {
+ const pickledOlmSession = session.pickle(notificationAccount.picklingKey);
+ const updatedOlmData = {
+ mainSession: pickledOlmSession,
+ pendingSessionUpdate: pickledOlmSession,
+ updateCreationTimestamp: Date.now(),
+ picklingKey: notificationAccount.picklingKey,
+ };
+ const updatedNotifsAccount = {
+ pickledAccount: account.pickle(notificationAccount.picklingKey),
+ picklingKey: notificationAccount.picklingKey,
+ };
+ return {
+ decryptedNotification,
+ updatedOlmData,
+ updatedNotifsAccount,
+ };
+ }
- return decryptedNotification;
+ // If there is a race condition but we win device id comparison
+ // we return object that carries decrypted data but won't persist
+ // any session state
+ return { decryptedNotification };
}
function decryptWithSession<T>(
diff --git a/web/push-notif/push-notifs-handler.js b/web/push-notif/push-notifs-handler.js
--- a/web/push-notif/push-notifs-handler.js
+++ b/web/push-notif/push-notifs-handler.js
@@ -17,6 +17,7 @@
type RecordAlertActionPayload,
} from 'lib/types/alert-types.js';
import { isDesktopPlatform } from 'lib/types/device-types.js';
+import type { SenderDeviceDescriptor } from 'lib/types/notif-types.js';
import { getConfig } from 'lib/utils/config.js';
import { convertNonPendingIDToNewSchema } from 'lib/utils/migration-utils.js';
import { shouldSkipPushPermissionAlert } from 'lib/utils/push-alerts.js';
@@ -84,15 +85,18 @@
return electron?.onEncryptedNotification?.(
async ({
encryptedPayload,
- keyserverID,
+ senderDeviceDescriptor,
+ type: messageType,
}: {
encryptedPayload: string,
- keyserverID?: string,
+ type: string,
+ senderDeviceDescriptor: SenderDeviceDescriptor,
}) => {
const decryptedPayload = await decryptDesktopNotification(
encryptedPayload,
+ messageType,
staffCanSee,
- keyserverID,
+ senderDeviceDescriptor,
);
electron?.showDecryptedNotification(decryptedPayload);
},

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 25, 5:16 AM (21 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2578449
Default Alt Text
D12838.diff (24 KB)

Event Timeline