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:
parent
aae68f7d1a
commit
bbe2084f66
6 changed files with 90 additions and 45 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
|
||||||
{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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>",
|
||||||
|
|
Loading…
Reference in a new issue