Date: Tue, 12 May 2020 17:17:17 -0600
Subject: [PATCH 10/86] Acquire a new session before enacting deactivation
Fixes https://github.com/vector-im/riot-web/issues/13645
Every time the checkbox value changes we acquire a new session now. This avoids us asking the server to change its direction partway through the request.
This causes a bit of UI jerk as the dialog goes from auth -> loading -> auth, however it's better than the alternative of reworking the entire UIA structure to support the `authData` dict changing. Originally this commit consisted of a `disabled` flag on the `InteractiveAuth` component which carried through to the stage's component, however it turns out that stack doesn't respect changes to the `authData` prop, which means the session ID we eventually send down is wrong (`erase: false` instead of the one with `erase: true`). Therefore, we do some logic to ensure we remount `InteractiveAuth` completely.
Further work in this area is described in https://github.com/vector-im/riot-web/issues/13646
---
.../views/dialogs/DeactivateAccountDialog.js | 46 ++++++++++++-------
1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/src/components/views/dialogs/DeactivateAccountDialog.js b/src/components/views/dialogs/DeactivateAccountDialog.js
index b269ec2fdb..d84042011d 100644
--- a/src/components/views/dialogs/DeactivateAccountDialog.js
+++ b/src/components/views/dialogs/DeactivateAccountDialog.js
@@ -34,6 +34,7 @@ export default class DeactivateAccountDialog extends React.Component {
shouldErase: false,
errStr: null,
authData: null, // for UIA
+ authEnabled: true, // see usages for information
// A few strings that are passed to InteractiveAuth for design or are displayed
// next to the InteractiveAuth component.
@@ -42,21 +43,7 @@ export default class DeactivateAccountDialog extends React.Component {
continueKind: null,
};
- MatrixClientPeg.get().deactivateAccount(null, false).then(r => {
- // If we got here, oops. The server didn't require any auth.
- // Our application lifecycle will catch the error and do the logout bits.
- // We'll try to log something in an vain attempt to record what happened (storage
- // is also obliterated on logout).
- console.warn("User's account got deactivated without confirmation: Server had no auth");
- this.setState({errStr: _t("Server did not require any authentication")});
- }).catch(e => {
- if (e && e.httpStatus === 401 && e.data) {
- // Valid UIA response
- this.setState({authData: e.data});
- } else {
- this.setState({errStr: _t("Server did not return valid authentication information.")});
- }
- });
+ this._initAuth(/* shouldErase= */false);
}
_onStagePhaseChange = (stage, phase) => {
@@ -124,13 +111,40 @@ export default class DeactivateAccountDialog extends React.Component {
_onEraseFieldChange = (ev) => {
this.setState({
shouldErase: ev.target.checked,
+
+ // Disable the auth form because we're going to have to reinitialize the auth
+ // information. We do this because we can't modify the parameters in the UIA
+ // session, and the user will have selected something which changes the request.
+ // Therefore, we throw away the last auth session and try a new one.
+ authEnabled: false,
});
+
+ // As mentioned above, set up for auth again to get updated UIA session info
+ this._initAuth(/* shouldErase= */ev.target.checked);
};
_onCancel() {
this.props.onFinished(false);
}
+ _initAuth(shouldErase) {
+ MatrixClientPeg.get().deactivateAccount(null, shouldErase).then(r => {
+ // If we got here, oops. The server didn't require any auth.
+ // Our application lifecycle will catch the error and do the logout bits.
+ // We'll try to log something in an vain attempt to record what happened (storage
+ // is also obliterated on logout).
+ console.warn("User's account got deactivated without confirmation: Server had no auth");
+ this.setState({errStr: _t("Server did not require any authentication")});
+ }).catch(e => {
+ if (e && e.httpStatus === 401 && e.data) {
+ // Valid UIA response
+ this.setState({authData: e.data, authEnabled: true});
+ } else {
+ this.setState({errStr: _t("Server did not return valid authentication information.")});
+ }
+ });
+ };
+
render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
@@ -142,7 +156,7 @@ export default class DeactivateAccountDialog extends React.Component {
}
let auth = {_t("Loading...")}
;
- if (this.state.authData) {
+ if (this.state.authData && this.state.authEnabled) {
auth = (
{this.state.bodyText}
From 5e86dc2d60cf0a3b9bbfef6baabc23aafb2cccb6 Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Tue, 12 May 2020 17:20:11 -0600
Subject: [PATCH 11/86] Update i18n strings
---
src/i18n/strings/en_EN.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index b2fe409aa5..30e033bb43 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1589,13 +1589,13 @@
"You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ": "You've previously used a newer version of Riot on %(host)s. To use this version again with end to end encryption, you will need to sign out and back in again. ",
"Incompatible Database": "Incompatible Database",
"Continue With Encryption Disabled": "Continue With Encryption Disabled",
- "Server did not require any authentication": "Server did not require any authentication",
- "Server did not return valid authentication information.": "Server did not return valid authentication information.",
"Confirm your account deactivation by using Single Sign On to prove your identity.": "Confirm your account deactivation by using Single Sign On to prove your identity.",
"Are you sure you want to deactivate your account? This is irreversible.": "Are you sure you want to deactivate your account? This is irreversible.",
"Confirm account deactivation": "Confirm account deactivation",
"To continue, please enter your password:": "To continue, please enter your password:",
"There was a problem communicating with the server. Please try again.": "There was a problem communicating with the server. Please try again.",
+ "Server did not require any authentication": "Server did not require any authentication",
+ "Server did not return valid authentication information.": "Server did not return valid authentication information.",
"This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.": "This will make your account permanently unusable. You will not be able to log in, and no one will be able to re-register the same user ID. This will cause your account to leave all rooms it is participating in, and it will remove your account details from your identity server. This action is irreversible.",
"Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.": "Deactivating your account does not by default cause us to forget messages you have sent. If you would like us to forget your messages, please tick the box below.",
"Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.": "Message visibility in Matrix is similar to email. Our forgetting your messages means that messages you have sent will not be shared with any new or unregistered users, but registered users who already have access to these messages will still have access to their copy.",
From 6d90a9d1a31170e497609eee9519ffd12ceff0af Mon Sep 17 00:00:00 2001
From: Travis Ralston
Date: Tue, 12 May 2020 17:20:26 -0600
Subject: [PATCH 12/86] Appease the linter
---
src/components/views/dialogs/DeactivateAccountDialog.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/views/dialogs/DeactivateAccountDialog.js b/src/components/views/dialogs/DeactivateAccountDialog.js
index d84042011d..ffef2a30c7 100644
--- a/src/components/views/dialogs/DeactivateAccountDialog.js
+++ b/src/components/views/dialogs/DeactivateAccountDialog.js
@@ -143,7 +143,7 @@ export default class DeactivateAccountDialog extends React.Component {
this.setState({errStr: _t("Server did not return valid authentication information.")});
}
});
- };
+ }
render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
From d8b6b7b976607d697125b4bdfa5c30b2912edf1c Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Wed, 13 May 2020 06:24:04 +0100
Subject: [PATCH 13/86] Pass screenAfterLogin through SSO in the callback url
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/BasePlatform.js | 14 ++++++--------
src/components/structures/MatrixChat.tsx | 9 ++++++++-
src/components/structures/auth/Login.js | 7 +++++--
src/components/structures/auth/SoftLogout.js | 4 +++-
src/components/views/auth/Welcome.js | 3 ++-
src/components/views/elements/SSOButton.js | 5 +++--
6 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/src/BasePlatform.js b/src/BasePlatform.js
index 7214031586..8a950dc2e3 100644
--- a/src/BasePlatform.js
+++ b/src/BasePlatform.js
@@ -167,13 +167,9 @@ export default class BasePlatform {
setLanguage(preferredLangs: string[]) {}
- getSSOCallbackUrl(hsUrl: string, isUrl: string): URL {
+ getSSOCallbackUrl(hsUrl: string, isUrl: string, fragmentAfterLogin: string): URL {
const url = new URL(window.location.href);
- // XXX: at this point, the fragment will always be #/login, which is no
- // use to anyone. Ideally, we would get the intended fragment from
- // MatrixChat.screenAfterLogin so that you could follow #/room links etc
- // through an SSO login.
- url.hash = "";
+ url.hash = fragmentAfterLogin || "";
url.searchParams.set("homeserver", hsUrl);
url.searchParams.set("identityServer", isUrl);
return url;
@@ -183,9 +179,11 @@ export default class BasePlatform {
* Begin Single Sign On flows.
* @param {MatrixClient} mxClient the matrix client using which we should start the flow
* @param {"sso"|"cas"} loginType the type of SSO it is, CAS/SSO.
+ * @param {string} fragmentAfterLogin the hash to pass to the app during sso callback.
*/
- startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas") {
- const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl());
+ startSingleSignOn(mxClient: MatrixClient, loginType: "sso" | "cas", fragmentAfterLogin: string) {
+ const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl(),
+ fragmentAfterLogin);
window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO
}
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index 3929711406..8ff8abb190 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -1973,6 +1973,11 @@ export default class MatrixChat extends React.PureComponent {
render() {
// console.log(`Rendering MatrixChat with view ${this.state.view}`);
+ let fragmentAfterLogin = "";
+ if (this.props.initialScreenAfterLogin) {
+ fragmentAfterLogin = `/${this.props.initialScreenAfterLogin.screen}`;
+ }
+
let view;
if (this.state.view === Views.LOADING) {
@@ -2052,7 +2057,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 = (
@@ -2091,6 +2096,7 @@ export default class MatrixChat extends React.PureComponent {
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
onForgotPasswordClick={this.onForgotPasswordClick}
onServerConfigChange={this.onServerConfigChange}
+ fragmentAfterLogin={fragmentAfterLogin}
{...this.getServerProperties()}
/>
);
@@ -2100,6 +2106,7 @@ export default class MatrixChat extends React.PureComponent {
);
} else {
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index 5d3cb69417..e65a223bd6 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -355,7 +355,8 @@ export default createReactClass({
ev.preventDefault();
ev.stopPropagation();
const ssoKind = step === 'm.login.sso' ? 'sso' : 'cas';
- PlatformPeg.get().startSingleSignOn(this._loginLogic.createTemporaryClient(), ssoKind);
+ PlatformPeg.get().startSingleSignOn(this._loginLogic.createTemporaryClient(), ssoKind,
+ this.props.fragmentAfterLogin);
} else {
// Don't intercept - just go through to the register page
this.onRegisterClick(ev);
@@ -628,7 +629,9 @@ export default createReactClass({
+ loginType={loginType}
+ fragmentAfterLogin={this.props.fragmentAfterLogin}
+ />
);
},
diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js
index 08ab7e8a61..ede1041f8a 100644
--- a/src/components/structures/auth/SoftLogout.js
+++ b/src/components/structures/auth/SoftLogout.js
@@ -244,7 +244,9 @@ export default class SoftLogout extends React.Component {
{introText}
+ loginType={this.state.loginView === LOGIN_VIEW.CAS ? "cas" : "sso"}
+ fragmentAfterLogin={this.props.fragmentAfterLogin}
+ />