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 @@ -385,6 +385,7 @@ cookieID: cookieID.toString(), codeVersion: versions ? versions.codeVersion : null, stateVersion: versions ? versions.stateVersion : null, + majorDesktopVersion: versions ? versions.desktopCodeVersion : null, }); } thisUserInfo.threadIDs.add(threadID); 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 @@ -25,7 +25,10 @@ rawThreadInfoFromServerThreadInfo, threadInfoFromRawThreadInfo, } from 'lib/shared/thread-utils.js'; -import { hasMinCodeVersion } from 'lib/shared/version-utils.js'; +import { + hasMinCodeVersion, + NEXT_CODE_VERSION, +} from 'lib/shared/version-utils.js'; import type { Platform, PlatformDetails } from 'lib/types/device-types.js'; import { messageTypes } from 'lib/types/message-types-enum.js'; import { @@ -89,6 +92,7 @@ +cookieID: string, +codeVersion: ?number, +stateVersion: ?number, + +majorDesktopVersion: ?number, }; type PushUserInfo = { @@ -302,6 +306,7 @@ const preparePromise: Promise<$ReadOnlyArray> = (async () => { const targetedNotifications = await prepareAPNsNotification( + userID, { notifTexts, newRawMessageInfos: shimmedNewRawMessageInfos, @@ -406,11 +411,13 @@ const macosVersionsToTokens = byPlatform.get('macos'); if (macosVersionsToTokens) { for (const [versionKey, devices] of macosVersionsToTokens) { - const { codeVersion, stateVersion } = stringToVersionKey(versionKey); + const { codeVersion, stateVersion, majorDesktopVersion } = + stringToVersionKey(versionKey); const platformDetails = { platform: 'macos', codeVersion, stateVersion, + majorDesktopVersion, }; const shimmedNewRawMessageInfos = shimUnsupportedRawMessageInfos( newRawMessageInfos, @@ -419,6 +426,7 @@ const preparePromise: Promise<$ReadOnlyArray> = (async () => { const targetedNotifications = await prepareAPNsNotification( + userID, { notifTexts, newRawMessageInfos: shimmedNewRawMessageInfos, @@ -791,10 +799,18 @@ return await createIDs('notifications', numIDsNeeded); } -type VersionKey = { codeVersion: number, stateVersion: number }; +type VersionKey = { + codeVersion: number, + stateVersion: number, + majorDesktopVersion?: number, +}; const versionKeyRegex: RegExp = new RegExp(/^-?\d+\|-?\d+$/); function versionKeyToString(versionKey: VersionKey): string { - return `${versionKey.codeVersion}|${versionKey.stateVersion}`; + const baseStringVersionKey = `${versionKey.codeVersion}|${versionKey.stateVersion}`; + if (!versionKey.majorDesktopVersion) { + return baseStringVersionKey; + } + return `${baseStringVersionKey}|${versionKey.majorDesktopVersion}`; } function stringToVersionKey(versionKeyString: string): VersionKey { @@ -802,8 +818,10 @@ versionKeyRegex.test(versionKeyString), 'should pass correct version key string', ); - const [codeVersion, stateVersion] = versionKeyString.split('|').map(Number); - return { codeVersion, stateVersion }; + const [codeVersion, stateVersion, majorDesktopVersion] = versionKeyString + .split('|') + .map(Number); + return { codeVersion, stateVersion, majorDesktopVersion }; } function getDevicesByPlatform( @@ -825,10 +843,15 @@ : -1; const stateVersion: number = device.stateVersion ?? -1; - const versionKey = versionKeyToString({ - codeVersion, - stateVersion, - }); + let versionsObject = { codeVersion, stateVersion }; + if (device.majorDesktopVersion) { + versionsObject = { + ...versionsObject, + majorDesktopVersion: device.majorDesktopVersion, + }; + } + + const versionKey = versionKeyToString(versionsObject); let innerMostArray = innerMap.get(versionKey); if (!innerMostArray) { innerMostArray = []; @@ -862,6 +885,7 @@ platformDetails: tPlatformDetails, }); async function prepareAPNsNotification( + userID: string, inputData: APNsNotifInputData, devices: $ReadOnlyArray, ): Promise<$ReadOnlyArray> { @@ -891,11 +915,22 @@ const canDecryptAllNotifTypes = platformDetails.codeVersion && platformDetails.codeVersion >= 267; - const shouldBeEncrypted = + const canDecryptIOSNotifs = platformDetails.platform === 'ios' && (canDecryptAllNotifTypes || (isNonCollapsibleTextNotification && canDecryptNonCollapsibleTextNotifs)); + const isStaffOrDev = isStaff(userID) || isDev; + const canDecryptDesktopNotifs = + isStaffOrDev && + platformDetails.platform === 'macos' && + hasMinCodeVersion(platformDetails, { + web: NEXT_CODE_VERSION, + majorDesktop: NEXT_CODE_VERSION, + }); + + const shouldBeEncrypted = canDecryptIOSNotifs || canDecryptDesktopNotifs; + const uniqueID = uuidv4(); const notification = new apn.Notification(); notification.topic = getAPNsNotificationTopic(platformDetails); @@ -1695,11 +1730,36 @@ notification.badge = unreadCount; notification.pushType = 'alert'; const preparePromise: Promise = (async () => { - return deviceInfos.map(({ deviceToken }) => ({ - notification: ({ + const isStaffOrDev = isStaff(userID) || isDev; + const shouldBeEncrypted = + isStaffOrDev && + hasMinCodeVersion(viewer.platformDetails, { + web: NEXT_CODE_VERSION, + majorDesktop: NEXT_CODE_VERSION, + }); + let targetedNotifications: $ReadOnlyArray; + if (shouldBeEncrypted) { + const notificationsArray = await prepareEncryptedAPNsNotifications( + deviceInfos, + notification, + codeVersion, + ); + targetedNotifications = notificationsArray.map( + ({ notification: notif, deviceToken, encryptionOrder }) => ({ + notification: notif, + deviceToken, + encryptionOrder, + }), + ); + } else { + targetedNotifications = deviceInfos.map(({ deviceToken }) => ({ deviceToken, notification, - }: TargetedAPNsNotification), + })); + } + + return targetedNotifications.map(targetedNotification => ({ + notification: targetedNotification, platform: 'macos', notificationInfo: { source, 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 @@ -6,7 +6,10 @@ import url from 'url'; import { isStaff } from 'lib/shared/staff-utils.js'; -import { hasMinCodeVersion } from 'lib/shared/version-utils.js'; +import { + hasMinCodeVersion, + NEXT_CODE_VERSION, +} from 'lib/shared/version-utils.js'; import type { Shape } from 'lib/types/core.js'; import type { SignedIdentityKeysBlob } from 'lib/types/crypto-types.js'; import { isWebPlatform } from 'lib/types/device-types.js'; @@ -830,10 +833,12 @@ !viewer.platformDetails || (viewer.platformDetails.platform !== 'ios' && viewer.platformDetails.platform !== 'android' && - !(viewer.platformDetails.platform === 'web' && isStaffOrDev)) || + !(viewer.platformDetails.platform === 'web' && isStaffOrDev) && + !(viewer.platformDetails.platform === 'macos' && isStaffOrDev)) || !hasMinCodeVersion(viewer.platformDetails, { native: 222, web: 43, + majorDesktop: NEXT_CODE_VERSION, }) ) { return false;