Prompt to restore backup rather than verify

Direct the user to restore the backup in order to both get the keys
out of the backup and start putting them in.

Also hide the advanced key backup stuff in a diclosure.
This commit is contained in:
David Baker 2019-02-08 11:51:22 +00:00
parent abcbd46fe1
commit ac98da4a8a
3 changed files with 47 additions and 101 deletions

View File

@ -38,7 +38,7 @@ export default class RoomRecoveryReminder extends React.PureComponent {
this.state = { this.state = {
loading: true, loading: true,
error: null, error: null,
unverifiedDevice: null, backupInfo: null,
}; };
} }
@ -47,10 +47,12 @@ export default class RoomRecoveryReminder extends React.PureComponent {
} }
async _loadBackupStatus() { async _loadBackupStatus() {
let backupSigStatus;
try { try {
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo); this.setState({
loading: false,
backupInfo,
});
} catch (e) { } catch (e) {
console.log("Unable to fetch key backup status", e); console.log("Unable to fetch key backup status", e);
this.setState({ this.setState({
@ -59,44 +61,20 @@ export default class RoomRecoveryReminder extends React.PureComponent {
}); });
return; return;
} }
let unverifiedDevice;
for (const sig of backupSigStatus.sigs) {
if (sig.device && !sig.device.isVerified()) {
unverifiedDevice = sig.device;
break;
}
}
this.setState({
loading: false,
unverifiedDevice,
});
} }
showSetupDialog = () => { showSetupDialog = () => {
if (this.state.unverifiedDevice) { if (this.state.backupInfo) {
// A key backup exists for this account, but the creating device is not // A key backup exists for this account, but the creating device is not
// verified, so we'll show the device verify dialog. // verified, so restore the backup which will give us the keys from it and
// TODO: Should change to a restore key backup flow that checks the recovery // allow us to trust it (ie. upload keys to it)
// passphrase while at the same time also cross-signing the device as well in const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
// a single flow (for cases where a key backup exists but the backup creating Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog, {});
// device is unverified). Since we don't have that yet, we'll look for an } else {
// unverified device and verify it. Note that this means we won't restore Modal.createTrackedDialogAsync("Key Backup", "Key Backup",
// keys yet; instead we'll only trust the backup for sending our own new keys import("../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog"),
// to it. );
const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
userId: MatrixClientPeg.get().credentials.userId,
device: this.state.unverifiedDevice,
});
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"),
);
} }
onDontAskAgainClick = () => { onDontAskAgainClick = () => {
@ -133,53 +111,41 @@ export default class RoomRecoveryReminder extends React.PureComponent {
const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton"); const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
let body; let body;
let primaryCaption = _t("Set up");
if (this.state.error) { if (this.state.error) {
body = <div className="error"> body = <div className="error">
{_t("Unable to load key backup status")} {_t("Unable to load key backup status")}
</div>; </div>;
} else if (this.state.unverifiedDevice) { } else if (this.state.backupInfo) {
// A key backup exists for this account, but the creating device is not // A key backup exists for this account, but we're not using it.
// verified.
body = <div> body = <div>
<p>{_t( <p>{_t(
"Secure Message Recovery has been set up on another device: <deviceName></deviceName>", "Secure Key Backup should be active on all of your devices to avoid " +
{}, "losing access to your encrypted messages.",
{
deviceName: () => <i>{this.state.unverifiedDevice.unsigned.device_display_name}</i>,
},
)}</p>
<p>{_t(
"To view your secure message history and ensure you can view new " +
"messages on future devices, verify that device now.",
)}</p> )}</p>
</div>; </div>;
primaryCaption = _t("Verify device");
} else { } 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( body = _t(
"If you log out or use another device, you'll lose your " + "Securely back up your decryption keys to the server to make sure " +
"secure message history. To prevent this, set up Secure " + "you'll always be able to read your encrypted messages.",
"Message Recovery.",
); );
} }
return ( return (
<div className="mx_RoomRecoveryReminder"> <div className="mx_RoomRecoveryReminder">
<div className="mx_RoomRecoveryReminder_header">{_t( <div className="mx_RoomRecoveryReminder_header">{_t(
"Secure Message Recovery", "Don't risk losing your encrypted messages!",
)}</div> )}</div>
<div className="mx_RoomRecoveryReminder_body">{body}</div> <div className="mx_RoomRecoveryReminder_body">{body}</div>
<div className="mx_RoomRecoveryReminder_buttons"> <div className="mx_RoomRecoveryReminder_buttons">
<AccessibleButton className="mx_RoomRecoveryReminder_button mx_RoomRecoveryReminder_secondary"
onClick={this.onDontAskAgainClick}>
{ _t("Don't ask again") }
</AccessibleButton>
<AccessibleButton className="mx_RoomRecoveryReminder_button" <AccessibleButton className="mx_RoomRecoveryReminder_button"
onClick={this.onSetupClick}> onClick={this.onSetupClick}>
{primaryCaption} {_t("Activate Secure Key Backup")}
</AccessibleButton> </AccessibleButton>
<p><AccessibleButton className="mx_RoomRecoveryReminder_button mx_RoomRecoveryReminder_secondary"
onClick={this.onDontAskAgainClick}>
{ _t("No Thanks") }
</AccessibleButton>
<div>{_t("I'll download a copy of my decryption keys before I log out")}</div></p>
</div> </div>
</div> </div>
); );

View File

@ -27,7 +27,6 @@ export default class KeyBackupPanel extends React.PureComponent {
this._startNewBackup = this._startNewBackup.bind(this); this._startNewBackup = this._startNewBackup.bind(this);
this._deleteBackup = this._deleteBackup.bind(this); this._deleteBackup = this._deleteBackup.bind(this);
this._verifyDevice = this._verifyDevice.bind(this);
this._onKeyBackupSessionsRemaining = this._onKeyBackupSessionsRemaining =
this._onKeyBackupSessionsRemaining.bind(this); this._onKeyBackupSessionsRemaining.bind(this);
this._onKeyBackupStatus = this._onKeyBackupStatus.bind(this); this._onKeyBackupStatus = this._onKeyBackupStatus.bind(this);
@ -133,19 +132,6 @@ export default class KeyBackupPanel extends React.PureComponent {
}); });
} }
_verifyDevice(e) {
const device = this.state.backupSigStatus.sigs[e.target.getAttribute('data-sigindex')].device;
const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
userId: MatrixClientPeg.get().credentials.userId,
device: device,
onFinished: () => {
this._loadBackupStatus();
},
});
}
render() { render() {
const Spinner = sdk.getComponent("elements.Spinner"); const Spinner = sdk.getComponent("elements.Spinner");
const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
@ -163,9 +149,8 @@ export default class KeyBackupPanel extends React.PureComponent {
if (MatrixClientPeg.get().getKeyBackupEnabled()) { if (MatrixClientPeg.get().getKeyBackupEnabled()) {
clientBackupStatus = _t("This device is using key backup"); clientBackupStatus = _t("This device is using key backup");
} else { } else {
// XXX: display why and how to fix it
clientBackupStatus = _t( clientBackupStatus = _t(
"This device is <b>not</b> using key backup", {}, "This device is <b>not</b> using key backup. Restore the backup to start using it.", {},
{b: x => <b>{x}</b>}, {b: x => <b>{x}</b>},
); );
} }
@ -233,17 +218,8 @@ export default class KeyBackupPanel extends React.PureComponent {
); );
} }
let verifyButton;
if (sig.device && !sig.device.isVerified()) {
verifyButton = <div><br /><AccessibleButton className="mx_GeneralButton"
onClick={this._verifyDevice} data-sigindex={i}>
{ _t("Verify...") }
</AccessibleButton></div>;
}
return <div key={i}> return <div key={i}>
{sigStatus} {sigStatus}
{verifyButton}
</div>; </div>;
}); });
if (this.state.backupSigStatus.sigs.length === 0) { if (this.state.backupSigStatus.sigs.length === 0) {
@ -256,12 +232,15 @@ export default class KeyBackupPanel extends React.PureComponent {
} }
return <div> return <div>
<div>{_t("Backup version: ")}{this.state.backupInfo.version}</div>
<div>{_t("Algorithm: ")}{this.state.backupInfo.algorithm}</div>
<div>{clientBackupStatus}</div> <div>{clientBackupStatus}</div>
{uploadStatus} <details>
<div>{backupSigStatuses}</div> <summary>{_t("Advanced")}</summary>
<div>{trustedLocally}</div> <div>{_t("Backup version: ")}{this.state.backupInfo.version}</div>
<div>{_t("Algorithm: ")}{this.state.backupInfo.algorithm}</div>
{uploadStatus}
<div>{backupSigStatuses}</div>
<div>{trustedLocally}</div>
</details>
<p> <p>
<AccessibleButton kind="primary" onClick={this._restoreBackup}> <AccessibleButton kind="primary" onClick={this._restoreBackup}>
{ _t("Restore backup") } { _t("Restore backup") }

View File

@ -329,7 +329,6 @@
"Got It": "Got It", "Got It": "Got It",
"Verify this user by confirming the following number appears on their screen.": "Verify this user by confirming the following number appears on their screen.", "Verify this user by confirming the following number appears on their screen.": "Verify this user by confirming the following number appears on their screen.",
"For maximum security, we recommend you do this in person or use another trusted means of communication.": "For maximum security, we recommend you do this in person or use another trusted means of communication.", "For maximum security, we recommend you do this in person or use another trusted means of communication.": "For maximum security, we recommend you do this in person or use another trusted means of communication.",
"To continue, click on each pair to confirm it's correct.": "To continue, click on each pair to confirm it's correct.",
"Continue": "Continue", "Continue": "Continue",
"Failed to upload profile picture!": "Failed to upload profile picture!", "Failed to upload profile picture!": "Failed to upload profile picture!",
"Upload new:": "Upload new:", "Upload new:": "Upload new:",
@ -374,7 +373,7 @@
"Delete backup": "Delete backup", "Delete backup": "Delete backup",
"Unable to load key backup status": "Unable to load key backup status", "Unable to load key backup status": "Unable to load key backup status",
"This device is using key backup": "This device is using key backup", "This device is using key backup": "This device is using key backup",
"This device is <b>not</b> using key backup": "This device is <b>not</b> using key backup", "This device is <b>not</b> using key backup. Restore the backup to start using it.": "This device is <b>not</b> using key backup. Restore the backup to start using it.",
"Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...", "Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...",
"All keys backed up": "All keys backed up", "All keys backed up": "All keys backed up",
"Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.": "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.", "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.": "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
@ -383,7 +382,6 @@
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>", "Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>", "Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>", "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>",
"Verify...": "Verify...",
"Backup is not signed by any of your devices": "Backup is not signed by any of your devices", "Backup is not signed by any of your devices": "Backup is not signed by any of your devices",
"This backup is trusted because it has been restored on this device": "This backup is trusted because it has been restored on this device", "This backup is trusted because it has been restored on this device": "This backup is trusted because it has been restored on this device",
"Backup version: ": "Backup version: ", "Backup version: ": "Backup version: ",
@ -719,13 +717,12 @@
"You are trying to access a room.": "You are trying to access a room.", "You are trying to access a room.": "You are trying to access a room.",
"<a>Click here</a> to join the discussion!": "<a>Click here</a> to join the discussion!", "<a>Click here</a> to join the discussion!": "<a>Click here</a> 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", "This is a preview of this room. Room interactions have been disabled": "This is a preview of this room. Room interactions have been disabled",
"Set up": "Set up", "Secure Key Backup should be active on all of your devices to avoid losing access to your encrypted messages.": "Secure Key Backup should be active on all of your devices to avoid losing access to your encrypted messages.",
"Secure Message Recovery has been set up on another device: <deviceName></deviceName>": "Secure Message Recovery has been set up on another device: <deviceName></deviceName>", "Securely back up your decryption keys to the server to make sure you'll always be able to read your encrypted messages.": "Securely back up your decryption keys to the server to make sure you'll always be able to read your encrypted messages.",
"To view your secure message history and ensure you can view new messages on future devices, verify that device now.": "To view your secure message history and ensure you can view new messages on future devices, verify that device now.", "Don't risk losing your encrypted messages!": "Don't risk losing your encrypted messages!",
"Verify device": "Verify device", "Activate Secure Key Backup": "Activate Secure Key Backup",
"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.", "No Thanks": "No Thanks",
"Secure Message Recovery": "Secure Message Recovery", "I'll download a copy of my decryption keys before I log out": "I'll download a copy of my decryption keys before I log out",
"Don't ask again": "Don't ask again",
"Add a topic": "Add a topic", "Add a topic": "Add a topic",
"This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.", "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.": "This room is using an unstable room version. If you aren't expecting this, please upgrade the room.",
"Click here to upgrade to the latest room version.": "Click here to upgrade to the latest room version.", "Click here to upgrade to the latest room version.": "Click here to upgrade to the latest room version.",
@ -860,6 +857,7 @@
"Unblacklist": "Unblacklist", "Unblacklist": "Unblacklist",
"Blacklist": "Blacklist", "Blacklist": "Blacklist",
"Unverify": "Unverify", "Unverify": "Unverify",
"Verify...": "Verify...",
"Join": "Join", "Join": "Join",
"No results": "No results", "No results": "No results",
"Delete": "Delete", "Delete": "Delete",
@ -991,6 +989,7 @@
"Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)", "Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)": "Please forget all messages I have sent when my account is deactivated (<b>Warning:</b> this will cause future users to see an incomplete view of conversations)",
"To continue, please enter your password:": "To continue, please enter your password:", "To continue, please enter your password:": "To continue, please enter your password:",
"password": "password", "password": "password",
"Verify device": "Verify device",
"Use Legacy Verification (for older clients)": "Use Legacy Verification (for older clients)", "Use Legacy Verification (for older clients)": "Use Legacy Verification (for older clients)",
"Verify by comparing a short text string.": "Verify by comparing a short text string.", "Verify by comparing a short text string.": "Verify by comparing a short text string.",
"Begin Verifying": "Begin Verifying", "Begin Verifying": "Begin Verifying",
@ -1457,6 +1456,8 @@
"Retry": "Retry", "Retry": "Retry",
"Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.", "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.": "Without setting up Secure Message Recovery, you'll lose your secure message history when you log out.",
"If you don't want to set this up now, you can later in Settings.": "If you don't want to set this up now, you can later in Settings.", "If you don't want to set this up now, you can later in Settings.": "If you don't want to set this up now, you can later in Settings.",
"Set up": "Set up",
"Don't ask again": "Don't ask again",
"New Recovery Method": "New Recovery Method", "New Recovery Method": "New Recovery Method",
"A new recovery passphrase and key for Secure Messages have been detected.": "A new recovery passphrase and key for Secure Messages have been detected.", "A new recovery passphrase and key for Secure Messages have been detected.": "A new recovery passphrase and key for Secure Messages have been detected.",
"If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.", "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.",