diff --git a/web/account/qr-code-login.react.js b/web/account/qr-code-login.react.js --- a/web/account/qr-code-login.react.js +++ b/web/account/qr-code-login.react.js @@ -1,19 +1,95 @@ // @flow +import olm from '@commapp/olm'; +import invariant from 'invariant'; import { QRCodeSVG } from 'qrcode.react'; import * as React from 'react'; +import { createSelector } from 'reselect'; +import { identityLogInActionTypes } from 'lib/actions/user-actions.js'; +import { QRAuthHandler } from 'lib/components/qr-auth-handler.react.js'; import { qrCodeLinkURL } from 'lib/facts/links.js'; import { generateKeyCommon } from 'lib/media/aes-crypto-utils-common.js'; import { uintArrayToHexString } from 'lib/media/data-utils.js'; +import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; +import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js'; +import type { CryptoStore, PickledOLMAccount } from 'lib/types/crypto-types.js'; +import type { + NonceChallenge, + SignedMessage, +} from 'lib/types/identity-service-types.js'; +import type { WebAppState } from 'lib/types/redux-types.js'; +import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import css from './qr-code-login.css'; +import { initOlm } from '../olm/olm-utils.js'; import { useSelector } from '../redux/redux-utils.js'; +const deviceIDAndPrimaryAccountSelector: (state: WebAppState) => { + ed25519Key: ?string, + primaryAccount: ?PickledOLMAccount, +} = createSelector( + (state: WebAppState) => state.cryptoStore, + (cryptoStore: ?CryptoStore) => ({ + ed25519Key: cryptoStore?.primaryIdentityKeys.ed25519, + primaryAccount: cryptoStore?.primaryAccount, + }), +); + function QrCodeLogin(): React.Node { const [qrCodeValue, setQrCodeValue] = React.useState(); - const ed25519Key = useSelector( - state => state.cryptoStore?.primaryIdentityKeys.ed25519, + const { ed25519Key, primaryAccount } = useSelector( + deviceIDAndPrimaryAccountSelector, + ); + const [deviceKeys, setDeviceKeys] = + React.useState(); + const { setUnauthorizedDeviceID } = useTunnelbroker(); + + const identityContext = React.useContext(IdentityClientContext); + const identityClient = identityContext?.identityClient; + + const dispatchActionPromise = useDispatchActionPromise(); + const performRegistration = React.useCallback( + async (userID: string) => { + if (!primaryAccount) { + return; + } + invariant(identityClient, 'identity context not set'); + try { + await initOlm(); + const primaryOLMAccount = new olm.Account(); + primaryOLMAccount.unpickle( + primaryAccount.picklingKey, + primaryAccount.pickledAccount, + ); + + const nonce = await identityClient.generateNonce(); + const nonceChallenge: NonceChallenge = { nonce }; + const nonceMessage = JSON.stringify(nonceChallenge); + const signature = await primaryOLMAccount.sign(nonceMessage); + const challengeResponse: SignedMessage = { + message: nonceMessage, + signature, + }; + + await dispatchActionPromise( + identityLogInActionTypes, + identityClient.uploadKeysForRegisteredDeviceAndLogIn( + userID, + challengeResponse, + ), + ); + setUnauthorizedDeviceID(null); + } catch (err) { + console.error('Secondary device registration error:', err); + } + }, + [ + dispatchActionPromise, + identityClient, + primaryAccount, + setUnauthorizedDeviceID, + ], ); const generateQRCode = React.useCallback(async () => { @@ -26,36 +102,45 @@ const aesKeyAsHexString: string = uintArrayToHexString(rawAESKey); const url = qrCodeLinkURL(aesKeyAsHexString, ed25519Key); + setUnauthorizedDeviceID(ed25519Key); setQrCodeValue(url); + setDeviceKeys({ deviceID: ed25519Key, aesKey: aesKeyAsHexString }); } catch (err) { console.error('Failed to generate QR Code:', err); } - }, [ed25519Key]); + }, [ed25519Key, setUnauthorizedDeviceID]); React.useEffect(() => { void generateQRCode(); }, [generateQRCode]); return ( -
-
Log in to Comm
-
- Open the Comm app on your phone and scan the QR code below -
- -
-
How to find the scanner:
-
- Go to Profile -
-
- Select Linked devices + <> + +
+
Log in to Comm
+
+ Open the Comm app on your phone and scan the QR code below
-
- Click Add on the top right + +
+
How to find the scanner:
+
+ Go to Profile +
+
+ Select Linked devices +
+
+ Click Add on the top right +
-
+ ); }