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
This commit is contained in:
parent
e8e691b746
commit
e56a61ec68
4 changed files with 42 additions and 2 deletions
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
|
@ -27,10 +27,12 @@ import {ModalManager} from "../Modal";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import {ActiveRoomObserver} from "../ActiveRoomObserver";
|
import {ActiveRoomObserver} from "../ActiveRoomObserver";
|
||||||
import {Notifier} from "../Notifier";
|
import {Notifier} from "../Notifier";
|
||||||
|
import type {Renderer} from "react-dom";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
Modernizr: ModernizrStatic;
|
Modernizr: ModernizrStatic;
|
||||||
|
matrixChat: ReturnType<Renderer>;
|
||||||
mxMatrixClientPeg: IMatrixClientPeg;
|
mxMatrixClientPeg: IMatrixClientPeg;
|
||||||
Olm: {
|
Olm: {
|
||||||
init: () => Promise<void>;
|
init: () => Promise<void>;
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {MatrixClientPeg} from './MatrixClientPeg';
|
import {MatrixClientPeg} from './MatrixClientPeg';
|
||||||
|
import dis from "./dispatcher/dispatcher";
|
||||||
import {
|
import {
|
||||||
hideToast as hideBulkUnverifiedSessionsToast,
|
hideToast as hideBulkUnverifiedSessionsToast,
|
||||||
showToast as showBulkUnverifiedSessionsToast,
|
showToast as showBulkUnverifiedSessionsToast,
|
||||||
|
@ -29,11 +30,15 @@ import {
|
||||||
showToast as showUnverifiedSessionsToast,
|
showToast as showUnverifiedSessionsToast,
|
||||||
} from "./toasts/UnverifiedSessionToast";
|
} from "./toasts/UnverifiedSessionToast";
|
||||||
import { privateShouldBeEncrypted } from "./createRoom";
|
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;
|
const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
|
||||||
|
|
||||||
export default class DeviceListener {
|
export default class DeviceListener {
|
||||||
|
private dispatcherRef: string;
|
||||||
// device IDs for which the user has dismissed the verify toast ('Later')
|
// device IDs for which the user has dismissed the verify toast ('Later')
|
||||||
private dismissed = new Set<string>();
|
private dismissed = new Set<string>();
|
||||||
// has the user dismissed any of the various nag toasts to setup encryption on this device?
|
// 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('crossSigning.keysChanged', this._onCrossSingingKeysChanged);
|
||||||
MatrixClientPeg.get().on('accountData', this._onAccountData);
|
MatrixClientPeg.get().on('accountData', this._onAccountData);
|
||||||
MatrixClientPeg.get().on('sync', this._onSync);
|
MatrixClientPeg.get().on('sync', this._onSync);
|
||||||
|
this.dispatcherRef = dis.register(this._onAction);
|
||||||
this._recheck();
|
this._recheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +80,10 @@ export default class DeviceListener {
|
||||||
MatrixClientPeg.get().removeListener('accountData', this._onAccountData);
|
MatrixClientPeg.get().removeListener('accountData', this._onAccountData);
|
||||||
MatrixClientPeg.get().removeListener('sync', this._onSync);
|
MatrixClientPeg.get().removeListener('sync', this._onSync);
|
||||||
}
|
}
|
||||||
|
if (this.dispatcherRef) {
|
||||||
|
dis.unregister(this.dispatcherRef);
|
||||||
|
this.dispatcherRef = null;
|
||||||
|
}
|
||||||
this.dismissed.clear();
|
this.dismissed.clear();
|
||||||
this.dismissedThisDeviceToast = false;
|
this.dismissedThisDeviceToast = false;
|
||||||
this.keyBackupInfo = null;
|
this.keyBackupInfo = null;
|
||||||
|
@ -159,6 +169,11 @@ export default class DeviceListener {
|
||||||
if (state === 'PREPARED' && prevState === null) this._recheck();
|
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
|
// The server doesn't tell us when key backup is set up, so we poll
|
||||||
// & cache the result
|
// & cache the result
|
||||||
async _getKeyBackupInfo() {
|
async _getKeyBackupInfo() {
|
||||||
|
@ -211,10 +226,18 @@ export default class DeviceListener {
|
||||||
showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION);
|
showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION);
|
||||||
} else {
|
} else {
|
||||||
// No cross-signing or key backup on account (set up encryption)
|
// No cross-signing or key backup on account (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);
|
showSetupEncryptionToast(SetupKind.SET_UP_ENCRYPTION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This needs to be done after awaiting on downloadKeys() above, so
|
// This needs to be done after awaiting on downloadKeys() above, so
|
||||||
// we make sure we get the devices after the fetch is done.
|
// we make sure we get the devices after the fetch is done.
|
||||||
|
|
|
@ -2085,3 +2085,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
</ErrorBoundary>;
|
</ErrorBoundary>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,14 @@ export interface IE2EEWellKnown {
|
||||||
default?: boolean;
|
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 {
|
export function getE2EEWellKnown(): IE2EEWellKnown {
|
||||||
const clientWellKnown = MatrixClientPeg.get().getClientWellKnown();
|
const clientWellKnown = MatrixClientPeg.get().getClientWellKnown();
|
||||||
if (clientWellKnown && clientWellKnown[E2EE_WK_KEY]) {
|
if (clientWellKnown && clientWellKnown[E2EE_WK_KEY]) {
|
||||||
|
|
Loading…
Reference in a new issue