diff --git a/desktop/flow-typed/npm/electron_v22.0.0.js b/desktop/flow-typed/npm/electron_v22.0.0.js --- a/desktop/flow-typed/npm/electron_v22.0.0.js +++ b/desktop/flow-typed/npm/electron_v22.0.0.js @@ -336,7 +336,7 @@ declare type PushNotificationsEvents = { 'received-apns-notification': ( event: Event, - userInfo: { +[string]: mixed }, + userInfo: { +[string]: mixed, +encryptedPayload?: string }, ) => void, }; diff --git a/desktop/src/main.js b/desktop/src/main.js --- a/desktop/src/main.js +++ b/desktop/src/main.js @@ -20,6 +20,7 @@ import { listenForNotifications, registerForNotifications, + showNewNotification, } from './push-notifications.js'; const isDev = process.env.ENV === 'dev'; @@ -303,13 +304,24 @@ } }; + const handleEncryptedNotification = (encryptedPayload: string) => { + if (mainWindow) { + mainWindow.webContents.send('on-encrypted-notification', { + encryptedPayload, + }); + } + }; + if (app.isPackaged) { try { initAutoUpdate(); } catch (error) { console.error(error); } - listenForNotifications(handleNotificationClick); + listenForNotifications( + handleNotificationClick, + handleEncryptedNotification, + ); ipcMain.on('fetch-device-token', sendDeviceTokenToWebApp); } @@ -321,6 +333,12 @@ ipcMain.on('get-version', event => { event.returnValue = app.getVersion().toString(); }); + ipcMain.on( + 'show-decrypted-notification', + (event, decryptedNotification) => { + showNewNotification(decryptedNotification, handleNotificationClick); + }, + ); show(); diff --git a/desktop/src/preload.js b/desktop/src/preload.js --- a/desktop/src/preload.js +++ b/desktop/src/preload.js @@ -41,6 +41,19 @@ ipcRenderer.removeListener('on-notification-clicked', withEvent); }, fetchDeviceToken: () => ipcRenderer.send('fetch-device-token'), + onEncryptedNotification: callback => { + const withEvent = ( + event: IpcRendererEvent, + ...args: $ReadOnlyArray + ) => { + callback(...args); + }; + ipcRenderer.on('on-encrypted-notification', withEvent); + return () => + ipcRenderer.removeListener('on-encrypted-notification', withEvent); + }, + showDecryptedNotification: decryptedPayload => + ipcRenderer.send('show-decrypted-notification', decryptedPayload), }; contextBridge.exposeInMainWorld('electronContextBridge', bridge); diff --git a/desktop/src/push-notifications.js b/desktop/src/push-notifications.js --- a/desktop/src/push-notifications.js +++ b/desktop/src/push-notifications.js @@ -127,10 +127,17 @@ notif.show(); } -function listenForNotifications(handleClick: (threadID?: string) => void) { +function listenForNotifications( + handleClick: (threadID?: string) => void, + handleEncryptedNotification: (encryptedPayload: string) => void, +) { if (process.platform === 'darwin') { pushNotifications.on('received-apns-notification', (event, userInfo) => { - showNewNotification(userInfo, handleClick); + if (userInfo.encryptedPayload) { + handleEncryptedNotification(userInfo.encryptedPayload); + } else { + showNewNotification(userInfo, handleClick); + } }); } else if (process.platform === 'win32') { windowsPushNotifEventEmitter.on('received-wns-notification', payload => { @@ -138,4 +145,8 @@ }); } } -export { listenForNotifications, registerForNotifications }; +export { + listenForNotifications, + registerForNotifications, + showNewNotification, +}; diff --git a/lib/types/electron-types.js b/lib/types/electron-types.js --- a/lib/types/electron-types.js +++ b/lib/types/electron-types.js @@ -11,6 +11,10 @@ type OnNotificationClickedListener = (data: { threadID: string }) => void; +type OnEncryptedNotificationListener = (data: { + encryptedPayload: string, +}) => mixed; + export type ElectronBridge = { // Returns a callback that you can call to remove the listener +onNavigate: OnNavigateListener => () => void, @@ -25,4 +29,6 @@ +onDeviceTokenRegistered?: OnDeviceTokenRegisteredListener => () => void, +onNotificationClicked?: OnNotificationClickedListener => () => void, +fetchDeviceToken: () => void, + +onEncryptedNotification?: OnEncryptedNotificationListener => () => void, + +showDecryptedNotification: (decryptedPayload: { +[string]: mixed }) => void, }; diff --git a/web/push-notif/push-notifs-handler.js b/web/push-notif/push-notifs-handler.js --- a/web/push-notif/push-notifs-handler.js +++ b/web/push-notif/push-notifs-handler.js @@ -17,6 +17,7 @@ import { useDispatch } from 'lib/utils/redux-utils.js'; import { ashoatKeyserverID } from 'lib/utils/validation-utils.js'; +import { decryptDesktopNotification } from './notif-crypto-utils.js'; import { WORKERS_MODULES_DIR_PATH, DEFAULT_OLM_FILENAME, @@ -33,6 +34,7 @@ function useCreateDesktopPushSubscription() { const dispatchActionPromise = useDispatchActionPromise(); const callSetDeviceToken = useSetDeviceTokenFanout(); + const staffCanSee = useStaffCanSee(); React.useEffect( () => @@ -49,6 +51,20 @@ electron?.fetchDeviceToken(); }, []); + React.useEffect( + () => + electron?.onEncryptedNotification?.( + async ({ encryptedPayload }: { encryptedPayload: string }) => { + const decryptedPayload = await decryptDesktopNotification( + encryptedPayload, + staffCanSee, + ); + electron?.showDecryptedNotification(decryptedPayload); + }, + ), + [staffCanSee], + ); + const dispatch = useDispatch(); React.useEffect(