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

Properly translate errors in ChangePassword.tsx so they show up translated to the user but not in our logs #10615

Merged
Merged
41 changes: 27 additions & 14 deletions src/components/views/settings/ChangePassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
import AccessibleButton from "../elements/AccessibleButton";
import Spinner from "../elements/Spinner";
import withValidation, { IFieldState, IValidationResult } from "../elements/Validation";
import { _t, _td } from "../../../languageHandler";
import { UserFriendlyError, _t, _td } from "../../../languageHandler";
import Modal from "../../../Modal";
import PassphraseField from "../auth/PassphraseField";
import { PASSWORD_MIN_SCORE } from "../auth/RegistrationForm";
Expand All @@ -48,7 +48,7 @@ interface IProps {
/** Was one or more other devices logged out whilst changing the password */
didLogoutOutOtherDevices: boolean;
}) => void;
onError: (error: { error: string }) => void;
onError: (error: Error) => void;
rowClassName?: string;
buttonClassName?: string;
buttonKind?: string;
Expand Down Expand Up @@ -183,7 +183,16 @@ export default class ChangePassword extends React.Component<IProps, IState> {
}
},
(err) => {
this.props.onError(err);
if (err instanceof Error) {
this.props.onError(err);
} else {
this.props.onError(
new UserFriendlyError("Error while setting password: %(error)s", {
error: String(err),
cause: undefined,
}),
);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SonarCloud coverage not happy with these files not tested at all but it's not something I'm going to invest in now.

Will need an exception here

},
)
.finally(() => {
Expand All @@ -196,15 +205,19 @@ export default class ChangePassword extends React.Component<IProps, IState> {
});
}

private checkPassword(oldPass: string, newPass: string, confirmPass: string): { error: string } | undefined {
/**
* Checks the `newPass` and throws an error if it is unacceptable.
* @param oldPass The old password
* @param newPass The new password that the user is trying to be set
* @param confirmPass The confirmation password where the user types the `newPass`
* again for confirmation and should match the `newPass` before we accept their new
* password.
*/
private checkPassword(oldPass: string, newPass: string, confirmPass: string): void {
if (newPass !== confirmPass) {
return {
error: _t("New passwords don't match"),
};
throw new UserFriendlyError("New passwords don't match");
} else if (!newPass || newPass.length === 0) {
return {
error: _t("Passwords can't be empty"),
};
throw new UserFriendlyError("Passwords can't be empty");
}
}

Expand Down Expand Up @@ -307,11 +320,11 @@ export default class ChangePassword extends React.Component<IProps, IState> {
const oldPassword = this.state.oldPassword;
const newPassword = this.state.newPassword;
const confirmPassword = this.state.newPasswordConfirm;
const err = this.checkPassword(oldPassword, newPassword, confirmPassword);
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
if (err) {
this.props.onError(err);
} else {
try {
this.checkPassword(oldPassword, newPassword, confirmPassword);
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
return this.onChangePassword(oldPassword, newPassword);
} catch (err) {
this.props.onError(err);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types";
import { IThreepid } from "matrix-js-sdk/src/@types/threepids";
import { logger } from "matrix-js-sdk/src/logger";
import { IDelegatedAuthConfig, M_AUTHENTICATION } from "matrix-js-sdk/src/matrix";
import { MatrixError } from "matrix-js-sdk/src/matrix";
import { HTTPError } from "matrix-js-sdk/src/matrix";

import { _t } from "../../../../../languageHandler";
import { UserFriendlyError, _t } from "../../../../../languageHandler";
import ProfileSettings from "../../ProfileSettings";
import * as languageHandler from "../../../../../languageHandler";
import SettingsStore from "../../../../../settings/SettingsStore";
Expand All @@ -43,7 +43,7 @@ import Spinner from "../../../elements/Spinner";
import { SettingLevel } from "../../../../../settings/SettingLevel";
import { UIFeature } from "../../../../../settings/UIFeature";
import { ActionPayload } from "../../../../../dispatcher/payloads";
import ErrorDialog from "../../../dialogs/ErrorDialog";
import ErrorDialog, { extractErrorMessageFromError } from "../../../dialogs/ErrorDialog";
import AccountPhoneNumbers from "../../account/PhoneNumbers";
import AccountEmailAddresses from "../../account/EmailAddresses";
import DiscoveryEmailAddresses from "../../discovery/EmailAddresses";
Expand Down Expand Up @@ -253,18 +253,37 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
PlatformPeg.get()?.setSpellCheckEnabled(spellCheckEnabled);
};

private onPasswordChangeError = (err: { error: string } & MatrixError): void => {
// TODO: Figure out a design that doesn't involve replacing the current dialog
let errMsg = err.error || err.message || "";
if (err.httpStatus === 403) {
errMsg = _t("Failed to change password. Is your password correct?");
} else if (!errMsg) {
errMsg += ` (HTTP status ${err.httpStatus})`;
private onPasswordChangeError = (err: Error): void => {
logger.error("Failed to change password: " + err);

let underlyingError = err;
if (err instanceof UserFriendlyError && err.cause instanceof Error) {
underlyingError = err.cause;
}
logger.error("Failed to change password: " + errMsg);

const errorMessage = extractErrorMessageFromError(
err,
_t("Unknown password change error (%(stringifiedError)s)", {
stringifiedError: String(err),
}),
);

let errorMessageToDisplay;
if (underlyingError instanceof HTTPError && underlyingError.httpStatus === 403) {
errorMessageToDisplay = _t("Failed to change password. Is your password correct?");
} else if (underlyingError instanceof HTTPError) {
errorMessageToDisplay = _t("%(errorMessage)s (HTTP status %(httpStatus)s)", {
errorMessage,
httpStatus: underlyingError.httpStatus,
});
} else {
errorMessageToDisplay = errorMessage;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would you think about doing something along the lines of:

let errorMessageToDisplay = errorMessage;
if(it is an HTTPError) {
  if(it is a 403) {
    reassign errorMessageToDisplay
  } else {
    reassign errorMessageToDisplay
  } 
}

I'm not completely sold on whether the nested if is better than what you have, but I'm a fan of being able to get rid of the last else with the initial assignment of errorMessageToDisplay at least.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both are 🤷 type of problems to me in this case.

A bigger better change would be to remove the else if (underlyingError instanceof HTTPError) case altogether in favor of translated HTTPError in the matrix-js-sdk as we're not providing much value by just translating ... (HTTP status ...) here.

but I'm a fan of being able to get rid of the last else with the initial assignment of errorMessageToDisplay at least.

I've updated to do this ⏩


// TODO: Figure out a design that doesn't involve replacing the current dialog
Modal.createDialog(ErrorDialog, {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining strict Typescript failures are unlrelated to this PR and the problem is generally tracked by element-hq/element-web#24899

title: _t("Error"),
description: errMsg,
title: _t("Error changing password"),
description: errorMessageToDisplay,
});
};

Expand Down