Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F33035710
D8377.1768409022.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D8377.1768409022.diff
View Options
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
@@ -3,11 +3,21 @@
import apn from '@parse/node-apn';
import invariant from 'invariant';
+import { NEXT_CODE_VERSION } from 'lib/shared/version-utils.js';
import { threadSubscriptions } from 'lib/types/subscription-types.js';
import { threadPermissions } from 'lib/types/thread-permission-types.js';
import { promiseAll } from 'lib/utils/promises.js';
+import {
+ prepareEncryptedAndroidNotificationRescinds,
+ prepareEncryptedIOSNotifications,
+} from './crypto.js';
import { getAPNsNotificationTopic } from './providers.js';
+import type {
+ NotificationTargetDevice,
+ TargetedAndroidNotification,
+ TargetedAPNsNotification,
+} from './types.js';
import { apnPush, fcmPush } from './utils.js';
import createIDs from '../creators/id-creator.js';
import { dbQuery, SQL } from '../database/database.js';
@@ -37,85 +47,90 @@
fetchQuery.append(SQL` GROUP BY n.id, m.user`);
const [fetchResult] = await dbQuery(fetchQuery);
+ const allDeviceTokens = [];
+ for (const row of fetchResult) {
+ const rawDelivery = JSON.parse(row.delivery);
+ const deliveries = Array.isArray(rawDelivery) ? rawDelivery : [rawDelivery];
+
+ for (const delivery of deliveries) {
+ if (delivery.iosID || delivery.deviceType === 'ios') {
+ const deviceTokens = delivery.iosDeviceTokens ?? delivery.deviceTokens;
+ allDeviceTokens.push(...deviceTokens);
+ } else if (delivery.androidID || delivery.deviceType === 'android') {
+ const deviceTokens =
+ delivery.androidDeviceTokens ?? delivery.deviceTokens;
+ allDeviceTokens.push(deviceTokens);
+ }
+ }
+ }
+ const deviceTokenToCookieID = await getDeviceTokenToCookieID(allDeviceTokens);
+
const deliveryPromises = {};
const notifInfo = {};
const rescindedIDs = [];
+
for (const row of fetchResult) {
const rawDelivery = JSON.parse(row.delivery);
const deliveries = Array.isArray(rawDelivery) ? rawDelivery : [rawDelivery];
const id = row.id.toString();
const threadID = row.thread.toString();
+
notifInfo[id] = {
userID: row.user.toString(),
threadID,
messageID: row.message.toString(),
};
+
for (const delivery of deliveries) {
- if (delivery.iosID && delivery.iosDeviceTokens) {
- // Old iOS
- const notification = prepareIOSNotification(
- delivery.iosID,
- row.unread_count,
- threadID,
- );
- const targetedNotifications = delivery.iosDeviceTokens.map(
- deviceToken => ({ deviceToken, notification }),
- );
- deliveryPromises[id] = apnPush({
- targetedNotifications,
- platformDetails: { platform: 'ios' },
- });
- } else if (delivery.androidID) {
- // Old Android
- const notification = prepareAndroidNotification(
- row.collapse_key ? row.collapse_key : id,
- row.unread_count,
- threadID,
- );
- deliveryPromises[id] = fcmPush({
- targetedNotifications: delivery.androidDeviceTokens.map(
- deviceToken => ({
- deviceToken,
- notification,
- }),
- ),
- codeVersion: null,
- });
- } else if (delivery.deviceType === 'ios') {
- // New iOS
- const { iosID, deviceTokens, codeVersion } = delivery;
- const notification = prepareIOSNotification(
- iosID,
- row.unread_count,
- threadID,
- codeVersion,
- );
- const targetedNotifications = deviceTokens.map(deviceToken => ({
+ if (delivery.iosID) {
+ const deviceTokens = delivery.iosDeviceTokens ?? delivery.deviceTokens;
+ const devices = deviceTokens.map(deviceToken => ({
deviceToken,
- notification,
+ cookieID: deviceTokenToCookieID[deviceToken],
}));
- deliveryPromises[id] = apnPush({
- targetedNotifications,
- platformDetails: { platform: 'ios', codeVersion },
- });
- } else if (delivery.deviceType === 'android') {
- // New Android
- const { deviceTokens, codeVersion } = delivery;
- const notification = prepareAndroidNotification(
- row.collapse_key ? row.collapse_key : id,
- row.unread_count,
- threadID,
- );
- deliveryPromises[id] = fcmPush({
- targetedNotifications: deviceTokens.map(deviceToken => ({
- deviceToken,
- notification,
- })),
- codeVersion,
- });
+
+ const deliveryPromise = (async () => {
+ const targetedNotifications = await prepareIOSNotification(
+ delivery.iosID,
+ row.unread_count,
+ threadID,
+ delivery.codeVersion,
+ devices,
+ );
+
+ return await apnPush({
+ targetedNotifications,
+ platformDetails: {
+ platform: 'ios',
+ codeVersion: delivery.codeVersion,
+ },
+ });
+ })();
+ deliveryPromises[id] = deliveryPromise;
+ } else if (delivery.androidID || delivery.deviceType === 'android') {
+ const deviceTokens =
+ delivery.androidDeviceTokens ?? delivery.deviceTokens;
+ const devices = deviceTokens.map(deviceToken => ({
+ deviceToken,
+ cookieID: deviceTokenToCookieID[deviceToken],
+ }));
+ const deliveryPromise = (async () => {
+ const targetedNotifications = await prepareAndroidNotification(
+ row.collapse_key ? row.collapse_key : id,
+ row.unread_count,
+ threadID,
+ delivery.codeVersion,
+ devices,
+ );
+ return await fcmPush({
+ targetedNotifications,
+ codeVersion: delivery.codeVersion,
+ });
+ })();
+ deliveryPromises[id] = deliveryPromise;
}
}
- rescindedIDs.push(row.id);
+ rescindedIDs.push(id);
}
const numRescinds = Object.keys(deliveryPromises).length;
@@ -165,12 +180,32 @@
}
}
-function prepareIOSNotification(
+async function getDeviceTokenToCookieID(
+ deviceTokens,
+): Promise<{ +[string]: string }> {
+ if (deviceTokens.length === 0) {
+ return {};
+ }
+
+ const deviceTokenToCookieID = {};
+ const fetchCookiesQuery = SQL`
+ SELECT id, device_token FROM cookies
+ WHERE device_token IN (${deviceTokens})
+ `;
+ const [fetchResult] = await dbQuery(fetchCookiesQuery);
+ for (const row of fetchResult) {
+ deviceTokenToCookieID[row.device_token.toString()] = row.id.toString();
+ }
+ return deviceTokenToCookieID;
+}
+
+async function prepareIOSNotification(
iosID: string,
unreadCount: number,
threadID: string,
codeVersion: ?number,
-): apn.Notification {
+ devices: $ReadOnlyArray<NotificationTargetDevice>,
+): Promise<$ReadOnlyArray<TargetedAPNsNotification>> {
const notification = new apn.Notification();
notification.topic = getAPNsNotificationTopic({
platform: 'ios',
@@ -203,15 +238,35 @@
notificationId: iosID,
},
};
- return notification;
+
+ const deviceTokens = devices.map(({ deviceToken }) => deviceToken);
+ const shouldBeEncrypted = codeVersion && codeVersion > NEXT_CODE_VERSION;
+
+ if (!shouldBeEncrypted) {
+ return deviceTokens.map(deviceToken => ({
+ notification,
+ deviceToken,
+ }));
+ }
+ const cookieIDs = devices.map(({ cookieID }) => cookieID);
+ const notifications = await prepareEncryptedIOSNotifications(
+ cookieIDs,
+ notification,
+ );
+ return notifications.map((notif, idx) => ({
+ notification: notif,
+ deviceToken: deviceTokens[idx],
+ }));
}
-function prepareAndroidNotification(
+async function prepareAndroidNotification(
notifID: string,
unreadCount: number,
threadID: string,
-): Object {
- return {
+ codeVersion: ?number,
+ devices: $ReadOnlyArray<NotificationTargetDevice>,
+): Promise<$ReadOnlyArray<TargetedAndroidNotification>> {
+ const notification = {
data: {
badge: unreadCount.toString(),
rescind: 'true',
@@ -220,6 +275,23 @@
threadID,
},
};
+ const deviceTokens = devices.map(({ deviceToken }) => deviceToken);
+ const shouldBeEncrypted = codeVersion && codeVersion > NEXT_CODE_VERSION;
+ if (!shouldBeEncrypted) {
+ return deviceTokens.map(deviceToken => ({
+ notification,
+ deviceToken,
+ }));
+ }
+ const cookieIDs = devices.map(({ cookieID }) => cookieID);
+ const notifications = await prepareEncryptedAndroidNotificationRescinds(
+ cookieIDs,
+ notification,
+ );
+ return notifications.map((notif, idx) => ({
+ notification: notif,
+ deviceToken: deviceTokens[idx],
+ }));
}
export { rescindPushNotifs };
diff --git a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
--- a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
+++ b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
@@ -78,12 +78,7 @@
@Override
public void onMessageReceived(RemoteMessage message) {
- String rescind = message.getData().get(RESCIND_KEY);
- if ("true".equals(rescind) &&
- android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
- handleNotificationRescind(message);
- }
-
+ Log.w("COMM", "Received notification");
if (message.getData().get(ENCRYPTED_PAYLOAD_KEY) != null) {
try {
message = this.decryptRemoteMessage(message);
@@ -103,6 +98,16 @@
"Received unencrypted notification for client with existing olm session for notifications");
}
+ String rescind = message.getData().get(RESCIND_KEY);
+ Log.w("COMM", "Received rescind with rescind: " + rescind);
+ if ("true".equals(rescind) &&
+ android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+ Log.w(
+ "COMM",
+ "Received rescind with id: " + message.getData().get(RESCIND_ID_KEY));
+ handleNotificationRescind(message);
+ }
+
String badge = message.getData().get(BADGE_KEY);
if (badge != null) {
try {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jan 14, 4:43 PM (8 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5932922
Default Alt Text
D8377.1768409022.diff (10 KB)
Attached To
Mode
D8377: Encrypt rescinds
Attached
Detach File
Event Timeline
Log In to Comment