From e56a61ec68a5baf63295ac22fd95697324f53620 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 19 Aug 2020 16:13:29 +0100 Subject: [PATCH] Invoke Secure Backup flow inside the app when requested by HS If the Secure Backup required mode is set the client `.well-known` file, then this will ensure that everyone already inside the app is required to complete setup matching that policy. Fixes https://github.com/vector-im/element-web/issues/14954 --- src/@types/global.d.ts | 2 ++ src/DeviceListener.ts | 27 ++++++++++++++++++++++-- src/components/structures/MatrixChat.tsx | 7 ++++++ src/utils/WellKnownUtils.ts | 8 +++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 86ee995a13..84340d8219 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -27,10 +27,12 @@ import {ModalManager} from "../Modal"; import SettingsStore from "../settings/SettingsStore"; import {ActiveRoomObserver} from "../ActiveRoomObserver"; import {Notifier} from "../Notifier"; +import type {Renderer} from "react-dom"; declare global { interface Window { Modernizr: ModernizrStatic; + matrixChat: ReturnType; mxMatrixClientPeg: IMatrixClientPeg; Olm: { init: () => Promise; diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index aa9580834f..41daa74376 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -15,6 +15,7 @@ limitations under the License. */ import {MatrixClientPeg} from './MatrixClientPeg'; +import dis from "./dispatcher/dispatcher"; import { hideToast as hideBulkUnverifiedSessionsToast, showToast as showBulkUnverifiedSessionsToast, @@ -29,11 +30,15 @@ import { showToast as showUnverifiedSessionsToast, } from "./toasts/UnverifiedSessionToast"; import { privateShouldBeEncrypted } from "./createRoom"; -import { isSecretStorageBeingAccessed } from "./CrossSigningManager"; +import { isSecretStorageBeingAccessed, accessSecretStorage } from "./CrossSigningManager"; +import { ensureClientWellKnown, isSecureBackupRequired } from './utils/WellKnownUtils'; +import { isLoggedIn } from './components/structures/MatrixChat'; + const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000; export default class DeviceListener { + private dispatcherRef: string; // device IDs for which the user has dismissed the verify toast ('Later') private dismissed = new Set(); // has the user dismissed any of the various nag toasts to setup encryption on this device? @@ -61,6 +66,7 @@ export default class DeviceListener { MatrixClientPeg.get().on('crossSigning.keysChanged', this._onCrossSingingKeysChanged); MatrixClientPeg.get().on('accountData', this._onAccountData); MatrixClientPeg.get().on('sync', this._onSync); + this.dispatcherRef = dis.register(this._onAction); this._recheck(); } @@ -74,6 +80,10 @@ export default class DeviceListener { MatrixClientPeg.get().removeListener('accountData', this._onAccountData); MatrixClientPeg.get().removeListener('sync', this._onSync); } + if (this.dispatcherRef) { + dis.unregister(this.dispatcherRef); + this.dispatcherRef = null; + } this.dismissed.clear(); this.dismissedThisDeviceToast = false; this.keyBackupInfo = null; @@ -159,6 +169,11 @@ export default class DeviceListener { if (state === 'PREPARED' && prevState === null) this._recheck(); }; + _onAction = ({ action }) => { + if (action !== "on_logged_in") return; + this._recheck(); + }; + // The server doesn't tell us when key backup is set up, so we poll // & cache the result async _getKeyBackupInfo() { @@ -211,7 +226,15 @@ export default class DeviceListener { showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION); } else { // No cross-signing or key backup on account (set up encryption) - showSetupEncryptionToast(SetupKind.SET_UP_ENCRYPTION); + await ensureClientWellKnown(); + if (isSecureBackupRequired() && isLoggedIn()) { + // If we're meant to set up, and Secure Backup is required, + // trigger the flow directly without a toast once logged in. + hideSetupEncryptionToast(); + accessSecretStorage(); + } else { + showSetupEncryptionToast(SetupKind.SET_UP_ENCRYPTION); + } } } } diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index ce96847d28..9929cc523e 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -2085,3 +2085,10 @@ export default class MatrixChat extends React.PureComponent { ; } } + +export function isLoggedIn(): boolean { + // JRS: Maybe we should move the step that writes this to the window out of + // `element-web` and into this file? + const app = window.matrixChat; + return app && (app as MatrixChat).state.view === Views.LOGGED_IN; +} diff --git a/src/utils/WellKnownUtils.ts b/src/utils/WellKnownUtils.ts index f16acdb408..1fe28f2b0c 100644 --- a/src/utils/WellKnownUtils.ts +++ b/src/utils/WellKnownUtils.ts @@ -23,6 +23,14 @@ export interface IE2EEWellKnown { default?: boolean; } +export async function ensureClientWellKnown() { + const cli = MatrixClientPeg.get(); + if (cli.haveAttemptedFetchingClientWellKnown()) return; + return new Promise(resolve => { + cli.once("WellKnown.attempted", resolve); + }); +} + export function getE2EEWellKnown(): IE2EEWellKnown { const clientWellKnown = MatrixClientPeg.get().getClientWellKnown(); if (clientWellKnown && clientWellKnown[E2EE_WK_KEY]) {