diff --git a/native/qr-code/qr-code-screen.react.js b/native/qr-code/qr-code-screen.react.js --- a/native/qr-code/qr-code-screen.react.js +++ b/native/qr-code/qr-code-screen.react.js @@ -4,23 +4,12 @@ import { View, Text } from 'react-native'; import QRCode from 'react-native-qrcode-svg'; +import { useQRAuthContext } from 'lib/components/qr-auth-provider.react.js'; import { qrCodeLinkURL } from 'lib/facts/links.js'; -import { useSecondaryDeviceLogIn } from 'lib/hooks/login-hooks.js'; -import { useQRAuth } from 'lib/hooks/qr-auth.js'; -import { uintArrayToHexString } from 'lib/media/data-utils.js'; -import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js'; -import { getContentSigningKey } from 'lib/utils/crypto-utils.js'; import type { QRCodeSignInNavigationProp } from './qr-code-sign-in-navigator.react.js'; -import { - composeTunnelbrokerQRAuthMessage, - handleSecondaryDeviceRegistrationError, - parseTunnelbrokerQRAuthMessage, - performBackupRestore, -} from './qr-code-utils.js'; import type { NavigationRoute } from '../navigation/route-names.js'; import { useStyles } from '../themes/colors.js'; -import * as AES from '../utils/aes-crypto-module.js'; type QRCodeScreenProps = { +navigation: QRCodeSignInNavigationProp<'QRCodeScreen'>, @@ -29,37 +18,7 @@ // eslint-disable-next-line no-unused-vars function QRCodeScreen(props: QRCodeScreenProps): React.Node { - const [qrData, setQRData] = - React.useState<?{ +deviceID: string, +aesKey: string }>(); - - const { setUnauthorizedDeviceID } = useTunnelbroker(); - const generateQRCode = React.useCallback(async () => { - try { - const [ed25519, rawAESKey] = await Promise.all([ - getContentSigningKey(), - AES.generateKey(), - ]); - const aesKeyAsHexString: string = uintArrayToHexString(rawAESKey); - - setUnauthorizedDeviceID(ed25519); - setQRData({ deviceID: ed25519, aesKey: aesKeyAsHexString }); - } catch (err) { - console.error('Failed to generate QR Code:', err); - } - }, [setUnauthorizedDeviceID]); - - const logInSecondaryDevice = useSecondaryDeviceLogIn(); - const performRegistration = React.useCallback( - async (userID: string) => { - try { - await logInSecondaryDevice(userID); - } catch (err) { - handleSecondaryDeviceRegistrationError(err); - void generateQRCode(); - } - }, - [logInSecondaryDevice, generateQRCode], - ); + const { qrData, generateQRCode } = useQRAuthContext(); React.useEffect(() => { void generateQRCode(); @@ -70,19 +29,6 @@ [qrData], ); - const qrAuthInput = React.useMemo( - () => ({ - secondaryDeviceID: qrData?.deviceID, - aesKey: qrData?.aesKey, - performSecondaryDeviceRegistration: performRegistration, - composeMessage: composeTunnelbrokerQRAuthMessage, - processMessage: parseTunnelbrokerQRAuthMessage, - performBackupRestore, - }), - [qrData, performRegistration], - ); - useQRAuth(qrAuthInput); - const styles = useStyles(unboundStyles); return ( <View style={styles.container}> diff --git a/native/qr-code/qr-code-utils.js b/native/qr-code/qr-code-utils.js --- a/native/qr-code/qr-code-utils.js +++ b/native/qr-code/qr-code-utils.js @@ -89,9 +89,14 @@ ); } +function generateQRAuthKey(): Promise<Uint8Array> { + return Promise.resolve(AES.generateKey()); +} + export { composeTunnelbrokerQRAuthMessage, parseTunnelbrokerQRAuthMessage, handleSecondaryDeviceRegistrationError, performBackupRestore, + generateQRAuthKey, }; diff --git a/native/root.react.js b/native/root.react.js --- a/native/root.react.js +++ b/native/root.react.js @@ -32,6 +32,7 @@ import { NeynarClientProvider } from 'lib/components/neynar-client-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'; import { StaffContextProvider } from 'lib/components/staff-provider.react.js'; import { DBOpsHandler } from 'lib/handlers/db-ops-handler.react.js'; import { UserInfosHandler } from 'lib/handlers/user-infos-handler.react.js'; @@ -76,6 +77,13 @@ import OrientationHandler from './navigation/orientation-handler.react.js'; import { navStateAsyncStorageKey } from './navigation/persistance.js'; import RootNavigator from './navigation/root-navigator.react.js'; +import { + composeTunnelbrokerQRAuthMessage, + handleSecondaryDeviceRegistrationError, + parseTunnelbrokerQRAuthMessage, + performBackupRestore, + generateQRAuthKey, +} from './qr-code/qr-code-utils.js'; import ConnectivityUpdater from './redux/connectivity-updater.react.js'; import { DimensionsUpdater } from './redux/dimensions-updater.react.js'; import { getPersistor } from './redux/persist.js'; @@ -309,63 +317,73 @@ <IdentityServiceContextProvider> <TunnelbrokerProvider> <IdentitySearchProvider> - <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 /> - <FarcasterDataHandler /> - <AutoJoinCommunityHandler /> - </PersistedStateGate> - {navigation} - </RegistrationContextProvider> - </BottomSheetProvider> - </MessageSearchProvider> - </MarkdownContextProvider> - </NativeEditThreadAvatarProvider> - </EditUserAvatarProvider> - </MediaCacheProvider> - </NeynarClientProvider> - </ENSCacheProvider> - </ActionSheetProvider> - </SafeAreaProvider> - </MessageEditingContextProvider> - </InputStateContainer> - </RootContext.Provider> - </NavContext.Provider> - </FeatureFlagsProvider> + <QRAuthProvider + processTunnelbrokerMessage={parseTunnelbrokerQRAuthMessage} + composeTunnelbrokerMessage={composeTunnelbrokerQRAuthMessage} + generateAESKey={generateQRAuthKey} + performBackupRestore={performBackupRestore} + onLoginError={handleSecondaryDeviceRegistrationError} + > + <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 /> + <FarcasterDataHandler /> + <AutoJoinCommunityHandler /> + </PersistedStateGate> + {navigation} + </RegistrationContextProvider> + </BottomSheetProvider> + </MessageSearchProvider> + </MarkdownContextProvider> + </NativeEditThreadAvatarProvider> + </EditUserAvatarProvider> + </MediaCacheProvider> + </NeynarClientProvider> + </ENSCacheProvider> + </ActionSheetProvider> + </SafeAreaProvider> + </MessageEditingContextProvider> + </InputStateContainer> + </RootContext.Provider> + </NavContext.Provider> + </FeatureFlagsProvider> + </QRAuthProvider> </IdentitySearchProvider> </TunnelbrokerProvider> </IdentityServiceContextProvider>