Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove "Upgrade your encryption" flow in CreateSecretStorageDialog #28290

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import React, { createRef } from "react";
import FileSaver from "file-saver";
import { logger } from "matrix-js-sdk/src/logger";
import { AuthDict, CrossSigningKeys, MatrixError, UIAFlow, UIAResponse } from "matrix-js-sdk/src/matrix";
import { CryptoEvent, BackupTrustInfo, GeneratedSecretStorageKey, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
import { BackupTrustInfo, GeneratedSecretStorageKey, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
import classNames from "classnames";
import CheckmarkIcon from "@vector-im/compound-design-tokens/assets/web/icons/check";

Expand All @@ -25,7 +25,6 @@ import StyledRadioButton from "../../../../components/views/elements/StyledRadio
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
import DialogButtons from "../../../../components/views/elements/DialogButtons";
import InlineSpinner from "../../../../components/views/elements/InlineSpinner";
import RestoreKeyBackupDialog from "../../../../components/views/dialogs/security/RestoreKeyBackupDialog";
import {
getSecureBackupSetupMethods,
isSecureBackupRequired,
Expand All @@ -45,7 +44,6 @@ enum Phase {
Loading = "loading",
LoadError = "load_error",
ChooseKeyPassphrase = "choose_key_passphrase",
Migrate = "migrate",
Passphrase = "passphrase",
PassphraseConfirm = "passphrase_confirm",
ShowKey = "show_key",
Expand Down Expand Up @@ -160,15 +158,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
accountPassword,
};

cli.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatusChange);

this.getInitialPhase();
}

public componentWillUnmount(): void {
MatrixClientPeg.get()?.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatusChange);
}

private getInitialPhase(): void {
const keyFromCustomisations = ModuleRunner.instance.extensions.cryptoSetup.createSecretStorageKey();
if (keyFromCustomisations) {
Expand Down Expand Up @@ -199,11 +191,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
// we may not have started crypto yet, in which case we definitely don't trust the backup
backupInfo ? await cli.getCrypto()?.isKeyBackupTrusted(backupInfo) : undefined;

const { forceReset } = this.props;
const phase = backupInfo && !forceReset ? Phase.Migrate : Phase.ChooseKeyPassphrase;

this.setState({
phase,
phase: Phase.ChooseKeyPassphrase,
backupInfo,
florianduros marked this conversation as resolved.
Show resolved Hide resolved
backupTrustInfo,
florianduros marked this conversation as resolved.
Show resolved Hide resolved
});
Expand Down Expand Up @@ -237,10 +226,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
}
}

private onKeyBackupStatusChange = (): void => {
if (this.state.phase === Phase.Migrate) this.fetchBackupInfo();
};

private onKeyPassphraseChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({
passPhraseKeySelected: e.target.value,
Expand All @@ -265,15 +250,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
}
};

private onMigrateFormSubmit = (e: React.FormEvent): void => {
e.preventDefault();
if (this.state.backupTrustInfo?.trusted) {
this.bootstrapSecretStorage();
} else {
this.restoreBackup();
}
};

private onCopyClick = (): void => {
const successful = copyNode(this.recoveryKeyNode.current);
if (successful) {
Expand Down Expand Up @@ -381,20 +357,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
phase: Phase.Stored,
});
} catch (e) {
if (
this.state.canUploadKeysWithPasswordOnly &&
e instanceof MatrixError &&
e.httpStatus === 401 &&
e.data.flows
) {
this.setState({
accountPassword: "",
accountPasswordCorrect: false,
phase: Phase.Migrate,
});
} else {
this.setState({ error: true });
}
this.setState({ error: true });
logger.error("Error bootstrapping secret storage", e);
}
};
Expand All @@ -403,24 +366,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
this.props.onFinished(false);
};

private restoreBackup = async (): Promise<void> => {
const { finished } = Modal.createDialog(
RestoreKeyBackupDialog,
{
showSummary: false,
},
undefined,
/* priority = */ false,
/* static = */ false,
);

await finished;
const backupTrustInfo = await this.fetchBackupInfo();
if (backupTrustInfo?.trusted && this.state.canUploadKeysWithPasswordOnly && this.state.accountPassword) {
this.bootstrapSecretStorage();
}
};

private onLoadRetryClick = (): void => {
this.setState({ phase: Phase.Loading });
this.fetchBackupInfo();
Expand Down Expand Up @@ -495,12 +440,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
});
};

private onAccountPasswordChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.setState({
accountPassword: e.target.value,
});
};

private renderOptionKey(): JSX.Element {
return (
<StyledRadioButton
Expand Down Expand Up @@ -565,55 +504,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
);
}

