diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 0e0d56647d..dbfd6a2775 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 265bfd3ee3..d03c5fc96d 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 81fcd963b3..ef659bf566 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",