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.)
This commit is contained in:
J. Ryan Stinnett 2020-09-08 18:01:56 +01:00
parent aae68f7d1a
commit bbe2084f66
6 changed files with 90 additions and 45 deletions

View file

@ -34,6 +34,10 @@ limitations under the License.
.mx_SecureBackupPanel_buttonRow { .mx_SecureBackupPanel_buttonRow {
margin: 1em 0; margin: 1em 0;
:nth-child(n + 1) {
margin-inline-end: 10px;
}
} }
.mx_SecureBackupPanel_statusList { .mx_SecureBackupPanel_statusList {

View file

@ -250,7 +250,7 @@ export async function accessSecretStorage(func = async () => { }, forceReset = f
'Cross-signing keys dialog', '', InteractiveAuthDialog, 'Cross-signing keys dialog', '', InteractiveAuthDialog,
{ {
title: _t("Setting up keys"), title: _t("Setting up keys"),
matrixClient: MatrixClientPeg.get(), matrixClient: cli,
makeRequest, makeRequest,
}, },
); );

View file

@ -280,6 +280,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
const { forceReset } = this.props; const { forceReset } = this.props;
try { 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) { if (forceReset) {
console.log("Forcing cross-signing and secret storage reset"); console.log("Forcing cross-signing and secret storage reset");
await cli.bootstrapSecretStorage({ await cli.bootstrapSecretStorage({

View file

@ -19,9 +19,9 @@ import React from 'react';
import {MatrixClientPeg} from '../../../MatrixClientPeg'; import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import * as sdk from '../../../index'; import * as sdk from '../../../index';
import { accessSecretStorage } from '../../../SecurityManager';
import Modal from '../../../Modal'; import Modal from '../../../Modal';
import Spinner from '../elements/Spinner'; import Spinner from '../elements/Spinner';
import InteractiveAuthDialog from '../dialogs/InteractiveAuthDialog';
export default class CrossSigningPanel extends React.PureComponent { export default class CrossSigningPanel extends React.PureComponent {
constructor(props) { constructor(props) {
@ -66,7 +66,7 @@ export default class CrossSigningPanel extends React.PureComponent {
}; };
_onBootstrapClick = () => { _onBootstrapClick = () => {
this._bootstrapSecureSecretStorage(false); this._bootstrapCrossSigning({ forceReset: false });
}; };
onStatusChanged = () => { onStatusChanged = () => {
@ -99,35 +99,50 @@ export default class CrossSigningPanel extends React.PureComponent {
} }
/** /**
* Bootstrapping secret storage may take one of these paths: * Bootstrapping cross-signing take one of these paths:
* 1. Create secret storage from a passphrase and store cross-signing keys * 1. Create cross-signing keys locally and store in secret storage (if it
* in secret storage. * already exists on the account).
* 2. Access existing secret storage by requesting passphrase and accessing * 2. Access existing secret storage by requesting passphrase and accessing
* cross-signing keys as needed. * cross-signing keys as needed.
* 3. All keys are loaded and there's nothing to do. * 3. All keys are loaded and there's nothing to do.
* @param {bool} [forceReset] Bootstrap again even if keys already present * @param {bool} [forceReset] Bootstrap again even if keys already present
*/ */
_bootstrapSecureSecretStorage = async (forceReset=false) => { _bootstrapCrossSigning = async ({ forceReset = false }) => {
this.setState({ error: null }); this.setState({ error: null });
try { 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) { } catch (e) {
this.setState({ error: e }); this.setState({ error: e });
console.error("Error bootstrapping secret storage", e); console.error("Error bootstrapping cross-signing", e);
} }
if (this._unmounted) return; if (this._unmounted) return;
this._getUpdatedStatus(); this._getUpdatedStatus();
} }
onDestroyStorage = (act) => { _resetCrossSigning = () => {
if (!act) return;
this._bootstrapSecureSecretStorage(true);
}
_destroySecureSecretStorage = () => {
const ConfirmDestroyCrossSigningDialog = sdk.getComponent("dialogs.ConfirmDestroyCrossSigningDialog"); const ConfirmDestroyCrossSigningDialog = sdk.getComponent("dialogs.ConfirmDestroyCrossSigningDialog");
Modal.createDialog(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) { if (keysExistAnywhere) {
resetButton = ( resetButton = (
<div className="mx_CrossSigningPanel_buttonRow"> <div className="mx_CrossSigningPanel_buttonRow">
<AccessibleButton kind="danger" onClick={this._destroySecureSecretStorage}> <AccessibleButton kind="danger" onClick={this._resetCrossSigning}>
{_t("Reset cross-signing and secret storage")} {_t("Reset")}
</AccessibleButton> </AccessibleButton>
</div> </div>
); );
@ -197,7 +212,7 @@ export default class CrossSigningPanel extends React.PureComponent {
bootstrapButton = ( bootstrapButton = (
<div className="mx_CrossSigningPanel_buttonRow"> <div className="mx_CrossSigningPanel_buttonRow">
<AccessibleButton kind="primary" onClick={this._onBootstrapClick}> <AccessibleButton kind="primary" onClick={this._onBootstrapClick}>
{_t("Bootstrap cross-signing and secret storage")} {_t("Set up")}
</AccessibleButton> </AccessibleButton>
</div> </div>
); );

View file

@ -25,6 +25,7 @@ import Spinner from '../elements/Spinner';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import QuestionDialog from '../dialogs/QuestionDialog'; import QuestionDialog from '../dialogs/QuestionDialog';
import RestoreKeyBackupDialog from '../dialogs/keybackup/RestoreKeyBackupDialog'; import RestoreKeyBackupDialog from '../dialogs/keybackup/RestoreKeyBackupDialog';
import { accessSecretStorage } from '../../../SecurityManager';
export default class SecureBackupPanel extends React.PureComponent { export default class SecureBackupPanel extends React.PureComponent {
constructor(props) { 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() { render() {
const { const {
loading, loading,
@ -201,7 +215,7 @@ export default class SecureBackupPanel extends React.PureComponent {
let statusDescription; let statusDescription;
let extraDetailsTableRows; let extraDetailsTableRows;
let extraDetails; let extraDetails;
let actions; let actions = [];
if (error) { if (error) {
statusDescription = ( statusDescription = (
<div className="error"> <div className="error">
@ -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"); trustedLocally = _t("This backup is trusted because it has been restored on this session");
} }
let deleteBackupButton;
if (!isSecureBackupRequired()) {
deleteBackupButton = <AccessibleButton kind="danger" onClick={this._deleteBackup}>
{_t("Delete Backup")}
</AccessibleButton>;
}
extraDetailsTableRows = <> extraDetailsTableRows = <>
<tr> <tr>
<td>{_t("Backup version:")}</td> <td>{_t("Backup version:")}</td>
@ -359,14 +366,19 @@ export default class SecureBackupPanel extends React.PureComponent {
<div>{trustedLocally}</div> <div>{trustedLocally}</div>
</>; </>;
actions = ( actions.push(
<div className="mx_SecureBackupPanel_buttonRow"> <AccessibleButton kind="primary" onClick={this._restoreBackup}>
<AccessibleButton kind="primary" onClick={this._restoreBackup}> {restoreButtonCaption}
{restoreButtonCaption} </AccessibleButton>,
</AccessibleButton>&nbsp;&nbsp;&nbsp;
{deleteBackupButton}
</div>
); );
if (!isSecureBackupRequired()) {
actions.push(
<AccessibleButton kind="danger" onClick={this._deleteBackup}>
{_t("Delete Backup")}
</AccessibleButton>,
);
}
} else { } else {
statusDescription = <> statusDescription = <>
<p>{_t( <p>{_t(
@ -375,12 +387,18 @@ export default class SecureBackupPanel extends React.PureComponent {
)}</p> )}</p>
<p>{_t("Back up your keys before signing out to avoid losing them.")}</p> <p>{_t("Back up your keys before signing out to avoid losing them.")}</p>
</>; </>;
actions = ( actions.push(
<div className="mx_SecureBackupPanel_buttonRow"> <AccessibleButton kind="primary" onClick={this._startNewBackup}>
<AccessibleButton kind="primary" onClick={this._startNewBackup}> {_t("Set up")}
{_t("Start using Key Backup")} </AccessibleButton>,
</AccessibleButton> );
</div> }
if (secretStorageKeyInAccount) {
actions.push(
<AccessibleButton kind="danger" onClick={this._resetSecretStorage}>
{_t("Reset")}
</AccessibleButton>,
); );
} }
@ -394,6 +412,13 @@ export default class SecureBackupPanel extends React.PureComponent {
} }
} }
let actionRow;
if (actions.length) {
actionRow = <div className="mx_SecureBackupPanel_buttonRow">
{actions}
</div>;
}
return ( return (
<div> <div>
<p>{_t( <p>{_t(
@ -430,7 +455,7 @@ export default class SecureBackupPanel extends React.PureComponent {
</tbody></table> </tbody></table>
{extraDetails} {extraDetails}
</details> </details>
{actions} {actionRow}
</div> </div>
); );
} }

View file

@ -648,8 +648,7 @@
"Cross-signing is ready for use.": "Cross-signing is ready for use.", "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.", "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.", "Cross-signing is not set up.": "Cross-signing is not set up.",
"Reset cross-signing and secret storage": "Reset cross-signing and secret storage", "Reset": "Reset",
"Bootstrap cross-signing and secret storage": "Bootstrap cross-signing and secret storage",
"Cross-signing public keys:": "Cross-signing public keys:", "Cross-signing public keys:": "Cross-signing public keys:",
"in memory": "in memory", "in memory": "in memory",
"not found": "not found", "not found": "not found",
@ -748,7 +747,6 @@
"Algorithm:": "Algorithm:", "Algorithm:": "Algorithm:",
"Your keys are <b>not being backed up from this session</b>.": "Your keys are <b>not being backed up from this session</b>.", "Your keys are <b>not being backed up from this session</b>.": "Your keys are <b>not being backed up from this session</b>.",
"Back up your keys before signing out to avoid losing them.": "Back up your keys before signing out to avoid losing them.", "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", "well formed": "well formed",
"unexpected type": "unexpected type", "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.", "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", "Uploaded sound": "Uploaded sound",
"Sounds": "Sounds", "Sounds": "Sounds",
"Notification sound": "Notification sound", "Notification sound": "Notification sound",
"Reset": "Reset",
"Set a new custom sound": "Set a new custom sound", "Set a new custom sound": "Set a new custom sound",
"Browse": "Browse", "Browse": "Browse",
"Change room avatar": "Change room avatar", "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.", "%(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.", "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 <issueLink>submit a bug report</issueLink>.": "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please <issueLink>submit a bug report</issueLink>.", "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please <issueLink>submit a bug report</issueLink>.": "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please <issueLink>submit a bug report</issueLink>.",
"Start using Key Backup": "Start using Key Backup",
"Never lose encrypted messages": "Never lose encrypted messages", "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.", "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. <a>Learn more.</a>": "Securely back up your keys to avoid losing them. <a>Learn more.</a>", "Securely back up your keys to avoid losing them. <a>Learn more.</a>": "Securely back up your keys to avoid losing them. <a>Learn more.</a>",