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 @@ -5,7 +5,7 @@ import type { FirebaseError } from 'firebase-admin'; import invariant from 'invariant'; -import { prepareEncryptedAndroidSilentNotifications } from 'lib/push/crypto.js'; +import { createAndroidNotificationRescind } from 'lib/push/notif-creators.js'; import type { PlatformDetails } from 'lib/types/device-types.js'; import type { NotificationTargetDevice, @@ -375,29 +375,17 @@ devices: $ReadOnlyArray, ): Promise<$ReadOnlyArray> { threadID = await validateOutput(platformDetails, tID, threadID); - const { codeVersion } = platformDetails; - - const notification = { - data: { + return await createAndroidNotificationRescind( + encryptedNotifUtilsAPI, + { + senderDeviceID: { keyserverID }, badge: unreadCount.toString(), - rescind: 'true', + platformDetails, rescindID: notifID, - setUnreadStatus: 'true', threadID, }, - }; - const targetedRescinds = await conditionallyEncryptNotification( - encryptedNotifUtilsAPI, - { keyserverID }, - notification, - codeVersion, devices, - prepareEncryptedAndroidSilentNotifications, ); - return targetedRescinds.map(targetedRescind => ({ - ...targetedRescind, - priority: 'normal', - })); } export { rescindPushNotifs }; 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 @@ -12,7 +12,6 @@ import t from 'tcomb'; import uuidv4 from 'uuid/v4.js'; -import { prepareEncryptedAndroidSilentNotifications } from 'lib/push/crypto.js'; import { type AndroidNotifInputData, androidNotifInputDataValidator, @@ -23,6 +22,7 @@ type WNSNotifInputData, wnsNotifInputDataValidator, createWNSNotification, + createAndroidBadgeOnlyNotification, } from 'lib/push/notif-creators.js'; import { oldValidUsernameRegex } from 'lib/shared/account-utils.js'; import { isUserMentioned } from 'lib/shared/mention-utils.js'; @@ -1604,39 +1604,21 @@ if (androidVersionsToTokens) { for (const [versionKey, deviceInfos] of androidVersionsToTokens) { const { codeVersion, stateVersion } = stringToVersionKey(versionKey); - const notificationData = { - badge: unreadCount.toString(), - badgeOnly: '1', - }; - const notification = { - data: { ...notificationData }, - }; const preparePromise: Promise = (async () => { - let targetedNotifications: $ReadOnlyArray; - const priority = 'normal'; - if (codeVersion > 222) { - const notificationsArray = - await prepareEncryptedAndroidSilentNotifications( - encryptedNotifUtilsAPI, - { keyserverID }, - deviceInfos, - notification, - ); - targetedNotifications = notificationsArray.map( - ({ notification: notif, deliveryID, encryptionOrder }) => ({ - priority, - notification: notif, - deliveryID, - encryptionOrder, - }), + const targetedNotifications: $ReadOnlyArray = + await createAndroidBadgeOnlyNotification( + encryptedNotifUtilsAPI, + { + senderDeviceID: { keyserverID }, + badge: unreadCount.toString(), + platformDetails: { + codeVersion, + stateVersion, + platform: 'android', + }, + }, + deviceInfos, ); - } else { - targetedNotifications = deviceInfos.map(({ deliveryID }) => ({ - priority, - deliveryID, - notification, - })); - } return targetedNotifications.map(targetedNotification => ({ notification: targetedNotification, platform: 'android', diff --git a/lib/push/notif-creators.js b/lib/push/notif-creators.js --- a/lib/push/notif-creators.js +++ b/lib/push/notif-creators.js @@ -1,12 +1,17 @@ // @flow +import invariant from 'invariant'; import t, { type TInterface } from 'tcomb'; import { prepareEncryptedAndroidVisualNotifications, + prepareEncryptedAndroidSilentNotifications, prepareEncryptedWNSNotifications, prepareEncryptedWebNotifications, } from './crypto.js'; -import { hasMinCodeVersion } from '../shared/version-utils.js'; +import { + hasMinCodeVersion, + FUTURE_CODE_VERSION, +} from '../shared/version-utils.js'; import type { PlatformDetails } from '../types/device-types.js'; import { messageTypes } from '../types/message-types-enum.js'; import { @@ -24,6 +29,7 @@ type SenderDeviceID, senderDeviceIDValidator, type EncryptedNotifUtilsAPI, + type AndroidBadgeOnlyNotification, } from '../types/notif-types.js'; import { tID, tPlatformDetails, tShape } from '../utils/validation-utils.js'; @@ -253,6 +259,137 @@ ...targetedNotifsWithoutMessageInfos, ]; } +type AndroidNotificationRescindInputData = { + +senderDeviceID: SenderDeviceID, + +threadID: string, + +rescindID?: string, + +badge?: string, + +platformDetails: PlatformDetails, +}; + +async function createAndroidNotificationRescind( + encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI, + inputData: AndroidNotificationRescindInputData, + devices: $ReadOnlyArray, +): Promise<$ReadOnlyArray> { + const { senderDeviceID, platformDetails, threadID, rescindID, badge } = + inputData; + + let notification = { + data: { + rescind: 'true', + setUnreadStatus: 'true', + threadID, + }, + }; + + invariant( + (rescindID && badge) || + hasMinCodeVersion(platformDetails, { native: FUTURE_CODE_VERSION }), + 'thick thread rescind not support for this client version', + ); + + if (rescindID && badge) { + notification = { + ...notification, + data: { + ...notification.data, + badge, + rescindID, + }, + }; + } + + const shouldBeEncrypted = hasMinCodeVersion(platformDetails, { native: 233 }); + if (!shouldBeEncrypted) { + return devices.map(({ deliveryID }) => ({ + notification, + deliveryID, + priority: 'normal', + })); + } + + const notifications = await prepareEncryptedAndroidSilentNotifications( + encryptedNotifUtilsAPI, + senderDeviceID, + devices, + notification, + ); + + return notifications.map(({ deliveryID, notification: notif }) => ({ + deliveryID, + notification: notif, + priority: 'normal', + })); +} + +type AndroidBadgeOnlyNotificationInputData = $ReadOnly<{ + +senderDeviceID: SenderDeviceID, + +platformDetails: PlatformDetails, + ... + | { + +badge: string, + } + | { threadID: string }, +}>; + +async function createAndroidBadgeOnlyNotification( + encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI, + inputData: AndroidBadgeOnlyNotificationInputData, + devices: $ReadOnlyArray, +): Promise<$ReadOnlyArray> { + const { senderDeviceID, platformDetails, badge, threadID } = inputData; + + invariant( + (!threadID && badge) || + hasMinCodeVersion(platformDetails, { native: FUTURE_CODE_VERSION }), + 'thick thread badge updates not support for this client version', + ); + + let notificationData = { badgeOnly: '1' }; + if (badge) { + notificationData = { + ...notificationData, + badge, + }; + } else { + invariant( + threadID, + 'Either badge or threadID must be present in badge only notif', + ); + notificationData = { + ...notificationData, + threadID, + }; + } + + const notification: AndroidBadgeOnlyNotification = { data: notificationData }; + const shouldBeEncrypted = hasMinCodeVersion(platformDetails, { native: 222 }); + + if (!shouldBeEncrypted) { + return devices.map(({ deliveryID }) => ({ + notification, + deliveryID, + priority: 'normal', + })); + } + + const notifications = await prepareEncryptedAndroidSilentNotifications( + encryptedNotifUtilsAPI, + senderDeviceID, + devices, + notification, + ); + + return notifications.map( + ({ notification: notif, deliveryID, encryptionOrder }) => ({ + priority: 'normal', + notification: notif, + deliveryID, + encryptionOrder, + }), + ); +} export type WebNotifInputData = { +id: string, @@ -361,6 +498,8 @@ export { createAndroidVisualNotification, + createAndroidNotificationRescind, + createAndroidBadgeOnlyNotification, createWebNotification, createWNSNotification, }; 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 @@ -141,7 +141,13 @@ | { +badge: string, +rescind: 'true', - +rescindID: string, + +rescindID?: string, + +setUnreadStatus: 'true', + +threadID: string, + +encryptionFailed?: string, + } + | { + +rescind: 'true', +setUnreadStatus: 'true', +threadID: string, +encryptionFailed?: string, @@ -162,6 +168,11 @@ +badgeOnly: '1', +encryptionFailed?: string, } + | { + +threadID: string, + +badgeOnly: '1', + +encryptionFailed?: string, + } | { +keyserverID: string, +encryptedPayload: string,