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 @@ -7,6 +7,7 @@ import _flow from 'lodash/fp/flow.js'; import _mapValues from 'lodash/fp/mapValues.js'; import _pickBy from 'lodash/fp/pickBy.js'; +import t from 'tcomb'; import uuidv4 from 'uuid/v4.js'; import { oldValidUsernameRegex } from 'lib/shared/account-utils.js'; @@ -28,14 +29,17 @@ type RawMessageInfo, type MessageData, } from 'lib/types/message-types.js'; +import { rawMessageInfoValidator } from 'lib/types/message-types.js'; import type { WebNotification, WNSNotification, ResolvedNotifTexts, } from 'lib/types/notif-types.js'; +import { resolvedNotifTextsValidator } from 'lib/types/notif-types.js'; import type { ServerThreadInfo } from 'lib/types/thread-types.js'; import { updateTypes } from 'lib/types/update-types-enum.js'; import { promiseAll } from 'lib/utils/promises.js'; +import { tID, tPlatformDetails, tShape } from 'lib/utils/validation-utils.js'; import { getAPNsNotificationTopic } from './providers.js'; import { rescindPushNotifs } from './rescind.js'; @@ -60,6 +64,7 @@ import { fetchUserInfos } from '../fetchers/user-fetchers.js'; import type { Viewer } from '../session/viewer.js'; import { getENSNames } from '../utils/ens-cache.js'; +import { validateOutput } from '../utils/validation-utils.js'; type Device = { +platform: Platform, @@ -253,11 +258,13 @@ const webVersionsToTokens = byPlatform.get('web'); if (webVersionsToTokens) { for (const [codeVersion, deviceTokens] of webVersionsToTokens) { + const platformDetails = { platform: 'web', codeVersion }; const deliveryPromise = (async () => { const notification = await prepareWebNotification({ notifTexts, threadID: threadInfo.id, unreadCount: unreadCounts[userID], + platformDetails, }); return await sendWebNotification(notification, [...deviceTokens], { ...notificationInfo, @@ -301,11 +308,13 @@ const windowsVersionsToTokens = byPlatform.get('windows'); if (windowsVersionsToTokens) { for (const [codeVersion, deviceTokens] of windowsVersionsToTokens) { + const platformDetails = { platform: 'windows', codeVersion }; const deliveryPromise = (async () => { const notification = await prepareWNSNotification({ notifTexts, threadID: threadInfo.id, unreadCount: unreadCounts[userID], + platformDetails, }); return await sendWNSNotification(notification, [...deviceTokens], { ...notificationInfo, @@ -609,9 +618,23 @@ +unreadCount: number, +platformDetails: PlatformDetails, }; +const apnsNotifInputDataValidator = tShape({ + notifTexts: resolvedNotifTextsValidator, + newRawMessageInfos: t.list(rawMessageInfoValidator), + threadID: tID, + collapseKey: t.maybe(t.String), + badgeOnly: t.Boolean, + unreadCount: t.Number, + platformDetails: tPlatformDetails, +}); async function prepareAPNsNotification( inputData: APNsNotifInputData, ): Promise { + const convertedData = validateOutput( + inputData.platformDetails, + apnsNotifInputDataValidator, + inputData, + ); const { notifTexts, newRawMessageInfos, @@ -620,7 +643,7 @@ badgeOnly, unreadCount, platformDetails, - } = inputData; + } = convertedData; const uniqueID = uuidv4(); const notification = new apn.Notification(); @@ -680,9 +703,18 @@ ...APNsNotifInputData, +dbID: string, }; +const androidNotifInputDataValidator = tShape({ + ...apnsNotifInputDataValidator.meta.props, + dbID: t.String, +}); async function prepareAndroidNotification( inputData: AndroidNotifInputData, ): Promise { + const convertedData = validateOutput( + inputData.platformDetails, + androidNotifInputDataValidator, + inputData, + ); const { notifTexts, newRawMessageInfos, @@ -692,7 +724,7 @@ unreadCount, platformDetails: { codeVersion }, dbID, - } = inputData; + } = convertedData; const notifID = collapseKey ? collapseKey : dbID; const { merged, ...rest } = notifTexts; @@ -746,11 +778,23 @@ +notifTexts: ResolvedNotifTexts, +threadID: string, +unreadCount: number, + +platformDetails: PlatformDetails, }; +const webNotifInputDataValidator = tShape({ + notifTexts: resolvedNotifTextsValidator, + threadID: tID, + unreadCount: t.Number, + platformDetails: tPlatformDetails, +}); async function prepareWebNotification( inputData: WebNotifInputData, ): Promise { - const { notifTexts, threadID, unreadCount } = inputData; + const convertedData = validateOutput( + inputData.platformDetails, + webNotifInputDataValidator, + inputData, + ); + const { notifTexts, threadID, unreadCount } = convertedData; const id = uuidv4(); const { merged, ...rest } = notifTexts; const notification = { @@ -766,11 +810,23 @@ +notifTexts: ResolvedNotifTexts, +threadID: string, +unreadCount: number, + +platformDetails: PlatformDetails, }; +const wnsNotifInputDataValidator = tShape({ + notifTexts: resolvedNotifTextsValidator, + threadID: tID, + unreadCount: t.Number, + platformDetails: tPlatformDetails, +}); async function prepareWNSNotification( inputData: WNSNotifInputData, ): Promise { - const { notifTexts, threadID, unreadCount } = inputData; + const convertedData = validateOutput( + inputData.platformDetails, + wnsNotifInputDataValidator, + inputData, + ); + const { notifTexts, threadID, unreadCount } = convertedData; const { merged, ...rest } = notifTexts; const notification = { ...rest, 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 @@ -1,6 +1,9 @@ // @flow +import t, { type TInterface } from 'tcomb'; + import type { EntityText, ThreadEntity } from '../utils/entity-text.js'; +import { tShape } from '../utils/validation-utils.js'; export type NotifTexts = { +merged: string | EntityText, @@ -15,6 +18,13 @@ +title: string, +prefix?: string, }; +export const resolvedNotifTextsValidator: TInterface = + tShape({ + merged: t.String, + body: t.String, + title: t.String, + prefix: t.maybe(t.String), + }); export type WebNotification = { +body: string,