Created
July 15, 2024 12:23
-
-
Save marcinwasowicz/8bdc755abad8ecf81f3bd01c6ca34376 to your computer and use it in GitHub Desktop.
Test notification inbound session creation from the NSE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/handlers/db-ops-handler.react.js b/lib/handlers/db-ops-handler.react.js | |
index 6eba0272ff..6b38d00814 100644 | |
--- a/lib/handlers/db-ops-handler.react.js | |
+++ b/lib/handlers/db-ops-handler.react.js | |
@@ -1,8 +1,10 @@ | |
// @flow | |
import * as React from 'react'; | |
+import uuid from 'uuid'; | |
import { opsProcessingFinishedActionType } from '../actions/db-ops-actions.js'; | |
+import { usePreparePushNotifs } from '../push/send-hooks.react.js'; | |
import { usePeerToPeerCommunication } from '../tunnelbroker/peer-to-peer-context.js'; | |
import { useTunnelbroker } from '../tunnelbroker/tunnelbroker-context.js'; | |
import type { DBOpsEntry } from '../types/db-ops-types.js'; | |
@@ -21,12 +23,13 @@ type Props = { | |
}; | |
function DBOpsHandler(props: Props): React.Node { | |
- const { sqliteAPI } = getConfig(); | |
+ const { sqliteAPI, encryptedNotifUtilsAPI } = getConfig(); | |
const { processDBStoreOperations } = props; | |
const queueFront = useSelector(state => state.dbOpsStore.queuedOps[0]); | |
const prevQueueFront = React.useRef<?DBOpsEntry>(null); | |
- const { sendMessage } = useTunnelbroker(); | |
+ const { sendMessage, sendNotif } = useTunnelbroker(); | |
const { processOutboundMessages } = usePeerToPeerCommunication(); | |
+ const preparePushNotifs = usePreparePushNotifs(); | |
const dispatch = useDispatch(); | |
@@ -43,6 +46,60 @@ function DBOpsHandler(props: Props): React.Node { | |
if (ops.outboundP2PMessages && ops.outboundP2PMessages.length > 0) { | |
processOutboundMessages(); | |
} | |
+ | |
+ const [preparedPushNotifs] = await Promise.all([ | |
+ (async () => { | |
+ const { notificationsMessageDatas } = ops; | |
+ const deviceID = await getContentSigningKey(); | |
+ return await preparePushNotifs( | |
+ encryptedNotifUtilsAPI, | |
+ { senderDeviceID: deviceID }, | |
+ notificationsMessageDatas ? notificationsMessageDatas : [], | |
+ ); | |
+ })(), | |
+ processDBStoreOperations(ops), | |
+ ]); | |
+ | |
+ if (preparePushNotifs) { | |
+ const sendPromises = []; | |
+ for (const userID in preparedPushNotifs) { | |
+ for (const notif of preparedPushNotifs[userID]) { | |
+ if (notif.platform !== 'ios') { | |
+ continue; | |
+ } | |
+ const { headers, ...payload } = | |
+ notif.targetedNotification.notification; | |
+ | |
+ if (headers) { | |
+ const newHeaders = { | |
+ ...headers, | |
+ 'apns-push-type': 'Alert', | |
+ }; | |
+ | |
+ const tunnelbrokerNotif = { | |
+ type: 'APNsNotif', | |
+ deviceID: notif.targetedNotification.deliveryID, | |
+ headers: JSON.stringify(newHeaders), | |
+ payload: JSON.stringify(payload), | |
+ clientMessageID: uuid.v4(), | |
+ }; | |
+ | |
+ console.log(tunnelbrokerNotif); | |
+ | |
+ sendPromises.push( | |
+ (async () => { | |
+ try { | |
+ await sendNotif(tunnelbrokerNotif); | |
+ } catch (e) { | |
+ console.log(e); | |
+ } | |
+ })(), | |
+ ); | |
+ } | |
+ } | |
+ } | |
+ await Promise.all(sendPromises); | |
+ } | |
} | |
dispatch({ | |
type: opsProcessingFinishedActionType, | |
@@ -71,12 +128,15 @@ function DBOpsHandler(props: Props): React.Node { | |
} | |
})(); | |
}, [ | |
+ sendNotif, | |
queueFront, | |
dispatch, | |
processDBStoreOperations, | |
sendMessage, | |
sqliteAPI, | |
processOutboundMessages, | |
+ encryptedNotifUtilsAPI, | |
+ preparePushNotifs, | |
]); | |
return null; | |
diff --git a/lib/push/crypto.js b/lib/push/crypto.js | |
index 08ab18e2df..568606b792 100644 | |
--- a/lib/push/crypto.js | |
+++ b/lib/push/crypto.js | |
@@ -85,7 +85,7 @@ async function encryptAndroidNotificationPayload<T>( | |
encryptionOrder, | |
}; | |
} catch (e) { | |
- console.log('Notification encryption failed: ' + e); | |
+ console.log('Notification encryption failed: ' + e.message); | |
const resultPayload = { | |
encryptionFailed: '1', | |
...unencryptedPayload, | |
diff --git a/lib/push/send-hooks.react.js b/lib/push/send-hooks.react.js | |
index 7db262720b..9b86381a9c 100644 | |
--- a/lib/push/send-hooks.react.js | |
+++ b/lib/push/send-hooks.react.js | |
@@ -8,6 +8,7 @@ import { | |
} from './send-utils.js'; | |
import { ENSCacheContext } from '../components/ens-cache-provider.react.js'; | |
import { NeynarClientContext } from '../components/neynar-client-provider.react.js'; | |
+import { useOlmSessionCreation } from '../hooks/peer-list-hooks.js'; | |
import type { MessageData } from '../types/message-types.js'; | |
import type { | |
EncryptedNotifUtilsAPI, | |
@@ -28,6 +29,8 @@ function usePreparePushNotifs(): ( | |
const { getENSNames } = React.useContext(ENSCacheContext); | |
const getFCNames = React.useContext(NeynarClientContext)?.getFCNames; | |
+ const olmSessionCreator = useOlmSessionCreation(); | |
+ | |
return React.useCallback( | |
( | |
encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI, | |
@@ -37,6 +40,7 @@ function usePreparePushNotifs(): ( | |
return preparePushNotifs({ | |
encryptedNotifUtilsAPI, | |
senderDeviceDescriptor, | |
+ olmSessionCreator, | |
messageInfos: rawMessageInfos, | |
rawThreadInfos, | |
auxUserInfos, | |
@@ -47,6 +51,7 @@ function usePreparePushNotifs(): ( | |
}); | |
}, | |
[ | |
+ olmSessionCreator, | |
rawMessageInfos, | |
rawThreadInfos, | |
auxUserInfos, | |
diff --git a/lib/push/send-utils.js b/lib/push/send-utils.js | |
index a9b5ace5e1..8854d043ca 100644 | |
--- a/lib/push/send-utils.js | |
+++ b/lib/push/send-utils.js | |
@@ -136,15 +136,15 @@ async function getPushUserInfo( | |
for (const memberInfo of threadInfo.members) { | |
if ( | |
!isMemberActive(memberInfo) || | |
- !hasPermission(memberInfo.permissions, 'visible') || | |
- !memberInfo.subscription | |
+ !hasPermission(memberInfo.permissions, 'visible') | |
+ // || !memberInfo.subscription | |
) { | |
continue; | |
} | |
- | |
+ const subscription: ThreadSubscription = { home: true, pushNotifs: true }; | |
if (pushUserThreadInfos[memberInfo.id]) { | |
pushUserThreadInfos[memberInfo.id].threadsWithSubscriptions[threadID] = | |
- { ...memberInfo.subscription, role: memberInfo.role }; | |
+ { ...subscription, role: memberInfo.role }; | |
continue; | |
} | |
@@ -168,7 +168,7 @@ async function getPushUserInfo( | |
pushUserThreadInfos[memberInfo.id] = { | |
devices, | |
threadsWithSubscriptions: { | |
- [threadID]: { ...memberInfo.subscription, role: memberInfo.role }, | |
+ [threadID]: { ...subscription, role: memberInfo.role }, | |
}, | |
}; | |
} | |
@@ -655,6 +655,7 @@ async function buildNotifsFromPushInfo( | |
type PreparePushNotifsInputData = { | |
+encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI, | |
+senderDeviceDescriptor: SenderDeviceDescriptor, | |
+ +olmSessionCreator: (userID: string, deviceID: string) => Promise<void>, | |
+messageInfos: { +[id: string]: RawMessageInfo }, | |
+rawThreadInfos: RawThreadInfos, | |
+auxUserInfos: AuxUserInfos, | |
@@ -670,6 +671,7 @@ async function preparePushNotifs( | |
const { | |
encryptedNotifUtilsAPI, | |
senderDeviceDescriptor, | |
+ olmSessionCreator, | |
messageDatas, | |
messageInfos, | |
auxUserInfos, | |
@@ -690,6 +692,17 @@ async function preparePushNotifs( | |
return null; | |
} | |
+ const olmSessionCreationPromises = []; | |
+ for (const userID in pushInfos) { | |
+ for (const device of pushInfos[userID].devices) { | |
+ olmSessionCreationPromises.push( | |
+ olmSessionCreator(userID, device.cryptoID), | |
+ ); | |
+ } | |
+ } | |
+ | |
+ await Promise.all(olmSessionCreationPromises); | |
+ | |
return await buildNotifsFromPushInfo({ | |
encryptedNotifUtilsAPI, | |
senderDeviceDescriptor, | |
diff --git a/lib/reducers/master-reducer.js b/lib/reducers/master-reducer.js | |
index aba9c44f5e..24a45bd893 100644 | |
--- a/lib/reducers/master-reducer.js | |
+++ b/lib/reducers/master-reducer.js | |
@@ -86,13 +86,16 @@ export default function baseReducer<N: BaseNavInfo, T: BaseAppState<N>>( | |
]; | |
// Only allow checkpoints to increase if we are connected | |
// or if the action is a STATE_SYNC | |
- const { messageStoreOperations, messageStore: reducedMessageStore } = | |
- reduceMessageStore( | |
- state.messageStore, | |
- action, | |
- threadInfos, | |
- onStateDifferenceForStaff, | |
- ); | |
+ const { | |
+ messageStoreOperations, | |
+ notificationsMessageDatas, | |
+ messageStore: reducedMessageStore, | |
+ } = reduceMessageStore( | |
+ state.messageStore, | |
+ action, | |
+ threadInfos, | |
+ onStateDifferenceForStaff, | |
+ ); | |
let messageStore = reducedMessageStore; | |
let { keyserverStore, keyserverStoreOperations } = reduceKeyserverStore( | |
@@ -246,6 +249,9 @@ export default function baseReducer<N: BaseNavInfo, T: BaseAppState<N>>( | |
auxUserStoreOperations, | |
threadActivityStoreOperations, | |
entryStoreOperations, | |
+ notificationsMessageDatas: notificationsMessageDatas | |
+ ? notificationsMessageDatas | |
+ : [], | |
}, | |
}; | |
} | |
diff --git a/lib/reducers/message-reducer.js b/lib/reducers/message-reducer.js | |
index d2f618f710..36b72a141a 100644 | |
--- a/lib/reducers/message-reducer.js | |
+++ b/lib/reducers/message-reducer.js | |
@@ -89,6 +89,7 @@ import { | |
messageTruncationStatus, | |
defaultNumberPerThread, | |
type ThreadMessageInfo, | |
+ type MessageData, | |
} from '../types/message-types.js'; | |
import type { RawImagesMessageInfo } from '../types/messages/images.js'; | |
import type { RawMediaMessageInfo } from '../types/messages/media.js'; | |
@@ -771,6 +772,7 @@ const { processStoreOperations: processMessageStoreOperations } = | |
messageStoreOpsHandlers; | |
type ReduceMessageStoreResult = { | |
+ +notificationsMessageDatas?: $ReadOnlyArray<MessageData>, | |
+messageStoreOperations: $ReadOnlyArray<MessageStoreOperation>, | |
+messageStore: MessageStore, | |
}; | |
@@ -1141,7 +1143,8 @@ function reduceMessageStore( | |
messageStore, | |
messageStoreOperations, | |
); | |
- | |
+ const { id, localID: locID, ...messageData } = action.payload; | |
+ const notificationsMessageDatas = [messageData]; | |
const newMessageStore = { | |
messages: processedMessageStore.messages, | |
threads: processedMessageStore.threads, | |
@@ -1150,6 +1153,7 @@ function reduceMessageStore( | |
}; | |
return { | |
+ notificationsMessageDatas, | |
messageStoreOperations, | |
messageStore: newMessageStore, | |
}; | |
diff --git a/lib/types/store-ops-types.js b/lib/types/store-ops-types.js | |
index c75c680729..3ac7ec0406 100644 | |
--- a/lib/types/store-ops-types.js | |
+++ b/lib/types/store-ops-types.js | |
@@ -15,6 +15,7 @@ import type { | |
ClientDBMessageInfo, | |
ClientDBThreadMessageInfo, | |
ClientDBLocalMessageInfo, | |
+ MessageData, | |
} from './message-types.js'; | |
import type { ClientReportCreationRequest } from './report-types.js'; | |
import type { OutboundP2PMessage } from './sqlite-types.js'; | |
@@ -89,6 +90,7 @@ export type StoreOperations = { | |
+threadActivityStoreOperations?: $ReadOnlyArray<ThreadActivityStoreOperation>, | |
+outboundP2PMessages?: $ReadOnlyArray<OutboundP2PMessage>, | |
+entryStoreOperations?: $ReadOnlyArray<EntryStoreOperation>, | |
+ +notificationsMessageDatas?: $ReadOnlyArray<MessageData>, | |
}; | |
export type ClientDBStoreOperations = { | |
diff --git a/lib/utils/__mocks__/config.js b/lib/utils/__mocks__/config.js | |
index 922e69015f..d239e5d203 100644 | |
--- a/lib/utils/__mocks__/config.js | |
+++ b/lib/utils/__mocks__/config.js | |
@@ -39,6 +39,12 @@ const getConfig = (): Config => ({ | |
markOutboundP2PMessageAsSent: jest.fn(), | |
removeOutboundP2PMessagesOlderThan: jest.fn(), | |
}, | |
+ encryptedNotifUtilsAPI: { | |
+ encryptSerializedNotifPayload: jest.fn(), | |
+ uploadLargeNotifPayload: jest.fn(), | |
+ getEncryptedNotifHash: jest.fn(), | |
+ getNotifByteSize: jest.fn(), | |
+ }, | |
}); | |
const hasConfig = (): boolean => true; | |
diff --git a/lib/utils/config.js b/lib/utils/config.js | |
index 3e0ca0d603..c2405fb063 100644 | |
--- a/lib/utils/config.js | |
+++ b/lib/utils/config.js | |
@@ -8,6 +8,7 @@ import type { InitialNotifMessageOptions } from '../shared/crypto-utils.js'; | |
import type { RecoveryActionSource } from '../types/account-types.js'; | |
import type { OlmAPI } from '../types/crypto-types.js'; | |
import type { PlatformDetails } from '../types/device-types.js'; | |
+import type { EncryptedNotifUtilsAPI } from '../types/notif-types.js'; | |
import type { SQLiteAPI } from '../types/sqlite-types.js'; | |
import type { DispatchActionPromise } from '../utils/redux-promise-utils.js'; | |
@@ -29,6 +30,7 @@ export type Config = { | |
+authoritativeKeyserverID: string, | |
+olmAPI: OlmAPI, | |
+sqliteAPI: SQLiteAPI, | |
+ +encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI, | |
}; | |
let registeredConfig: ?Config = null; | |
diff --git a/native/config.js b/native/config.js | |
index 53c5fb32b3..61b2867b3c 100644 | |
--- a/native/config.js | |
+++ b/native/config.js | |
@@ -8,6 +8,7 @@ import { resolveKeyserverSessionInvalidationUsingNativeCredentials } from './acc | |
import { authoritativeKeyserverID } from './authoritative-keyserver.js'; | |
import { olmAPI } from './crypto/olm-api.js'; | |
import { sqliteAPI } from './database/sqlite-api.js'; | |
+import encryptedNotifUtilsAPI from './push/encrypted-notif-utils-api.js'; | |
import { persistConfig, codeVersion } from './redux/persist.js'; | |
registerConfig({ | |
@@ -22,4 +23,5 @@ registerConfig({ | |
authoritativeKeyserverID, | |
olmAPI, | |
sqliteAPI, | |
+ encryptedNotifUtilsAPI, | |
}); | |
diff --git a/web/app.react.js b/web/app.react.js | |
index 1a042395ce..958aa5b717 100644 | |
--- a/web/app.react.js | |
+++ b/web/app.react.js | |
@@ -70,6 +70,7 @@ import UpdateModalHandler from './modals/update-modal.react.js'; | |
import SettingsSwitcher from './navigation-panels/settings-switcher.react.js'; | |
import Topbar from './navigation-panels/topbar.react.js'; | |
import useBadgeHandler from './push-notif/badge-handler.react.js'; | |
+import encryptedNotifUtilsAPI from './push-notif/encrypted-notif-utils-api.js'; | |
import { PushNotificationsHandler } from './push-notif/push-notifs-handler.js'; | |
import { updateNavInfoActionType } from './redux/action-types.js'; | |
import DisconnectedBar from './redux/disconnected-bar.js'; | |
@@ -124,6 +125,7 @@ registerConfig({ | |
authoritativeKeyserverID, | |
olmAPI, | |
sqliteAPI, | |
+ encryptedNotifUtilsAPI, | |
}); | |
const versionBroadcast = new BroadcastChannel('comm_version'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment