From 3524d678f7f5dd1a842a9a409f3bee0b97b2bd64 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 25 Jun 2020 21:24:24 +0100 Subject: [PATCH 1/6] Fix Welcome.html URLs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/BasePlatform.ts | 15 ++++++++++----- src/components/views/auth/Welcome.js | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index d54dc7dd23..aed063ca32 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -227,6 +227,15 @@ export default abstract class BasePlatform { return url; } + // persist hs url and is url for when the user is returned to the app with the login token + // MUST be called before using URLs from getSSOCallbackUrl, internally called by startSingleSignOn + persistSSODetails(mxClient: MatrixClient) { + localStorage.setItem(HOMESERVER_URL_KEY, mxClient.getHomeserverUrl()); + if (mxClient.getIdentityServerUrl()) { + localStorage.setItem(ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl()); + } + } + /** * Begin Single Sign On flows. * @param {MatrixClient} mxClient the matrix client using which we should start the flow @@ -234,11 +243,7 @@ export default abstract class BasePlatform { * @param {string} fragmentAfterLogin the hash to pass to the app during sso callback. */ startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) { - // persist hs url and is url for when the user is returned to the app with the login token - localStorage.setItem(HOMESERVER_URL_KEY, mxClient.getHomeserverUrl()); - if (mxClient.getIdentityServerUrl()) { - localStorage.setItem(ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl()); - } + this.persistSSODetails(mxClient); const callbackUrl = this.getSSOCallbackUrl(fragmentAfterLogin); window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO } diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 91ba368f70..c01b846739 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -45,8 +45,8 @@ export default class Welcome extends React.PureComponent { idBaseUrl: isUrl, }); const plaf = PlatformPeg.get(); - const callbackUrl = plaf.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl(), - this.props.fragmentAfterLogin); + plaf.persistSSODetails(tmpClient); + const callbackUrl = plaf.getSSOCallbackUrl(this.props.fragmentAfterLogin); return ( From 1c00ae8dd35857bc052b21ee882e863e205e9e2b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 25 Jun 2020 21:59:46 +0100 Subject: [PATCH 2/6] Move to mx_sso_hs_url and co for sso persistance to not conflict with guest creds Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/BasePlatform.ts | 21 ++++++++------------ src/Lifecycle.js | 9 ++++++--- src/components/structures/auth/SoftLogout.js | 6 +++--- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/BasePlatform.ts b/src/BasePlatform.ts index aed063ca32..1d11495e61 100644 --- a/src/BasePlatform.ts +++ b/src/BasePlatform.ts @@ -25,8 +25,8 @@ import {CheckUpdatesPayload} from "./dispatcher/payloads/CheckUpdatesPayload"; import {Action} from "./dispatcher/actions"; import {hideToast as hideUpdateToast} from "./toasts/UpdateToast"; -export const HOMESERVER_URL_KEY = "mx_hs_url"; -export const ID_SERVER_URL_KEY = "mx_is_url"; +export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url"; +export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url"; export enum UpdateCheckStatus { Checking = "CHECKING", @@ -221,21 +221,12 @@ export default abstract class BasePlatform { setLanguage(preferredLangs: string[]) {} - getSSOCallbackUrl(fragmentAfterLogin: string): URL { + protected getSSOCallbackUrl(fragmentAfterLogin: string): URL { const url = new URL(window.location.href); url.hash = fragmentAfterLogin || ""; return url; } - // persist hs url and is url for when the user is returned to the app with the login token - // MUST be called before using URLs from getSSOCallbackUrl, internally called by startSingleSignOn - persistSSODetails(mxClient: MatrixClient) { - localStorage.setItem(HOMESERVER_URL_KEY, mxClient.getHomeserverUrl()); - if (mxClient.getIdentityServerUrl()) { - localStorage.setItem(ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl()); - } - } - /** * Begin Single Sign On flows. * @param {MatrixClient} mxClient the matrix client using which we should start the flow @@ -243,7 +234,11 @@ export default abstract class BasePlatform { * @param {string} fragmentAfterLogin the hash to pass to the app during sso callback. */ startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) { - this.persistSSODetails(mxClient); + // persist hs url and is url for when the user is returned to the app with the login token + localStorage.setItem(SSO_HOMESERVER_URL_KEY, mxClient.getHomeserverUrl()); + if (mxClient.getIdentityServerUrl()) { + localStorage.setItem(SSO_ID_SERVER_URL_KEY, mxClient.getIdentityServerUrl()); + } const callbackUrl = this.getSSOCallbackUrl(fragmentAfterLogin); window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO } diff --git a/src/Lifecycle.js b/src/Lifecycle.js index 96cefaf593..facde3011c 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -41,7 +41,10 @@ import {IntegrationManagers} from "./integrations/IntegrationManagers"; import {Mjolnir} from "./mjolnir/Mjolnir"; import DeviceListener from "./DeviceListener"; import {Jitsi} from "./widgets/Jitsi"; -import {HOMESERVER_URL_KEY, ID_SERVER_URL_KEY} from "./BasePlatform"; +import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "./BasePlatform"; + +export const HOMESERVER_URL_KEY = "mx_hs_url"; +export const ID_SERVER_URL_KEY = "mx_is_url"; /** * Called at startup, to attempt to build a logged-in Matrix session. It tries @@ -164,8 +167,8 @@ export function attemptTokenLogin(queryParams, defaultDeviceDisplayName) { return Promise.resolve(false); } - const homeserver = localStorage.getItem(HOMESERVER_URL_KEY); - const identityServer = localStorage.getItem(ID_SERVER_URL_KEY); + const homeserver = localStorage.getItem(SSO_HOMESERVER_URL_KEY); + 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"); return Promise.resolve(false); diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js index a2824b63a3..6577386fae 100644 --- a/src/components/structures/auth/SoftLogout.js +++ b/src/components/structures/auth/SoftLogout.js @@ -25,7 +25,7 @@ import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {sendLoginRequest} from "../../../Login"; import AuthPage from "../../views/auth/AuthPage"; import SSOButton from "../../views/elements/SSOButton"; -import {HOMESERVER_URL_KEY, ID_SERVER_URL_KEY} from "../../../BasePlatform"; +import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "../../../BasePlatform"; const LOGIN_VIEW = { LOADING: 1, @@ -158,8 +158,8 @@ export default class SoftLogout extends React.Component { async trySsoLogin() { this.setState({busy: true}); - const hsUrl = localStorage.getItem(HOMESERVER_URL_KEY); - const isUrl = localStorage.getItem(ID_SERVER_URL_KEY) || MatrixClientPeg.get().getIdentityServerUrl(); + const hsUrl = localStorage.getItem(SSO_HOMESERVER_URL_KEY); + const isUrl = localStorage.getItem(SSO_ID_SERVER_URL_KEY) || MatrixClientPeg.get().getIdentityServerUrl(); const loginType = "m.login.token"; const loginParams = { token: this.props.realQueryParams['loginToken'], From c65ccbcacf1ab3096c405434da6ec91349aebf75 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 25 Jun 2020 22:00:22 +0100 Subject: [PATCH 3/6] Instead of passing sso and cas urls to Welcome, route via start_sso and start_cas Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/MatrixChat.tsx | 26 ++++++++++++++++++++---- src/components/views/auth/Welcome.js | 15 ++------------ 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index d5f73fa3df..a48b1e62a9 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -18,6 +18,7 @@ limitations under the License. */ import React, { createRef } from 'react'; +import { createClient } from "matrix-js-sdk"; import { InvalidStoreError } from "matrix-js-sdk/src/errors"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; @@ -1612,6 +1613,19 @@ export default class MatrixChat extends React.PureComponent { }); } else if (screen === 'directory') { dis.fire(Action.ViewRoomDirectory); + } else if (screen === "start_sso" || screen === "start_cas") { + // TODO if logged in, skip SSO + let cli = MatrixClientPeg.get(); + if (!cli) { + const {hsUrl, isUrl} = this.props.serverConfig; + cli = createClient({ + baseUrl: hsUrl, + idBaseUrl: isUrl, + }); + } + + const type = screen === "start_sso" ? "sso" : "cas"; + PlatformPeg.get().startSingleSignOn(cli, type, this.getFragmentAfterLogin()); } else if (screen === 'groups') { dis.dispatch({ action: 'view_my_groups', @@ -1922,9 +1936,7 @@ export default class MatrixChat extends React.PureComponent { this.onLoggedIn(); }; - render() { - // console.log(`Rendering MatrixChat with view ${this.state.view}`); - + getFragmentAfterLogin() { let fragmentAfterLogin = ""; if (this.props.initialScreenAfterLogin && // XXX: workaround for https://github.com/vector-im/riot-web/issues/11643 causing a login-loop @@ -1932,7 +1944,13 @@ export default class MatrixChat extends React.PureComponent { ) { fragmentAfterLogin = `/${this.props.initialScreenAfterLogin.screen}`; } + return fragmentAfterLogin; + } + render() { + // console.log(`Rendering MatrixChat with view ${this.state.view}`); + + const fragmentAfterLogin = this.getFragmentAfterLogin(); let view; if (this.state.view === Views.LOADING) { @@ -2011,7 +2029,7 @@ export default class MatrixChat extends React.PureComponent { } } else if (this.state.view === Views.WELCOME) { const Welcome = sdk.getComponent('auth.Welcome'); - view = ; + view = ; } else if (this.state.view === Views.REGISTER) { const Registration = sdk.getComponent('structures.auth.Registration'); view = ( diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index c01b846739..5a30a02490 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -18,9 +18,7 @@ import React from 'react'; import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; -import * as Matrix from "matrix-js-sdk"; import {_td} from "../../../languageHandler"; -import PlatformPeg from "../../../PlatformPeg"; // translatable strings for Welcome pages _td("Sign in with SSO"); @@ -39,15 +37,6 @@ export default class Welcome extends React.PureComponent { pageUrl = 'welcome.html'; } - const {hsUrl, isUrl} = this.props.serverConfig; - const tmpClient = Matrix.createClient({ - baseUrl: hsUrl, - idBaseUrl: isUrl, - }); - const plaf = PlatformPeg.get(); - plaf.persistSSODetails(tmpClient); - const callbackUrl = plaf.getSSOCallbackUrl(this.props.fragmentAfterLogin); - return (
@@ -55,8 +44,8 @@ export default class Welcome extends React.PureComponent { className="mx_WelcomePage" url={pageUrl} replaceMap={{ - "$riot:ssoUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "sso"), - "$riot:casUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "cas"), + "$riot:ssoUrl": "#/start_sso", + "$riot:casUrl": "#/start_cas", }} /> From f02c52b758439022b1746d0006d2e54dd1163ec0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 25 Jun 2020 22:01:41 +0100 Subject: [PATCH 4/6] unexport things which need not exporting Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/Lifecycle.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lifecycle.js b/src/Lifecycle.js index facde3011c..9ae4ae7e03 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -43,8 +43,8 @@ import DeviceListener from "./DeviceListener"; import {Jitsi} from "./widgets/Jitsi"; import {SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY} from "./BasePlatform"; -export const HOMESERVER_URL_KEY = "mx_hs_url"; -export const ID_SERVER_URL_KEY = "mx_is_url"; +const HOMESERVER_URL_KEY = "mx_hs_url"; +const ID_SERVER_URL_KEY = "mx_is_url"; /** * Called at startup, to attempt to build a logged-in Matrix session. It tries From 29b0505bdbbfe21162d4a0c978a06238dc5f0991 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 25 Jun 2020 22:02:39 +0100 Subject: [PATCH 5/6] Welcome no longer needs any props Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/MatrixChat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index a48b1e62a9..26621fb439 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -2029,7 +2029,7 @@ export default class MatrixChat extends React.PureComponent { } } else if (this.state.view === Views.WELCOME) { const Welcome = sdk.getComponent('auth.Welcome'); - view = ; + view = ; } else if (this.state.view === Views.REGISTER) { const Registration = sdk.getComponent('structures.auth.Registration'); view = ( From 6116cfc2b96d753dbbe32b88c0ae8f715ad9a2de Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 25 Jun 2020 23:52:32 +0100 Subject: [PATCH 6/6] js-sdk imports suck Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/MatrixChat.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 26621fb439..7f838f1e9e 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -18,7 +18,7 @@ limitations under the License. */ import React, { createRef } from 'react'; -import { createClient } from "matrix-js-sdk"; +import { createClient } from "matrix-js-sdk/src"; import { InvalidStoreError } from "matrix-js-sdk/src/errors"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; @@ -1948,8 +1948,6 @@ export default class MatrixChat extends React.PureComponent { } render() { - // console.log(`Rendering MatrixChat with view ${this.state.view}`); - const fragmentAfterLogin = this.getFragmentAfterLogin(); let view;