diff --git a/keyserver/flow-typed/npm/@parse/node-apn_vx.x.x.js b/keyserver/flow-typed/npm/@parse/node-apn_vx.x.x.js --- a/keyserver/flow-typed/npm/@parse/node-apn_vx.x.x.js +++ b/keyserver/flow-typed/npm/@parse/node-apn_vx.x.x.js @@ -38,7 +38,7 @@ // be accessed from apn.Notification instance aps: { +badge: string | number, - +alert: string, + +alert: string | {+body?: string, ...}, +'thread-id': string, +'mutable-content': boolean, +sound: string, 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 @@ -3,6 +3,8 @@ import apn from '@parse/node-apn'; import invariant from 'invariant'; +import { NEXT_CODE_VERSION } from 'lib/shared/version-utils.js'; + import type { AndroidNotification, AndroidNotificationRescind, @@ -12,6 +14,7 @@ async function encryptIOSNotification( cookieID: string, notification: apn.Notification, + codeVersion?: ?number, ): Promise { invariant( !notification.collapseId, @@ -63,6 +66,12 @@ }; return encryptedNotification; } + if (codeVersion && codeVersion > NEXT_CODE_VERSION) { + encryptedNotification.aps = { + alert: { body: 'ENCRYPTED' }, + ...encryptedNotification.aps, + }; + } encryptedNotification.payload.encryptedPayload = encryptedSerializedPayload.body; @@ -129,9 +138,10 @@ function prepareEncryptedIOSNotifications( cookieIDs: $ReadOnlyArray, notification: apn.Notification, + codeVersion?: ?number, ): Promise<$ReadOnlyArray> { const notificationPromises = cookieIDs.map(cookieID => - encryptIOSNotification(cookieID, notification), + encryptIOSNotification(cookieID, notification, codeVersion), ); return Promise.all(notificationPromises); } 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 @@ -225,9 +225,10 @@ encryptCallback: ( cookieIDs: $ReadOnlyArray, notification: T, + codeVersion?: ?number, ) => Promise<$ReadOnlyArray>, ): Promise<$ReadOnlyArray<{ +deviceToken: string, +notification: T }>> { - const shouldBeEncrypted = codeVersion && codeVersion > NEXT_CODE_VERSION; + const shouldBeEncrypted = codeVersion && codeVersion >= NEXT_CODE_VERSION; if (!shouldBeEncrypted) { return devices.map(({ deviceToken }) => ({ notification, @@ -236,7 +237,11 @@ } const notificationPromises = devices.map(({ cookieID, deviceToken }) => (async () => { - const [encryptedNotif] = await encryptCallback([cookieID], notification); + const [encryptedNotif] = await encryptCallback( + [cookieID], + notification, + codeVersion, + ); return { notification: encryptedNotif, deviceToken, 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 @@ -731,8 +731,16 @@ ) { const cookieIDs = devices.map(({ cookieID }) => cookieID); const [notifications, notificationsWithMessageInfos] = await Promise.all([ - prepareEncryptedIOSNotifications(cookieIDs, notification), - prepareEncryptedIOSNotifications(cookieIDs, copyWithMessageInfos), + prepareEncryptedIOSNotifications( + cookieIDs, + notification, + platformDetails.codeVersion, + ), + prepareEncryptedIOSNotifications( + cookieIDs, + copyWithMessageInfos, + platformDetails.codeVersion, + ), ]); return notificationsWithMessageInfos.map((notif, idx) => ({ notification: evaluateAndSelectNotifPayload(notifications[idx], notif), @@ -1239,6 +1247,7 @@ notificationsArray = await prepareEncryptedIOSNotifications( cookieIDs, notification, + codeVersion, ); } else { notificationsArray = cookieIDs.map(() => notification); diff --git a/native/ios/NotificationService/NotificationService.mm b/native/ios/NotificationService/NotificationService.mm --- a/native/ios/NotificationService/NotificationService.mm +++ b/native/ios/NotificationService/NotificationService.mm @@ -58,6 +58,15 @@ self.contentHandler([[UNNotificationContent alloc] init]); return; } + + if ([self isBadgeOnly:self.bestAttemptContent.userInfo]) { + UNMutableNotificationContent *badgeOnlyContent = + [[[UNNotificationContent alloc] init] mutableCopy]; + badgeOnlyContent.badge = self.bestAttemptContent.badge; + self.contentHandler(badgeOnlyContent); + return; + } + [self sendNewMessageInfosNotification]; // TODO modify self.bestAttemptContent here @@ -155,6 +164,12 @@ [payload[backgroundNotificationTypeKey] isEqualToString:@"CLEAR"]; } +- (BOOL)isBadgeOnly:(NSDictionary *)payload { + // TODO: refactor this check by introducing + // badgeOnly property in iOS notification payload + return !payload[@"threadID"]; +} + - (void)sendNewMessageInfosNotification { CFNotificationCenterPostNotification( CFNotificationCenterGetDarwinNotifyCenter(),