Allow user to control if they are signed out of all devices when changing password (#8259)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
ee2ee3c08c
commit
bb4064ff43
5 changed files with 157 additions and 76 deletions
|
@ -19,6 +19,7 @@ limitations under the License.
|
|||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { createClient } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { _t, _td } from '../../../languageHandler';
|
||||
import Modal from "../../../Modal";
|
||||
|
@ -37,6 +38,7 @@ import AuthHeader from "../../views/auth/AuthHeader";
|
|||
import AuthBody from "../../views/auth/AuthBody";
|
||||
import PassphraseConfirmField from "../../views/auth/PassphraseConfirmField";
|
||||
import AccessibleButton from '../../views/elements/AccessibleButton';
|
||||
import StyledCheckbox from '../../views/elements/StyledCheckbox';
|
||||
|
||||
enum Phase {
|
||||
// Show the forgot password inputs
|
||||
|
@ -72,6 +74,9 @@ interface IState {
|
|||
serverDeadError: string;
|
||||
|
||||
currentHttpRequest?: Promise<any>;
|
||||
|
||||
serverSupportsControlOfDevicesLogout: boolean;
|
||||
logoutDevices: boolean;
|
||||
}
|
||||
|
||||
enum ForgotPasswordField {
|
||||
|
@ -97,11 +102,14 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
|||
serverIsAlive: true,
|
||||
serverErrorIsFatal: false,
|
||||
serverDeadError: "",
|
||||
serverSupportsControlOfDevicesLogout: false,
|
||||
logoutDevices: false,
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
this.reset = null;
|
||||
this.checkServerLiveliness(this.props.serverConfig);
|
||||
this.checkServerCapabilities(this.props.serverConfig);
|
||||
}
|
||||
|
||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||
|
@ -112,6 +120,9 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
|||
|
||||
// Do a liveliness check on the new URLs
|
||||
this.checkServerLiveliness(newProps.serverConfig);
|
||||
|
||||
// Do capabilities check on new URLs
|
||||
this.checkServerCapabilities(newProps.serverConfig);
|
||||
}
|
||||
|
||||
private async checkServerLiveliness(serverConfig): Promise<void> {
|
||||
|
@ -129,12 +140,25 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
public submitPasswordReset(email: string, password: string): void {
|
||||
private async checkServerCapabilities(serverConfig: ValidatedServerConfig): Promise<void> {
|
||||
const tempClient = createClient({
|
||||
baseUrl: serverConfig.hsUrl,
|
||||
});
|
||||
|
||||
const serverSupportsControlOfDevicesLogout = await tempClient.doesServerSupportLogoutDevices();
|
||||
|
||||
this.setState({
|
||||
logoutDevices: !serverSupportsControlOfDevicesLogout,
|
||||
serverSupportsControlOfDevicesLogout,
|
||||
});
|
||||
}
|
||||
|
||||
public submitPasswordReset(email: string, password: string, logoutDevices = true): void {
|
||||
this.setState({
|
||||
phase: Phase.SendingEmail,
|
||||
});
|
||||
this.reset = new PasswordReset(this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl);
|
||||
this.reset.resetPassword(email, password).then(() => {
|
||||
this.reset.resetPassword(email, password, logoutDevices).then(() => {
|
||||
this.setState({
|
||||
phase: Phase.EmailSent,
|
||||
});
|
||||
|
@ -174,24 +198,35 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
|||
return;
|
||||
}
|
||||
|
||||
Modal.createTrackedDialog('Forgot Password Warning', '', QuestionDialog, {
|
||||
title: _t('Warning!'),
|
||||
description:
|
||||
<div>
|
||||
{ _t(
|
||||
"Changing your password will reset any end-to-end encryption keys " +
|
||||
"on all of your sessions, making encrypted chat history unreadable. Set up " +
|
||||
"Key Backup or export your room keys from another session before resetting your " +
|
||||
"password.",
|
||||
) }
|
||||
</div>,
|
||||
button: _t('Continue'),
|
||||
onFinished: (confirmed) => {
|
||||
if (confirmed) {
|
||||
this.submitPasswordReset(this.state.email, this.state.password);
|
||||
}
|
||||
},
|
||||
});
|
||||
if (this.state.logoutDevices) {
|
||||
const { finished } = Modal.createTrackedDialog<[boolean]>('Forgot Password Warning', '', QuestionDialog, {
|
||||
title: _t('Warning!'),
|
||||
description:
|
||||
<div>
|
||||
<p>{ !this.state.serverSupportsControlOfDevicesLogout ?
|
||||
_t(
|
||||
"Resetting your password on this homeserver will cause all of your devices to be " +
|
||||
"signed out. This will delete the message encryption keys stored on them, " +
|
||||
"making encrypted chat history unreadable.",
|
||||
) :
|
||||
_t(
|
||||
"Signing out your devices will delete the message encryption keys stored on them, " +
|
||||
"making encrypted chat history unreadable.",
|
||||
)
|
||||
}</p>
|
||||
<p>{ _t(
|
||||
"If you want to retain access to your chat history in encrypted rooms, set up Key Backup " +
|
||||
"or export your message keys from one of your other devices before proceeding.",
|
||||
) }</p>
|
||||
</div>,
|
||||
button: _t('Continue'),
|
||||
});
|
||||
const [confirmed] = await finished;
|
||||
|
||||
if (!confirmed) return;
|
||||
}
|
||||
|
||||
this.submitPasswordReset(this.state.email, this.state.password, this.state.logoutDevices);
|
||||
};
|
||||
|
||||
private async verifyFieldsBeforeSubmit() {
|
||||
|
@ -316,6 +351,13 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
|||
autoComplete="new-password"
|
||||
/>
|
||||
</div>
|
||||
{ this.state.serverSupportsControlOfDevicesLogout ?
|
||||
<div className="mx_AuthBody_fieldRow">
|
||||
<StyledCheckbox onChange={() => this.setState({ logoutDevices: !this.state.logoutDevices })} checked={this.state.logoutDevices}>
|
||||
{ _t("Sign out all devices") }
|
||||
</StyledCheckbox>
|
||||
</div> : null
|
||||
}
|
||||
<span>{ _t(
|
||||
'A verification email will be sent to your inbox to confirm ' +
|
||||
'setting your new password.',
|
||||
|
@ -355,11 +397,14 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
|
|||
renderDone() {
|
||||
return <div>
|
||||
<p>{ _t("Your password has been reset.") }</p>
|
||||
<p>{ _t(
|
||||
"You have been logged out of all sessions and will no longer receive " +
|
||||
"push notifications. To re-enable notifications, sign in again on each " +
|
||||
"device.",
|
||||
) }</p>
|
||||
{ this.state.logoutDevices ?
|
||||
<p>{ _t(
|
||||
"You have been logged out of all devices and will no longer receive " +
|
||||
"push notifications. To re-enable notifications, sign in again on each " +
|
||||
"device.",
|
||||
) }</p>
|
||||
: null
|
||||
}
|
||||
<input
|
||||
className="mx_Login_submit"
|
||||
type="button"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue