Merge pull request #4041 from matrix-org/foldleft/12221-reset-cross-signing

Button to reset cross-signing and SSSS keys
This commit is contained in:
Zoe 2020-02-10 17:14:05 +00:00 committed by GitHub
commit d47d13256f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 107 additions and 8 deletions

View file

@ -148,18 +148,21 @@ 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 () => { }) {
export async function accessSecretStorage(func = async () => { }, force = false) {
const cli = MatrixClientPeg.get();
secretStorageBeingAccessed = true;
try {
if (!await cli.hasSecretStorageKey()) {
if (!await cli.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) {

View file

@ -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,

View file

@ -0,0 +1,65 @@
/*
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 (
<BaseDialog
className='mx_ConfirmDestroyCrossSigningDialog'
hasCancel={true}
onFinished={this.props.onFinished}
title={_t("Destroy cross-signing keys?")}>
<div className='mx_ConfirmDestroyCrossSigningDialog_content'>
<p>
{_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.",
)}
</p>
</div>
<DialogButtons
primaryButton={_t("Clear cross-signing keys")}
onPrimaryButtonClick={this._onConfirm}
primaryButtonClass="danger"
cancelButton={_t("Cancel")}
onCancel={this._onDecline}
/>
</BaseDialog>
);
}
}

View file

@ -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) {
@ -86,11 +87,12 @@ 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 () => {
_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 +101,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 +157,12 @@ export default class CrossSigningPanel extends React.PureComponent {
{_t("Bootstrap cross-signing and secret storage")}
</AccessibleButton>
</div>;
} else {
bootstrapButton = <div className="mx_CrossSigningPanel_buttonRow">
<AccessibleButton kind="danger" onClick={this._destroySecureSecretStorage}>
{_t("Reset cross-signing and secret storage")}
</AccessibleButton>
</div>;
}
return (

View file

@ -558,6 +558,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 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",
@ -1435,6 +1436,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?",