Consolidate login errors (#10722)
This commit is contained in:
parent
70326b98f2
commit
0a22ed90ef
7 changed files with 463 additions and 146 deletions
|
@ -63,6 +63,7 @@ import { Action } from "./dispatcher/actions";
|
||||||
import AbstractLocalStorageSettingsHandler from "./settings/handlers/AbstractLocalStorageSettingsHandler";
|
import AbstractLocalStorageSettingsHandler from "./settings/handlers/AbstractLocalStorageSettingsHandler";
|
||||||
import { OverwriteLoginPayload } from "./dispatcher/payloads/OverwriteLoginPayload";
|
import { OverwriteLoginPayload } from "./dispatcher/payloads/OverwriteLoginPayload";
|
||||||
import { SdkContextClass } from "./contexts/SDKContext";
|
import { SdkContextClass } from "./contexts/SDKContext";
|
||||||
|
import { messageForLoginError } from "./utils/ErrorUtils";
|
||||||
|
|
||||||
const HOMESERVER_URL_KEY = "mx_hs_url";
|
const HOMESERVER_URL_KEY = "mx_hs_url";
|
||||||
const ID_SERVER_URL_KEY = "mx_is_url";
|
const ID_SERVER_URL_KEY = "mx_is_url";
|
||||||
|
@ -230,17 +231,10 @@ export function attemptTokenLogin(
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
title: _t("We couldn't log you in"),
|
title: _t("We couldn't log you in"),
|
||||||
description:
|
description: messageForLoginError(err, {
|
||||||
err.name === "ConnectionError"
|
hsUrl: homeserver,
|
||||||
? _t(
|
hsName: homeserver,
|
||||||
"Your homeserver was unreachable and was not able to log you in. Please try again. " +
|
}),
|
||||||
"If this continues, please contact your homeserver administrator.",
|
|
||||||
)
|
|
||||||
: _t(
|
|
||||||
"Your homeserver rejected your log in attempt. " +
|
|
||||||
"This could be due to things just taking too long. Please try again. " +
|
|
||||||
"If this continues, please contact your homeserver administrator.",
|
|
||||||
),
|
|
||||||
button: _t("Try again"),
|
button: _t("Try again"),
|
||||||
onFinished: (tryAgain) => {
|
onFinished: (tryAgain) => {
|
||||||
if (tryAgain) {
|
if (tryAgain) {
|
||||||
|
|
|
@ -15,15 +15,13 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { ConnectionError, MatrixError } from "matrix-js-sdk/src/http-api";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { ISSOFlow, LoginFlow, SSOAction } from "matrix-js-sdk/src/@types/auth";
|
import { ISSOFlow, LoginFlow, SSOAction } from "matrix-js-sdk/src/@types/auth";
|
||||||
|
|
||||||
import { _t, _td } from "../../../languageHandler";
|
import { _t, _td } from "../../../languageHandler";
|
||||||
import Login from "../../../Login";
|
import Login from "../../../Login";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import { messageForConnectionError, messageForLoginError } from "../../../utils/ErrorUtils";
|
||||||
import { messageForResourceLimitError } from "../../../utils/ErrorUtils";
|
|
||||||
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
|
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
|
||||||
import AuthPage from "../../views/auth/AuthPage";
|
import AuthPage from "../../views/auth/AuthPage";
|
||||||
import PlatformPeg from "../../../PlatformPeg";
|
import PlatformPeg from "../../../PlatformPeg";
|
||||||
|
@ -212,56 +210,20 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
this.props.onLoggedIn(data, password);
|
this.props.onLoggedIn(data, password);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
if (this.unmounted) {
|
if (this.unmounted) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
let errorText: ReactNode;
|
|
||||||
|
|
||||||
|
let errorText: ReactNode;
|
||||||
// Some error strings only apply for logging in
|
// Some error strings only apply for logging in
|
||||||
const usingEmail = username && username.indexOf("@") > 0;
|
if (error.httpStatus === 400 && username && username.indexOf("@") > 0) {
|
||||||
if (error.httpStatus === 400 && usingEmail) {
|
|
||||||
errorText = _t("This homeserver does not support login using email address.");
|
errorText = _t("This homeserver does not support login using email address.");
|
||||||
} else if (error.errcode === "M_RESOURCE_LIMIT_EXCEEDED") {
|
|
||||||
const errorTop = messageForResourceLimitError(error.data.limit_type, error.data.admin_contact, {
|
|
||||||
"monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."),
|
|
||||||
"hs_blocked": _td("This homeserver has been blocked by its administrator."),
|
|
||||||
"": _td("This homeserver has exceeded one of its resource limits."),
|
|
||||||
});
|
|
||||||
const errorDetail = messageForResourceLimitError(error.data.limit_type, error.data.admin_contact, {
|
|
||||||
"": _td("Please <a>contact your service administrator</a> to continue using this service."),
|
|
||||||
});
|
|
||||||
errorText = (
|
|
||||||
<div>
|
|
||||||
<div>{errorTop}</div>
|
|
||||||
<div className="mx_Login_smallError">{errorDetail}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (error.httpStatus === 401 || error.httpStatus === 403) {
|
|
||||||
if (error.errcode === "M_USER_DEACTIVATED") {
|
|
||||||
errorText = _t("This account has been deactivated.");
|
|
||||||
} else if (SdkConfig.get("disable_custom_urls")) {
|
|
||||||
errorText = (
|
|
||||||
<div>
|
|
||||||
<div>{_t("Incorrect username and/or password.")}</div>
|
|
||||||
<div className="mx_Login_smallError">
|
|
||||||
{_t("Please note you are logging into the %(hs)s server, not matrix.org.", {
|
|
||||||
hs: this.props.serverConfig.hsName,
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
errorText = _t("Incorrect username and/or password.");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// other errors, not specific to doing a password login
|
errorText = messageForLoginError(error, this.props.serverConfig);
|
||||||
errorText = this.errorTextFromError(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
busy: false,
|
busy: false,
|
||||||
busyLoggingIn: false,
|
busyLoggingIn: false,
|
||||||
errorText: errorText,
|
errorText,
|
||||||
// 401 would be the sensible status code for 'incorrect password'
|
// 401 would be the sensible status code for 'incorrect password'
|
||||||
// but the login API gives a 403 https://matrix.org/jira/browse/SYN-744
|
// but the login API gives a 403 https://matrix.org/jira/browse/SYN-744
|
||||||
// mentions this (although the bug is for UI auth which is not this)
|
// mentions this (although the bug is for UI auth which is not this)
|
||||||
|
@ -425,7 +387,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
errorText: this.errorTextFromError(err),
|
errorText: messageForConnectionError(err, this.props.serverConfig),
|
||||||
loginIncorrect: false,
|
loginIncorrect: false,
|
||||||
canTryLogin: false,
|
canTryLogin: false,
|
||||||
});
|
});
|
||||||
|
@ -448,67 +410,6 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
private errorTextFromError(err: MatrixError): ReactNode {
|
|
||||||
let errCode = err.errcode;
|
|
||||||
if (!errCode && err.httpStatus) {
|
|
||||||
errCode = "HTTP " + err.httpStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
let errorText: ReactNode =
|
|
||||||
_t("There was a problem communicating with the homeserver, please try again later.") +
|
|
||||||
(errCode ? " (" + errCode + ")" : "");
|
|
||||||
|
|
||||||
if (err instanceof ConnectionError) {
|
|
||||||
if (
|
|
||||||
window.location.protocol === "https:" &&
|
|
||||||
(this.props.serverConfig.hsUrl.startsWith("http:") || !this.props.serverConfig.hsUrl.startsWith("http"))
|
|
||||||
) {
|
|
||||||
errorText = (
|
|
||||||
<span>
|
|
||||||
{_t(
|
|
||||||
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. " +
|
|
||||||
"Either use HTTPS or <a>enable unsafe scripts</a>.",
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
a: (sub) => {
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
href="https://www.google.com/search?&q=enable%20unsafe%20scripts"
|
|
||||||
>
|
|
||||||
{sub}
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
errorText = (
|
|
||||||
<span>
|
|
||||||
{_t(
|
|
||||||
"Can't connect to homeserver - please check your connectivity, ensure your " +
|
|
||||||
"<a>homeserver's SSL certificate</a> is trusted, and that a browser extension " +
|
|
||||||
"is not blocking requests.",
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
a: (sub) => (
|
|
||||||
<a target="_blank" rel="noreferrer noopener" href={this.props.serverConfig.hsUrl}>
|
|
||||||
{sub}
|
|
||||||
</a>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderLoginComponentForFlows(): ReactNode {
|
public renderLoginComponentForFlows(): ReactNode {
|
||||||
if (!this.state.flows) return null;
|
if (!this.state.flows) return null;
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ import classNames from "classnames";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { ISSOFlow, SSOAction } from "matrix-js-sdk/src/@types/auth";
|
import { ISSOFlow, SSOAction } from "matrix-js-sdk/src/@types/auth";
|
||||||
|
|
||||||
import { _t, _td } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { messageForResourceLimitError } from "../../../utils/ErrorUtils";
|
import { adminContactStrings, messageForResourceLimitError, resourceLimitStrings } from "../../../utils/ErrorUtils";
|
||||||
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
|
import AutoDiscoveryUtils from "../../../utils/AutoDiscoveryUtils";
|
||||||
import * as Lifecycle from "../../../Lifecycle";
|
import * as Lifecycle from "../../../Lifecycle";
|
||||||
import { IMatrixClientCreds, MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { IMatrixClientCreds, MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
|
@ -313,17 +313,15 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
let errorText: ReactNode = (response as Error).message || (response as Error).toString();
|
let errorText: ReactNode = (response as Error).message || (response as Error).toString();
|
||||||
// can we give a better error message?
|
// can we give a better error message?
|
||||||
if (response instanceof MatrixError && response.errcode === "M_RESOURCE_LIMIT_EXCEEDED") {
|
if (response instanceof MatrixError && response.errcode === "M_RESOURCE_LIMIT_EXCEEDED") {
|
||||||
const errorTop = messageForResourceLimitError(response.data.limit_type, response.data.admin_contact, {
|
const errorTop = messageForResourceLimitError(
|
||||||
"monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."),
|
response.data.limit_type,
|
||||||
"hs_blocked": _td("This homeserver has been blocked by its administrator."),
|
response.data.admin_contact,
|
||||||
"": _td("This homeserver has exceeded one of its resource limits."),
|
resourceLimitStrings,
|
||||||
});
|
);
|
||||||
const errorDetail = messageForResourceLimitError(
|
const errorDetail = messageForResourceLimitError(
|
||||||
response.data.limit_type,
|
response.data.limit_type,
|
||||||
response.data.admin_contact,
|
response.data.admin_contact,
|
||||||
{
|
adminContactStrings,
|
||||||
"": _td("Please <a>contact your service administrator</a> to continue using this service."),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
errorText = (
|
errorText = (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -103,8 +103,6 @@
|
||||||
"We couldn't log you in": "We couldn't log you in",
|
"We couldn't log you in": "We couldn't log you in",
|
||||||
"We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.": "We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.",
|
"We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.": "We asked the browser to remember which homeserver you use to let you sign in, but unfortunately your browser has forgotten it. Go to the sign in page and try again.",
|
||||||
"Try again": "Try again",
|
"Try again": "Try again",
|
||||||
"Your homeserver was unreachable and was not able to log you in. Please try again. If this continues, please contact your homeserver administrator.": "Your homeserver was unreachable and was not able to log you in. Please try again. If this continues, please contact your homeserver administrator.",
|
|
||||||
"Your homeserver rejected your log in attempt. This could be due to things just taking too long. Please try again. If this continues, please contact your homeserver administrator.": "Your homeserver rejected your log in attempt. This could be due to things just taking too long. Please try again. If this continues, please contact your homeserver administrator.",
|
|
||||||
"Database unexpectedly closed": "Database unexpectedly closed",
|
"Database unexpectedly closed": "Database unexpectedly closed",
|
||||||
"This may be caused by having the app open in multiple tabs or due to clearing browser data.": "This may be caused by having the app open in multiple tabs or due to clearing browser data.",
|
"This may be caused by having the app open in multiple tabs or due to clearing browser data.": "This may be caused by having the app open in multiple tabs or due to clearing browser data.",
|
||||||
"Reload": "Reload",
|
"Reload": "Reload",
|
||||||
|
@ -703,8 +701,14 @@
|
||||||
"This homeserver has hit its Monthly Active User limit.": "This homeserver has hit its Monthly Active User limit.",
|
"This homeserver has hit its Monthly Active User limit.": "This homeserver has hit its Monthly Active User limit.",
|
||||||
"This homeserver has been blocked by its administrator.": "This homeserver has been blocked by its administrator.",
|
"This homeserver has been blocked by its administrator.": "This homeserver has been blocked by its administrator.",
|
||||||
"This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.",
|
"This homeserver has exceeded one of its resource limits.": "This homeserver has exceeded one of its resource limits.",
|
||||||
"Please <a>contact your service administrator</a> to continue using the service.": "Please <a>contact your service administrator</a> to continue using the service.",
|
"Please <a>contact your service administrator</a> to continue using this service.": "Please <a>contact your service administrator</a> to continue using this service.",
|
||||||
"Unable to connect to Homeserver. Retrying…": "Unable to connect to Homeserver. Retrying…",
|
"Unable to connect to Homeserver. Retrying…": "Unable to connect to Homeserver. Retrying…",
|
||||||
|
"This account has been deactivated.": "This account has been deactivated.",
|
||||||
|
"Incorrect username and/or password.": "Incorrect username and/or password.",
|
||||||
|
"Please note you are logging into the %(hs)s server, not matrix.org.": "Please note you are logging into the %(hs)s server, not matrix.org.",
|
||||||
|
"There was a problem communicating with the homeserver, please try again later.": "There was a problem communicating with the homeserver, please try again later.",
|
||||||
|
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.",
|
||||||
|
"Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.": "Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.",
|
||||||
"%(items)s and %(count)s others|other": "%(items)s and %(count)s others",
|
"%(items)s and %(count)s others|other": "%(items)s and %(count)s others",
|
||||||
"%(items)s and %(count)s others|one": "%(items)s and one other",
|
"%(items)s and %(count)s others|one": "%(items)s and one other",
|
||||||
"%(items)s and %(lastItem)s": "%(items)s and %(lastItem)s",
|
"%(items)s and %(lastItem)s": "%(items)s and %(lastItem)s",
|
||||||
|
@ -3553,15 +3557,8 @@
|
||||||
"Identity server URL does not appear to be a valid identity server": "Identity server URL does not appear to be a valid identity server",
|
"Identity server URL does not appear to be a valid identity server": "Identity server URL does not appear to be a valid identity server",
|
||||||
"General failure": "General failure",
|
"General failure": "General failure",
|
||||||
"This homeserver does not support login using email address.": "This homeserver does not support login using email address.",
|
"This homeserver does not support login using email address.": "This homeserver does not support login using email address.",
|
||||||
"Please <a>contact your service administrator</a> to continue using this service.": "Please <a>contact your service administrator</a> to continue using this service.",
|
|
||||||
"This account has been deactivated.": "This account has been deactivated.",
|
|
||||||
"Incorrect username and/or password.": "Incorrect username and/or password.",
|
|
||||||
"Please note you are logging into the %(hs)s server, not matrix.org.": "Please note you are logging into the %(hs)s server, not matrix.org.",
|
|
||||||
"Failed to perform homeserver discovery": "Failed to perform homeserver discovery",
|
"Failed to perform homeserver discovery": "Failed to perform homeserver discovery",
|
||||||
"This homeserver doesn't offer any login flows which are supported by this client.": "This homeserver doesn't offer any login flows which are supported by this client.",
|
"This homeserver doesn't offer any login flows which are supported by this client.": "This homeserver doesn't offer any login flows which are supported by this client.",
|
||||||
"There was a problem communicating with the homeserver, please try again later.": "There was a problem communicating with the homeserver, please try again later.",
|
|
||||||
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.": "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or <a>enable unsafe scripts</a>.",
|
|
||||||
"Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.": "Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.",
|
|
||||||
"Syncing…": "Syncing…",
|
"Syncing…": "Syncing…",
|
||||||
"Signing In…": "Signing In…",
|
"Signing In…": "Signing In…",
|
||||||
"If you've joined lots of rooms, this might take a while": "If you've joined lots of rooms, this might take a while",
|
"If you've joined lots of rooms, this might take a while": "If you've joined lots of rooms, this might take a while",
|
||||||
|
|
|
@ -15,9 +15,21 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { MatrixError } from "matrix-js-sdk/src/http-api";
|
import { MatrixError, ConnectionError } from "matrix-js-sdk/src/http-api";
|
||||||
|
|
||||||
import { _t, _td, Tags, TranslatedString } from "../languageHandler";
|
import { _t, _td, Tags, TranslatedString } from "../languageHandler";
|
||||||
|
import SdkConfig from "../SdkConfig";
|
||||||
|
import { ValidatedServerConfig } from "./ValidatedServerConfig";
|
||||||
|
|
||||||
|
export const resourceLimitStrings = {
|
||||||
|
"monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."),
|
||||||
|
"hs_blocked": _td("This homeserver has been blocked by its administrator."),
|
||||||
|
"": _td("This homeserver has exceeded one of its resource limits."),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const adminContactStrings = {
|
||||||
|
"": _td("Please <a>contact your service administrator</a> to continue using this service."),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce a translated error message for a
|
* Produce a translated error message for a
|
||||||
|
@ -63,14 +75,16 @@ export function messageForResourceLimitError(
|
||||||
|
|
||||||
export function messageForSyncError(err: Error): ReactNode {
|
export function messageForSyncError(err: Error): ReactNode {
|
||||||
if (err instanceof MatrixError && err.errcode === "M_RESOURCE_LIMIT_EXCEEDED") {
|
if (err instanceof MatrixError && err.errcode === "M_RESOURCE_LIMIT_EXCEEDED") {
|
||||||
const limitError = messageForResourceLimitError(err.data.limit_type, err.data.admin_contact, {
|
const limitError = messageForResourceLimitError(
|
||||||
"monthly_active_user": _td("This homeserver has hit its Monthly Active User limit."),
|
err.data.limit_type,
|
||||||
"hs_blocked": _td("This homeserver has been blocked by its administrator."),
|
err.data.admin_contact,
|
||||||
"": _td("This homeserver has exceeded one of its resource limits."),
|
resourceLimitStrings,
|
||||||
});
|
);
|
||||||
const adminContact = messageForResourceLimitError(err.data.limit_type, err.data.admin_contact, {
|
const adminContact = messageForResourceLimitError(
|
||||||
"": _td("Please <a>contact your service administrator</a> to continue using the service."),
|
err.data.limit_type,
|
||||||
});
|
err.data.admin_contact,
|
||||||
|
adminContactStrings,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>{limitError}</div>
|
<div>{limitError}</div>
|
||||||
|
@ -81,3 +95,109 @@ export function messageForSyncError(err: Error): ReactNode {
|
||||||
return <div>{_t("Unable to connect to Homeserver. Retrying…")}</div>;
|
return <div>{_t("Unable to connect to Homeserver. Retrying…")}</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function messageForLoginError(
|
||||||
|
err: MatrixError,
|
||||||
|
serverConfig: Pick<ValidatedServerConfig, "hsName" | "hsUrl">,
|
||||||
|
): ReactNode {
|
||||||
|
if (err.errcode === "M_RESOURCE_LIMIT_EXCEEDED") {
|
||||||
|
const errorTop = messageForResourceLimitError(
|
||||||
|
err.data.limit_type,
|
||||||
|
err.data.admin_contact,
|
||||||
|
resourceLimitStrings,
|
||||||
|
);
|
||||||
|
const errorDetail = messageForResourceLimitError(
|
||||||
|
err.data.limit_type,
|
||||||
|
err.data.admin_contact,
|
||||||
|
adminContactStrings,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>{errorTop}</div>
|
||||||
|
<div className="mx_Login_smallError">{errorDetail}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (err.httpStatus === 401 || err.httpStatus === 403) {
|
||||||
|
if (err.errcode === "M_USER_DEACTIVATED") {
|
||||||
|
return _t("This account has been deactivated.");
|
||||||
|
} else if (SdkConfig.get("disable_custom_urls")) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>{_t("Incorrect username and/or password.")}</div>
|
||||||
|
<div className="mx_Login_smallError">
|
||||||
|
{_t("Please note you are logging into the %(hs)s server, not matrix.org.", {
|
||||||
|
hs: serverConfig.hsName,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return _t("Incorrect username and/or password.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return messageForConnectionError(err, serverConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function messageForConnectionError(
|
||||||
|
err: Error,
|
||||||
|
serverConfig: Pick<ValidatedServerConfig, "hsName" | "hsUrl">,
|
||||||
|
): ReactNode {
|
||||||
|
let errorText = _t("There was a problem communicating with the homeserver, please try again later.");
|
||||||
|
|
||||||
|
if (err instanceof ConnectionError) {
|
||||||
|
if (
|
||||||
|
window.location.protocol === "https:" &&
|
||||||
|
(serverConfig.hsUrl.startsWith("http:") || !serverConfig.hsUrl.startsWith("http"))
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{_t(
|
||||||
|
"Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. " +
|
||||||
|
"Either use HTTPS or <a>enable unsafe scripts</a>.",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
a: (sub) => {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
href="https://www.google.com/search?&q=enable%20unsafe%20scripts"
|
||||||
|
>
|
||||||
|
{sub}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{_t(
|
||||||
|
"Can't connect to homeserver - please check your connectivity, ensure your " +
|
||||||
|
"<a>homeserver's SSL certificate</a> is trusted, and that a browser extension " +
|
||||||
|
"is not blocking requests.",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
a: (sub) => (
|
||||||
|
<a target="_blank" rel="noreferrer noopener" href={serverConfig.hsUrl}>
|
||||||
|
{sub}
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if (err instanceof MatrixError) {
|
||||||
|
if (err.errcode) {
|
||||||
|
errorText += `(${err.errcode})`;
|
||||||
|
} else if (err.httpStatus) {
|
||||||
|
errorText += ` (HTTP ${err.httpStatus})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorText;
|
||||||
|
}
|
||||||
|
|
182
test/utils/ErrorUtils-test.ts
Normal file
182
test/utils/ErrorUtils-test.ts
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ReactElement } from "react";
|
||||||
|
import { render } from "@testing-library/react";
|
||||||
|
import { MatrixError, ConnectionError } from "matrix-js-sdk/src/http-api";
|
||||||
|
|
||||||
|
import {
|
||||||
|
adminContactStrings,
|
||||||
|
messageForConnectionError,
|
||||||
|
messageForLoginError,
|
||||||
|
messageForResourceLimitError,
|
||||||
|
messageForSyncError,
|
||||||
|
resourceLimitStrings,
|
||||||
|
} from "../../src/utils/ErrorUtils";
|
||||||
|
|
||||||
|
describe("messageForResourceLimitError", () => {
|
||||||
|
it("should match snapshot for monthly_active_user", () => {
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForResourceLimitError("monthly_active_user", "some@email", resourceLimitStrings) as ReactElement,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should match snapshot for admin contact links", () => {
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForResourceLimitError("", "some@email", adminContactStrings) as ReactElement,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("messageForSyncError", () => {
|
||||||
|
it("should match snapshot for M_RESOURCE_LIMIT_EXCEEDED", () => {
|
||||||
|
const err = new MatrixError({
|
||||||
|
errcode: "M_RESOURCE_LIMIT_EXCEEDED",
|
||||||
|
data: {
|
||||||
|
limit_type: "monthly_active_user",
|
||||||
|
admin_contact: "some@email",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { asFragment } = render(messageForSyncError(err) as ReactElement);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should match snapshot for other errors", () => {
|
||||||
|
const err = new MatrixError({
|
||||||
|
errcode: "OTHER_ERROR",
|
||||||
|
});
|
||||||
|
const { asFragment } = render(messageForSyncError(err) as ReactElement);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("messageForLoginError", () => {
|
||||||
|
it("should match snapshot for M_RESOURCE_LIMIT_EXCEEDED", () => {
|
||||||
|
const err = new MatrixError({
|
||||||
|
errcode: "M_RESOURCE_LIMIT_EXCEEDED",
|
||||||
|
data: {
|
||||||
|
limit_type: "monthly_active_user",
|
||||||
|
admin_contact: "some@email",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForLoginError(err, {
|
||||||
|
hsUrl: "hsUrl",
|
||||||
|
hsName: "hsName",
|
||||||
|
}) as ReactElement,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should match snapshot for M_USER_DEACTIVATED", () => {
|
||||||
|
const err = new MatrixError(
|
||||||
|
{
|
||||||
|
errcode: "M_USER_DEACTIVATED",
|
||||||
|
},
|
||||||
|
403,
|
||||||
|
);
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForLoginError(err, {
|
||||||
|
hsUrl: "hsUrl",
|
||||||
|
hsName: "hsName",
|
||||||
|
}) as ReactElement,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should match snapshot for 401", () => {
|
||||||
|
const err = new MatrixError(
|
||||||
|
{
|
||||||
|
errcode: "UNKNOWN",
|
||||||
|
},
|
||||||
|
401,
|
||||||
|
);
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForLoginError(err, {
|
||||||
|
hsUrl: "hsUrl",
|
||||||
|
hsName: "hsName",
|
||||||
|
}) as ReactElement,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should match snapshot for unknown error", () => {
|
||||||
|
const err = new MatrixError({}, 400);
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForLoginError(err, {
|
||||||
|
hsUrl: "hsUrl",
|
||||||
|
hsName: "hsName",
|
||||||
|
}) as ReactElement,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("messageForConnectionError", () => {
|
||||||
|
it("should match snapshot for ConnectionError", () => {
|
||||||
|
const err = new ConnectionError("Internal Server Error", new MatrixError({}, 500));
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForConnectionError(err, {
|
||||||
|
hsUrl: "hsUrl",
|
||||||
|
hsName: "hsName",
|
||||||
|
}) as ReactElement,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should match snapshot for MatrixError M_NOT_FOUND", () => {
|
||||||
|
const err = new MatrixError(
|
||||||
|
{
|
||||||
|
errcode: "M_NOT_FOUND",
|
||||||
|
},
|
||||||
|
404,
|
||||||
|
);
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForConnectionError(err, {
|
||||||
|
hsUrl: "hsUrl",
|
||||||
|
hsName: "hsName",
|
||||||
|
}) as ReactElement,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should match snapshot for unknown error", () => {
|
||||||
|
const err = new Error("What even");
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForConnectionError(err, {
|
||||||
|
hsUrl: "hsUrl",
|
||||||
|
hsName: "hsName",
|
||||||
|
}) as ReactElement,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should match snapshot for mixed content error", () => {
|
||||||
|
const err = new ConnectionError("Mixed content maybe?");
|
||||||
|
Object.defineProperty(window, "location", { value: { protocol: "https:" } });
|
||||||
|
const { asFragment } = render(
|
||||||
|
messageForConnectionError(err, {
|
||||||
|
hsUrl: "http://server.com",
|
||||||
|
hsName: "hsName",
|
||||||
|
}) as ReactElement,
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
125
test/utils/__snapshots__/ErrorUtils-test.ts.snap
Normal file
125
test/utils/__snapshots__/ErrorUtils-test.ts.snap
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`messageForConnectionError should match snapshot for ConnectionError 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<span>
|
||||||
|
<span>
|
||||||
|
Can't connect to homeserver - please check your connectivity, ensure your
|
||||||
|
<a
|
||||||
|
href="hsUrl"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
homeserver's SSL certificate
|
||||||
|
</a>
|
||||||
|
is trusted, and that a browser extension is not blocking requests.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForConnectionError should match snapshot for MatrixError M_NOT_FOUND 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
There was a problem communicating with the homeserver, please try again later.(M_NOT_FOUND)
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForConnectionError should match snapshot for mixed content error 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<span>
|
||||||
|
<span>
|
||||||
|
Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or
|
||||||
|
<a
|
||||||
|
href="https://www.google.com/search?&q=enable%20unsafe%20scripts"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
enable unsafe scripts
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForConnectionError should match snapshot for unknown error 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
There was a problem communicating with the homeserver, please try again later.
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForLoginError should match snapshot for 401 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
Incorrect username and/or password.
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForLoginError should match snapshot for M_RESOURCE_LIMIT_EXCEEDED 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
This homeserver has exceeded one of its resource limits.
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mx_Login_smallError"
|
||||||
|
>
|
||||||
|
Please contact your service administrator to continue using this service.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForLoginError should match snapshot for M_USER_DEACTIVATED 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
This account has been deactivated.
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForLoginError should match snapshot for unknown error 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
There was a problem communicating with the homeserver, please try again later. (HTTP 400)
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForResourceLimitError should match snapshot for admin contact links 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<span>
|
||||||
|
Please
|
||||||
|
<a
|
||||||
|
href="some@email"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
contact your service administrator
|
||||||
|
</a>
|
||||||
|
to continue using this service.
|
||||||
|
</span>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForResourceLimitError should match snapshot for monthly_active_user 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
This homeserver has hit its Monthly Active User limit.
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForSyncError should match snapshot for M_RESOURCE_LIMIT_EXCEEDED 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
This homeserver has exceeded one of its resource limits.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Please contact your service administrator to continue using this service.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`messageForSyncError should match snapshot for other errors 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div>
|
||||||
|
Unable to connect to Homeserver. Retrying…
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
Loading…
Reference in a new issue