Add New Recovery Method dialog
Adds a New Recovery Method dialog which is shown when key backup fails because of a version mismatch / version not found error. The set up button in the dialog currently only marks a device as verified (via a verification prompt) instead of the eventual restore and cross-sign flow, since those pieces don't exist yet. Signed-off-by: J. Ryan Stinnett <jryans@gmail.com>pull/21833/head
parent
2b14f2af5c
commit
acc2e98355
|
@ -34,7 +34,7 @@ body {
|
|||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
}
|
||||
|
||||
div.error, div.warning {
|
||||
.error, .warning {
|
||||
color: $warning-color;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
@import "./views/dialogs/_ShareDialog.scss";
|
||||
@import "./views/dialogs/_UnknownDeviceDialog.scss";
|
||||
@import "./views/dialogs/keybackup/_CreateKeyBackupDialog.scss";
|
||||
@import "./views/dialogs/keybackup/_NewRecoveryMethodDialog.scss";
|
||||
@import "./views/dialogs/keybackup/_RestoreKeyBackupDialog.scss";
|
||||
@import "./views/directory/_NetworkDropdown.scss";
|
||||
@import "./views/elements/_AccessibleButton.scss";
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_NewRecoveryMethodDialog .mx_Dialog_title {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.mx_NewRecoveryMethodDialog_title {
|
||||
position: relative;
|
||||
padding-left: 45px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
&:before {
|
||||
mask: url("../../../img/e2e/lock-warning.svg");
|
||||
mask-repeat: no-repeat;
|
||||
background-color: $primary-fg-color;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_NewRecoveryMethodDialog .mx_Dialog_buttons {
|
||||
margin-top: 36px;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg height="42" width="37" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><mask id="a" fill="#fff"><path d="m23.521 14.596h-1.777a.454.454 0 0 1 -.456-.45v-4.14a8.974 8.974 0 0 0 -8.57-9 8.884 8.884 0 0 0 -9.253 8.82v4.365a.454.454 0 0 1 -.456.45h-1.78a1.218 1.218 0 0 0 -1.229 1.215v15.93a1.218 1.218 0 0 0 1.229 1.214h22.247a1.218 1.218 0 0 0 1.231-1.215v-15.974a1.153 1.153 0 0 0 -1.186-1.215zm-17.276-4.77a6.114 6.114 0 0 1 6.473-6.075 6.251 6.251 0 0 1 5.88 6.255v4.185a.454.454 0 0 1 -.456.45h-11.486a.454.454 0 0 1 -.456-.45v-4.365zm20.255 11.174c6.344.019 11.481 5.156 11.5 11.5 0 6.351-5.149 11.5-11.5 11.5s-11.5-5.149-11.5-11.5 5.149-11.5 11.5-11.5z" fill="#fff" fill-rule="evenodd"/></mask><g fill="#000" fill-rule="evenodd"><path d="m-.909 32.909h19.773c2.392-6.604 4.34-10.526 5.844-11.766s1.808-8.258.912-21.052h-26.529z" mask="url(#a)" transform="translate(0 -1)"/><path d="m26.5 21c-5.799 0-10.5 4.701-10.5 10.5s4.701 10.5 10.5 10.5 10.5-4.701 10.5-10.5c-.017-5.792-4.708-10.483-10.5-10.5zm1.444 16.012h-2.888v-2.493h3.019v2.494zm.131-9.712-.787 5.775h-1.575l-.788-5.775v-1.312h3.15z" fill-rule="nonzero"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import sdk from "../../../../index";
|
||||
import MatrixClientPeg from '../../../../MatrixClientPeg';
|
||||
import dis from "../../../../dispatcher";
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import Modal from "../../../../Modal";
|
||||
|
||||
export default class NewRecoveryMethodDialog extends React.PureComponent {
|
||||
static propTypes = {
|
||||
onFinished: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
onGoToSettingsClick = () => {
|
||||
this.props.onFinished();
|
||||
dis.dispatch({ action: 'view_user_settings' });
|
||||
}
|
||||
|
||||
onSetupClick = async() => {
|
||||
// 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. 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.
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
let unverifiedDevice;
|
||||
for (const sig of backupSigStatus.sigs) {
|
||||
if (!sig.device.isVerified()) {
|
||||
unverifiedDevice = sig.device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!unverifiedDevice) {
|
||||
console.log("Unable to find a device to verify.");
|
||||
return;
|
||||
}
|
||||
|
||||
const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
|
||||
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
|
||||
userId: MatrixClientPeg.get().credentials.userId,
|
||||
device: unverifiedDevice,
|
||||
onFinished: this.props.onFinished,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const BaseDialog = sdk.getComponent("views.dialogs.BaseDialog");
|
||||
const DialogButtons = sdk.getComponent("views.elements.DialogButtons");
|
||||
const title = <span className="mx_NewRecoveryMethodDialog_title">
|
||||
{_t("New Recovery Method")}
|
||||
</span>;
|
||||
|
||||
return (
|
||||
<BaseDialog className="mx_NewRecoveryMethodDialog"
|
||||
onFinished={this.props.onFinished}
|
||||
title={title}
|
||||
hasCancel={false}
|
||||
>
|
||||
<div>
|
||||
<p>{_t(
|
||||
"A new recovery passphrase and key for Secure " +
|
||||
"Messages has been detected.",
|
||||
)}</p>
|
||||
<p>{_t(
|
||||
"Setting up Secure Messages on this device " +
|
||||
"will re-encrypt this device's message history with " +
|
||||
"the new recovery method.",
|
||||
)}</p>
|
||||
<p className="warning">{_t(
|
||||
"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.",
|
||||
)}</p>
|
||||
<DialogButtons
|
||||
primaryButton={_t("Set up Secure Messages")}
|
||||
onPrimaryButtonClick={this.onSetupClick}
|
||||
cancelButton={_t("Go to Settings")}
|
||||
onCancel={this.onGoToSettingsClick}
|
||||
/>
|
||||
</div>
|
||||
</BaseDialog>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1430,6 +1430,11 @@ export default React.createClass({
|
|||
break;
|
||||
}
|
||||
});
|
||||
cli.on("crypto.keyBackupFailed", () => {
|
||||
Modal.createTrackedDialogAsync('New Recovery Method', 'New Recovery Method',
|
||||
import('../../async-components/views/dialogs/keybackup/NewRecoveryMethodDialog'),
|
||||
);
|
||||
});
|
||||
|
||||
// Fire the tinter right on startup to ensure the default theme is applied
|
||||
// A later sync can/will correct the tint to be the right value for the user
|
||||
|
|
|
@ -57,8 +57,7 @@ export default React.createClass({
|
|||
className: PropTypes.string,
|
||||
|
||||
// Title for the dialog.
|
||||
// (could probably actually be something more complicated than a string if desired)
|
||||
title: PropTypes.string.isRequired,
|
||||
title: PropTypes.node.isRequired,
|
||||
|
||||
// children should be the content of the dialog
|
||||
children: PropTypes.node,
|
||||
|
|
|
@ -154,6 +154,7 @@ export default class KeyBackupPanel extends React.Component {
|
|||
}
|
||||
|
||||
let backupSigStatuses = this.state.backupSigStatus.sigs.map((sig, i) => {
|
||||
const deviceName = sig.device.getDisplayName() || sig.device.deviceId;
|
||||
const sigStatusSubstitutions = {
|
||||
validity: sub =>
|
||||
<span className={sig.valid ? 'mx_KeyBackupPanel_sigValid' : 'mx_KeyBackupPanel_sigInvalid'}>
|
||||
|
@ -163,7 +164,7 @@ export default class KeyBackupPanel extends React.Component {
|
|||
<span className={sig.device.isVerified() ? 'mx_KeyBackupPanel_deviceVerified' : 'mx_KeyBackupPanel_deviceNotVerified'}>
|
||||
{sub}
|
||||
</span>,
|
||||
device: sub => <span className="mx_KeyBackupPanel_deviceName">{sig.device.getDisplayName()}</span>,
|
||||
device: sub => <span className="mx_KeyBackupPanel_deviceName">{deviceName}</span>,
|
||||
};
|
||||
let sigStatus;
|
||||
if (sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) {
|
||||
|
@ -174,7 +175,7 @@ export default class KeyBackupPanel extends React.Component {
|
|||
} else if (sig.valid && sig.device.isVerified()) {
|
||||
sigStatus = _t(
|
||||
"Backup has a <validity>valid</validity> signature from " +
|
||||
"<verify>verified</verify> device <device>x</device>",
|
||||
"<verify>verified</verify> device <device></device>",
|
||||
{}, sigStatusSubstitutions,
|
||||
);
|
||||
} else if (sig.valid && !sig.device.isVerified()) {
|
||||
|
|
|
@ -351,7 +351,7 @@
|
|||
"This device is uploading keys to this backup": "This device is uploading keys to this backup",
|
||||
"This device is <b>not</b> uploading keys to this backup": "This device is <b>not</b> uploading keys to this backup",
|
||||
"Backup has a <validity>valid</validity> signature from this device": "Backup has a <validity>valid</validity> signature from this device",
|
||||
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device>x</device>": "Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device>x</device>",
|
||||
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>verified</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>unverified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>unverified</verify> device <device></device>",
|
||||
|
@ -1401,6 +1401,12 @@
|
|||
"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.",
|
||||
"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.",
|
||||
"New Recovery Method": "New Recovery Method",
|
||||
"A new recovery passphrase and key for Secure Messages has been detected.": "A new recovery passphrase and key for Secure Messages has been detected.",
|
||||
"Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.": "Setting up Secure Messages on this device will re-encrypt this device's message history with the new recovery method.",
|
||||
"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.",
|
||||
"Set up Secure Messages": "Set up Secure Messages",
|
||||
"Go to Settings": "Go to Settings",
|
||||
"Failed to set direct chat tag": "Failed to set direct chat tag",
|
||||
"Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room",
|
||||
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room"
|
||||
|
|
Loading…
Reference in New Issue