diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index 927de5a0a8..d0d5e60ce8 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -30,6 +30,7 @@ import {idbLoad, idbSave, idbDelete} from "./utils/StorageManager"; export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url"; export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url"; +export const SSO_IDP_ID_KEY = "mx_sso_idp_id"; export enum UpdateCheckStatus { Checking = "CHECKING", @@ -258,6 +259,9 @@ export default abstract class BasePlatform { if (mxClient.getIdentityServerUrl()) { localStorage.setItem(SSO_ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl()); } + if (idpId) { + localStorage.setItem(SSO_IDP_ID_KEY, idpId); + } const callbackUrl = this.getSSOCallbackUrl(fragmentAfterLogin); window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType, idpId); // redirect to SSO } diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 4602f2b5bb..7780d4c87a 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -46,11 +46,13 @@ import {IntegrationManagers} from "./integrations/IntegrationManagers"; import {Mjolnir} from "./mjolnir/Mjolnir"; import DeviceListener from "./DeviceListener"; import {Jitsi} from "./widgets/Jitsi"; -import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "./BasePlatform"; +import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY, SSO_IDP_ID_KEY} from "./BasePlatform"; import ThreepidInviteStore from "./stores/ThreepidInviteStore"; import CountlyAnalytics from "./CountlyAnalytics"; import CallHandler from './CallHandler'; import LifecycleCustomisations from "./customisations/Lifecycle"; +import ErrorDialog from "./components/views/dialogs/ErrorDialog"; +import {_t} from "./languageHandler"; const HOMESERVER_URL_KEY = "mx_hs_url"; const ID_SERVER_URL_KEY = "mx_is_url"; @@ -162,7 +164,8 @@ export async function getStoredSessionOwner(): Promise<[string, boolean]> { * query-parameters extracted from the real query-string of the starting * URI. * - * @param {String} defaultDeviceDisplayName + * @param {string} defaultDeviceDisplayName + * @param {string} fragmentAfterLogin path to go to after a successful login, only used for "Try again" * * @returns {Promise} promise which resolves to true if we completed the token * login, else false @@ -170,6 +173,7 @@ export async function getStoredSessionOwner(): Promise<[string, boolean]> { export function attemptTokenLogin( queryParams: Record, defaultDeviceDisplayName?: string, + fragmentAfterLogin?: string, ): Promise { if (!queryParams.loginToken) { return Promise.resolve(false); @@ -179,6 +183,12 @@ export function attemptTokenLogin( const identityServer = localStorage.getItem(SSO_ID_SERVER_URL_KEY); if (!homeserver) { console.warn("Cannot log in with token: can't determine HS URL to use"); + Modal.createTrackedDialog("SSO", "Unknown HS", ErrorDialog, { + title: _t("We couldn't log you in"), + description: _t("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."), + button: _t("Try again"), + }); return Promise.resolve(false); } @@ -198,8 +208,28 @@ export function attemptTokenLogin( return true; }); }).catch((err) => { - console.error("Failed to log in with login token: " + err + " " + - err.data); + Modal.createTrackedDialog("SSO", "Token Rejected", ErrorDialog, { + title: _t("We couldn't log you in"), + description: err.name === "ConnectionError" + ? _t("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"), + onFinished: tryAgain => { + if (tryAgain) { + const cli = Matrix.createClient({ + baseUrl: homeserver, + idBaseUrl: identityServer, + }); + const idpId = localStorage.getItem(SSO_IDP_ID_KEY) || undefined; + PlatformPeg.get().startSingleSignOn(cli, "sso", fragmentAfterLogin, idpId); + } + }, + }); + console.error("Failed to log in with login token:"); + console.error(err); return false; }); } diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 2c652f7c8c..8ed4b6cd11 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -325,6 +325,7 @@ export default class MatrixChat extends React.PureComponent { Lifecycle.attemptTokenLogin( this.props.realQueryParams, this.props.defaultDeviceDisplayName, + this.getFragmentAfterLogin(), ).then(async (loggedIn) => { if (this.props.realQueryParams?.loginToken) { // remove the loginToken from the URL regardless diff --git a/src/components/views/dialogs/ErrorDialog.js b/src/components/views/dialogs/ErrorDialog.js index acebdcd854..3bfa635adf 100644 --- a/src/components/views/dialogs/ErrorDialog.js +++ b/src/components/views/dialogs/ErrorDialog.js @@ -50,6 +50,10 @@ export default class ErrorDialog extends React.Component { button: null, }; + onClick = () => { + this.props.onFinished(true); + }; + render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); return ( @@ -64,7 +68,7 @@ export default class ErrorDialog extends React.Component { { this.props.description || _t('An error has occurred.') }
-
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 06b1023a51..823efd1adf 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -118,6 +118,11 @@ "This action requires accessing the default identity server to validate an email address or phone number, but the server does not have any terms of service.": "This action requires accessing the default identity server to validate an email address or phone number, but the server does not have any terms of service.", "Only continue if you trust the owner of the server.": "Only continue if you trust the owner of the server.", "Trust": "Trust", + "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.", + "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.", "%(name)s is requesting verification": "%(name)s is requesting verification", "%(brand)s does not have permission to send you notifications - please check your browser settings": "%(brand)s does not have permission to send you notifications - please check your browser settings", "%(brand)s was not given permission to send notifications - please try again": "%(brand)s was not given permission to send notifications - please try again",