Delegate to new ResetIdentityDialog from SetupEncryptionBody (#29701)
This commit is contained in:
@@ -78,9 +78,6 @@ export default class CompleteSecurity extends React.Component<IProps, IState> {
|
||||
} else if (phase === Phase.Busy) {
|
||||
icon = <span className="mx_CompleteSecurity_headerIcon mx_E2EIcon_warning" />;
|
||||
title = _t("encryption|verification|after_new_login|verify_this_device");
|
||||
} else if (phase === Phase.ConfirmReset) {
|
||||
icon = <span className="mx_CompleteSecurity_headerIcon mx_E2EIcon_warning" />;
|
||||
title = _t("encryption|verification|after_new_login|reset_confirmation");
|
||||
} else if (phase === Phase.Finished) {
|
||||
// SetupEncryptionBody will take care of calling onFinished, we don't need to do anything
|
||||
} else {
|
||||
@@ -90,7 +87,7 @@ export default class CompleteSecurity extends React.Component<IProps, IState> {
|
||||
const forceVerification = SdkConfig.get("force_verification");
|
||||
|
||||
let skipButton;
|
||||
if (!forceVerification && (phase === Phase.Intro || phase === Phase.ConfirmReset)) {
|
||||
if (!forceVerification && phase === Phase.Intro) {
|
||||
skipButton = (
|
||||
<AccessibleButton
|
||||
onClick={this.onSkipClick}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2024, 2025 New Vector Ltd.
|
||||
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
@@ -19,6 +19,7 @@ import { SetupEncryptionStore, Phase } from "../../../stores/SetupEncryptionStor
|
||||
import EncryptionPanel from "../../views/right_panel/EncryptionPanel";
|
||||
import AccessibleButton, { type ButtonEvent } from "../../views/elements/AccessibleButton";
|
||||
import Spinner from "../../views/elements/Spinner";
|
||||
import { ResetIdentityDialog } from "../../views/dialogs/ResetIdentityDialog";
|
||||
|
||||
function keyHasPassphrase(keyInfo: SecretStorageKeyDescription): boolean {
|
||||
return Boolean(keyInfo.passphrase && keyInfo.passphrase.salt && keyInfo.passphrase.iterations);
|
||||
@@ -112,19 +113,15 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||
|
||||
private onResetClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
const store = SetupEncryptionStore.sharedInstance();
|
||||
store.reset();
|
||||
};
|
||||
|
||||
private onResetConfirmClick = (): void => {
|
||||
this.props.onFinished();
|
||||
const store = SetupEncryptionStore.sharedInstance();
|
||||
store.resetConfirm();
|
||||
};
|
||||
|
||||
private onResetBackClick = (): void => {
|
||||
const store = SetupEncryptionStore.sharedInstance();
|
||||
store.returnAfterReset();
|
||||
Modal.createDialog(ResetIdentityDialog, {
|
||||
onReset: () => {
|
||||
// The user completed the reset process - close this dialog
|
||||
this.props.onFinished();
|
||||
const store = SetupEncryptionStore.sharedInstance();
|
||||
store.done();
|
||||
},
|
||||
variant: "confirm",
|
||||
});
|
||||
};
|
||||
|
||||
private onDoneClick = (): void => {
|
||||
@@ -157,7 +154,7 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||
<p>{_t("encryption|verification|no_key_or_device")}</p>
|
||||
|
||||
<div className="mx_CompleteSecurity_actionRow">
|
||||
<AccessibleButton kind="primary" onClick={this.onResetConfirmClick}>
|
||||
<AccessibleButton kind="primary" onClick={this.onResetClick}>
|
||||
{_t("encryption|verification|reset_proceed_prompt")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
@@ -246,22 +243,6 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (phase === Phase.ConfirmReset) {
|
||||
return (
|
||||
<div>
|
||||
<p>{_t("encryption|verification|verify_reset_warning_1")}</p>
|
||||
<p>{_t("encryption|verification|verify_reset_warning_2")}</p>
|
||||
|
||||
<div className="mx_CompleteSecurity_actionRow">
|
||||
<AccessibleButton kind="danger_outline" onClick={this.onResetConfirmClick}>
|
||||
{_t("encryption|verification|reset_proceed_prompt")}
|
||||
</AccessibleButton>
|
||||
<AccessibleButton kind="primary" onClick={this.onResetBackClick}>
|
||||
{_t("action|go_back")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (phase === Phase.Busy || phase === Phase.Loading) {
|
||||
return <Spinner />;
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { type JSX } from "react";
|
||||
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { ResetIdentityBody, type ResetIdentityBodyVariant } from "../settings/encryption/ResetIdentityBody";
|
||||
|
||||
interface ResetIdentityDialogProps {
|
||||
/**
|
||||
* Called when the dialog is complete.
|
||||
*
|
||||
* `ResetIdentityDialog` expects this to be provided by `Modal.createDialog`, and that it will close the dialog.
|
||||
*/
|
||||
onFinished: () => void;
|
||||
|
||||
/**
|
||||
* Called when the identity is reset (before onFinished is called).
|
||||
*/
|
||||
onReset: () => void;
|
||||
|
||||
/**
|
||||
* Which variant of this dialog to show.
|
||||
*/
|
||||
variant: ResetIdentityBodyVariant;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dialog for resetting the identity of the current user.
|
||||
*/
|
||||
export function ResetIdentityDialog({ onFinished, onReset, variant }: ResetIdentityDialogProps): JSX.Element {
|
||||
const matrixClient = MatrixClientPeg.safeGet();
|
||||
|
||||
const onResetWrapper: () => void = () => {
|
||||
onReset();
|
||||
// Close the dialog
|
||||
onFinished();
|
||||
};
|
||||
return (
|
||||
<MatrixClientContext.Provider value={matrixClient}>
|
||||
<ResetIdentityBody onReset={onResetWrapper} onCancelClick={onFinished} variant={variant} />
|
||||
</MatrixClientContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import { Button, InlineSpinner, VisualList, VisualListItem } from "@vector-im/co
|
||||
import CheckIcon from "@vector-im/compound-design-tokens/assets/web/icons/check";
|
||||
import InfoIcon from "@vector-im/compound-design-tokens/assets/web/icons/info";
|
||||
import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error-solid";
|
||||
import React, { type JSX, useState, type MouseEventHandler } from "react";
|
||||
import React, { type JSX, useState } from "react";
|
||||
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import { EncryptionCard } from "./EncryptionCard";
|
||||
@@ -22,7 +22,8 @@ interface ResetIdentityBodyProps {
|
||||
/**
|
||||
* Called when the identity is reset.
|
||||
*/
|
||||
onFinish: MouseEventHandler<HTMLButtonElement>;
|
||||
onReset: () => void;
|
||||
|
||||
/**
|
||||
* Called when the cancel button is clicked.
|
||||
*/
|
||||
@@ -36,22 +37,26 @@ interface ResetIdentityBodyProps {
|
||||
}
|
||||
|
||||
/**
|
||||
* "compromised" is shown when the user chooses 'reset' explicitly in settings, usually because they believe their
|
||||
* identity has been compromised.
|
||||
* The variant of the panel to show. This affects the message displayed to the user.
|
||||
*
|
||||
* "compromised" is shown when the user chose 'Reset cryptographic identity' explicitly in settings, usually because
|
||||
* they believe their identity has been compromised.
|
||||
*
|
||||
* "sync_failed" is shown when the user tried to recover their identity but the process failed, probably because
|
||||
* the required information is missing from recovery.
|
||||
*
|
||||
* "forgot" is shown when the user has just forgotten their passphrase.
|
||||
* "forgot" is shown when the user chose 'Forgot recovery key?' during `SetupEncryptionToast`.
|
||||
*
|
||||
* "confirm" is shown when the user chose 'Reset all' during `SetupEncryptionBody`.
|
||||
*/
|
||||
export type ResetIdentityBodyVariant = "compromised" | "forgot" | "sync_failed";
|
||||
export type ResetIdentityBodyVariant = "compromised" | "forgot" | "sync_failed" | "confirm";
|
||||
|
||||
/**
|
||||
* User interface component allowing the user to reset their cryptographic identity.
|
||||
*
|
||||
* Used by {@link ResetIdentityPanel}.
|
||||
*/
|
||||
export function ResetIdentityBody({ onCancelClick, onFinish, variant }: ResetIdentityBodyProps): JSX.Element {
|
||||
export function ResetIdentityBody({ onCancelClick, onReset, variant }: ResetIdentityBodyProps): JSX.Element {
|
||||
const matrixClient = useMatrixClientContext();
|
||||
|
||||
// After the user clicks "Continue", we disable the button so it can't be
|
||||
@@ -78,12 +83,12 @@ export function ResetIdentityBody({ onCancelClick, onFinish, variant }: ResetIde
|
||||
<Button
|
||||
destructive={true}
|
||||
disabled={inProgress}
|
||||
onClick={async (evt) => {
|
||||
onClick={async () => {
|
||||
setInProgress(true);
|
||||
await matrixClient
|
||||
.getCrypto()
|
||||
?.resetEncryption((makeRequest) => uiAuthCallback(matrixClient, makeRequest));
|
||||
onFinish(evt);
|
||||
onReset();
|
||||
}}
|
||||
>
|
||||
{inProgress ? (
|
||||
@@ -113,11 +118,10 @@ export function ResetIdentityBody({ onCancelClick, onFinish, variant }: ResetIde
|
||||
function titleForVariant(variant: ResetIdentityBodyVariant): string {
|
||||
switch (variant) {
|
||||
case "compromised":
|
||||
case "confirm":
|
||||
return _t("settings|encryption|advanced|breadcrumb_title");
|
||||
case "sync_failed":
|
||||
return _t("settings|encryption|advanced|breadcrumb_title_sync_failed");
|
||||
|
||||
default:
|
||||
case "forgot":
|
||||
return _t("settings|encryption|advanced|breadcrumb_title_forgot");
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
import { Breadcrumb } from "@vector-im/compound-web";
|
||||
import React, { type JSX, type MouseEventHandler } from "react";
|
||||
import React, { type JSX } from "react";
|
||||
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import { ResetIdentityBody, type ResetIdentityBodyVariant } from "./ResetIdentityBody";
|
||||
@@ -15,7 +15,8 @@ interface ResetIdentityPanelProps {
|
||||
/**
|
||||
* Called when the identity is reset.
|
||||
*/
|
||||
onFinish: MouseEventHandler<HTMLButtonElement>;
|
||||
onReset: () => void;
|
||||
|
||||
/**
|
||||
* Called when the cancel button is clicked or when we go back in the breadcrumbs.
|
||||
*/
|
||||
@@ -32,7 +33,7 @@ interface ResetIdentityPanelProps {
|
||||
*
|
||||
* A thin wrapper around {@link ResetIdentityBody}, just adding breadcrumbs.
|
||||
*/
|
||||
export function ResetIdentityPanel({ onCancelClick, onFinish, variant }: ResetIdentityPanelProps): JSX.Element {
|
||||
export function ResetIdentityPanel({ onCancelClick, onReset, variant }: ResetIdentityPanelProps): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<Breadcrumb
|
||||
@@ -41,7 +42,7 @@ export function ResetIdentityPanel({ onCancelClick, onFinish, variant }: ResetId
|
||||
pages={[_t("settings|encryption|title"), _t("settings|encryption|advanced|breadcrumb_page")]}
|
||||
onPageClick={onCancelClick}
|
||||
/>
|
||||
<ResetIdentityBody onFinish={onFinish} onCancelClick={onCancelClick} variant={variant} />
|
||||
<ResetIdentityBody onReset={onReset} onCancelClick={onCancelClick} variant={variant} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ export function EncryptionUserSettingsTab({ initialState = "loading" }: Props):
|
||||
<ResetIdentityPanel
|
||||
variant={findResetVariant(state)}
|
||||
onCancelClick={checkEncryptionState}
|
||||
onFinish={checkEncryptionState}
|
||||
onReset={checkEncryptionState}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user