From 402f58225f6a87032be71fa0ee854f09a44ecf29 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 2 Jan 2019 15:32:14 -0600 Subject: [PATCH] Show in-room reminder when key backup creating device unverified If the current device hasn't verified the device that created the account's current key backup version, then the current device is won't use the key backup. This change adjusts an existing in-room reminder to do the right thing for this case by allowing the user to verify the device that created the key backup. Fixes vector-im/riot-web#7902. --- src/components/structures/RoomView.js | 7 ++ .../views/rooms/RoomRecoveryReminder.js | 101 ++++++++++++++++-- src/i18n/strings/en_EN.json | 3 +- 3 files changed, 102 insertions(+), 9 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 0e0d56647d0..dbfd6a27752 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -161,6 +161,7 @@ module.exports = React.createClass({ MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember); MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership); MatrixClientPeg.get().on("accountData", this.onAccountData); + MatrixClientPeg.get().on("crypto.keyBackupStatus", this.onKeyBackupStatus); this._fetchMediaConfig(); // Start listening for RoomViewStore updates this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); @@ -449,6 +450,7 @@ module.exports = React.createClass({ MatrixClientPeg.get().removeListener("Room.myMembership", this.onMyMembership); MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember); MatrixClientPeg.get().removeListener("accountData", this.onAccountData); + MatrixClientPeg.get().removeListener("crypto.keyBackupStatus", this.onKeyBackupStatus); } window.removeEventListener('beforeunload', this.onPageUnload); @@ -618,6 +620,11 @@ module.exports = React.createClass({ false, ); } + }, + + onKeyBackupStatus() { + // Key backup status changes affect whether the in-room recovery + // reminder is displayed. this.forceUpdate(); }, diff --git a/src/components/views/rooms/RoomRecoveryReminder.js b/src/components/views/rooms/RoomRecoveryReminder.js index 265bfd3ee39..d03c5fc96d7 100644 --- a/src/components/views/rooms/RoomRecoveryReminder.js +++ b/src/components/views/rooms/RoomRecoveryReminder.js @@ -19,13 +19,76 @@ import PropTypes from "prop-types"; import sdk from "../../../index"; import { _t } from "../../../languageHandler"; import Modal from "../../../Modal"; +import MatrixClientPeg from "../../../MatrixClientPeg"; export default class RoomRecoveryReminder extends React.PureComponent { static propTypes = { onFinished: PropTypes.func.isRequired, } - showKeyBackupDialog = () => { + constructor(props) { + super(props); + + this.state = { + loading: true, + error: null, + unverifiedDevice: null, + }; + } + + componentWillMount() { + this._loadBackupStatus(); + } + + async _loadBackupStatus() { + let backupSigStatus; + try { + const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); + backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo); + } catch (e) { + console.log("Unable to fetch key backup status", e); + this.setState({ + loading: false, + error: e, + }); + return; + } + + let unverifiedDevice; + for (const sig of backupSigStatus.sigs) { + if (!sig.device.isVerified()) { + unverifiedDevice = sig.device; + break; + } + } + this.setState({ + loading: false, + unverifiedDevice, + }); + } + + showSetupDialog = () => { + if (this.state.unverifiedDevice) { + // A key backup exists for this account, but the creating device is not + // verified, so we'll show the device verify dialog. + // TODO: Should change to a restore key backup flow that checks the recovery + // passphrase while at the same time also cross-signing the device as well in + // a single flow (for cases where a key backup exists but the backup creating + // device is unverified). Since we don't have that yet, we'll look for an + // unverified device and verify it. Note that this means we won't restore + // keys yet; instead we'll only trust the backup for sending our own new keys + // to it. + const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog'); + Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, { + userId: MatrixClientPeg.get().credentials.userId, + device: this.state.unverifiedDevice, + onFinished: this.props.onFinished, + }); + return; + } + + // The default case assumes that a key backup doesn't exist for this account, so + // we'll show the create key backup flow. Modal.createTrackedDialogAsync("Key Backup", "Key Backup", import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"), { @@ -46,29 +109,51 @@ export default class RoomRecoveryReminder extends React.PureComponent { this.props.onFinished(false); }, onSetup: () => { - this.showKeyBackupDialog(); + this.showSetupDialog(); }, }, ); } onSetupClick = () => { - this.showKeyBackupDialog(); + this.showSetupDialog(); } render() { + if (this.state.loading) { + return null; + } + const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton"); + let body; + if (this.state.error) { + body =
+ {_t("Unable to load key backup status")} +
; + } else if (this.state.unverifiedDevice) { + // A key backup exists for this account, but the creating device is not + // verified. + body = _t( + "To view your secure message history and ensure you can view new " + + "messages on future devices, set up Secure Message Recovery.", + ); + } else { + // The default case assumes that a key backup doesn't exist for this account. + // (This component doesn't currently check that itself.) + body = _t( + "If you log out or use another device, you'll lose your " + + "secure message history. To prevent this, set up Secure " + + "Message Recovery.", + ); + } + return (
{_t( "Secure Message Recovery", )}
-
{_t( - "If you log out or use another device, you'll lose your " + - "secure message history. To prevent this, set up Secure " + - "Message Recovery.", - )}
+
{body}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 81fcd963b36..ef659bf566f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -569,8 +569,9 @@ "You are trying to access a room.": "You are trying to access a room.", "Click here to join the discussion!": "Click here to join the discussion!", "This is a preview of this room. Room interactions have been disabled": "This is a preview of this room. Room interactions have been disabled", - "Secure Message Recovery": "Secure Message Recovery", + "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.": "To view your secure message history and ensure you can view new messages on future devices, set up Secure Message Recovery.", "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.": "If you log out or use another device, you'll lose your secure message history. To prevent this, set up Secure Message Recovery.", + "Secure Message Recovery": "Secure Message Recovery", "Don't ask again": "Don't ask again", "Set up": "Set up", "To change the room's avatar, you must be a": "To change the room's avatar, you must be a",