Page MenuHomePhabricator

D7874.id27188.diff
No OneTemporary

D7874.id27188.diff

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
@@ -73,8 +73,12 @@
threadID,
);
deliveryPromises[id] = fcmPush({
- notification,
- deviceTokens: delivery.androidDeviceTokens,
+ targetedNotifications: delivery.androidDeviceTokens.map(
+ deviceToken => ({
+ deviceToken,
+ notification,
+ }),
+ ),
codeVersion: null,
});
} else if (delivery.deviceType === 'ios') {
@@ -103,8 +107,10 @@
threadID,
);
deliveryPromises[id] = fcmPush({
- notification,
- deviceTokens,
+ targetedNotifications: deviceTokens.map(deviceToken => ({
+ deviceToken,
+ notification,
+ })),
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
@@ -41,10 +41,16 @@
import { promiseAll } from 'lib/utils/promises.js';
import { tID, tPlatformDetails, tShape } from 'lib/utils/validation-utils.js';
-import { prepareEncryptedIOSNotifications } from './crypto.js';
+import {
+ prepareEncryptedIOSNotifications,
+ prepareEncryptedAndroidNotifications,
+} from './crypto.js';
import { getAPNsNotificationTopic } from './providers.js';
import { rescindPushNotifs } from './rescind.js';
-import type { TargetedAPNsNotification } from './types.js';
+import type {
+ TargetedAPNsNotification,
+ TargetedAndroidNotification,
+} from './types.js';
import {
apnPush,
fcmPush,
@@ -238,18 +244,20 @@
platformDetails,
);
const deliveryPromise = (async () => {
- const notification = await prepareAndroidNotification({
- notifTexts,
- newRawMessageInfos: shimmedNewRawMessageInfos,
- threadID: threadInfo.id,
- collapseKey: notifInfo.collapseKey,
- badgeOnly,
- unreadCount: unreadCounts[userID],
- platformDetails,
- dbID,
- });
- const deviceTokens = devices.map(({ deviceToken }) => deviceToken);
- return await sendAndroidNotification(notification, deviceTokens, {
+ const targetedNotifications = await prepareAndroidNotification(
+ {
+ notifTexts,
+ newRawMessageInfos: shimmedNewRawMessageInfos,
+ threadID: threadInfo.id,
+ collapseKey: notifInfo.collapseKey,
+ badgeOnly,
+ unreadCount: unreadCounts[userID],
+ platformDetails,
+ dbID,
+ },
+ devices,
+ );
+ return await sendAndroidNotification(targetedNotifications, {
...notificationInfo,
codeVersion,
});
@@ -755,7 +763,8 @@
});
async function prepareAndroidNotification(
inputData: AndroidNotifInputData,
-): Promise<Object> {
+ devices: $ReadOnlyArray<NotificationTargetDevice>,
+): Promise<$ReadOnlyArray<TargetedAndroidNotification>> {
const convertedData = validateOutput(
inputData.platformDetails,
androidNotifInputDataValidator,
@@ -772,6 +781,13 @@
dbID,
} = convertedData;
+ const isTextNotification = newRawMessageInfos.every(
+ newRawMessageInfo => newRawMessageInfo.type === messageTypes.TEXT,
+ );
+
+ const shouldBeEncrypted =
+ isTextNotification && !collapseKey && codeVersion && codeVersion > 222;
+
const notifID = collapseKey ? collapseKey : dbID;
const { merged, ...rest } = notifTexts;
const notification = {
@@ -802,22 +818,44 @@
data: { ...notification.data, messageInfos },
};
- if (
- Buffer.byteLength(JSON.stringify(copyWithMessageInfos)) <=
- fcmMaxNotificationPayloadByteSize
- ) {
- return copyWithMessageInfos;
- }
+ const evaluateAndSelectNotification = (notif, notifWithMessageInfos) => {
+ if (
+ Buffer.byteLength(JSON.stringify(notifWithMessageInfos)) <=
+ fcmMaxNotificationPayloadByteSize
+ ) {
+ return notifWithMessageInfos;
+ }
+ if (
+ Buffer.byteLength(JSON.stringify(notif)) >
+ fcmMaxNotificationPayloadByteSize
+ ) {
+ console.warn(
+ `Android notification ${notifID} exceeds size limit, even with messageInfos omitted`,
+ );
+ }
+ return notif;
+ };
- if (
- Buffer.byteLength(JSON.stringify(notification)) >
- fcmMaxNotificationPayloadByteSize
- ) {
- console.warn(
- `Android notification ${notifID} exceeds size limit, even with messageInfos omitted`,
- );
+ const deviceTokens = devices.map(({ deviceToken }) => deviceToken);
+ if (shouldBeEncrypted) {
+ const cookieIDs = devices.map(({ cookieID }) => cookieID);
+ const [notifications, notificationsWithMessageInfos] = await Promise.all([
+ prepareEncryptedAndroidNotifications(cookieIDs, notification),
+ prepareEncryptedAndroidNotifications(cookieIDs, copyWithMessageInfos),
+ ]);
+ return notificationsWithMessageInfos.map((notif, idx) => ({
+ notification: evaluateAndSelectNotification(notifications[idx], notif),
+ deviceToken: deviceTokens[idx],
+ }));
}
- return notification;
+ const notificationToSend = evaluateAndSelectNotification(
+ notification,
+ copyWithMessageInfos,
+ );
+ return deviceTokens.map(deviceToken => ({
+ notification: notificationToSend,
+ deviceToken,
+ }));
}
type WebNotifInputData = {
@@ -975,8 +1013,7 @@
invalidTokens?: $ReadOnlyArray<string>,
};
async function sendAndroidNotification(
- notification: Object,
- deviceTokens: $ReadOnlyArray<string>,
+ targetedNotifications: $ReadOnlyArray<TargetedAndroidNotification>,
notificationInfo: NotificationInfo,
): Promise<AndroidResult> {
const collapseKey = notificationInfo.collapseKey
@@ -984,11 +1021,13 @@
: null; // for Flow...
const { source, codeVersion } = notificationInfo;
const response = await fcmPush({
- notification,
- deviceTokens,
+ targetedNotifications,
collapseKey,
codeVersion,
});
+ const deviceTokens = targetedNotifications.map(
+ ({ deviceToken }) => deviceToken,
+ );
const androidIDs = response.fcmIDs ? response.fcmIDs : [];
const delivery: AndroidDelivery = {
source,
@@ -1234,15 +1273,31 @@
? { badge: unreadCount.toString() }
: { badge: unreadCount.toString(), badgeOnly: '1' };
const notification = { data: notificationData };
- const deviceTokens = deviceInfos.map(({ deviceToken }) => deviceToken);
- deliveryPromises.push(
- sendAndroidNotification(notification, deviceTokens, {
+ const deliveryPromise = (async () => {
+ const cookieIDs = deviceInfos.map(({ cookieID }) => cookieID);
+ let notificationsArray;
+ if (codeVersion > 222) {
+ notificationsArray = await prepareEncryptedAndroidNotifications(
+ cookieIDs,
+ notification,
+ );
+ } else {
+ notificationsArray = cookieIDs.map(() => notification);
+ }
+ const targetedNotifications = deviceInfos.map(
+ ({ deviceToken }, idx) => ({
+ deviceToken,
+ notification: notificationsArray[idx],
+ }),
+ );
+ return await sendAndroidNotification(targetedNotifications, {
source,
dbID,
userID,
codeVersion,
- }),
- );
+ });
+ })();
+ deliveryPromises.push(deliveryPromise);
}
}
diff --git a/keyserver/src/push/types.js b/keyserver/src/push/types.js
--- a/keyserver/src/push/types.js
+++ b/keyserver/src/push/types.js
@@ -14,3 +14,8 @@
+[string]: string,
},
};
+
+export type TargetedAndroidNotification = {
+ +notification: AndroidNotification,
+ +deviceToken: string,
+};
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
@@ -23,7 +23,7 @@
ensureWebPushInitialized,
getWNSToken,
} from './providers.js';
-import type { TargetedAPNsNotification } from './types.js';
+import type { TargetedAPNsNotification, AndroidNotification } from './types.js';
import { dbQuery, SQL } from '../database/database.js';
const fcmTokenInvalidationErrors = new Set([
@@ -102,13 +102,14 @@
+invalidTokens?: $ReadOnlyArray<string>,
};
async function fcmPush({
- notification,
- deviceTokens,
+ targetedNotifications,
collapseKey,
codeVersion,
}: {
- +notification: Object,
- +deviceTokens: $ReadOnlyArray<string>,
+ +targetedNotifications: $ReadOnlyArray<{
+ +notification: AndroidNotification,
+ +deviceToken: string,
+ }>,
+codeVersion: ?number,
+collapseKey?: ?string,
}): Promise<FCMPushResult> {
@@ -131,7 +132,7 @@
// won't explain which of the device tokens is invalid. So we're forced to
// avoid the multicast functionality and call it once per deviceToken.
const promises = [];
- for (const deviceToken of deviceTokens) {
+ for (const { notification, deviceToken } of targetedNotifications) {
promises.push(
fcmSinglePush(fcmProvider, notification, deviceToken, options),
);
@@ -146,7 +147,7 @@
for (const error of pushResult.errors) {
errors.push(error);
if (fcmTokenInvalidationErrors.has(error.errorInfo.code)) {
- invalidTokens.push(deviceTokens[i]);
+ invalidTokens.push(targetedNotifications[i].deviceToken);
}
}
for (const id of pushResult.fcmIDs) {
diff --git a/keyserver/src/session/cookies.js b/keyserver/src/session/cookies.js
--- a/keyserver/src/session/cookies.js
+++ b/keyserver/src/session/cookies.js
@@ -828,7 +828,8 @@
): Promise<boolean> {
if (
!viewer.platformDetails ||
- viewer.platformDetails.platform !== 'ios' ||
+ (viewer.platformDetails.platform !== 'ios' &&
+ viewer.platformDetails.platform !== 'android') ||
!viewer.platformDetails.codeVersion ||
viewer.platformDetails.codeVersion < 222
) {

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 30, 6:50 PM (21 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2601999
Default Alt Text
D7874.id27188.diff (9 KB)

Event Timeline