OIDC: extract success/failure handlers from token login function (#11154)

* extract success/failure handlers from token login function

* typo

* use for no homeserver error dialog too

* i18n

* tidy

* Update src/Lifecycle.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* move try again responsibility

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
Kerry 2023-06-30 10:33:44 +12:00 committed by GitHub
parent f62fe2626c
commit 3930f1a10b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 31 deletions

View file

@ -17,6 +17,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { ReactNode } from "react";
import { createClient } from "matrix-js-sdk/src/matrix";
import { InvalidStoreError } from "matrix-js-sdk/src/errors";
import { MatrixClient } from "matrix-js-sdk/src/client";
@ -204,14 +205,12 @@ export function attemptTokenLogin(
const identityServer = localStorage.getItem(SSO_ID_SERVER_URL_KEY) ?? undefined;
if (!homeserver) {
logger.warn("Cannot log in with token: can't determine HS URL to use");
Modal.createDialog(ErrorDialog, {
title: _t("We couldn't log you in"),
description: _t(
onFailedDelegatedAuthLogin(
_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);
}
@ -219,40 +218,61 @@ export function attemptTokenLogin(
token: queryParams.loginToken as string,
initial_device_display_name: defaultDeviceDisplayName,
})
.then(function (creds) {
.then(async function (creds) {
logger.log("Logged in with token");
return clearStorage().then(async (): Promise<boolean> => {
await persistCredentials(creds);
// remember that we just logged in
sessionStorage.setItem("mx_fresh_login", String(true));
return true;
});
await onSuccessfulDelegatedAuthLogin(creds);
return true;
})
.catch((err) => {
Modal.createDialog(ErrorDialog, {
title: _t("We couldn't log you in"),
description: messageForLoginError(err, {
.catch((error) => {
const tryAgainCallback: TryAgainFunction = () => {
const cli = createClient({
baseUrl: homeserver,
idBaseUrl: identityServer,
});
const idpId = localStorage.getItem(SSO_IDP_ID_KEY) || undefined;
PlatformPeg.get()?.startSingleSignOn(cli, "sso", fragmentAfterLogin, idpId, SSOAction.LOGIN);
};
onFailedDelegatedAuthLogin(
messageForLoginError(error, {
hsUrl: homeserver,
hsName: homeserver,
}),
button: _t("Try again"),
onFinished: (tryAgain) => {
if (tryAgain) {
const cli = createClient({
baseUrl: homeserver,
idBaseUrl: identityServer,
});
const idpId = localStorage.getItem(SSO_IDP_ID_KEY) || undefined;
PlatformPeg.get()?.startSingleSignOn(cli, "sso", fragmentAfterLogin, idpId, SSOAction.LOGIN);
}
},
});
logger.error("Failed to log in with login token:");
logger.error(err);
tryAgainCallback,
);
logger.error("Failed to log in with login token:", error);
return false;
});
}
/**
* Called after a successful token login or OIDC authorization.
* Clear storage then save new credentials in storage
* @param credentials as returned from login
*/
async function onSuccessfulDelegatedAuthLogin(credentials: IMatrixClientCreds): Promise<void> {
await clearStorage();
await persistCredentials(credentials);
// remember that we just logged in
sessionStorage.setItem("mx_fresh_login", String(true));
}
type TryAgainFunction = () => void;
/**
* Display a friendly error to the user when token login or OIDC authorization fails
* @param description error description
* @param tryAgain OPTIONAL function to call on try again button from error dialog
*/
async function onFailedDelegatedAuthLogin(description: string | ReactNode, tryAgain?: TryAgainFunction): Promise<void> {
Modal.createDialog(ErrorDialog, {
title: _t("We couldn't log you in"),
description,
button: _t("Try again"),
// if we have a tryAgain callback, call it the primary 'try again' button was clicked in the dialog
onFinished: tryAgain ? (shouldTryAgain?: boolean) => shouldTryAgain && tryAgain() : undefined,
});
}
export function handleInvalidStoreError(e: InvalidStoreError): Promise<void> | void {
if (e.reason === InvalidStoreError.TOGGLED_LAZY_LOADING) {
return Promise.resolve()