From 8fdae73e030546decf346d0f23a9c956faa456e2 Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 7 Feb 2020 14:55:01 +0000 Subject: [PATCH 1/6] Button to reset cross-signing and SSSS keys --- src/CrossSigningManager.js | 11 ++-- .../CreateSecretStorageDialog.js | 10 ++- .../ConfirmDestroyCrossSigningDialog.js | 63 +++++++++++++++++++ .../views/settings/CrossSigningPanel.js | 24 ++++++- src/i18n/strings/en_EN.json | 4 ++ 5 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js diff --git a/src/CrossSigningManager.js b/src/CrossSigningManager.js index a560c956f1..08ec459f26 100644 --- a/src/CrossSigningManager.js +++ b/src/CrossSigningManager.js @@ -116,17 +116,20 @@ export const crossSigningCallbacks = { * @param {Function} [func] An operation to perform once secret storage has been * bootstrapped. Optional. */ -export async function accessSecretStorage(func = async () => { }) { +export async function accessSecretStorage(func = async () => { }, force = false) { const cli = MatrixClientPeg.get(); secretStorageBeingAccessed = true; - try { - if (!await cli.hasSecretStorageKey()) { + if (!await cli.hasSecretStorageKey() || force) { + console.warn(!force ? "!hasSecretStorageKey()" : "force"); // This dialog calls bootstrap itself after guiding the user through // passphrase creation. const { finished } = Modal.createTrackedDialogAsync('Create Secret Storage dialog', '', import("./async-components/views/dialogs/secretstorage/CreateSecretStorageDialog"), - null, null, /* priority = */ false, /* static = */ true, + { + force, + }, + null, /* priority = */ false, /* static = */ true, ); const [confirmed] = await finished; if (!confirmed) { diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js index 679b3907d1..c3574c0094 100644 --- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js +++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js @@ -55,10 +55,12 @@ export default class CreateSecretStorageDialog extends React.PureComponent { static propTypes = { hasCancel: PropTypes.bool, accountPassword: PropTypes.string, + force: PropTypes.bool, }; static defaultProps = { hasCancel: true, + force: false, }; constructor(props) { @@ -107,7 +109,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent { MatrixClientPeg.get().isCryptoEnabled() && await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo) ); - const phase = backupInfo ? PHASE_MIGRATE : PHASE_PASSPHRASE; + const { force } = this.props; + const phase = (backupInfo && !force) ? PHASE_MIGRATE : PHASE_PASSPHRASE; this.setState({ phase, @@ -219,12 +222,15 @@ export default class CreateSecretStorageDialog extends React.PureComponent { const cli = MatrixClientPeg.get(); + const { force } = this.props; + try { await cli.bootstrapSecretStorage({ + setupNewSecretStorage: force, authUploadDeviceSigningKeys: this._doBootstrapUIAuth, createSecretStorageKey: async () => this._keyInfo, keyBackupInfo: this.state.backupInfo, - setupNewKeyBackup: !this.state.backupInfo && this.state.useKeyBackup, + setupNewKeyBackup: force || !this.state.backupInfo && this.state.useKeyBackup, }); this.setState({ phase: PHASE_DONE, diff --git a/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js b/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js new file mode 100644 index 0000000000..942249e07d --- /dev/null +++ b/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js @@ -0,0 +1,63 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +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 {_t} from "../../../languageHandler"; +import * as sdk from "../../../index"; + +export default class ConfirmDestroyCrossSigningDialog extends React.Component { + static propTypes = { + onFinished: PropTypes.func.isRequired, + }; + + _onConfirm = () => { + this.props.onFinished(true); + }; + + _onDecline = () => { + this.props.onFinished(false); + }; + + render() { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + + return ( + +
+

+ {_t( + "Deleting cross-signing keys is permanent. " + + "Anyone you have verified with will see security alerts. " + + "You almost certainly don't want to do this, unless " + + "you've lost every device you can cross-sign from." + )} +

+
+ +
+ ); + } +} diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js index f99968c44f..35f617b83b 100644 --- a/src/components/views/settings/CrossSigningPanel.js +++ b/src/components/views/settings/CrossSigningPanel.js @@ -20,6 +20,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg'; import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import { accessSecretStorage } from '../../../CrossSigningManager'; +import Modal from '../../../Modal'; export default class CrossSigningPanel extends React.PureComponent { constructor(props) { @@ -87,10 +88,10 @@ export default class CrossSigningPanel extends React.PureComponent { * cross-signing keys as needed. * 3. All keys are loaded and there's nothing to do. */ - _bootstrapSecureSecretStorage = async () => { + _bootstrapSecureSecretStorage = async (force=false) => { this.setState({ error: null }); try { - await accessSecretStorage(); + await accessSecretStorage(() => undefined, force); } catch (e) { this.setState({ error: e }); console.error("Error bootstrapping secret storage", e); @@ -99,6 +100,19 @@ export default class CrossSigningPanel extends React.PureComponent { this._getUpdatedStatus(); } + onDestroyStorage = (act) => { + if (!act) return; + console.log("Destroy secret storage:", act); + this._bootstrapSecureSecretStorage(true); + } + + _destroySecureSecretStorage = () => { + const ConfirmDestoryCrossSigningDialog = sdk.getComponent("dialogs.ConfirmDestroyCrossSigningDialog"); + Modal.createDialog(ConfirmDestoryCrossSigningDialog, { + onFinished: this.onDestroyStorage + }); + } + render() { const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); const { @@ -142,6 +156,12 @@ export default class CrossSigningPanel extends React.PureComponent { {_t("Bootstrap cross-signing and secret storage")} ; + } else { + bootstrapButton =
+ + {_t("Torpedo cross-signing")} + +
; } return ( diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d125d10cfb..edb0da8780 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -553,6 +553,7 @@ "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 and secret storage are not yet set up.": "Cross-signing and secret storage are not yet set up.", "Bootstrap cross-signing and secret storage": "Bootstrap cross-signing and secret storage", + "Torpedo cross-signing": "Torpedo cross-signing", "Cross-signing public keys:": "Cross-signing public keys:", "in memory": "in memory", "not found": "not found", @@ -1430,6 +1431,9 @@ "Changelog": "Changelog", "You cannot delete this message. (%(code)s)": "You cannot delete this message. (%(code)s)", "Removing…": "Removing…", + "Destroy cross-signing keys?": "Destroy cross-signing keys?", + "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.": "Deleting cross-signing keys is permanent. Anyone you have verified with will see security alerts. You almost certainly don't want to do this, unless you've lost every device you can cross-sign from.", + "Clear cross-signing keys": "Clear cross-signing keys", "Confirm Removal": "Confirm Removal", "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.", "Clear all data in this session?": "Clear all data in this session?", From b08c5d84107b0e60b89f932c830b4767d0bc60d7 Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 7 Feb 2020 15:46:31 +0000 Subject: [PATCH 2/6] lint --- src/CrossSigningManager.js | 1 + .../views/dialogs/ConfirmDestroyCrossSigningDialog.js | 2 +- src/components/views/settings/CrossSigningPanel.js | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/CrossSigningManager.js b/src/CrossSigningManager.js index 08ec459f26..3381f3e93b 100644 --- a/src/CrossSigningManager.js +++ b/src/CrossSigningManager.js @@ -115,6 +115,7 @@ export const crossSigningCallbacks = { * * @param {Function} [func] An operation to perform once secret storage has been * bootstrapped. Optional. + * @param {bool} [force] Reset secret storage even if it's already set up */ export async function accessSecretStorage(func = async () => { }, force = false) { const cli = MatrixClientPeg.get(); diff --git a/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js b/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js index 942249e07d..3242afd5f1 100644 --- a/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js +++ b/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js @@ -46,7 +46,7 @@ export default class ConfirmDestroyCrossSigningDialog extends React.Component { "Deleting cross-signing keys is permanent. " + "Anyone you have verified with will see security alerts. " + "You almost certainly don't want to do this, unless " + - "you've lost every device you can cross-sign from." + "you've lost every device you can cross-sign from.", )}

diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js index 35f617b83b..77cae79324 100644 --- a/src/components/views/settings/CrossSigningPanel.js +++ b/src/components/views/settings/CrossSigningPanel.js @@ -87,6 +87,7 @@ export default class CrossSigningPanel extends React.PureComponent { * 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} [force] Bootstrap again even if keys already present */ _bootstrapSecureSecretStorage = async (force=false) => { this.setState({ error: null }); @@ -109,7 +110,7 @@ export default class CrossSigningPanel extends React.PureComponent { _destroySecureSecretStorage = () => { const ConfirmDestoryCrossSigningDialog = sdk.getComponent("dialogs.ConfirmDestroyCrossSigningDialog"); Modal.createDialog(ConfirmDestoryCrossSigningDialog, { - onFinished: this.onDestroyStorage + onFinished: this.onDestroyStorage, }); } From a260d7a1471d15b8af31dea56f220d457e5dfd1d Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 7 Feb 2020 15:53:43 +0000 Subject: [PATCH 3/6] manual lint --- src/CrossSigningManager.js | 1 - .../views/dialogs/ConfirmDestroyCrossSigningDialog.js | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/CrossSigningManager.js b/src/CrossSigningManager.js index 3381f3e93b..45e0a336d5 100644 --- a/src/CrossSigningManager.js +++ b/src/CrossSigningManager.js @@ -122,7 +122,6 @@ export async function accessSecretStorage(func = async () => { }, force = false) secretStorageBeingAccessed = true; try { if (!await cli.hasSecretStorageKey() || force) { - console.warn(!force ? "!hasSecretStorageKey()" : "force"); // This dialog calls bootstrap itself after guiding the user through // passphrase creation. const { finished } = Modal.createTrackedDialogAsync('Create Secret Storage dialog', '', diff --git a/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js b/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js index 3242afd5f1..9e1980e98d 100644 --- a/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js +++ b/src/components/views/dialogs/ConfirmDestroyCrossSigningDialog.js @@ -37,9 +37,11 @@ export default class ConfirmDestroyCrossSigningDialog extends React.Component { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( - +

{_t( From 69dc725006960053be0fa69cd16f303074c7035d Mon Sep 17 00:00:00 2001 From: Zoe Date: Mon, 10 Feb 2020 15:43:02 +0000 Subject: [PATCH 4/6] rename button --- src/components/views/settings/CrossSigningPanel.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js index 77cae79324..6f68193729 100644 --- a/src/components/views/settings/CrossSigningPanel.js +++ b/src/components/views/settings/CrossSigningPanel.js @@ -160,7 +160,7 @@ export default class CrossSigningPanel extends React.PureComponent { } else { bootstrapButton =

- {_t("Torpedo cross-signing")} + {_t("Reset Secret Store and Cross-signing")}
; } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index edb0da8780..1832a6123b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -553,7 +553,7 @@ "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 and secret storage are not yet set up.": "Cross-signing and secret storage are not yet set up.", "Bootstrap cross-signing and secret storage": "Bootstrap cross-signing and secret storage", - "Torpedo cross-signing": "Torpedo cross-signing", + "Reset Secret Store and Cross-signing": "Reset Secret Store and Cross-signing", "Cross-signing public keys:": "Cross-signing public keys:", "in memory": "in memory", "not found": "not found", From 4f4b52d6665ad318c2dae57e1f217587a30ca65a Mon Sep 17 00:00:00 2001 From: Zoe Date: Mon, 10 Feb 2020 16:59:17 +0000 Subject: [PATCH 5/6] Update src/components/views/settings/CrossSigningPanel.js Co-Authored-By: J. Ryan Stinnett --- src/components/views/settings/CrossSigningPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js index 6f68193729..95b9f76858 100644 --- a/src/components/views/settings/CrossSigningPanel.js +++ b/src/components/views/settings/CrossSigningPanel.js @@ -160,7 +160,7 @@ export default class CrossSigningPanel extends React.PureComponent { } else { bootstrapButton =
- {_t("Reset Secret Store and Cross-signing")} + {_t("Reset cross-signing and secret storage")}
; } From 2d425051245763b605f63b6250bc31af80757bd2 Mon Sep 17 00:00:00 2001 From: Zoe Date: Mon, 10 Feb 2020 17:00:03 +0000 Subject: [PATCH 6/6] and re-run yarn i18n --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 1832a6123b..d9bd4c3b14 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -553,7 +553,7 @@ "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 and secret storage are not yet set up.": "Cross-signing and secret storage are not yet set up.", "Bootstrap cross-signing and secret storage": "Bootstrap cross-signing and secret storage", - "Reset Secret Store and Cross-signing": "Reset Secret Store and Cross-signing", + "Reset cross-signing and secret storage": "Reset cross-signing and secret storage", "Cross-signing public keys:": "Cross-signing public keys:", "in memory": "in memory", "not found": "not found",