From bbe2084f66b4102934db263cb2767ef3443ba11a Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 8 Sep 2020 18:01:56 +0100 Subject: [PATCH] Add independent set up / reset actions in Settings This adds set up and reset actions to each of cross-signing and secure backup that do separate things, rather than mixing concerns together. (It's temporarily still a bit of lie for backup, as more changes are needed to stop resetting cross-signing as well.) --- .../views/settings/_SecureBackupPanel.scss | 4 ++ src/SecurityManager.js | 2 +- .../CreateSecretStorageDialog.js | 3 + .../views/settings/CrossSigningPanel.js | 51 +++++++++----- .../views/settings/SecureBackupPanel.js | 69 +++++++++++++------ src/i18n/strings/en_EN.json | 6 +- 6 files changed, 90 insertions(+), 45 deletions(-) diff --git a/res/css/views/settings/_SecureBackupPanel.scss b/res/css/views/settings/_SecureBackupPanel.scss index 587cab8f36..a9dab06b57 100644 --- a/res/css/views/settings/_SecureBackupPanel.scss +++ b/res/css/views/settings/_SecureBackupPanel.scss @@ -34,6 +34,10 @@ limitations under the License. .mx_SecureBackupPanel_buttonRow { margin: 1em 0; + + :nth-child(n + 1) { + margin-inline-end: 10px; + } } .mx_SecureBackupPanel_statusList { diff --git a/src/SecurityManager.js b/src/SecurityManager.js index 891f43b705..cc7db3ead7 100644 --- a/src/SecurityManager.js +++ b/src/SecurityManager.js @@ -250,7 +250,7 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f 'Cross-signing keys dialog', '', InteractiveAuthDialog, { title: _t("Setting up keys"), - matrixClient: MatrixClientPeg.get(), + matrixClient: cli, makeRequest, }, ); diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js index 07ff3c9b76..d4b1a73c3e 100644 --- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js +++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js @@ -280,6 +280,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent { const { forceReset } = this.props; try { + // JRS: In an upcoming change, the cross-signing steps will be + // removed from here and this will instead be about secret storage + // only. if (forceReset) { console.log("Forcing cross-signing and secret storage reset"); await cli.bootstrapSecretStorage({ diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js index 8ef68e4b2a..a0ca84645f 100644 --- a/src/components/views/settings/CrossSigningPanel.js +++ b/src/components/views/settings/CrossSigningPanel.js @@ -19,9 +19,9 @@ import React from 'react'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; -import { accessSecretStorage } from '../../../SecurityManager'; import Modal from '../../../Modal'; import Spinner from '../elements/Spinner'; +import InteractiveAuthDialog from '../dialogs/InteractiveAuthDialog'; export default class CrossSigningPanel extends React.PureComponent { constructor(props) { @@ -66,7 +66,7 @@ export default class CrossSigningPanel extends React.PureComponent { }; _onBootstrapClick = () => { - this._bootstrapSecureSecretStorage(false); + this._bootstrapCrossSigning({ forceReset: false }); }; onStatusChanged = () => { @@ -99,35 +99,50 @@ export default class CrossSigningPanel extends React.PureComponent { } /** - * Bootstrapping secret storage may take one of these paths: - * 1. Create secret storage from a passphrase and store cross-signing keys - * in secret storage. + * Bootstrapping cross-signing take one of these paths: + * 1. Create cross-signing keys locally and store in secret storage (if it + * already exists on the account). * 2. Access existing secret storage by requesting passphrase and accessing * cross-signing keys as needed. * 3. All keys are loaded and there's nothing to do. * @param {bool} [forceReset] Bootstrap again even if keys already present */ - _bootstrapSecureSecretStorage = async (forceReset=false) => { + _bootstrapCrossSigning = async ({ forceReset = false }) => { this.setState({ error: null }); try { - await accessSecretStorage(() => undefined, forceReset); + const cli = MatrixClientPeg.get(); + await cli.bootstrapCrossSigning({ + authUploadDeviceSigningKeys: async (makeRequest) => { + const { finished } = Modal.createTrackedDialog( + 'Cross-signing keys dialog', '', InteractiveAuthDialog, + { + title: _t("Setting up keys"), + matrixClient: cli, + makeRequest, + }, + ); + const [confirmed] = await finished; + if (!confirmed) { + throw new Error("Cross-signing key upload auth canceled"); + } + }, + setupNewCrossSigning: forceReset, + }); } catch (e) { this.setState({ error: e }); - console.error("Error bootstrapping secret storage", e); + console.error("Error bootstrapping cross-signing", e); } if (this._unmounted) return; this._getUpdatedStatus(); } - onDestroyStorage = (act) => { - if (!act) return; - this._bootstrapSecureSecretStorage(true); - } - - _destroySecureSecretStorage = () => { + _resetCrossSigning = () => { const ConfirmDestroyCrossSigningDialog = sdk.getComponent("dialogs.ConfirmDestroyCrossSigningDialog"); Modal.createDialog(ConfirmDestroyCrossSigningDialog, { - onFinished: this.onDestroyStorage, + onFinished: (act) => { + if (!act) return; + this._bootstrapCrossSigning({ forceReset: true }); + }, }); } @@ -184,8 +199,8 @@ export default class CrossSigningPanel extends React.PureComponent { if (keysExistAnywhere) { resetButton = (
- - {_t("Reset cross-signing and secret storage")} + + {_t("Reset")}
); @@ -197,7 +212,7 @@ export default class CrossSigningPanel extends React.PureComponent { bootstrapButton = (
- {_t("Bootstrap cross-signing and secret storage")} + {_t("Set up")}
); diff --git a/src/components/views/settings/SecureBackupPanel.js b/src/components/views/settings/SecureBackupPanel.js index 0f43770288..7d4cfc2c10 100644 --- a/src/components/views/settings/SecureBackupPanel.js +++ b/src/components/views/settings/SecureBackupPanel.js @@ -25,6 +25,7 @@ import Spinner from '../elements/Spinner'; import AccessibleButton from '../elements/AccessibleButton'; import QuestionDialog from '../dialogs/QuestionDialog'; import RestoreKeyBackupDialog from '../dialogs/keybackup/RestoreKeyBackupDialog'; +import { accessSecretStorage } from '../../../SecurityManager'; export default class SecureBackupPanel extends React.PureComponent { constructor(props) { @@ -184,6 +185,19 @@ export default class SecureBackupPanel extends React.PureComponent { ); } + _resetSecretStorage = async () => { + this.setState({ error: null }); + try { + await accessSecretStorage(() => { }, /* forceReset = */ true); + } catch (e) { + console.error("Error resetting secret storage", e); + if (this._unmounted) return; + this.setState({ error: e }); + } + if (this._unmounted) return; + this._loadBackupStatus(); + } + render() { const { loading, @@ -201,7 +215,7 @@ export default class SecureBackupPanel extends React.PureComponent { let statusDescription; let extraDetailsTableRows; let extraDetails; - let actions; + let actions = []; if (error) { statusDescription = (
@@ -335,13 +349,6 @@ export default class SecureBackupPanel extends React.PureComponent { trustedLocally = _t("This backup is trusted because it has been restored on this session"); } - let deleteBackupButton; - if (!isSecureBackupRequired()) { - deleteBackupButton = - {_t("Delete Backup")} - ; - } - extraDetailsTableRows = <> {_t("Backup version:")} @@ -359,14 +366,19 @@ export default class SecureBackupPanel extends React.PureComponent {
{trustedLocally}
; - actions = ( -
- - {restoreButtonCaption} -     - {deleteBackupButton} -
+ actions.push( + + {restoreButtonCaption} + , ); + + if (!isSecureBackupRequired()) { + actions.push( + + {_t("Delete Backup")} + , + ); + } } else { statusDescription = <>

{_t( @@ -375,12 +387,18 @@ export default class SecureBackupPanel extends React.PureComponent { )}

{_t("Back up your keys before signing out to avoid losing them.")}

; - actions = ( -
- - {_t("Start using Key Backup")} - -
+ actions.push( + + {_t("Set up")} + , + ); + } + + if (secretStorageKeyInAccount) { + actions.push( + + {_t("Reset")} + , ); } @@ -394,6 +412,13 @@ export default class SecureBackupPanel extends React.PureComponent { } } + let actionRow; + if (actions.length) { + actionRow =
+ {actions} +
; + } + return (

{_t( @@ -430,7 +455,7 @@ export default class SecureBackupPanel extends React.PureComponent { {extraDetails} - {actions} + {actionRow}

); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 1bf431f6e0..b73d2b25fe 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -648,8 +648,7 @@ "Cross-signing is ready for use.": "Cross-signing is ready for use.", "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.", "Cross-signing is not set up.": "Cross-signing is not set up.", - "Reset cross-signing and secret storage": "Reset cross-signing and secret storage", - "Bootstrap cross-signing and secret storage": "Bootstrap cross-signing and secret storage", + "Reset": "Reset", "Cross-signing public keys:": "Cross-signing public keys:", "in memory": "in memory", "not found": "not found", @@ -748,7 +747,6 @@ "Algorithm:": "Algorithm:", "Your keys are not being backed up from this session.": "Your keys are not being backed up from this session.", "Back up your keys before signing out to avoid losing them.": "Back up your keys before signing out to avoid losing them.", - "Start using Key Backup": "Start using Key Backup", "well formed": "well formed", "unexpected type": "unexpected type", "Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Recovery Key.": "Back up your encryption keys with your account data in case you lose access to your sessions. Your keys will be secured with a unique Recovery Key.", @@ -948,7 +946,6 @@ "Uploaded sound": "Uploaded sound", "Sounds": "Sounds", "Notification sound": "Notification sound", - "Reset": "Reset", "Set a new custom sound": "Set a new custom sound", "Browse": "Browse", "Change room avatar": "Change room avatar", @@ -1173,6 +1170,7 @@ "%(roomName)s is not accessible at this time.": "%(roomName)s is not accessible at this time.", "Try again later, or ask a room admin to check if you have access.": "Try again later, or ask a room admin to check if you have access.", "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please submit a bug report.": "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please submit a bug report.", + "Start using Key Backup": "Start using Key Backup", "Never lose encrypted messages": "Never lose encrypted messages", "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.", "Securely back up your keys to avoid losing them. Learn more.": "Securely back up your keys to avoid losing them. Learn more.",