Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3367705
D12395.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
20 KB
Referenced Files
None
Subscribers
None
D12395.diff
View Options
diff --git a/keyserver/src/push/crypto.js b/keyserver/src/push/crypto.js
--- a/keyserver/src/push/crypto.js
+++ b/keyserver/src/push/crypto.js
@@ -11,13 +11,13 @@
PlainTextWebNotificationPayload,
WebNotification,
PlainTextWNSNotification,
- PlainTextWNSNotificationPayload,
WNSNotification,
AndroidVisualNotification,
AndroidVisualNotificationPayload,
AndroidBadgeOnlyNotification,
AndroidNotificationRescind,
NotificationTargetDevice,
+ SenderDeviceDescriptor,
} from 'lib/types/notif-types.js';
import { toBase64URL } from 'lib/utils/base64.js';
@@ -27,6 +27,7 @@
async function encryptAPNsNotification(
cookieID: string,
+ senderDeviceID: SenderDeviceDescriptor,
notification: apn.Notification,
codeVersion?: ?number,
notificationSizeValidator?: apn.Notification => boolean,
@@ -58,8 +59,7 @@
encryptedNotification.pushType = 'alert';
encryptedNotification.mutableContent = true;
- const { id, keyserverID, ...payloadSansUnencryptedData } =
- notification.payload;
+ const { id, ...payloadSansUnencryptedData } = notification.payload;
const unencryptedPayload = {
...payloadSansUnencryptedData,
badge: notification.aps.badge.toString(),
@@ -95,6 +95,10 @@
);
encryptedNotification.payload.encryptedPayload = serializedPayload.body;
+ encryptedNotification.payload = {
+ ...senderDeviceID,
+ ...encryptedNotification.payload,
+ };
if (codeVersion && codeVersion >= 254 && codeVersion % 2 === 0) {
encryptedNotification.aps = {
@@ -137,10 +141,15 @@
async function encryptAndroidNotificationPayload<T>(
cookieID: string,
+ senderDeviceID: SenderDeviceDescriptor,
unencryptedPayload: T,
- payloadSizeValidator?: (T | { +encryptedPayload: string }) => boolean,
+ payloadSizeValidator?: (
+ T | $ReadOnly<{ ...SenderDeviceDescriptor, +encryptedPayload: string }>,
+ ) => boolean,
): Promise<{
- +resultPayload: T | { +encryptedPayload: string },
+ +resultPayload:
+ | T
+ | $ReadOnly<{ ...SenderDeviceDescriptor, +encryptedPayload: string }>,
+payloadSizeExceeded: boolean,
+encryptionOrder?: number,
}> {
@@ -161,7 +170,11 @@
serializedPayload,
}: {
+[string]: EncryptResult,
- }) => payloadSizeValidator({ encryptedPayload: serializedPayload.body });
+ }) =>
+ payloadSizeValidator({
+ encryptedPayload: serializedPayload.body,
+ ...senderDeviceID,
+ });
}
const {
@@ -177,7 +190,10 @@
dbPersistCondition,
);
return {
- resultPayload: { encryptedPayload: serializedPayload.body },
+ resultPayload: {
+ encryptedPayload: serializedPayload.body,
+ ...senderDeviceID,
+ },
payloadSizeExceeded: !!dbPersistConditionViolated,
encryptionOrder,
};
@@ -197,6 +213,7 @@
}
async function encryptAndroidVisualNotification(
+ senderDeviceID: SenderDeviceDescriptor,
cookieID: string,
notification: AndroidVisualNotification,
notificationSizeValidator?: AndroidVisualNotification => boolean,
@@ -206,11 +223,11 @@
+payloadSizeExceeded: boolean,
+encryptionOrder?: number,
}> {
- const { id, keyserverID, ...rest } = notification.data;
+ const { id, ...rest } = notification.data;
- let unencryptedData = { keyserverID };
+ let unencryptedData = {};
if (id) {
- unencryptedData = { ...unencryptedData, id };
+ unencryptedData = { id };
}
let unencryptedPayload = rest;
@@ -221,7 +238,9 @@
let payloadSizeValidator;
if (notificationSizeValidator) {
payloadSizeValidator = (
- payload: AndroidVisualNotificationPayload | { +encryptedPayload: string },
+ payload:
+ | AndroidVisualNotificationPayload
+ | $ReadOnly<{ ...SenderDeviceDescriptor, +encryptedPayload: string }>,
) => {
return notificationSizeValidator({
data: { ...unencryptedData, ...payload },
@@ -231,6 +250,7 @@
const { resultPayload, payloadSizeExceeded, encryptionOrder } =
await encryptAndroidNotificationPayload(
cookieID,
+ senderDeviceID,
unencryptedPayload,
payloadSizeValidator,
);
@@ -248,31 +268,32 @@
async function encryptAndroidSilentNotification(
cookieID: string,
+ senderDeviceID: SenderDeviceDescriptor,
notification: AndroidNotificationRescind | AndroidBadgeOnlyNotification,
): Promise<AndroidNotificationRescind | AndroidBadgeOnlyNotification> {
// We don't validate payload size for rescind
// since they are expected to be small and
// never exceed any FCM limit
- const { keyserverID, ...unencryptedPayload } = notification.data;
+ const { ...unencryptedPayload } = notification.data;
const { resultPayload } = await encryptAndroidNotificationPayload(
cookieID,
+ senderDeviceID,
unencryptedPayload,
);
if (resultPayload.encryptedPayload) {
return {
- data: { keyserverID, ...resultPayload },
+ data: { ...resultPayload },
};
}
if (resultPayload.rescind) {
return {
- data: { keyserverID, ...resultPayload },
+ data: { ...resultPayload },
};
}
return {
data: {
- keyserverID,
...resultPayload,
},
};
@@ -280,9 +301,14 @@
async function encryptBasicPayload<T>(
cookieID: string,
+ senderDeviceID: SenderDeviceDescriptor,
basicPayload: T,
): Promise<
- | { +encryptedPayload: string, +encryptionOrder?: number }
+ | $ReadOnly<{
+ ...SenderDeviceDescriptor,
+ +encryptedPayload: string,
+ +encryptionOrder?: number,
+ }>
| { ...T, +encryptionFailed: '1' },
> {
const unencryptedSerializedPayload = JSON.stringify(basicPayload);
@@ -300,6 +326,7 @@
});
return {
+ ...senderDeviceID,
encryptedPayload: serializedPayload.body,
encryptionOrder,
};
@@ -314,37 +341,42 @@
async function encryptWebNotification(
cookieID: string,
+ senderDeviceID: SenderDeviceDescriptor,
notification: PlainTextWebNotification,
): Promise<{ +notification: WebNotification, +encryptionOrder?: number }> {
- const { id, keyserverID, ...payloadSansId } = notification;
+ const { id, ...payloadSansId } = notification;
const { encryptionOrder, ...encryptionResult } =
await encryptBasicPayload<PlainTextWebNotificationPayload>(
cookieID,
+ senderDeviceID,
payloadSansId,
);
+
return {
- notification: { id, keyserverID, ...encryptionResult },
+ notification: { id, ...encryptionResult },
encryptionOrder,
};
}
async function encryptWNSNotification(
cookieID: string,
+ senderDeviceID: SenderDeviceDescriptor,
notification: PlainTextWNSNotification,
): Promise<{ +notification: WNSNotification, +encryptionOrder?: number }> {
- const { keyserverID, ...payloadSansKeyserverID } = notification;
const { encryptionOrder, ...encryptionResult } =
- await encryptBasicPayload<PlainTextWNSNotificationPayload>(
+ await encryptBasicPayload<PlainTextWNSNotification>(
cookieID,
- payloadSansKeyserverID,
+ senderDeviceID,
+ notification,
);
return {
- notification: { keyserverID, ...encryptionResult },
+ notification: { ...encryptionResult },
encryptionOrder,
};
}
function prepareEncryptedAPNsNotifications(
+ senderDeviceID: SenderDeviceDescriptor,
devices: $ReadOnlyArray<NotificationTargetDevice>,
notification: apn.Notification,
codeVersion?: ?number,
@@ -363,6 +395,7 @@
async ({ cookieID, deviceToken, blobHolder }) => {
const notif = await encryptAPNsNotification(
cookieID,
+ senderDeviceID,
notification,
codeVersion,
notificationSizeValidator,
@@ -375,6 +408,7 @@
}
function prepareEncryptedIOSNotificationRescind(
+ senderDeviceID: SenderDeviceDescriptor,
devices: $ReadOnlyArray<NotificationTargetDevice>,
notification: apn.Notification,
codeVersion?: ?number,
@@ -389,6 +423,7 @@
async ({ deviceToken, cookieID }) => {
const { notification: notif } = await encryptAPNsNotification(
cookieID,
+ senderDeviceID,
notification,
codeVersion,
);
@@ -399,6 +434,7 @@
}
function prepareEncryptedAndroidVisualNotifications(
+ senderDeviceID: SenderDeviceDescriptor,
devices: $ReadOnlyArray<NotificationTargetDevice>,
notification: AndroidVisualNotification,
notificationSizeValidator?: (
@@ -416,6 +452,7 @@
const notificationPromises = devices.map(
async ({ deviceToken, cookieID, blobHolder }) => {
const notif = await encryptAndroidVisualNotification(
+ senderDeviceID,
cookieID,
notification,
notificationSizeValidator,
@@ -428,6 +465,7 @@
}
function prepareEncryptedAndroidSilentNotifications(
+ senderDeviceID: SenderDeviceDescriptor,
devices: $ReadOnlyArray<NotificationTargetDevice>,
notification: AndroidNotificationRescind | AndroidBadgeOnlyNotification,
): Promise<
@@ -442,6 +480,7 @@
async ({ deviceToken, cookieID }) => {
const notif = await encryptAndroidSilentNotification(
cookieID,
+ senderDeviceID,
notification,
);
return { deviceToken, cookieID, notification: notif };
@@ -451,6 +490,7 @@
}
function prepareEncryptedWebNotifications(
+ senderDeviceID: SenderDeviceDescriptor,
devices: $ReadOnlyArray<NotificationTargetDevice>,
notification: PlainTextWebNotification,
): Promise<
@@ -462,7 +502,11 @@
> {
const notificationPromises = devices.map(
async ({ deviceToken, cookieID }) => {
- const notif = await encryptWebNotification(cookieID, notification);
+ const notif = await encryptWebNotification(
+ cookieID,
+ senderDeviceID,
+ notification,
+ );
return { ...notif, deviceToken };
},
);
@@ -470,6 +514,7 @@
}
function prepareEncryptedWNSNotifications(
+ senderDeviceID: SenderDeviceDescriptor,
devices: $ReadOnlyArray<NotificationTargetDevice>,
notification: PlainTextWNSNotification,
): Promise<
@@ -481,7 +526,11 @@
> {
const notificationPromises = devices.map(
async ({ deviceToken, cookieID }) => {
- const notif = await encryptWNSNotification(cookieID, notification);
+ const notif = await encryptWNSNotification(
+ cookieID,
+ senderDeviceID,
+ notification,
+ );
return { ...notif, deviceToken };
},
);
diff --git a/keyserver/src/push/rescind.js b/keyserver/src/push/rescind.js
--- a/keyserver/src/push/rescind.js
+++ b/keyserver/src/push/rescind.js
@@ -9,6 +9,7 @@
import type {
NotificationTargetDevice,
TargetedAndroidNotification,
+ SenderDeviceDescriptor,
} from 'lib/types/notif-types.js';
import { threadSubscriptions } from 'lib/types/subscription-types.js';
import { threadPermissions } from 'lib/types/thread-permission-types.js';
@@ -274,10 +275,12 @@
}
async function conditionallyEncryptNotification<T>(
+ senderDeviceID: SenderDeviceDescriptor,
notification: T,
codeVersion: ?number,
devices: $ReadOnlyArray<NotificationTargetDevice>,
encryptCallback: (
+ senderDeviceID: SenderDeviceDescriptor,
devices: $ReadOnlyArray<NotificationTargetDevice>,
notification: T,
codeVersion?: ?number,
@@ -298,6 +301,7 @@
}));
}
const notifications = await encryptCallback(
+ senderDeviceID,
devices,
notification,
codeVersion,
@@ -350,6 +354,7 @@
},
};
return await conditionallyEncryptNotification(
+ { keyserverID },
notification,
codeVersion,
devices,
@@ -375,10 +380,10 @@
rescindID: notifID,
setUnreadStatus: 'true',
threadID,
- keyserverID,
},
};
const targetedRescinds = await conditionallyEncryptNotification(
+ { keyserverID },
notification,
codeVersion,
devices,
diff --git a/keyserver/src/push/send.js b/keyserver/src/push/send.js
--- a/keyserver/src/push/send.js
+++ b/keyserver/src/push/send.js
@@ -992,7 +992,6 @@
notification.pushType = 'alert';
notification.payload.id = uniqueID;
notification.payload.threadID = threadID;
- notification.payload.keyserverID = keyserverID;
if (platformDetails.codeVersion && platformDetails.codeVersion > 198) {
notification.mutableContent = true;
@@ -1033,6 +1032,7 @@
if (platformDetails.platform === 'macos') {
const macOSNotifsWithoutMessageInfos =
await prepareEncryptedAPNsNotifications(
+ { keyserverID },
devices,
notification,
platformDetails.codeVersion,
@@ -1046,6 +1046,7 @@
}
const notifsWithMessageInfos = await prepareEncryptedAPNsNotifications(
+ { keyserverID },
devices,
copyWithMessageInfos,
platformDetails.codeVersion,
@@ -1054,7 +1055,10 @@
const devicesWithExcessiveSizeNoHolders = notifsWithMessageInfos
.filter(({ payloadSizeExceeded }) => payloadSizeExceeded)
- .map(({ deviceToken, cookieID }) => ({ deviceToken, cookieID }));
+ .map(({ deviceToken, cookieID }) => ({
+ deviceToken,
+ cookieID,
+ }));
if (devicesWithExcessiveSizeNoHolders.length === 0) {
return notifsWithMessageInfos.map(
@@ -1112,6 +1116,7 @@
}
const notifsWithoutMessageInfos = await prepareEncryptedAPNsNotifications(
+ { keyserverID },
devicesWithExcessiveSize,
notification,
platformDetails.codeVersion,
@@ -1202,7 +1207,6 @@
const { merged, ...rest } = notifTexts;
const notification = {
data: {
- keyserverID,
badge: unreadCount.toString(),
...rest,
threadID,
@@ -1259,6 +1263,7 @@
const notifsWithMessageInfos =
await prepareEncryptedAndroidVisualNotifications(
+ { keyserverID },
devices,
copyWithMessageInfos,
notificationsSizeValidator,
@@ -1320,6 +1325,7 @@
const notifsWithoutMessageInfos =
await prepareEncryptedAndroidVisualNotifications(
+ { keyserverID },
devicesWithExcessiveSize,
notification,
);
@@ -1379,7 +1385,6 @@
unreadCount,
id,
threadID,
- keyserverID,
};
const shouldBeEncrypted = hasMinCodeVersion(convertedData.platformDetails, {
@@ -1390,7 +1395,11 @@
return devices.map(({ deviceToken }) => ({ deviceToken, notification }));
}
- return prepareEncryptedWebNotifications(devices, notification);
+ return prepareEncryptedWebNotifications(
+ { keyserverID },
+ devices,
+ notification,
+ );
}
type WNSNotifInputData = {
@@ -1422,7 +1431,6 @@
...rest,
unreadCount,
threadID,
- keyserverID,
};
if (
@@ -1442,7 +1450,11 @@
notification,
}));
}
- return await prepareEncryptedWNSNotifications(devices, notification);
+ return await prepareEncryptedWNSNotifications(
+ { keyserverID },
+ devices,
+ notification,
+ );
}
type NotificationInfo =
@@ -1791,11 +1803,11 @@
});
notification.badge = unreadCount;
notification.pushType = 'alert';
- notification.payload.keyserverID = keyserverID;
const preparePromise: Promise<PreparePushResult[]> = (async () => {
let targetedNotifications: $ReadOnlyArray<TargetedAPNsNotification>;
if (codeVersion > 222) {
const notificationsArray = await prepareEncryptedAPNsNotifications(
+ { keyserverID },
deviceInfos,
notification,
codeVersion,
@@ -1839,7 +1851,7 @@
badgeOnly: '1',
};
const notification = {
- data: { ...notificationData, keyserverID },
+ data: { ...notificationData },
};
const preparePromise: Promise<PreparePushResult[]> = (async () => {
let targetedNotifications: $ReadOnlyArray<TargetedAndroidNotification>;
@@ -1847,6 +1859,7 @@
if (codeVersion > 222) {
const notificationsArray =
await prepareEncryptedAndroidSilentNotifications(
+ { keyserverID },
deviceInfos,
notification,
);
@@ -1904,6 +1917,7 @@
let targetedNotifications: $ReadOnlyArray<TargetedAPNsNotification>;
if (shouldBeEncrypted) {
const notificationsArray = await prepareEncryptedAPNsNotifications(
+ { keyserverID },
deviceInfos,
notification,
codeVersion,
diff --git a/lib/types/notif-types.js b/lib/types/notif-types.js
--- a/lib/types/notif-types.js
+++ b/lib/types/notif-types.js
@@ -26,6 +26,10 @@
prefix: t.maybe(t.String),
});
+export type SenderDeviceDescriptor =
+ | { +keyserverID: string }
+ | { +senderDeviceID: string };
+
export type PlainTextWebNotificationPayload = {
+body: string,
+prefix?: string,
@@ -35,23 +39,23 @@
+encryptionFailed?: '1',
};
-export type PlainTextWebNotification = {
+export type PlainTextWebNotification = $ReadOnly<{
+id: string,
- +keyserverID: string,
...PlainTextWebNotificationPayload,
-};
+}>;
-export type EncryptedWebNotification = {
+export type EncryptedWebNotification = $ReadOnly<{
+ ...SenderDeviceDescriptor,
+id: string,
- +keyserverID: string,
+encryptedPayload: string,
-};
+ +type?: '0' | '1',
+}>;
export type WebNotification =
| PlainTextWebNotification
| EncryptedWebNotification;
-export type PlainTextWNSNotificationPayload = {
+export type PlainTextWNSNotification = {
+body: string,
+prefix?: string,
+title: string,
@@ -60,15 +64,11 @@
+encryptionFailed?: '1',
};
-export type PlainTextWNSNotification = {
- +keyserverID: string,
- ...PlainTextWNSNotificationPayload,
-};
-
-export type EncryptedWNSNotification = {
- +keyserverID: string,
+export type EncryptedWNSNotification = $ReadOnly<{
+ ...SenderDeviceDescriptor,
+encryptedPayload: string,
-};
+ +type?: '0' | '1',
+}>;
export type WNSNotification =
| PlainTextWNSNotification
@@ -85,39 +85,46 @@
+encryptionFailed?: '1',
}>;
-export type AndroidVisualNotificationPayload = $ReadOnly<
- | {
- ...AndroidVisualNotificationPayloadBase,
- +messageInfos?: string,
- }
- | {
- ...AndroidVisualNotificationPayloadBase,
- +blobHash: string,
- +encryptionKey: string,
- },
->;
+type AndroidSmallVisualNotificationPayload = $ReadOnly<{
+ ...AndroidVisualNotificationPayloadBase,
+ +messageInfos?: string,
+}>;
+
+type AndroidLargeVisualNotificationPayload = $ReadOnly<{
+ ...AndroidVisualNotificationPayloadBase,
+ +blobHash: string,
+ +encryptionKey: string,
+}>;
+
+export type AndroidVisualNotificationPayload =
+ | AndroidSmallVisualNotificationPayload
+ | AndroidLargeVisualNotificationPayload;
+
+type EncryptedThinThreadPayload = {
+ +keyserverID: string,
+ +encryptedPayload: string,
+ +type?: '0' | '1',
+};
+
+type EncryptedThickThreadPayload = {
+ +senderDeviceID: string,
+ +encryptedPayload: string,
+ +type?: '0' | '1',
+};
export type AndroidVisualNotification = {
+data: $ReadOnly<{
+id?: string,
- +keyserverID: string,
...
- | {
- ...AndroidVisualNotificationPayloadBase,
- +messageInfos?: string,
- }
- | {
- ...AndroidVisualNotificationPayloadBase,
- +blobHash: string,
- +encryptionKey: string,
- }
- | { +encryptedPayload: string },
+ | AndroidSmallVisualNotificationPayload
+ | AndroidLargeVisualNotificationPayload
+ | EncryptedThinThreadPayload
+ | EncryptedThickThreadPayload,
}>,
};
export type AndroidNotificationRescind = {
+data: $ReadOnly<{
- +keyserverID: string,
...
| {
+badge: string,
@@ -127,20 +134,21 @@
+threadID: string,
+encryptionFailed?: string,
}
- | { +encryptedPayload: string },
+ | EncryptedThinThreadPayload
+ | EncryptedThickThreadPayload,
}>,
};
export type AndroidBadgeOnlyNotification = {
+data: $ReadOnly<{
- +keyserverID: string,
...
| {
+badge: string,
+badgeOnly: '1',
+encryptionFailed?: string,
}
- | { +encryptedPayload: string },
+ | EncryptedThinThreadPayload
+ | EncryptedThickThreadPayload,
}>,
};
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
@@ -1,6 +1,7 @@
// @flow
import olm from '@commapp/olm';
+import invariant from 'invariant';
import localforage from 'localforage';
import {
@@ -64,6 +65,7 @@
encryptedNotification: EncryptedWebNotification,
): Promise<PlainTextWebNotification | WebNotifDecryptionError> {
const { id, keyserverID, encryptedPayload } = encryptedNotification;
+ invariant(keyserverID, 'KeyserverID must be present to decrypt a notif');
const utilsData = await localforage.getItem<WebNotifsServiceUtilsData>(
WEB_NOTIFS_SERVICE_UTILS_KEY,
);
@@ -108,6 +110,8 @@
);
const { unreadCount } = decryptedNotification;
+
+ invariant(keyserverID, 'Keyserver ID must be set to update badge counts');
await updateNotifsUnreadCountStorage({
[keyserverID]: unreadCount,
});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 26, 3:53 PM (20 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2578841
Default Alt Text
D12395.diff (20 KB)
Attached To
Mode
D12395: Enable encrypted notifications to have keyservevrID or senderDeviceID
Attached
Detach File
Event Timeline
Log In to Comment