Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3386938
D11330.id38081.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D11330.id38081.diff
View Options
diff --git a/lib/components/qr-auth-handler.react.js b/lib/components/qr-auth-handler.react.js
new file mode 100644
--- /dev/null
+++ b/lib/components/qr-auth-handler.react.js
@@ -0,0 +1,136 @@
+// @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 {
+ tunnelbrokerMessageTypes,
+ type TunnelbrokerMessage,
+} from '../types/tunnelbroker/messages.js';
+import { peerToPeerMessageTypes } from '../types/tunnelbroker/peer-to-peer-message-types.js';
+import { qrCodeAuthMessageTypes } from '../types/tunnelbroker/qr-code-auth-message-types.js';
+import {
+ createQRAuthTunnelbrokerMessage,
+ parseQRAuthTunnelbrokerMessage,
+} from '../utils/qr-code-auth.js';
+
+type QRAuthHandlerProps = {
+ secondaryDeviceID: ?string,
+ aesKey: ?string,
+ performSecondaryDeviceRegistration: (userID: string) => Promise<void>,
+};
+
+function QRAuthHandler(props: QRAuthHandlerProps): React.Node {
+ const { secondaryDeviceID, aesKey, performSecondaryDeviceRegistration } =
+ props;
+ const [primaryDeviceID, setPrimaryDeviceID] = React.useState<?string>();
+ const {
+ setUnauthorizedDeviceID,
+ addListener,
+ removeListener,
+ connected: tunnelbrokerConnected,
+ isAuthorized,
+ sendMessage,
+ } = useTunnelbroker();
+
+ const identityContext = React.useContext(IdentityClientContext);
+ const identityClient = identityContext?.identityClient;
+
+ React.useEffect(() => {
+ if (
+ !secondaryDeviceID ||
+ !aesKey ||
+ !tunnelbrokerConnected ||
+ !isAuthorized ||
+ !primaryDeviceID
+ ) {
+ return;
+ }
+
+ void (async () => {
+ const message = createQRAuthTunnelbrokerMessage(aesKey, {
+ type: qrCodeAuthMessageTypes.SECONDARY_DEVICE_REGISTRATION_SUCCESS,
+ });
+ await sendMessage({
+ deviceID: primaryDeviceID,
+ payload: JSON.stringify(message),
+ });
+ })();
+ }, [
+ tunnelbrokerConnected,
+ isAuthorized,
+ sendMessage,
+ primaryDeviceID,
+ aesKey,
+ secondaryDeviceID,
+ ]);
+
+ const tunnelbrokerMessageListener = React.useCallback(
+ async (message: TunnelbrokerMessage) => {
+ invariant(identityClient, 'identity context not set');
+ if (
+ !aesKey ||
+ message.type !== tunnelbrokerMessageTypes.MESSAGE_TO_DEVICE
+ ) {
+ return;
+ }
+
+ const innerMessage = JSON.parse(message.payload);
+ if (innerMessage.type !== peerToPeerMessageTypes.QR_CODE_AUTH_MESSAGE) {
+ return;
+ }
+ const qrCodeAuthMessage = parseQRAuthTunnelbrokerMessage(
+ aesKey,
+ innerMessage,
+ );
+
+ if (
+ qrCodeAuthMessage?.type ===
+ qrCodeAuthMessageTypes.BACKUP_DATA_KEY_MESSAGE
+ ) {
+ return;
+ }
+
+ if (
+ !qrCodeAuthMessage ||
+ qrCodeAuthMessage.type !==
+ qrCodeAuthMessageTypes.DEVICE_LIST_UPDATE_SUCCESS
+ ) {
+ return;
+ }
+ const { primaryDeviceID: receivedPrimaryDeviceID, userID } =
+ qrCodeAuthMessage;
+ setPrimaryDeviceID(receivedPrimaryDeviceID);
+
+ await performSecondaryDeviceRegistration(userID);
+ setUnauthorizedDeviceID(null);
+ },
+ [
+ setUnauthorizedDeviceID,
+ identityClient,
+ aesKey,
+ performSecondaryDeviceRegistration,
+ ],
+ );
+
+ React.useEffect(() => {
+ if (!secondaryDeviceID) {
+ return () => {};
+ }
+ addListener(tunnelbrokerMessageListener);
+
+ return () => {
+ removeListener(tunnelbrokerMessageListener);
+ };
+ }, [
+ secondaryDeviceID,
+ addListener,
+ removeListener,
+ tunnelbrokerMessageListener,
+ ]);
+ return null;
+}
+
+export { QRAuthHandler };
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
@@ -5,6 +5,7 @@
import { View, Text } from 'react-native';
import QRCode from 'react-native-qrcode-svg';
+import { QRAuthHandler } from 'lib/components/qr-auth-handler.react.js';
import { qrCodeLinkURL } from 'lib/facts/links.js';
import { uintArrayToHexString } from 'lib/media/data-utils.js';
import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
@@ -13,16 +14,6 @@
NonceChallenge,
SignedMessage,
} from 'lib/types/identity-service-types.js';
-import {
- tunnelbrokerMessageTypes,
- type TunnelbrokerMessage,
-} from 'lib/types/tunnelbroker/messages.js';
-import { peerToPeerMessageTypes } from 'lib/types/tunnelbroker/peer-to-peer-message-types.js';
-import { qrCodeAuthMessageTypes } from 'lib/types/tunnelbroker/qr-code-auth-message-types.js';
-import {
- createQRAuthTunnelbrokerMessage,
- parseQRAuthTunnelbrokerMessage,
-} from 'lib/utils/qr-code-auth.js';
import type { QRCodeSignInNavigationProp } from './qr-code-sign-in-navigator.react.js';
import { commCoreModule } from '../native-modules.js';
@@ -42,79 +33,14 @@
const [qrCodeValue, setQrCodeValue] = React.useState<?string>();
const [deviceKeys, setDeviceKeys] =
React.useState<?{ +deviceID: string, +aesKey: string }>();
- const [primaryDeviceID, setPrimaryDeviceID] = React.useState<?string>();
- const {
- setUnauthorizedDeviceID,
- addListener,
- removeListener,
- connected: tunnelbrokerConnected,
- isAuthorized,
- sendMessage,
- } = useTunnelbroker();
+ const { setUnauthorizedDeviceID } = useTunnelbroker();
+
const identityContext = React.useContext(IdentityClientContext);
const identityClient = identityContext?.identityClient;
- React.useEffect(() => {
- if (
- !(tunnelbrokerConnected && isAuthorized && primaryDeviceID && deviceKeys)
- ) {
- return;
- }
-
- const message = createQRAuthTunnelbrokerMessage(deviceKeys.aesKey, {
- type: qrCodeAuthMessageTypes.SECONDARY_DEVICE_REGISTRATION_SUCCESS,
- });
- console.log('SECONDARY MESSAGE', message);
- void sendMessage({
- deviceID: primaryDeviceID,
- payload: JSON.stringify(message),
- });
- }, [
- tunnelbrokerConnected,
- isAuthorized,
- sendMessage,
- primaryDeviceID,
- deviceKeys,
- ]);
-
- const tunnelbrokerMessageListener = React.useCallback(
- async (message: TunnelbrokerMessage) => {
+ const performRegistration = React.useCallback(
+ async (userID: string) => {
invariant(identityClient, 'identity context not set');
- if (
- !deviceKeys ||
- message.type !== tunnelbrokerMessageTypes.MESSAGE_TO_DEVICE
- ) {
- return;
- }
-
- const innerMessage = JSON.parse(message.payload);
- if (innerMessage.type !== peerToPeerMessageTypes.QR_CODE_AUTH_MESSAGE) {
- return;
- }
- const qrCodeAuthMessage = parseQRAuthTunnelbrokerMessage(
- deviceKeys.aesKey,
- innerMessage,
- );
-
- if (
- qrCodeAuthMessage?.type ===
- qrCodeAuthMessageTypes.BACKUP_DATA_KEY_MESSAGE
- ) {
- console.log('Received backup data key:', qrCodeAuthMessage);
- return;
- }
-
- if (
- !qrCodeAuthMessage ||
- qrCodeAuthMessage.type !==
- qrCodeAuthMessageTypes.DEVICE_LIST_UPDATE_SUCCESS
- ) {
- return;
- }
- const { primaryDeviceID: receivedPrimaryDeviceID, userID } =
- qrCodeAuthMessage;
- setPrimaryDeviceID(receivedPrimaryDeviceID);
-
try {
const nonce = await identityClient.generateNonce();
const nonceChallenge: NonceChallenge = { nonce };
@@ -137,28 +63,9 @@
]);
}
},
- [setUnauthorizedDeviceID, identityClient, deviceKeys],
+ [setUnauthorizedDeviceID, identityClient],
);
- React.useEffect(() => {
- if (!deviceKeys) {
- return () => {};
- }
- addListener(tunnelbrokerMessageListener);
- setUnauthorizedDeviceID(deviceKeys.deviceID);
-
- return () => {
- removeListener(tunnelbrokerMessageListener);
- setUnauthorizedDeviceID(null);
- };
- }, [
- setUnauthorizedDeviceID,
- deviceKeys,
- addListener,
- removeListener,
- tunnelbrokerMessageListener,
- ]);
-
const generateQRCode = React.useCallback(async () => {
try {
const rawAESKey: Uint8Array = await AES.generateKey();
@@ -167,12 +74,13 @@
const ed25519Key: string = await getContentSigningKey();
const url = qrCodeLinkURL(aesKeyAsHexString, ed25519Key);
+ setUnauthorizedDeviceID(ed25519Key);
setQrCodeValue(url);
setDeviceKeys({ deviceID: ed25519Key, aesKey: aesKeyAsHexString });
} catch (err) {
console.error('Failed to generate QR Code:', err);
}
- }, []);
+ }, [setUnauthorizedDeviceID]);
React.useEffect(() => {
void generateQRCode();
@@ -180,29 +88,36 @@
const styles = useStyles(unboundStyles);
return (
- <View style={styles.container}>
- <Text style={styles.heading}>Log in to Comm</Text>
- <Text style={styles.headingSubtext}>
- Open the Comm app on your phone and scan the QR code below
- </Text>
- <QRCode value={qrCodeValue} size={200} />
- <View style={styles.instructionsBox}>
- <Text style={styles.instructionsTitle}>How to find the scanner:</Text>
- <Text style={styles.instructionsStep}>
- <Text>Go to </Text>
- <Text style={styles.instructionsBold}>Profile</Text>
- </Text>
- <Text style={styles.instructionsStep}>
- <Text>Select </Text>
- <Text style={styles.instructionsBold}>Linked devices </Text>
- </Text>
- <Text style={styles.instructionsStep}>
- <Text>Click </Text>
- <Text style={styles.instructionsBold}>Add </Text>
- <Text>on the top right</Text>
+ <>
+ <QRAuthHandler
+ secondaryDeviceID={deviceKeys?.deviceID}
+ aesKey={deviceKeys?.aesKey}
+ performSecondaryDeviceRegistration={performRegistration}
+ />
+ <View style={styles.container}>
+ <Text style={styles.heading}>Log in to Comm</Text>
+ <Text style={styles.headingSubtext}>
+ Open the Comm app on your phone and scan the QR code below
</Text>
+ <QRCode value={qrCodeValue} size={200} />
+ <View style={styles.instructionsBox}>
+ <Text style={styles.instructionsTitle}>How to find the scanner:</Text>
+ <Text style={styles.instructionsStep}>
+ <Text>Go to </Text>
+ <Text style={styles.instructionsBold}>Profile</Text>
+ </Text>
+ <Text style={styles.instructionsStep}>
+ <Text>Select </Text>
+ <Text style={styles.instructionsBold}>Linked devices </Text>
+ </Text>
+ <Text style={styles.instructionsStep}>
+ <Text>Click </Text>
+ <Text style={styles.instructionsBold}>Add </Text>
+ <Text>on the top right</Text>
+ </Text>
+ </View>
</View>
- </View>
+ </>
);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 30, 6:53 AM (19 h, 46 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2600017
Default Alt Text
D11330.id38081.diff (10 KB)
Attached To
Mode
D11330: [lib][native] Extract QR code to a spearate component
Attached
Detach File
Event Timeline
Log In to Comment