Switch OIDC to response_mode=fragment (#33100)
* Refactor: kill off `parseQs` in favour of URLSearchParams * Consolidate app-load url parameter handling * Switch to responseMode=fragment
This commit is contained in:
@@ -20,7 +20,6 @@ import {
|
||||
type SyncStateData,
|
||||
type TimelineEvents,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { type QueryDict } from "matrix-js-sdk/src/utils";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { throttle } from "lodash";
|
||||
import { CryptoEvent, type KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
|
||||
@@ -141,6 +140,8 @@ import Markdown from "../../Markdown";
|
||||
import { LinkedTextConfiguration, sanitizeHtmlParams } from "../../Linkify";
|
||||
import { isOnlyAdmin } from "../../utils/membership";
|
||||
import { ModuleApi } from "../../modules/Api.ts";
|
||||
import { type IScreen } from "../../vector/routing.ts";
|
||||
import { type URLParams } from "../../vector/url_utils.ts";
|
||||
|
||||
// legacy export
|
||||
export { default as Views } from "../../Views";
|
||||
@@ -152,21 +153,14 @@ const AUTH_SCREENS = ["register", "mobile_register", "login", "forgot_password",
|
||||
// re-factoring to be included in this list in future.
|
||||
const ONBOARDING_FLOW_STARTERS = [Action.ViewUserSettings, Action.CreateChat, Action.CreateRoom];
|
||||
|
||||
interface IScreen {
|
||||
screen: string;
|
||||
params?: QueryDict;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
config: ConfigOptions;
|
||||
onNewScreen: (screen: string, replaceLast: boolean) => void;
|
||||
enableGuest?: boolean;
|
||||
// the queryParams extracted from the [real] query-string of the URI
|
||||
realQueryParams: QueryDict;
|
||||
// the initial queryParams extracted from the hash-fragment of the URI
|
||||
startingFragmentQueryParams?: QueryDict;
|
||||
// the params extracted from the [real] query-string & fragment of the URI
|
||||
urlParams: URLParams;
|
||||
// called when we have completed a token login
|
||||
onTokenLoginCompleted: () => void;
|
||||
onTokenLoginCompleted: (urlParams: URLParams, fragmentAfterLogin: string) => void;
|
||||
// Represents the screen to display as a result of parsing the initial window.location
|
||||
initialScreenAfterLogin?: IScreen;
|
||||
// displayname, if any, to set on the device when logging in/registering.
|
||||
@@ -227,11 +221,8 @@ interface IState {
|
||||
export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
public static displayName = "MatrixChat";
|
||||
|
||||
public static defaultProps = {
|
||||
realQueryParams: {},
|
||||
startingFragmentQueryParams: {},
|
||||
public static defaultProps: Partial<IProps> = {
|
||||
config: {},
|
||||
onTokenLoginCompleted: (): void => {},
|
||||
};
|
||||
|
||||
private firstSyncComplete = false;
|
||||
@@ -353,18 +344,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
|
||||
// Otherwise, the first thing to do is to try the token params in the query-string
|
||||
const delegatedAuthSucceeded = await Lifecycle.attemptDelegatedAuthLogin(
|
||||
this.props.realQueryParams,
|
||||
this.props.urlParams,
|
||||
this.props.defaultDeviceDisplayName,
|
||||
this.getFragmentAfterLogin(),
|
||||
);
|
||||
|
||||
// remove the loginToken or auth code from the URL regardless
|
||||
if (
|
||||
this.props.realQueryParams?.loginToken ||
|
||||
this.props.realQueryParams?.code ||
|
||||
this.props.realQueryParams?.state
|
||||
) {
|
||||
this.props.onTokenLoginCompleted();
|
||||
if (!!this.props.urlParams.legacy_sso || !!this.props.urlParams.oidc) {
|
||||
this.props.onTokenLoginCompleted(this.props.urlParams, this.getFragmentAfterLogin());
|
||||
}
|
||||
|
||||
if (delegatedAuthSucceeded) {
|
||||
@@ -592,7 +579,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
return Lifecycle.loadSession({
|
||||
fragmentQueryParams: this.props.startingFragmentQueryParams,
|
||||
urlParams: this.props.urlParams,
|
||||
enableGuest: this.props.enableGuest,
|
||||
guestHsUrl: this.getServerProperties().serverConfig.hsUrl,
|
||||
guestIsUrl: this.getServerProperties().serverConfig.isUrl,
|
||||
@@ -1835,7 +1822,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
public showScreen(screen: string, params?: { [key: string]: any }): void {
|
||||
public showScreen(screen: string, params?: Record<string, any>): void {
|
||||
logger.debug(`showScreen ${screen}`);
|
||||
|
||||
const cli = MatrixClientPeg.get();
|
||||
@@ -2267,14 +2254,14 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||
onForgotPasswordClick={showPasswordReset ? this.onForgotPasswordClick : undefined}
|
||||
onServerConfigChange={this.onServerConfigChange}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
defaultUsername={this.props.startingFragmentQueryParams?.defaultUsername as string | undefined}
|
||||
defaultUsername={this.props.urlParams?.defaults?.defaultUsername}
|
||||
{...this.getServerProperties()}
|
||||
/>
|
||||
);
|
||||
} else if (this.state.view === Views.SOFT_LOGOUT) {
|
||||
view = (
|
||||
<SoftLogout
|
||||
realQueryParams={this.props.realQueryParams}
|
||||
urlParams={this.props.urlParams}
|
||||
onTokenLoginCompleted={this.props.onTokenLoginCompleted}
|
||||
fragmentAfterLogin={fragmentAfterLogin}
|
||||
/>
|
||||
|
||||
@@ -26,6 +26,7 @@ import Spinner from "../../views/elements/Spinner";
|
||||
import AuthHeader from "../../views/auth/AuthHeader";
|
||||
import AuthBody from "../../views/auth/AuthBody";
|
||||
import { SDKContext } from "../../../contexts/SDKContext";
|
||||
import { type URLParams } from "../../../vector/url_utils.ts";
|
||||
|
||||
enum LoginView {
|
||||
Loading,
|
||||
@@ -43,14 +44,11 @@ const STATIC_FLOWS_TO_VIEWS: Record<string, LoginView> = {
|
||||
};
|
||||
|
||||
interface IProps {
|
||||
// Query parameters from MatrixChat
|
||||
realQueryParams: {
|
||||
loginToken?: string;
|
||||
};
|
||||
fragmentAfterLogin?: string;
|
||||
urlParams: URLParams;
|
||||
fragmentAfterLogin: string;
|
||||
|
||||
// Called when the SSO login completes
|
||||
onTokenLoginCompleted: () => void;
|
||||
onTokenLoginCompleted: (urlParams: URLParams, fragmentAfterLogin: string) => void;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@@ -98,8 +96,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||
};
|
||||
|
||||
private async initLogin(): Promise<void> {
|
||||
const queryParams = this.props.realQueryParams;
|
||||
const hasAllParams = queryParams?.["loginToken"];
|
||||
const hasAllParams = !!this.props.urlParams?.legacy_sso;
|
||||
if (hasAllParams) {
|
||||
this.setState({ loginView: LoginView.Loading });
|
||||
|
||||
@@ -189,7 +186,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||
const isUrl = localStorage.getItem(SSO_ID_SERVER_URL_KEY) || MatrixClientPeg.safeGet().getIdentityServerUrl();
|
||||
const loginType = "m.login.token";
|
||||
const loginParams = {
|
||||
token: this.props.realQueryParams["loginToken"],
|
||||
token: this.props.urlParams?.legacy_sso?.loginToken,
|
||||
device_id: MatrixClientPeg.safeGet().getDeviceId() ?? undefined,
|
||||
};
|
||||
|
||||
@@ -204,9 +201,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
||||
|
||||
return Lifecycle.hydrateSession(credentials)
|
||||
.then(() => {
|
||||
if (this.props.onTokenLoginCompleted) {
|
||||
this.props.onTokenLoginCompleted();
|
||||
}
|
||||
this.props.onTokenLoginCompleted(this.props.urlParams, this.props.fragmentAfterLogin);
|
||||
return true;
|
||||
})
|
||||
.catch((e) => {
|
||||
|
||||
Reference in New Issue
Block a user