Page MenuHomePhabricator

D12453.diff
No OneTemporary

D12453.diff

diff --git a/lib/components/qr-auth-provider.react.js b/lib/components/qr-auth-provider.react.js
--- a/lib/components/qr-auth-provider.react.js
+++ b/lib/components/qr-auth-provider.react.js
@@ -4,12 +4,23 @@
import * as React from 'react';
import { useSecondaryDeviceLogIn } from '../hooks/login-hooks.js';
-import { useQRAuth } from '../hooks/qr-auth.js';
import { uintArrayToHexString } from '../media/data-utils.js';
+import { IdentityClientContext } from '../shared/identity-client-context.js';
import { useTunnelbroker } from '../tunnelbroker/tunnelbroker-context.js';
import type { BackupKeys } from '../types/backup-types.js';
-import type { QRCodeAuthMessage } from '../types/tunnelbroker/peer-to-peer-message-types.js';
-import type { QRCodeAuthMessagePayload } from '../types/tunnelbroker/qr-code-auth-message-types.js';
+import {
+ tunnelbrokerMessageTypes,
+ type TunnelbrokerMessage,
+} from '../types/tunnelbroker/messages.js';
+import {
+ type QRCodeAuthMessage,
+ peerToPeerMessageTypes,
+ peerToPeerMessageValidator,
+} from '../types/tunnelbroker/peer-to-peer-message-types.js';
+import {
+ qrCodeAuthMessageTypes,
+ type QRCodeAuthMessagePayload,
+} from '../types/tunnelbroker/qr-code-auth-message-types.js';
import { getContentSigningKey } from '../utils/crypto-utils.js';
type Props = {
@@ -50,9 +61,19 @@
performBackupRestore,
} = props;
+ const [primaryDeviceID, setPrimaryDeviceID] = React.useState<?string>();
const [qrData, setQRData] = React.useState<?QRData>();
- const { setUnauthorizedDeviceID } = useTunnelbroker();
+ const {
+ setUnauthorizedDeviceID,
+ addListener,
+ removeListener,
+ socketState,
+ sendMessage,
+ } = useTunnelbroker();
+
+ const identityContext = React.useContext(IdentityClientContext);
+ const identityClient = identityContext?.identityClient;
const generateQRCode = React.useCallback(async () => {
try {
@@ -82,24 +103,116 @@
[logInSecondaryDevice, onLoginError, generateQRCode],
);
- const qrAuthInput = React.useMemo(
- () => ({
- secondaryDeviceID: qrData?.deviceID,
- aesKey: qrData?.aesKey,
- performSecondaryDeviceRegistration: performLogIn,
- composeMessage: composeTunnelbrokerMessage,
- processMessage: processTunnelbrokerMessage,
- performBackupRestore,
- }),
+ React.useEffect(() => {
+ if (!qrData || !socketState.isAuthorized || !primaryDeviceID) {
+ return;
+ }
+
+ void (async () => {
+ const message = await composeTunnelbrokerMessage(qrData?.aesKey, {
+ type: qrCodeAuthMessageTypes.SECONDARY_DEVICE_REGISTRATION_SUCCESS,
+ requestBackupKeys: true,
+ });
+ await sendMessage({
+ deviceID: primaryDeviceID,
+ payload: JSON.stringify(message),
+ });
+ })();
+ }, [
+ sendMessage,
+ primaryDeviceID,
+ qrData,
+ socketState,
+ composeTunnelbrokerMessage,
+ ]);
+
+ const tunnelbrokerMessageListener = React.useCallback(
+ async (message: TunnelbrokerMessage) => {
+ invariant(identityClient, 'identity context not set');
+ if (
+ !qrData?.aesKey ||
+ message.type !== tunnelbrokerMessageTypes.MESSAGE_TO_DEVICE
+ ) {
+ return;
+ }
+
+ let innerMessage;
+ try {
+ innerMessage = JSON.parse(message.payload);
+ } catch {
+ return;
+ }
+ if (
+ !peerToPeerMessageValidator.is(innerMessage) ||
+ innerMessage.type !== peerToPeerMessageTypes.QR_CODE_AUTH_MESSAGE
+ ) {
+ return;
+ }
+
+ let qrCodeAuthMessage;
+ try {
+ qrCodeAuthMessage = await processTunnelbrokerMessage(
+ qrData?.aesKey,
+ innerMessage,
+ );
+ } catch (err) {
+ console.warn('Failed to decrypt Tunnelbroker QR auth message:', err);
+ return;
+ }
+
+ if (
+ qrCodeAuthMessage &&
+ qrCodeAuthMessage.type ===
+ qrCodeAuthMessageTypes.BACKUP_DATA_KEY_MESSAGE
+ ) {
+ const { backupID, backupDataKey, backupLogDataKey } = qrCodeAuthMessage;
+ void performBackupRestore?.({
+ backupID,
+ backupDataKey,
+ backupLogDataKey,
+ });
+ return;
+ }
+
+ if (
+ !qrCodeAuthMessage ||
+ qrCodeAuthMessage.type !==
+ qrCodeAuthMessageTypes.DEVICE_LIST_UPDATE_SUCCESS
+ ) {
+ return;
+ }
+ const { primaryDeviceID: receivedPrimaryDeviceID, userID } =
+ qrCodeAuthMessage;
+ setPrimaryDeviceID(receivedPrimaryDeviceID);
+
+ await performLogIn(userID);
+ setUnauthorizedDeviceID(null);
+ },
[
- qrData,
+ identityClient,
+ qrData?.aesKey,
performLogIn,
- composeTunnelbrokerMessage,
+ setUnauthorizedDeviceID,
processTunnelbrokerMessage,
performBackupRestore,
],
);
- useQRAuth(qrAuthInput);
+
+ React.useEffect(() => {
+ if (!qrData?.deviceID) {
+ return undefined;
+ }
+
+ addListener(tunnelbrokerMessageListener);
+ return () => {
+ removeListener(tunnelbrokerMessageListener);
+ };
+ }, [
+ addListener,
+ removeListener,
+ tunnelbrokerMessageListener,
+ qrData?.deviceID,
+ ]);
const value = React.useMemo(
() => ({
diff --git a/lib/hooks/qr-auth.js b/lib/hooks/qr-auth.js
deleted file mode 100644
--- a/lib/hooks/qr-auth.js
+++ /dev/null
@@ -1,174 +0,0 @@
-// @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 type { BackupKeys } from '../types/backup-types.js';
-import {
- tunnelbrokerMessageTypes,
- type TunnelbrokerMessage,
-} from '../types/tunnelbroker/messages.js';
-import {
- peerToPeerMessageTypes,
- peerToPeerMessageValidator,
- type QRCodeAuthMessage,
-} from '../types/tunnelbroker/peer-to-peer-message-types.js';
-import {
- qrCodeAuthMessageTypes,
- type QRCodeAuthMessagePayload,
-} from '../types/tunnelbroker/qr-code-auth-message-types.js';
-
-type QRAuthHandlerInput = {
- +secondaryDeviceID: ?string,
- +aesKey: ?string,
- +performSecondaryDeviceRegistration: (userID: string) => Promise<void>,
- +composeMessage: (
- encryptionKey: string,
- payload: QRCodeAuthMessagePayload,
- ) => Promise<QRCodeAuthMessage>,
- +processMessage: (
- encryptionKey: string,
- message: QRCodeAuthMessage,
- ) => Promise<?QRCodeAuthMessagePayload>,
- +performBackupRestore?: (backupKeys: BackupKeys) => Promise<void>,
-};
-
-function useQRAuth(input: QRAuthHandlerInput) {
- const {
- secondaryDeviceID,
- aesKey,
- processMessage,
- composeMessage,
- performSecondaryDeviceRegistration,
- performBackupRestore,
- } = input;
- const [primaryDeviceID, setPrimaryDeviceID] = React.useState<?string>();
- const {
- setUnauthorizedDeviceID,
- addListener,
- removeListener,
- socketState,
- sendMessage,
- } = useTunnelbroker();
-
- const identityContext = React.useContext(IdentityClientContext);
- const identityClient = identityContext?.identityClient;
-
- React.useEffect(() => {
- if (
- !secondaryDeviceID ||
- !aesKey ||
- !socketState.isAuthorized ||
- !primaryDeviceID
- ) {
- return;
- }
-
- void (async () => {
- const message = await composeMessage(aesKey, {
- type: qrCodeAuthMessageTypes.SECONDARY_DEVICE_REGISTRATION_SUCCESS,
- requestBackupKeys: true,
- });
- await sendMessage({
- deviceID: primaryDeviceID,
- payload: JSON.stringify(message),
- });
- })();
- }, [
- sendMessage,
- primaryDeviceID,
- aesKey,
- secondaryDeviceID,
- composeMessage,
- socketState,
- ]);
-
- const tunnelbrokerMessageListener = React.useCallback(
- async (message: TunnelbrokerMessage) => {
- invariant(identityClient, 'identity context not set');
- if (
- !aesKey ||
- message.type !== tunnelbrokerMessageTypes.MESSAGE_TO_DEVICE
- ) {
- return;
- }
-
- let innerMessage;
- try {
- innerMessage = JSON.parse(message.payload);
- } catch {
- return;
- }
- if (
- !peerToPeerMessageValidator.is(innerMessage) ||
- innerMessage.type !== peerToPeerMessageTypes.QR_CODE_AUTH_MESSAGE
- ) {
- return;
- }
-
- let qrCodeAuthMessage;
- try {
- qrCodeAuthMessage = await processMessage(aesKey, innerMessage);
- } catch (err) {
- console.warn('Failed to decrypt Tunnelbroker QR auth message:', err);
- return;
- }
-
- if (
- qrCodeAuthMessage &&
- qrCodeAuthMessage.type ===
- qrCodeAuthMessageTypes.BACKUP_DATA_KEY_MESSAGE
- ) {
- const { backupID, backupDataKey, backupLogDataKey } = qrCodeAuthMessage;
- void performBackupRestore?.({
- backupID,
- backupDataKey,
- backupLogDataKey,
- });
- 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,
- performBackupRestore,
- processMessage,
- ],
- );
-
- React.useEffect(() => {
- if (!secondaryDeviceID) {
- return undefined;
- }
-
- addListener(tunnelbrokerMessageListener);
- return () => {
- removeListener(tunnelbrokerMessageListener);
- };
- }, [
- secondaryDeviceID,
- addListener,
- removeListener,
- tunnelbrokerMessageListener,
- ]);
-}
-
-export { useQRAuth };

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 26, 12:42 AM (22 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2581809
Default Alt Text
D12453.diff (9 KB)

Event Timeline