Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save marcinwasowicz/047b0f1b00079562b2547ebe3a8c18ad to your computer and use it in GitHub Desktop.
Save marcinwasowicz/047b0f1b00079562b2547ebe3a8c18ad to your computer and use it in GitHub Desktop.
Test outbound notifications session creation
diff --git a/lib/handlers/db-ops-handler.react.js b/lib/handlers/db-ops-handler.react.js
index 6eba0272ff..184bf066a9 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,58 @@ 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(),
+ };
+
+ sendPromises.push(
+ (async () => {
+ try {
+ await sendNotif(tunnelbrokerNotif);
+ } catch (e) {
+ console.log(e);
+ }
+ })(),
+ );
+ }
+ }
+ }
+ await Promise.all(sendPromises);
+ }
}
dispatch({
type: opsProcessingFinishedActionType,
@@ -71,12 +126,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 399a0a1983..f53c5c152f 100644
--- a/web/app.react.js
+++ b/web/app.react.js
@@ -68,6 +68,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';
@@ -122,6 +123,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