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>
pull/28217/head
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()

View File

@ -330,6 +330,8 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.tokenLogin = true;
// Create and start the client
// accesses the new credentials just set in storage during attemptTokenLogin
// and sets logged in state
await Lifecycle.restoreFromLocalStorage({
ignoreGuest: true,
});

View File

@ -101,8 +101,8 @@
"Failed to transfer call": "Failed to transfer call",
"Permission Required": "Permission Required",
"You do not have permission to start a conference call in this room": "You do not have permission to start a conference call in this room",
"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 couldn't log you in": "We couldn't log you in",
"Try again": "Try again",
"User is not logged in": "User is not logged in",
"Database unexpectedly closed": "Database unexpectedly closed",