Page MenuHomePhabricator

D12673.diff
No OneTemporary

D12673.diff

diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js
--- a/lib/actions/user-actions.js
+++ b/lib/actions/user-actions.js
@@ -3,6 +3,7 @@
import invariant from 'invariant';
import * as React from 'react';
+import { usePeerOlmSessionsCreatorContext } from '../components/peer-olm-session-creator-provider.react.js';
import {
useBroadcastDeviceListUpdates,
useBroadcastAccountDeletion,
@@ -90,7 +91,6 @@
} from '../types/user-types.js';
import { authoritativeKeyserverID } from '../utils/authoritative-keyserver.js';
import { getConfig } from '../utils/config.js';
-import { createOlmSessionWithPeer } from '../utils/crypto-utils.js';
import { getMessageForException } from '../utils/errors.js';
import { useSelector } from '../utils/redux-utils.js';
import { usingCommServicesAccessToken } from '../utils/services-utils.js';
@@ -273,6 +273,7 @@
const foreignPeerDevices = useSelector(getForeignPeerDevices);
const logOut = useLogOut(primaryDeviceLogOutOptions);
+ const { createOlmSessionsWithPeer } = usePeerOlmSessionsCreatorContext();
return React.useCallback(async () => {
const { identityClient, getAuthMetadata } = identityContext;
const authMetadata = await getAuthMetadata();
@@ -310,13 +311,7 @@
});
} catch {
try {
- await createOlmSessionWithPeer(
- authMetadata,
- identityClient,
- sendMessageToDevice,
- userID,
- deviceID,
- );
+ await createOlmSessionsWithPeer(userID, deviceID);
const encryptedData = await olmAPI.encrypt(
JSON.stringify(messageContents),
deviceID,
@@ -349,6 +344,7 @@
await broadcastDeviceListUpdates(foreignPeerDevices);
return logOutResult;
}, [
+ createOlmSessionsWithPeer,
broadcastDeviceListUpdates,
foreignPeerDevices,
identityContext,
@@ -369,6 +365,7 @@
if (!identityContext) {
throw new Error('Identity service client is not initialized');
}
+ const { createOlmSessionsWithPeer } = usePeerOlmSessionsCreatorContext();
return React.useCallback(async () => {
const { identityClient, getAuthMetadata } = identityContext;
@@ -407,13 +404,7 @@
});
} catch {
try {
- await createOlmSessionWithPeer(
- authMetadata,
- identityClient,
- sendMessageToDevice,
- userID,
- primaryDeviceID,
- );
+ await createOlmSessionsWithPeer(userID, primaryDeviceID);
const encryptedData = await olmAPI.encrypt(
JSON.stringify(messageContents),
primaryDeviceID,
@@ -434,7 +425,7 @@
// log out of identity service, keyserver and visually
return logOut();
- }, [identityContext, sendMessageToDevice, logOut]);
+ }, [createOlmSessionsWithPeer, identityContext, sendMessageToDevice, logOut]);
}
const claimUsernameActionTypes = Object.freeze({
diff --git a/lib/components/peer-olm-session-creator-provider.react.js b/lib/components/peer-olm-session-creator-provider.react.js
new file mode 100644
--- /dev/null
+++ b/lib/components/peer-olm-session-creator-provider.react.js
@@ -0,0 +1,87 @@
+// @flow
+
+import invariant from 'invariant';
+import * as React from 'react';
+
+import { IdentityClientContext } from '../shared/identity-client-context.js';
+import { useTunnelbroker } from '../tunnelbroker/tunnelbroker-context.js';
+import { createOlmSessionWithPeer } from '../utils/crypto-utils.js';
+
+export type PeerOlmSessionCreatorContextType = {
+ +createOlmSessionsWithPeer: (
+ userID: string,
+ deviceID: string,
+ ) => Promise<void>,
+};
+
+const PeerOlmSessionCreatorContext: React.Context<?PeerOlmSessionCreatorContextType> =
+ React.createContext<?PeerOlmSessionCreatorContextType>();
+
+type Props = {
+ +children: React.Node,
+};
+function PeerOlmSessionCreatorProvider(props: Props): React.Node {
+ const identityContext = React.useContext(IdentityClientContext);
+ invariant(identityContext, 'Identity context should be set');
+ const { identityClient, getAuthMetadata } = identityContext;
+
+ const { sendMessageToDevice } = useTunnelbroker();
+
+ const runningPromises = React.useRef<{
+ [userID: string]: { [deviceID: string]: ?Promise<void> },
+ }>({});
+
+ const createOlmSessionsWithPeer = React.useCallback(
+ (userID: string, deviceID: string) => {
+ if (
+ runningPromises.current[userID] &&
+ runningPromises.current[userID][deviceID]
+ ) {
+ return runningPromises.current[userID][deviceID];
+ }
+
+ const promise = (async () => {
+ const authMetadata = await getAuthMetadata();
+ await createOlmSessionWithPeer(
+ authMetadata,
+ identityClient,
+ sendMessageToDevice,
+ userID,
+ deviceID,
+ );
+
+ runningPromises.current[userID][deviceID] = null;
+ })();
+
+ if (!runningPromises.current[userID]) {
+ runningPromises.current[userID] = {};
+ }
+
+ runningPromises.current[userID][deviceID] = promise;
+ return promise;
+ },
+ [identityClient, sendMessageToDevice, getAuthMetadata],
+ );
+
+ const peerOlmSessionCreatorContextValue: PeerOlmSessionCreatorContextType =
+ React.useMemo(
+ () => ({ createOlmSessionsWithPeer }),
+ [createOlmSessionsWithPeer],
+ );
+
+ return (
+ <PeerOlmSessionCreatorContext.Provider
+ value={peerOlmSessionCreatorContextValue}
+ >
+ {props.children}
+ </PeerOlmSessionCreatorContext.Provider>
+ );
+}
+
+function usePeerOlmSessionsCreatorContext(): PeerOlmSessionCreatorContextType {
+ const context = React.useContext(PeerOlmSessionCreatorContext);
+ invariant(context, 'PeerOlmSessionsCreatorContext should be set');
+ return context;
+}
+
+export { PeerOlmSessionCreatorProvider, usePeerOlmSessionsCreatorContext };
diff --git a/lib/hooks/peer-list-hooks.js b/lib/hooks/peer-list-hooks.js
--- a/lib/hooks/peer-list-hooks.js
+++ b/lib/hooks/peer-list-hooks.js
@@ -4,6 +4,7 @@
import * as React from 'react';
import { setPeerDeviceListsActionType } from '../actions/aux-user-actions.js';
+import { usePeerOlmSessionsCreatorContext } from '../components/peer-olm-session-creator-provider.react.js';
import {
getAllPeerDevices,
getForeignPeerDevices,
@@ -26,10 +27,7 @@
type AccountDeletionP2PMessage,
} from '../types/tunnelbroker/user-actions-peer-to-peer-message-types.js';
import { getConfig } from '../utils/config.js';
-import {
- getContentSigningKey,
- createOlmSessionWithPeer,
-} from '../utils/crypto-utils.js';
+import { getContentSigningKey } from '../utils/crypto-utils.js';
import { convertSignedDeviceListsToRawDeviceLists } from '../utils/device-list-utils.js';
import { values } from '../utils/objects.js';
import { useDispatch, useSelector } from '../utils/redux-utils.js';
@@ -160,9 +158,10 @@
? getAllPeerDevices
: getForeignPeerDevices;
const peerDevices = useSelector(devicesSelector);
+ const { createOlmSessionsWithPeer } = usePeerOlmSessionsCreatorContext();
return React.useCallback(async () => {
- const { identityClient, getAuthMetadata } = identityContext;
+ const { getAuthMetadata } = identityContext;
const authMetadata = await getAuthMetadata();
const { userID, deviceID: thisDeviceID } = authMetadata;
if (!thisDeviceID || !userID) {
@@ -194,13 +193,7 @@
});
} catch {
try {
- await createOlmSessionWithPeer(
- authMetadata,
- identityClient,
- sendMessageToDevice,
- userID,
- deviceID,
- );
+ await createOlmSessionsWithPeer(userID, deviceID);
const encryptedData = await olmAPI.encrypt(rawPayload, deviceID);
const encryptedMessage: EncryptedMessage = {
type: peerToPeerMessageTypes.ENCRYPTED_MESSAGE,
@@ -219,7 +212,12 @@
}
}
}
- }, [identityContext, peerDevices, sendMessageToDevice]);
+ }, [
+ createOlmSessionsWithPeer,
+ identityContext,
+ peerDevices,
+ sendMessageToDevice,
+ ]);
}
export {
diff --git a/lib/push/send-hooks.react.js b/lib/push/send-hooks.react.js
--- a/lib/push/send-hooks.react.js
+++ b/lib/push/send-hooks.react.js
@@ -8,6 +8,7 @@
} from './send-utils.js';
import { ENSCacheContext } from '../components/ens-cache-provider.react.js';
import { NeynarClientContext } from '../components/neynar-client-provider.react.js';
+import { usePeerOlmSessionsCreatorContext } from '../components/peer-olm-session-creator-provider.react.js';
import { thickRawThreadInfosSelector } from '../selectors/thread-selectors.js';
import type { MessageData } from '../types/message-types.js';
import type {
@@ -29,6 +30,9 @@
const { getENSNames } = React.useContext(ENSCacheContext);
const getFCNames = React.useContext(NeynarClientContext)?.getFCNames;
+ const { createOlmSessionsWithPeer: olmSessionCreator } =
+ usePeerOlmSessionsCreatorContext();
+
return React.useCallback(
(
encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
@@ -38,6 +42,7 @@
return preparePushNotifs({
encryptedNotifUtilsAPI,
senderDeviceDescriptor,
+ olmSessionCreator,
messageInfos: rawMessageInfos,
thickRawThreadInfos,
auxUserInfos,
@@ -48,6 +53,7 @@
});
},
[
+ olmSessionCreator,
rawMessageInfos,
thickRawThreadInfos,
auxUserInfos,
diff --git a/lib/push/send-utils.js b/lib/push/send-utils.js
--- a/lib/push/send-utils.js
+++ b/lib/push/send-utils.js
@@ -48,6 +48,7 @@
import type { ThreadSubscription } from '../types/subscription-types.js';
import type { ThickRawThreadInfos } from '../types/thread-types.js';
import type { UserInfos } from '../types/user-types.js';
+import { getConfig } from '../utils/config.js';
import { type GetENSNames } from '../utils/ens-helpers.js';
import { type GetFCNames } from '../utils/farcaster-helpers.js';
import { promiseAll } from '../utils/promises.js';
@@ -654,6 +655,7 @@
type PreparePushNotifsInputData = {
+encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
+senderDeviceDescriptor: SenderDeviceDescriptor,
+ +olmSessionCreator: (userID: string, deviceID: string) => Promise<void>,
+messageInfos: { +[id: string]: RawMessageInfo },
+thickRawThreadInfos: ThickRawThreadInfos,
+auxUserInfos: AuxUserInfos,
@@ -669,6 +671,7 @@
const {
encryptedNotifUtilsAPI,
senderDeviceDescriptor,
+ olmSessionCreator,
messageDatas,
messageInfos,
auxUserInfos,
@@ -689,6 +692,43 @@
return null;
}
+ const {
+ initializeCryptoAccount,
+ isNotificationsSessionInitializedWithDevices,
+ } = getConfig().olmAPI;
+ await initializeCryptoAccount();
+
+ const deviceIDsToUserIDs: { [string]: string } = {};
+ for (const userID in pushInfos) {
+ for (const device of pushInfos[userID].devices) {
+ deviceIDsToUserIDs[device.cryptoID] = userID;
+ }
+ }
+
+ const deviceIDsToSessionPresence =
+ await isNotificationsSessionInitializedWithDevices(
+ Object.keys(deviceIDsToUserIDs),
+ );
+
+ const olmSessionCreationPromises = [];
+ for (const deviceID in deviceIDsToSessionPresence) {
+ if (deviceIDsToSessionPresence[deviceID]) {
+ continue;
+ }
+ olmSessionCreationPromises.push(
+ olmSessionCreator(deviceIDsToUserIDs[deviceID], deviceID),
+ );
+ }
+
+ try {
+ await Promise.allSettled(olmSessionCreationPromises);
+ } catch (e) {
+ // session creation may fail for some devices
+ // but we should still pursue notification
+ // delivery for others
+ console.log(e);
+ }
+
return await buildNotifsFromPushInfo({
encryptedNotifUtilsAPI,
senderDeviceDescriptor,
diff --git a/lib/tunnelbroker/peer-to-peer-context.js b/lib/tunnelbroker/peer-to-peer-context.js
--- a/lib/tunnelbroker/peer-to-peer-context.js
+++ b/lib/tunnelbroker/peer-to-peer-context.js
@@ -8,6 +8,7 @@
type TunnelbrokerClientMessageToDevice,
useTunnelbroker,
} from './tunnelbroker-context.js';
+import { usePeerOlmSessionsCreatorContext } from '../components/peer-olm-session-creator-provider.react.js';
import {
createMessagesToPeersFromDMOp,
type DMOperationSpecification,
@@ -26,7 +27,6 @@
peerToPeerMessageTypes,
} from '../types/tunnelbroker/peer-to-peer-message-types.js';
import { getConfig } from '../utils/config.js';
-import { createOlmSessionWithPeer } from '../utils/crypto-utils.js';
import { getMessageForException } from '../utils/errors.js';
import { useDispatch, useSelector } from '../utils/redux-utils.js';
@@ -51,6 +51,7 @@
messageID: ?string,
) => Promise<void>,
identityContext: IdentityClientContextType,
+ peerOlmSessionsCreator: (userID: string, deviceID: string) => Promise<void>,
messageIDs: ?$ReadOnlyArray<string>,
): Promise<void> {
const authMetadata = await identityContext.getAuthMetadata();
@@ -125,13 +126,7 @@
await sendMessageToPeer(encryptedMessage);
} catch (e) {
try {
- await createOlmSessionWithPeer(
- authMetadata,
- identityContext.identityClient,
- sendMessage,
- message.userID,
- peerDeviceID,
- );
+ await peerOlmSessionsCreator(message.userID, peerDeviceID);
const result = await olmAPI.encryptAndPersist(
message.plaintext,
message.deviceID,
@@ -204,6 +199,9 @@
>([]);
const promiseRunning = React.useRef<boolean>(false);
+ const { createOlmSessionsWithPeer: peerOlmSessionsCreator } =
+ usePeerOlmSessionsCreatorContext();
+
const processOutboundMessages = React.useCallback(
(outboundMessageIDs: ?$ReadOnlyArray<string>, dmOpID: ?string) => {
processingQueue.current.push({ outboundMessageIDs, dmOpID });
@@ -216,6 +214,7 @@
await processOutboundP2PMessages(
sendMessageToDevice,
identityContext,
+ peerOlmSessionsCreator,
queueFront?.outboundMessageIDs,
);
if (queueFront.dmOpID) {
@@ -244,7 +243,7 @@
})();
}
},
- [identityContext, sendMessageToDevice],
+ [peerOlmSessionsCreator, identityContext, sendMessageToDevice],
);
React.useEffect(() => {
diff --git a/lib/tunnelbroker/tunnelbroker-context.js b/lib/tunnelbroker/tunnelbroker-context.js
--- a/lib/tunnelbroker/tunnelbroker-context.js
+++ b/lib/tunnelbroker/tunnelbroker-context.js
@@ -8,6 +8,7 @@
import { PeerToPeerProvider } from './peer-to-peer-context.js';
import { PeerToPeerMessageHandler } from './peer-to-peer-message-handler.js';
import type { SecondaryTunnelbrokerConnection } from './secondary-tunnelbroker-connection.js';
+import { PeerOlmSessionCreatorProvider } from '../components/peer-olm-session-creator-provider.react.js';
import { tunnnelbrokerURL } from '../facts/tunnelbroker.js';
import { DMOpsQueueHandler } from '../shared/dm-ops/dm-ops-queue-handler.react.js';
import { IdentityClientContext } from '../shared/identity-client-context.js';
@@ -461,7 +462,9 @@
doesSocketExist={doesSocketExist}
socketSend={socketSend}
/>
- <PeerToPeerProvider>{children}</PeerToPeerProvider>
+ <PeerOlmSessionCreatorProvider>
+ <PeerToPeerProvider>{children}</PeerToPeerProvider>
+ </PeerOlmSessionCreatorProvider>
<DMOpsQueueHandler />
</TunnelbrokerContext.Provider>
);
diff --git a/lib/utils/crypto-utils.js b/lib/utils/crypto-utils.js
--- a/lib/utils/crypto-utils.js
+++ b/lib/utils/crypto-utils.js
@@ -11,8 +11,9 @@
import type {
IdentityKeysBlob,
OLMIdentityKeys,
+ OutboundSessionCreationResult,
SignedIdentityKeysBlob,
-} from '../types/crypto-types';
+} from '../types/crypto-types.js';
import type { IdentityServiceClient } from '../types/identity-service-types';
import {
type OutboundSessionCreation,
@@ -115,6 +116,14 @@
): Promise<void> {
const { olmAPI } = getConfig();
await olmAPI.initializeCryptoAccount();
+ const [hasContentSession, hasNotifsSession] = await Promise.all([
+ olmAPI.isContentSessionInitialized(deviceID),
+ olmAPI.isDeviceNotificationsSessionInitialized(deviceID),
+ ]);
+
+ if (hasContentSession && hasNotifsSession) {
+ return;
+ }
const {
userID: authUserID,
@@ -134,14 +143,40 @@
}
const { keys } = deviceKeysResponse;
- const { primaryIdentityPublicKeys } = keys.identityKeysBlob;
+ const { primaryIdentityPublicKeys, notificationIdentityPublicKeys } =
+ keys.identityKeysBlob;
const recipientDeviceID = primaryIdentityPublicKeys.ed25519;
- const { sessionVersion, encryptedData } =
- await olmAPI.contentOutboundSessionCreator(
+ if (hasContentSession) {
+ await olmAPI.notificationsOutboundSessionCreator(
+ recipientDeviceID,
+ notificationIdentityPublicKeys,
+ keys.notifInitializationInfo,
+ );
+ return;
+ }
+
+ let outboundSessionCreationResult: OutboundSessionCreationResult;
+ if (hasNotifsSession) {
+ outboundSessionCreationResult = await olmAPI.contentOutboundSessionCreator(
primaryIdentityPublicKeys,
keys.contentInitializationInfo,
);
+ } else {
+ [outboundSessionCreationResult] = await Promise.all([
+ await olmAPI.contentOutboundSessionCreator(
+ primaryIdentityPublicKeys,
+ keys.contentInitializationInfo,
+ ),
+ olmAPI.notificationsOutboundSessionCreator(
+ recipientDeviceID,
+ notificationIdentityPublicKeys,
+ keys.notifInitializationInfo,
+ ),
+ ]);
+ }
+
+ const { sessionVersion, encryptedData } = outboundSessionCreationResult;
const sessionCreationMessage: OutboundSessionCreation = {
type: peerToPeerMessageTypes.OUTBOUND_SESSION_CREATION,
diff --git a/native/push/encrypted-notif-utils-api.js b/native/push/encrypted-notif-utils-api.js
--- a/native/push/encrypted-notif-utils-api.js
+++ b/native/push/encrypted-notif-utils-api.js
@@ -14,8 +14,7 @@
type: '1' | '0',
) => boolean,
) => {
- const { initializeCryptoAccount, encryptNotification } = getConfig().olmAPI;
- await initializeCryptoAccount();
+ const { encryptNotification } = getConfig().olmAPI;
const { message: body, messageType: type } = await encryptNotification(
unencryptedPayload,
cryptoID,
diff --git a/web/push-notif/encrypted-notif-utils-api.js b/web/push-notif/encrypted-notif-utils-api.js
--- a/web/push-notif/encrypted-notif-utils-api.js
+++ b/web/push-notif/encrypted-notif-utils-api.js
@@ -12,8 +12,7 @@
type: '1' | '0',
) => boolean,
) => {
- const { initializeCryptoAccount, encryptNotification } = getConfig().olmAPI;
- await initializeCryptoAccount();
+ const { encryptNotification } = getConfig().olmAPI;
const { message: body, messageType: type } = await encryptNotification(
unencryptedPayload,
cryptoID,

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 22, 7:38 PM (18 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2564390
Default Alt Text
D12673.diff (18 KB)

Event Timeline