diff --git a/res/css/_components.scss b/res/css/_components.scss
index e8a8877d62..6ce8d6efa9 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -109,6 +109,7 @@
@import "./views/rooms/_TopUnreadMessagesBar.scss";
@import "./views/settings/_DevicesPanel.scss";
@import "./views/settings/_IntegrationsManager.scss";
+@import "./views/settings/_KeyBackupPanel.scss";
@import "./views/settings/_Notifications.scss";
@import "./views/voip/_CallView.scss";
@import "./views/voip/_IncomingCallbox.scss";
diff --git a/res/css/views/settings/_KeyBackupPanel.scss b/res/css/views/settings/_KeyBackupPanel.scss
new file mode 100644
index 0000000000..1bcc0ab10d
--- /dev/null
+++ b/res/css/views/settings/_KeyBackupPanel.scss
@@ -0,0 +1,32 @@
+/*
+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_KeyBackupPanel_sigValid, .mx_KeyBackupPanel_sigInvalid,
+.mx_KeyBackupPanel_deviceVerified, .mx_KeyBackupPanel_deviceNotVerified {
+ font-weight: bold;
+}
+
+.mx_KeyBackupPanel_sigValid, .mx_KeyBackupPanel_deviceVerified {
+ color: $e2e-verified-color;
+}
+
+.mx_KeyBackupPanel_sigInvalid, .mx_KeyBackupPanel_deviceNotVerified {
+ color: $e2e-warning-color;
+}
+
+.mx_KeyBackupPanel_deviceName {
+ font-style: italic;
+}
diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js
index 3b452e77f8..1794b94792 100644
--- a/src/components/views/settings/KeyBackupPanel.js
+++ b/src/components/views/settings/KeyBackupPanel.js
@@ -28,6 +28,8 @@ export default class KeyBackupPanel extends React.Component {
this._startNewBackup = this._startNewBackup.bind(this);
this._deleteBackup = this._deleteBackup.bind(this);
+ this._verifyDevice = this._verifyDevice.bind(this);
+ this._onKeyBackupStatus = this._onKeyBackupStatus.bind(this);
this._unmounted = false;
this.state = {
@@ -35,20 +37,33 @@ export default class KeyBackupPanel extends React.Component {
error: null,
backupInfo: null,
};
+ }
+
+ componentWillMount() {
this._loadBackupStatus();
+
+ MatrixClientPeg.get().on('keyBackupStatus', this._onKeyBackupStatus);
}
componentWillUnmount() {
this._unmounted = true;
+
+ MatrixClientPeg.get().removeListener('keyBackupStatus', this._onKeyBackupStatus);
+ }
+
+ _onKeyBackupStatus() {
+ this._loadBackupStatus();
}
async _loadBackupStatus() {
this.setState({loading: true});
try {
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion();
+ const backupSigStatus = await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo);
if (this._unmounted) return;
this.setState({
backupInfo,
+ backupSigStatus,
loading: false,
});
} catch (e) {
@@ -92,6 +107,19 @@ export default class KeyBackupPanel extends React.Component {
}
+ _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() {
const Spinner = sdk.getComponent("elements.Spinner");
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
@@ -112,10 +140,47 @@ export default class KeyBackupPanel extends React.Component {
// XXX: display why and how to fix it
clientBackupStatus = _t("This device is not uploading keys to this backup", {}, {b: x => {x}});
}
+
+ let backupSigStatuses = this.state.backupSigStatus.sigs.map((sig, i) => {
+ const sigStatSub = {
+ validity: sub => {sub},
+ verify: sub => {sub},
+ device: sub => {sig.device.getDisplayName()},
+ };
+ let sigStat;
+ if (sig.valid && sig.device.isVerified()) {
+ sigStat = _t("Backup has a