Page MenuHomePhabricator

D12673.id42347.diff
No OneTemporary

D12673.id42347.diff

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,80 @@
+// @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 { sendMessage } = useTunnelbroker();
+
+ const runningPromises = React.useRef<{ [deviceID: string]: ?Promise<void> }>(
+ {},
+ );
+
+ const createOlmSessionsWithPeer = React.useCallback(
+ (userID: string, deviceID: string) => {
+ if (runningPromises.current[deviceID]) {
+ return runningPromises.current[deviceID];
+ }
+
+ const promise = (async () => {
+ const authMetadata = await getAuthMetadata();
+ await createOlmSessionWithPeer(
+ authMetadata,
+ identityClient,
+ sendMessage,
+ userID,
+ deviceID,
+ );
+
+ runningPromises.current[deviceID] = null;
+ })();
+
+ runningPromises.current[deviceID] = promise;
+ return promise;
+ },
+ [identityClient, sendMessage, 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/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,
@@ -106,6 +107,9 @@
}
}
+// TODO: This must be exposed via context to make sure
+// there are no two promises running at the same time
+// the same device
async function createOlmSessionWithPeer(
authMetadata: AuthMetadata,
identityClient: IdentityServiceClient,
@@ -115,6 +119,14 @@
): Promise<void> {
const { olmAPI } = getConfig();
await olmAPI.initializeCryptoAccount();
+ const [hasContentSession, hasNotifsSession] = await Promise.all([
+ olmAPI.isContentSessionInitialized(deviceID),
+ olmAPI.isPeerNotificationsSessionInitialized(deviceID),
+ ]);
+
+ if (hasContentSession && hasNotifsSession) {
+ return;
+ }
const {
userID: authUserID,
@@ -134,14 +146,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(
+ notificationIdentityPublicKeys,
+ primaryIdentityPublicKeys,
+ 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(
+ notificationIdentityPublicKeys,
+ primaryIdentityPublicKeys,
+ keys.notifInitializationInfo,
+ ),
+ ]);
+ }
+
+ const { sessionVersion, encryptedData } = outboundSessionCreationResult;
const sessionCreationMessage: OutboundSessionCreation = {
type: peerToPeerMessageTypes.OUTBOUND_SESSION_CREATION,
diff --git a/native/root.react.js b/native/root.react.js
--- a/native/root.react.js
+++ b/native/root.react.js
@@ -30,6 +30,7 @@
import IntegrityHandler from 'lib/components/integrity-handler.react.js';
import { MediaCacheProvider } from 'lib/components/media-cache-provider.react.js';
import { NeynarClientProvider } from 'lib/components/neynar-client-provider.react.js';
+import { PeerOlmSessionCreatorProvider } from 'lib/components/peer-olm-session-creator-provider.react.js';
import PlatformDetailsSynchronizer from 'lib/components/platform-details-synchronizer.react.js';
import PrekeysHandler from 'lib/components/prekeys-handler.react.js';
import { QRAuthProvider } from 'lib/components/qr-auth-provider.react.js';
@@ -322,76 +323,80 @@
<StaffContextProvider>
<IdentityServiceContextProvider>
<TunnelbrokerProvider>
- <IdentitySearchProvider>
- <QRAuthProvider
- parseTunnelbrokerQRAuthMessage={parseTunnelbrokerQRAuthMessage}
- composeTunnelbrokerQRAuthMessage={
- composeTunnelbrokerQRAuthMessage
- }
- generateAESKey={generateQRAuthAESKey}
- performBackupRestore={performBackupRestore}
- onLogInError={handleSecondaryDeviceLogInError}
- >
- <FeatureFlagsProvider>
- <NavContext.Provider value={navContext}>
- <RootContext.Provider value={rootContext}>
- <InputStateContainer>
- <MessageEditingContextProvider>
- <SafeAreaProvider
- initialMetrics={initialWindowMetrics}
- >
- <ActionSheetProvider>
- <ENSCacheProvider provider={provider}>
- <NeynarClientProvider apiKey={neynarKey}>
- <MediaCacheProvider
- persistence={filesystemMediaCache}
- >
- <EditUserAvatarProvider>
- <NativeEditThreadAvatarProvider>
- <MarkdownContextProvider>
- <MessageSearchProvider>
- <BottomSheetProvider>
- <RegistrationContextProvider>
- <SQLiteDataHandler />
- <ConnectedStatusBar />
- <ReduxPersistGate
- persistor={getPersistor()}
- >
- {gated}
- </ReduxPersistGate>
- <PersistedStateGate>
- <KeyserverConnectionsHandler
- socketComponent={Socket}
- detectUnsupervisedBackgroundRef={
- detectUnsupervisedBackgroundRef
- }
- />
- <VersionSupportedChecker />
- <PlatformDetailsSynchronizer />
- <BackgroundIdentityLoginHandler />
- <PrekeysHandler />
- <ReportHandler />
- <AutoJoinCommunityHandler />
- </PersistedStateGate>
- {navigation}
- </RegistrationContextProvider>
- </BottomSheetProvider>
- </MessageSearchProvider>
- </MarkdownContextProvider>
- </NativeEditThreadAvatarProvider>
- </EditUserAvatarProvider>
- </MediaCacheProvider>
- </NeynarClientProvider>
- </ENSCacheProvider>
- </ActionSheetProvider>
- </SafeAreaProvider>
- </MessageEditingContextProvider>
- </InputStateContainer>
- </RootContext.Provider>
- </NavContext.Provider>
- </FeatureFlagsProvider>
- </QRAuthProvider>
- </IdentitySearchProvider>
+ <PeerOlmSessionCreatorProvider>
+ <IdentitySearchProvider>
+ <QRAuthProvider
+ parseTunnelbrokerQRAuthMessage={
+ parseTunnelbrokerQRAuthMessage
+ }
+ composeTunnelbrokerQRAuthMessage={
+ composeTunnelbrokerQRAuthMessage
+ }
+ generateAESKey={generateQRAuthAESKey}
+ performBackupRestore={performBackupRestore}
+ onLogInError={handleSecondaryDeviceLogInError}
+ >
+ <FeatureFlagsProvider>
+ <NavContext.Provider value={navContext}>
+ <RootContext.Provider value={rootContext}>
+ <InputStateContainer>
+ <MessageEditingContextProvider>
+ <SafeAreaProvider
+ initialMetrics={initialWindowMetrics}
+ >
+ <ActionSheetProvider>
+ <ENSCacheProvider provider={provider}>
+ <NeynarClientProvider apiKey={neynarKey}>
+ <MediaCacheProvider
+ persistence={filesystemMediaCache}
+ >
+ <EditUserAvatarProvider>
+ <NativeEditThreadAvatarProvider>
+ <MarkdownContextProvider>
+ <MessageSearchProvider>
+ <BottomSheetProvider>
+ <RegistrationContextProvider>
+ <SQLiteDataHandler />
+ <ConnectedStatusBar />
+ <ReduxPersistGate
+ persistor={getPersistor()}
+ >
+ {gated}
+ </ReduxPersistGate>
+ <PersistedStateGate>
+ <KeyserverConnectionsHandler
+ socketComponent={Socket}
+ detectUnsupervisedBackgroundRef={
+ detectUnsupervisedBackgroundRef
+ }
+ />
+ <VersionSupportedChecker />
+ <PlatformDetailsSynchronizer />
+ <BackgroundIdentityLoginHandler />
+ <PrekeysHandler />
+ <ReportHandler />
+ <AutoJoinCommunityHandler />
+ </PersistedStateGate>
+ {navigation}
+ </RegistrationContextProvider>
+ </BottomSheetProvider>
+ </MessageSearchProvider>
+ </MarkdownContextProvider>
+ </NativeEditThreadAvatarProvider>
+ </EditUserAvatarProvider>
+ </MediaCacheProvider>
+ </NeynarClientProvider>
+ </ENSCacheProvider>
+ </ActionSheetProvider>
+ </SafeAreaProvider>
+ </MessageEditingContextProvider>
+ </InputStateContainer>
+ </RootContext.Provider>
+ </NavContext.Provider>
+ </FeatureFlagsProvider>
+ </QRAuthProvider>
+ </IdentitySearchProvider>
+ </PeerOlmSessionCreatorProvider>
</TunnelbrokerProvider>
</IdentityServiceContextProvider>
</StaffContextProvider>
diff --git a/web/app.react.js b/web/app.react.js
--- a/web/app.react.js
+++ b/web/app.react.js
@@ -21,6 +21,7 @@
useModalContext,
} from 'lib/components/modal-provider.react.js';
import { NeynarClientProvider } from 'lib/components/neynar-client-provider.react.js';
+import { PeerOlmSessionCreatorProvider } from 'lib/components/peer-olm-session-creator-provider.react.js';
import PlatformDetailsSynchronizer from 'lib/components/platform-details-synchronizer.react.js';
import { QRAuthProvider } from 'lib/components/qr-auth-provider.react.js';
import { StaffContextProvider } from 'lib/components/staff-provider.react.js';
@@ -559,27 +560,29 @@
onClose={releaseLockOrAbortRequest}
secondaryTunnelbrokerConnection={secondaryTunnelbrokerConnection}
>
- <IdentitySearchProvider>
- <QRAuthProvider
- parseTunnelbrokerQRAuthMessage={parseTunnelbrokerQRAuthMessage}
- composeTunnelbrokerQRAuthMessage={
- composeTunnelbrokerQRAuthMessage
- }
- generateAESKey={generateQRAuthAESKey}
- onLogInError={handleSecondaryDeviceLogInError}
- >
- <App
- {...props}
- navInfo={navInfo}
- entriesLoadingStatus={entriesLoadingStatus}
- loggedIn={loggedIn}
- activeThreadCurrentlyUnread={activeThreadCurrentlyUnread}
- dispatch={dispatch}
- modals={modals}
- />
- </QRAuthProvider>
- <DBOpsHandler />
- </IdentitySearchProvider>
+ <PeerOlmSessionCreatorProvider>
+ <IdentitySearchProvider>
+ <QRAuthProvider
+ parseTunnelbrokerQRAuthMessage={parseTunnelbrokerQRAuthMessage}
+ composeTunnelbrokerQRAuthMessage={
+ composeTunnelbrokerQRAuthMessage
+ }
+ generateAESKey={generateQRAuthAESKey}
+ onLogInError={handleSecondaryDeviceLogInError}
+ >
+ <App
+ {...props}
+ navInfo={navInfo}
+ entriesLoadingStatus={entriesLoadingStatus}
+ loggedIn={loggedIn}
+ activeThreadCurrentlyUnread={activeThreadCurrentlyUnread}
+ dispatch={dispatch}
+ modals={modals}
+ />
+ </QRAuthProvider>
+ <DBOpsHandler />
+ </IdentitySearchProvider>
+ </PeerOlmSessionCreatorProvider>
</TunnelbrokerProvider>
</AppThemeWrapper>
);

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 23, 12:23 AM (17 h, 8 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2566833
Default Alt Text
D12673.id42347.diff (17 KB)

Event Timeline