private renderPhaseMigrate(): JSX.Element {
let authPrompt;
let nextCaption = _t("action|next");
if (this.state.canUploadKeysWithPasswordOnly) {
authPrompt = (
<div>
<div>{_t("settings|key_backup|setup_secure_backup|requires_password_confirmation")}</div>
<div>
<Field
id="mx_CreateSecretStorageDialog_password"
type="password"
label={_t("common|password")}
value={this.state.accountPassword}
onChange={this.onAccountPasswordChange}
forceValidity={this.state.accountPasswordCorrect === false ? false : undefined}
autoFocus={true}
/>
</div>
</div>
);
} else if (!this.state.backupTrustInfo?.trusted) {
authPrompt = (
<div>
<div>{_t("settings|key_backup|setup_secure_backup|requires_key_restore")}</div>
</div>
);
nextCaption = _t("action|restore");
} else {
authPrompt = <p>{_t("settings|key_backup|setup_secure_backup|requires_server_authentication")}</p>;
}

return (
<form onSubmit={this.onMigrateFormSubmit}>
<p>{_t("settings|key_backup|setup_secure_backup|session_upgrade_description")}</p>
<div>{authPrompt}</div>
<DialogButtons
primaryButton={nextCaption}
onPrimaryButtonClick={this.onMigrateFormSubmit}
hasCancel={false}
primaryDisabled={!!this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
>
<button type="button" className="danger" onClick={this.onCancelClick}>
{_t("action|skip")}
</button>
</DialogButtons>
</form>
);
}

private renderPhasePassPhrase(): JSX.Element {
return (
<form onSubmit={this.onPassPhraseNextClick}>
Expand Down Expand Up @@ -829,8 +719,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
switch (phase) {
case Phase.ChooseKeyPassphrase:
return _t("encryption|set_up_toast_title");
case Phase.Migrate:
return _t("settings|key_backup|setup_secure_backup|title_upgrade_encryption");
case Phase.Passphrase:
return _t("settings|key_backup|setup_secure_backup|title_set_phrase");
case Phase.PassphraseConfirm:
Expand Down Expand Up @@ -889,9 +777,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
case Phase.ChooseKeyPassphrase:
content = this.renderPhaseChooseKeyPassphrase();
break;
case Phase.Migrate:
content = this.renderPhaseMigrate();
break;
case Phase.Passphrase:
content = this.renderPhasePassPhrase();
break;
Expand Down
6 changes: 0 additions & 6 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@
"report_content": "Report Content",
"resend": "Resend",
"reset": "Reset",
"restore": "Restore",
"resume": "Resume",
"retry": "Retry",
"review": "Review",
Expand Down Expand Up @@ -2588,18 +2587,13 @@
"pass_phrase_match_failed": "That doesn't match.",
"pass_phrase_match_success": "That matches!",
"phrase_strong_enough": "Great! This Security Phrase looks strong enough.",
"requires_key_restore": "Restore your key backup to upgrade your encryption",
"requires_password_confirmation": "Enter your account password to confirm the upgrade:",
"requires_server_authentication": "You'll need to authenticate with the server to confirm the upgrade.",
"secret_storage_query_failure": "Unable to query secret storage status",
"security_key_safety_reminder": "Store your Security Key somewhere safe, like a password manager or a safe, as it's used to safeguard your encrypted data.",
"session_upgrade_description": "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.",
"set_phrase_again": "Go back to set it again.",
"settings_reminder": "You can also set up Secure Backup & manage your keys in Settings.",
"title_confirm_phrase": "Confirm Security Phrase",
"title_save_key": "Save your Security Key",
"title_set_phrase": "Set a Security Phrase",
"title_upgrade_encryption": "Upgrade your encryption",
"unable_to_setup": "Unable to set up secret storage",
"use_different_passphrase": "Use a different passphrase?",
"use_phrase_only_you_know": "Use a secret phrase only you know, and optionally save a Security Key to use for backup."
Expand Down
5 changes: 5 additions & 0 deletions test/test-utils/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ export function createTestClient(): MatrixClient {
prepareToEncrypt: jest.fn(),
bootstrapCrossSigning: jest.fn(),
getActiveSessionBackupVersion: jest.fn().mockResolvedValue(null),
isKeyBackupTrusted: jest.fn().mockResolvedValue({}),
createRecoveryKeyFromPassphrase: jest.fn().mockResolvedValue({}),
bootstrapSecretStorage: jest.fn(),
isDehydrationSupported: jest.fn().mockResolvedValue(false),
}),

getPushActionsForEvent: jest.fn(),
Expand Down Expand Up @@ -270,6 +274,7 @@ export function createTestClient(): MatrixClient {
getOrCreateFilter: jest.fn(),
sendStickerMessage: jest.fn(),
getLocalAliases: jest.fn().mockReturnValue([]),
uploadDeviceSigningKeys: jest.fn(),
} as unknown as MatrixClient;

client.reEmitter = new ReEmitter(client);
Expand Down
Loading
Loading