diff --git a/lib/components/keyserver-connection-handler.js b/lib/components/keyserver-connection-handler.js --- a/lib/components/keyserver-connection-handler.js +++ b/lib/components/keyserver-connection-handler.js @@ -24,7 +24,6 @@ import { isLoggedInToKeyserver } from '../selectors/user-selectors.js'; import { useInitialNotificationsEncryptedMessage } from '../shared/crypto-utils.js'; import { IdentityClientContext } from '../shared/identity-client-context.js'; -import { OlmSessionCreatorContext } from '../shared/olm-session-creator-context.js'; import type { BaseSocketProps } from '../socket/socket.react.js'; import { logInActionSources, @@ -100,8 +99,7 @@ invariant(identityContext, 'Identity context should be set'); const { identityClient, getAuthMetadata } = identityContext; - const olmSessionCreator = React.useContext(OlmSessionCreatorContext); - invariant(olmSessionCreator, 'Olm session creator should be set'); + const { olmAPI } = getConfig(); const [authInProgress, setAuthInProgress] = React.useState(false); const performAuth = React.useCallback(() => { @@ -115,8 +113,10 @@ const promise = (async () => { try { - const keyserverKeys = - await identityClient.getKeyserverKeys(keyserverID); + const [keyserverKeys] = await Promise.all([ + identityClient.getKeyserverKeys(keyserverID), + olmAPI.initializeCryptoAccount(), + ]); if (cancelled) { throw new Error(CANCELLED_ERROR); @@ -124,13 +124,13 @@ const [notifsSession, contentSession, { userID, deviceID }] = await Promise.all([ - olmSessionCreator.notificationsSessionCreator( + olmAPI.notificationsSessionCreator( cookie, keyserverKeys.identityKeysBlob.notificationIdentityPublicKeys, keyserverKeys.notifInitializationInfo, keyserverID, ), - olmSessionCreator.contentSessionCreator( + olmAPI.contentOutboundSessionCreator( keyserverKeys.identityKeysBlob.primaryIdentityPublicKeys, keyserverKeys.contentInitializationInfo, ), @@ -203,7 +203,7 @@ identityClient, keyserverAuth, keyserverID, - olmSessionCreator, + olmAPI, ]); const activeSessionRecovery = useSelector( diff --git a/lib/shared/crypto-utils.js b/lib/shared/crypto-utils.js --- a/lib/shared/crypto-utils.js +++ b/lib/shared/crypto-utils.js @@ -1,6 +1,5 @@ // @flow -import invariant from 'invariant'; import * as React from 'react'; import { @@ -8,13 +7,13 @@ getOlmSessionInitializationDataActionTypes, } from '../actions/user-actions.js'; import { cookieSelector } from '../selectors/keyserver-selectors.js'; -import { OlmSessionCreatorContext } from '../shared/olm-session-creator-context.js'; import type { OLMOneTimeKeys, OLMPrekey } from '../types/crypto-types.js'; import { useLegacyAshoatKeyserverCall } from '../utils/action-utils.js'; import type { CallSingleKeyserverEndpointOptions, CallSingleKeyserverEndpoint, } from '../utils/call-single-keyserver-endpoint.js'; +import { getConfig } from '../utils/config.js'; import { values } from '../utils/objects.js'; import { useDispatchActionPromise } from '../utils/redux-promise-utils.js'; import { useSelector } from '../utils/redux-utils.js'; @@ -38,9 +37,7 @@ const cookie = useSelector(cookieSelector(keyserverID)); - const olmSessionCreator = React.useContext(OlmSessionCreatorContext); - invariant(olmSessionCreator, 'Olm session creator should be set'); - const { notificationsSessionCreator } = olmSessionCreator; + const { olmAPI } = getConfig(); return React.useCallback( async options => { @@ -60,14 +57,17 @@ olmSessionDataPromise, ); - const { signedIdentityKeysBlob, notifInitializationInfo } = - await olmSessionDataPromise; + const [{ signedIdentityKeysBlob, notifInitializationInfo }] = + await Promise.all([ + olmSessionDataPromise, + olmAPI.initializeCryptoAccount(), + ]); const { notificationIdentityPublicKeys } = JSON.parse( signedIdentityKeysBlob.payload, ); - return await notificationsSessionCreator( + return await olmAPI.notificationsSessionCreator( cookie, notificationIdentityPublicKeys, notifInitializationInfo, @@ -77,7 +77,7 @@ [ callGetOlmSessionInitializationData, dispatchActionPromise, - notificationsSessionCreator, + olmAPI, cookie, keyserverID, ], diff --git a/lib/shared/olm-session-creator-context.js b/lib/shared/olm-session-creator-context.js deleted file mode 100644 --- a/lib/shared/olm-session-creator-context.js +++ /dev/null @@ -1,24 +0,0 @@ -// @flow - -import * as React from 'react'; - -import type { OLMIdentityKeys } from '../types/crypto-types.js'; -import type { OlmSessionInitializationInfo } from '../types/request-types.js'; - -export type OlmSessionCreatorContextType = { - +notificationsSessionCreator: ( - cookie: ?string, - notificationsIdentityKeys: OLMIdentityKeys, - notificationsInitializationInfo: OlmSessionInitializationInfo, - keyserverID: string, - ) => Promise, - +contentSessionCreator: ( - contentIdentityKeys: OLMIdentityKeys, - contentInitializationInfo: OlmSessionInitializationInfo, - ) => Promise, -}; - -const OlmSessionCreatorContext: React.Context = - React.createContext(null); - -export { OlmSessionCreatorContext }; diff --git a/native/account/account-hooks.js b/native/account/account-hooks.js deleted file mode 100644 --- a/native/account/account-hooks.js +++ /dev/null @@ -1,56 +0,0 @@ -// @flow - -import * as React from 'react'; - -import { OlmSessionCreatorContext } from 'lib/shared/olm-session-creator-context.js'; -import type { OLMIdentityKeys } from 'lib/types/crypto-types.js'; -import type { OlmSessionInitializationInfo } from 'lib/types/request-types.js'; - -import { - nativeNotificationsSessionCreator, - nativeOutboundContentSessionCreator, -} from '../utils/crypto-utils.js'; - -type Props = { - +children: React.Node, -}; - -function notificationsSessionCreator( - cookie: ?string, - notificationsIdentityKeys: OLMIdentityKeys, - notificationsInitializationInfo: OlmSessionInitializationInfo, - keyserverID: string, -) { - return nativeNotificationsSessionCreator( - notificationsIdentityKeys, - notificationsInitializationInfo, - keyserverID, - ); -} - -function contentSessionCreator( - contentIdentityKeys: OLMIdentityKeys, - contentInitializationInfo: OlmSessionInitializationInfo, -) { - return nativeOutboundContentSessionCreator( - contentIdentityKeys, - contentInitializationInfo, - contentIdentityKeys.ed25519, - ); -} - -const contextValue = { - notificationsSessionCreator, - contentSessionCreator, -}; - -function OlmSessionCreatorProvider(props: Props): React.Node { - const { children } = props; - return ( - - {children} - - ); -} - -export { OlmSessionCreatorProvider }; diff --git a/native/root.react.js b/native/root.react.js --- a/native/root.react.js +++ b/native/root.react.js @@ -38,7 +38,6 @@ import { TunnelbrokerProvider } from 'lib/tunnelbroker/tunnelbroker-context.js'; import { actionLogger } from 'lib/utils/action-logger.js'; -import { OlmSessionCreatorProvider } from './account/account-hooks.js'; import { RegistrationContextProvider } from './account/registration/registration-context-provider.react.js'; import NativeEditThreadAvatarProvider from './avatars/native-edit-thread-avatar-provider.react.js'; import BackupHandler from './backup/backup-handler.js'; @@ -307,68 +306,64 @@ - - - - - - - - - - - - - - - - - - - - - - - {gated} - - - - - - - - - {navigation} - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + {gated} + + + + + + + + + {navigation} + + + + + + + + + + + + + + + + + + diff --git a/native/utils/crypto-utils.js b/native/utils/crypto-utils.js deleted file mode 100644 --- a/native/utils/crypto-utils.js +++ /dev/null @@ -1,47 +0,0 @@ -// @flow - -import type { OLMIdentityKeys } from 'lib/types/crypto-types.js'; -import type { OlmSessionInitializationInfo } from 'lib/types/request-types.js'; - -import { commCoreModule } from '../native-modules.js'; - -function nativeNotificationsSessionCreator( - notificationsIdentityKeys: OLMIdentityKeys, - notificationsInitializationInfo: OlmSessionInitializationInfo, - keyserverID: string, -): Promise { - const { prekey, prekeySignature, oneTimeKey } = - notificationsInitializationInfo; - return commCoreModule.initializeNotificationsSession( - JSON.stringify(notificationsIdentityKeys), - prekey, - prekeySignature, - oneTimeKey, - keyserverID, - ); -} - -function nativeOutboundContentSessionCreator( - contentIdentityKeys: OLMIdentityKeys, - contentInitializationInfo: OlmSessionInitializationInfo, - deviceID: string, -): Promise { - const { prekey, prekeySignature, oneTimeKey } = contentInitializationInfo; - const identityKeys = JSON.stringify({ - curve25519: contentIdentityKeys.curve25519, - ed25519: contentIdentityKeys.ed25519, - }); - - return commCoreModule.initializeContentOutboundSession( - identityKeys, - prekey, - prekeySignature, - oneTimeKey, - deviceID, - ); -} - -export { - nativeNotificationsSessionCreator, - nativeOutboundContentSessionCreator, -}; diff --git a/web/account/account-hooks.js b/web/account/account-hooks.js --- a/web/account/account-hooks.js +++ b/web/account/account-hooks.js @@ -2,49 +2,28 @@ import olm from '@commapp/olm'; import invariant from 'invariant'; -import localforage from 'localforage'; import * as React from 'react'; import uuid from 'uuid'; -import { initialEncryptedMessageContent } from 'lib/shared/crypto-utils.js'; -import { OlmSessionCreatorContext } from 'lib/shared/olm-session-creator-context.js'; -import { - hasMinCodeVersion, - NEXT_CODE_VERSION, -} from 'lib/shared/version-utils.js'; import type { SignedIdentityKeysBlob, CryptoStore, IdentityKeysBlob, CryptoStoreContextType, - OLMIdentityKeys, - NotificationsOlmDataType, } from 'lib/types/crypto-types.js'; import { type IdentityNewDeviceKeyUpload, type IdentityExistingDeviceKeyUpload, } from 'lib/types/identity-service-types.js'; -import type { OlmSessionInitializationInfo } from 'lib/types/request-types.js'; -import { getConfig } from 'lib/utils/config.js'; import { retrieveIdentityKeysAndPrekeys, getAccountOneTimeKeys, } from 'lib/utils/olm-utils.js'; import { useDispatch } from 'lib/utils/redux-utils.js'; -import { - generateCryptoKey, - encryptData, - exportKeyToJWK, -} from '../crypto/aes-gcm-crypto-utils.js'; import { initOlm } from '../olm/olm-utils.js'; -import { - getOlmDataContentKeyForCookie, - getOlmEncryptionKeyDBLabelForCookie, -} from '../push-notif/notif-crypto-utils.js'; import { setCryptoStore } from '../redux/crypto-store-reducer.js'; import { useSelector } from '../redux/redux-utils.js'; -import { isDesktopSafari } from '../shared-worker/utils/db-utils.js'; const CryptoStoreContext: React.Context = React.createContext(null); @@ -318,197 +297,9 @@ }, [dispatch, getOrCreateCryptoStore, getSignedIdentityKeysBlob]); } -function OlmSessionCreatorProvider(props: Props): React.Node { - const getOrCreateCryptoStore = useGetOrCreateCryptoStore(); - const currentCryptoStore = useSelector(state => state.cryptoStore); - const platformDetails = getConfig().platformDetails; - - const createNewNotificationsSession = React.useCallback( - async ( - cookie: ?string, - notificationsIdentityKeys: OLMIdentityKeys, - notificationsInitializationInfo: OlmSessionInitializationInfo, - keyserverID: string, - ) => { - const [{ notificationAccount }, encryptionKey] = await Promise.all([ - getOrCreateCryptoStore(), - generateCryptoKey({ extractable: isDesktopSafari }), - initOlm(), - ]); - - const account = new olm.Account(); - const { picklingKey, pickledAccount } = notificationAccount; - account.unpickle(picklingKey, pickledAccount); - - const notificationsPrekey = notificationsInitializationInfo.prekey; - - const session = new olm.Session(); - session.create_outbound( - account, - notificationsIdentityKeys.curve25519, - notificationsIdentityKeys.ed25519, - notificationsPrekey, - notificationsInitializationInfo.prekeySignature, - notificationsInitializationInfo.oneTimeKey, - ); - const { body: initialNotificationsEncryptedMessage } = session.encrypt( - JSON.stringify(initialEncryptedMessageContent), - ); - - const mainSession = session.pickle(picklingKey); - const notificationsOlmData: NotificationsOlmDataType = { - mainSession, - pendingSessionUpdate: mainSession, - updateCreationTimestamp: Date.now(), - picklingKey, - }; - const encryptedOlmData = await encryptData( - new TextEncoder().encode(JSON.stringify(notificationsOlmData)), - encryptionKey, - ); - - let notifsOlmDataContentKey; - let notifsOlmDataEncryptionKeyDBLabel; - - if ( - hasMinCodeVersion(platformDetails, { majorDesktop: NEXT_CODE_VERSION }) - ) { - notifsOlmDataEncryptionKeyDBLabel = getOlmEncryptionKeyDBLabelForCookie( - cookie, - keyserverID, - ); - notifsOlmDataContentKey = getOlmDataContentKeyForCookie( - cookie, - keyserverID, - ); - } else { - notifsOlmDataEncryptionKeyDBLabel = - getOlmEncryptionKeyDBLabelForCookie(cookie); - notifsOlmDataContentKey = getOlmDataContentKeyForCookie(cookie); - } - - const persistEncryptionKeyPromise = (async () => { - let cryptoKeyPersistentForm; - if (isDesktopSafari) { - // Safari doesn't support structured clone algorithm in service - // worker context so we have to store CryptoKey as JSON - cryptoKeyPersistentForm = await exportKeyToJWK(encryptionKey); - } else { - cryptoKeyPersistentForm = encryptionKey; - } - - await localforage.setItem( - notifsOlmDataEncryptionKeyDBLabel, - cryptoKeyPersistentForm, - ); - })(); - - await Promise.all([ - localforage.setItem(notifsOlmDataContentKey, encryptedOlmData), - persistEncryptionKeyPromise, - ]); - - return initialNotificationsEncryptedMessage; - }, - [getOrCreateCryptoStore, platformDetails], - ); - - const createNewContentSession = React.useCallback( - async ( - contentIdentityKeys: OLMIdentityKeys, - contentInitializationInfo: OlmSessionInitializationInfo, - ) => { - const [{ primaryAccount }] = await Promise.all([ - getOrCreateCryptoStore(), - initOlm(), - ]); - - const account = new olm.Account(); - const { picklingKey, pickledAccount } = primaryAccount; - account.unpickle(picklingKey, pickledAccount); - - const contentPrekey = contentInitializationInfo.prekey; - - const session = new olm.Session(); - session.create_outbound( - account, - contentIdentityKeys.curve25519, - contentIdentityKeys.ed25519, - contentPrekey, - contentInitializationInfo.prekeySignature, - contentInitializationInfo.oneTimeKey, - ); - const { body: initialContentEncryptedMessage } = session.encrypt( - JSON.stringify(initialEncryptedMessageContent), - ); - return initialContentEncryptedMessage; - }, - [getOrCreateCryptoStore], - ); - - const perKeyserverNotificationsSessionPromises = React.useRef<{ - [keyserverID: string]: ?Promise, - }>({}); - - const createNotificationsSession = React.useCallback( - async ( - cookie: ?string, - notificationsIdentityKeys: OLMIdentityKeys, - notificationsInitializationInfo: OlmSessionInitializationInfo, - keyserverID: string, - ) => { - if (perKeyserverNotificationsSessionPromises.current[keyserverID]) { - return perKeyserverNotificationsSessionPromises.current[keyserverID]; - } - - const newNotificationsSessionPromise = (async () => { - try { - return await createNewNotificationsSession( - cookie, - notificationsIdentityKeys, - notificationsInitializationInfo, - keyserverID, - ); - } catch (e) { - perKeyserverNotificationsSessionPromises.current[keyserverID] = - undefined; - throw e; - } - })(); - - perKeyserverNotificationsSessionPromises.current[keyserverID] = - newNotificationsSessionPromise; - return newNotificationsSessionPromise; - }, - [createNewNotificationsSession], - ); - - const isCryptoStoreSet = !!currentCryptoStore; - React.useEffect(() => { - if (!isCryptoStoreSet) { - perKeyserverNotificationsSessionPromises.current = {}; - } - }, [isCryptoStoreSet]); - - const contextValue = React.useMemo( - () => ({ - notificationsSessionCreator: createNotificationsSession, - contentSessionCreator: createNewContentSession, - }), - [createNewContentSession, createNotificationsSession], - ); - - return ( - - {props.children} - - ); -} - export { useGetSignedIdentityKeysBlob, useGetOrCreateCryptoStore, - OlmSessionCreatorProvider, GetOrCreateCryptoStoreProvider, useGetNewDeviceKeyUpload, useGetExistingDeviceKeyUpload, diff --git a/web/root.js b/web/root.js --- a/web/root.js +++ b/web/root.js @@ -16,10 +16,6 @@ import { CallKeyserverEndpointProvider } from 'lib/keyserver-conn/call-keyserver-endpoint-provider.react.js'; import { reduxLoggerMiddleware } from 'lib/utils/action-logger.js'; -import { - GetOrCreateCryptoStoreProvider, - OlmSessionCreatorProvider, -} from './account/account-hooks.js'; import App from './app.react.js'; import ErrorBoundary from './error-boundary.react.js'; import IdentityServiceContextProvider from './grpc/identity-service-context-provider.react.js'; @@ -54,20 +50,16 @@ - - - - - - - - - - - - - - + + + + + + + + + +