Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3536760
D7815.id26613.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
D7815.id26613.diff
View Options
diff --git a/keyserver/src/creators/message-creator.js b/keyserver/src/creators/message-creator.js
--- a/keyserver/src/creators/message-creator.js
+++ b/keyserver/src/creators/message-creator.js
@@ -52,6 +52,7 @@
{
+platform: string,
+deviceToken: string,
+ +cookieID: string,
+codeVersion: ?string,
},
>,
@@ -323,7 +324,7 @@
const time = earliestFocusedTimeConsideredExpired();
const visibleExtractString = `$.${threadPermissions.VISIBLE}.value`;
const query = SQL`
- SELECT m.user, m.thread, c.platform, c.device_token, c.versions,
+ SELECT m.user, m.thread, c.platform, c.device_token, c.versions, c.id,
f.user AS focused_user
`;
query.append(subthreadSelects);
@@ -349,6 +350,7 @@
const focusedUser = !!row.focused_user;
const { platform } = row;
const versions = JSON.parse(row.versions);
+ const cookieID = row.id;
let thisUserInfo = perUserInfo.get(userID);
if (!thisUserInfo) {
thisUserInfo = {
@@ -384,10 +386,11 @@
}
}
}
- if (deviceToken) {
+ if (deviceToken && cookieID) {
thisUserInfo.devices.set(deviceToken, {
platform,
deviceToken,
+ cookieID: cookieID.toString(),
codeVersion: versions ? versions.codeVersion : null,
});
}
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
@@ -53,13 +53,11 @@
for (const delivery of deliveries) {
if (delivery.iosID && delivery.iosDeviceTokens) {
// Old iOS
- const notification = prepareIOSNotification(
- delivery.iosID,
- row.unread_count,
- threadID,
- );
+ const notifications = [
+ prepareIOSNotification(delivery.iosID, row.unread_count, threadID),
+ ];
deliveryPromises[id] = apnPush({
- notification,
+ notifications,
deviceTokens: delivery.iosDeviceTokens,
platformDetails: { platform: 'ios' },
});
@@ -78,14 +76,16 @@
} else if (delivery.deviceType === 'ios') {
// New iOS
const { iosID, deviceTokens, codeVersion } = delivery;
- const notification = prepareIOSNotification(
- iosID,
- row.unread_count,
- threadID,
- codeVersion,
- );
+ const notifications = [
+ prepareIOSNotification(
+ iosID,
+ row.unread_count,
+ threadID,
+ codeVersion,
+ ),
+ ];
deliveryPromises[id] = apnPush({
- notification,
+ notifications,
deviceTokens,
platformDetails: { platform: 'ios', codeVersion },
});
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
@@ -37,6 +37,7 @@
import { updateTypes } from 'lib/types/update-types-enum.js';
import { promiseAll } from 'lib/utils/promises.js';
+import { prepareEncryptedIOSNotifications } from './crypto.js';
import { getAPNsNotificationTopic } from './providers.js';
import { rescindPushNotifs } from './rescind.js';
import {
@@ -64,6 +65,7 @@
type Device = {
+platform: Platform,
+deviceToken: string,
+ +cookieID: string,
+codeVersion: ?number,
};
type PushUserInfo = {
@@ -190,25 +192,32 @@
const iosVersionsToTokens = byPlatform.get('ios');
if (iosVersionsToTokens) {
- for (const [codeVersion, deviceTokens] of iosVersionsToTokens) {
+ for (const [
+ codeVersion,
+ { cookieIDs, deviceTokens },
+ ] of iosVersionsToTokens) {
const platformDetails = { platform: 'ios', codeVersion };
const shimmedNewRawMessageInfos = shimUnsupportedRawMessageInfos(
newRawMessageInfos,
platformDetails,
);
+
const deliveryPromise = (async () => {
- const notification = await prepareAPNsNotification({
- notifTexts,
- newRawMessageInfos: shimmedNewRawMessageInfos,
- threadID: threadInfo.id,
- collapseKey: notifInfo.collapseKey,
- badgeOnly,
- unreadCount: unreadCounts[userID],
- platformDetails,
- });
+ const notificationsArray = await prepareAPNsNotification(
+ {
+ notifTexts,
+ newRawMessageInfos: shimmedNewRawMessageInfos,
+ threadID: threadInfo.id,
+ collapseKey: notifInfo.collapseKey,
+ badgeOnly,
+ unreadCount: unreadCounts[userID],
+ platformDetails,
+ },
+ [...cookieIDs],
+ );
return await sendAPNsNotification(
'ios',
- notification,
+ notificationsArray,
[...deviceTokens],
{
...notificationInfo,
@@ -221,7 +230,7 @@
}
const androidVersionsToTokens = byPlatform.get('android');
if (androidVersionsToTokens) {
- for (const [codeVersion, deviceTokens] of androidVersionsToTokens) {
+ for (const [codeVersion, { deviceTokens }] of androidVersionsToTokens) {
const platformDetails = { platform: 'android', codeVersion };
const shimmedNewRawMessageInfos = shimUnsupportedRawMessageInfos(
newRawMessageInfos,
@@ -252,7 +261,7 @@
}
const webVersionsToTokens = byPlatform.get('web');
if (webVersionsToTokens) {
- for (const [codeVersion, deviceTokens] of webVersionsToTokens) {
+ for (const [codeVersion, { deviceTokens }] of webVersionsToTokens) {
const deliveryPromise = (async () => {
const notification = await prepareWebNotification({
notifTexts,
@@ -269,7 +278,7 @@
}
const macosVersionsToTokens = byPlatform.get('macos');
if (macosVersionsToTokens) {
- for (const [codeVersion, deviceTokens] of macosVersionsToTokens) {
+ for (const [codeVersion, { deviceTokens }] of macosVersionsToTokens) {
const platformDetails = { platform: 'macos', codeVersion };
const shimmedNewRawMessageInfos = shimUnsupportedRawMessageInfos(
newRawMessageInfos,
@@ -300,7 +309,7 @@
}
const windowsVersionsToTokens = byPlatform.get('windows');
if (windowsVersionsToTokens) {
- for (const [codeVersion, deviceTokens] of windowsVersionsToTokens) {
+ for (const [codeVersion, { deviceTokens }] of windowsVersionsToTokens) {
const deliveryPromise = (async () => {
const notification = await prepareWNSNotification({
notifTexts,
@@ -577,8 +586,11 @@
}
function getDevicesByPlatform(
- devices: Device[],
-): Map<Platform, Map<number, Set<string>>> {
+ devices: $ReadOnlyArray<Device>,
+): Map<
+ Platform,
+ Map<number, { cookieIDs: Set<string>, deviceTokens: Set<string> }>,
+> {
const byPlatform = new Map();
for (const device of devices) {
let innerMap = byPlatform.get(device.platform);
@@ -590,12 +602,14 @@
device.codeVersion !== null && device.codeVersion !== undefined
? device.codeVersion
: -1;
- let innerMostSet = innerMap.get(codeVersion);
- if (!innerMostSet) {
- innerMostSet = new Set();
- innerMap.set(codeVersion, innerMostSet);
+ let innerMostPair = innerMap.get(codeVersion);
+ if (!innerMostPair) {
+ innerMostPair = { cookieIDs: new Set(), deviceTokens: new Set() };
+ innerMap.set(codeVersion, innerMostPair);
}
- innerMostSet.add(device.deviceToken);
+ const { cookieIDs, deviceTokens } = innerMostPair;
+ cookieIDs.add(device.cookieID);
+ deviceTokens.add(device.deviceToken);
}
return byPlatform;
}
@@ -611,7 +625,8 @@
};
async function prepareAPNsNotification(
inputData: APNsNotifInputData,
-): Promise<apn.Notification> {
+ cookieIDs?: $ReadOnlyArray<string>,
+): Promise<Array<apn.Notification>> {
const {
notifTexts,
newRawMessageInfos,
@@ -622,6 +637,12 @@
platformDetails,
} = inputData;
+ const isTextNotification = newRawMessageInfos.every(
+ newRawMessageInfo => newRawMessageInfo.type === messageTypes.TEXT,
+ );
+ const shouldBeEncrypted =
+ platformDetails.platform === 'ios' && !collapseKey && isTextNotification;
+
const uniqueID = uuidv4();
const notification = new apn.Notification();
notification.topic = getAPNsNotificationTopic(platformDetails);
@@ -662,18 +683,43 @@
...copyWithMessageInfos.payload,
messageInfos,
};
- if (copyWithMessageInfos.length() <= apnMaxNotificationPayloadByteSize) {
- notification.payload.messageInfos = messageInfos;
- return notification;
+
+ let notifications, notificationsWithMessageInfos;
+ if (shouldBeEncrypted && cookieIDs) {
+ [notifications, notificationsWithMessageInfos] = await Promise.all([
+ prepareEncryptedIOSNotifications(cookieIDs, notification),
+ prepareEncryptedIOSNotifications(cookieIDs, copyWithMessageInfos),
+ ]);
+ } else {
+ notifications = [notification];
+ notificationsWithMessageInfos = [copyWithMessageInfos];
}
- const notificationCopy = _cloneDeep(notification);
- if (notificationCopy.length() > apnMaxNotificationPayloadByteSize) {
- console.warn(
- `${platformDetails.platform} notification ${uniqueID} ` +
- `exceeds size limit, even with messageInfos omitted`,
- );
+
+ const shouldAddMessageInfos = notificationsWithMessageInfos.map(notif => {
+ const copy = _cloneDeep(notif);
+ return copy.length() <= apnMaxNotificationPayloadByteSize;
+ });
+
+ const notificationsToSend = shouldAddMessageInfos.map(
+ (addMessageInfos, idx) => {
+ if (addMessageInfos) {
+ return notificationsWithMessageInfos[idx];
+ }
+ return notifications[idx];
+ },
+ );
+
+ for (const notifToSend of notificationsToSend) {
+ const copy = _cloneDeep(notifToSend);
+ if (copy.length() > apnMaxNotificationPayloadByteSize) {
+ console.warn(
+ `${platformDetails.platform} notification ${uniqueID} ` +
+ `exceeds size limit, even with messageInfos omitted`,
+ );
+ }
}
- return notification;
+
+ return notificationsToSend;
}
type AndroidNotifInputData = {
@@ -819,16 +865,18 @@
};
async function sendAPNsNotification(
platform: 'ios' | 'macos',
- notification: apn.Notification,
+ notifications: $ReadOnlyArray<apn.Notification>,
deviceTokens: $ReadOnlyArray<string>,
notificationInfo: NotificationInfo,
): Promise<APNsResult> {
const { source, codeVersion } = notificationInfo;
+
const response = await apnPush({
- notification,
+ notifications,
deviceTokens,
platformDetails: { platform, codeVersion },
});
+ const [notification] = notifications;
const delivery: APNsDelivery = {
source,
deviceType: platform,
@@ -1078,7 +1126,10 @@
const iosVersionsToTokens = byPlatform.get('ios');
if (iosVersionsToTokens) {
- for (const [codeVersion, deviceTokens] of iosVersionsToTokens) {
+ for (const [
+ codeVersion,
+ { cookieIDs, deviceTokens },
+ ] of iosVersionsToTokens) {
const notification = new apn.Notification();
notification.topic = getAPNsNotificationTopic({
platform: 'ios',
@@ -1086,8 +1137,12 @@
});
notification.badge = unreadCount;
notification.pushType = 'alert';
+ const notificationsArray = await prepareEncryptedIOSNotifications(
+ [...cookieIDs],
+ notification,
+ );
deliveryPromises.push(
- sendAPNsNotification('ios', notification, [...deviceTokens], {
+ sendAPNsNotification('ios', notificationsArray, [...deviceTokens], {
source,
dbID,
userID,
@@ -1099,7 +1154,7 @@
const androidVersionsToTokens = byPlatform.get('android');
if (androidVersionsToTokens) {
- for (const [codeVersion, deviceTokens] of androidVersionsToTokens) {
+ for (const [codeVersion, { deviceTokens }] of androidVersionsToTokens) {
const notificationData =
codeVersion < 69
? { badge: unreadCount.toString() }
@@ -1118,7 +1173,7 @@
const macosVersionsToTokens = byPlatform.get('macos');
if (macosVersionsToTokens) {
- for (const [codeVersion, deviceTokens] of macosVersionsToTokens) {
+ for (const [codeVersion, { deviceTokens }] of macosVersionsToTokens) {
const notification = new apn.Notification();
notification.topic = getAPNsNotificationTopic({
platform: 'macos',
@@ -1127,7 +1182,7 @@
notification.badge = unreadCount;
notification.pushType = 'alert';
deliveryPromises.push(
- sendAPNsNotification('macos', notification, [...deviceTokens], {
+ sendAPNsNotification('macos', [notification], [...deviceTokens], {
source,
dbID,
userID,
diff --git a/keyserver/src/push/utils.js b/keyserver/src/push/utils.js
--- a/keyserver/src/push/utils.js
+++ b/keyserver/src/push/utils.js
@@ -46,11 +46,11 @@
+invalidTokens?: $ReadOnlyArray<string>,
};
async function apnPush({
- notification,
+ notifications,
deviceTokens,
platformDetails,
}: {
- +notification: apn.Notification,
+ +notifications: $ReadOnlyArray<apn.Notification>,
+deviceTokens: $ReadOnlyArray<string>,
+platformDetails: PlatformDetails,
}): Promise<APNPushResult> {
@@ -61,10 +61,22 @@
return { success: true };
}
invariant(apnProvider, `keyserver/secrets/${pushProfile}.json should exist`);
- const result = await apnProvider.send(notification, deviceTokens);
+
+ const results = await Promise.all(
+ notifications.map((notification, idx) => {
+ return apnProvider.send(notification, deviceTokens[idx]);
+ }),
+ );
+
+ const mergedResults = { sent: [], failed: [] };
+ for (const result of results) {
+ mergedResults.sent.push(...result.sent);
+ mergedResults.failed.push(...result.failed);
+ }
+
const errors = [];
const invalidTokens = [];
- for (const error of result.failed) {
+ for (const error of mergedResults.failed) {
errors.push(error);
/* eslint-disable eqeqeq */
if (
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Dec 26, 6:55 PM (11 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2708175
Default Alt Text
D7815.id26613.diff (14 KB)
Attached To
Mode
D7815: Send encrypted notifications to iOS devices
Attached
Detach File
Event Timeline
Log In to Comment