diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index a93492cd41..db5b7d034b 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -283,29 +283,32 @@ export default React.createClass({
}
// the first thing to do is to try the token params in the query-string
- Lifecycle.attemptTokenLogin(this.props.realQueryParams).then((loggedIn) => {
- if (loggedIn) {
- this.props.onTokenLoginCompleted();
+ // if the session isn't soft logged out (ie: is a clean session being logged in)
+ if (!Lifecycle.isSoftLogout()) {
+ Lifecycle.attemptTokenLogin(this.props.realQueryParams).then((loggedIn) => {
+ if (loggedIn) {
+ this.props.onTokenLoginCompleted();
- // don't do anything else until the page reloads - just stay in
- // the 'loading' state.
- return;
- }
+ // don't do anything else until the page reloads - just stay in
+ // the 'loading' state.
+ return;
+ }
- // if the user has followed a login or register link, don't reanimate
- // the old creds, but rather go straight to the relevant page
- const firstScreen = this._screenAfterLogin ?
- this._screenAfterLogin.screen : null;
+ // if the user has followed a login or register link, don't reanimate
+ // the old creds, but rather go straight to the relevant page
+ const firstScreen = this._screenAfterLogin ?
+ this._screenAfterLogin.screen : null;
- if (firstScreen === 'login' ||
+ if (firstScreen === 'login' ||
firstScreen === 'register' ||
firstScreen === 'forgot_password') {
- this._showScreenAfterLogin();
- return;
- }
+ this._showScreenAfterLogin();
+ return;
+ }
- return this._loadSession();
- });
+ return this._loadSession();
+ });
+ }
if (SettingsStore.getValue("showCookieBar")) {
this.setState({
@@ -1250,10 +1253,7 @@ export default React.createClass({
this._screenAfterLogin = null;
} else if (localStorage && localStorage.getItem('mx_last_room_id')) {
// Before defaulting to directory, show the last viewed room
- dis.dispatch({
- action: 'view_room',
- room_id: localStorage.getItem('mx_last_room_id'),
- });
+ this._viewLastRoom();
} else {
if (MatrixClientPeg.get().isGuest()) {
dis.dispatch({action: 'view_welcome_page'});
@@ -1267,6 +1267,13 @@ export default React.createClass({
}
},
+ _viewLastRoom: function() {
+ dis.dispatch({
+ action: 'view_room',
+ room_id: localStorage.getItem('mx_last_room_id'),
+ });
+ },
+
/**
* Called when the session is logged out
*/
@@ -1565,6 +1572,17 @@ export default React.createClass({
action: 'start_password_recovery',
params: params,
});
+ } else if (screen === 'soft_logout') {
+ if (MatrixClientPeg.get() && MatrixClientPeg.get().getUserId() && !Lifecycle.isSoftLogout()) {
+ // Logged in - visit a room
+ this._viewLastRoom();
+ } else {
+ // Ultimately triggers soft_logout if needed
+ dis.dispatch({
+ action: 'start_login',
+ params: params,
+ });
+ }
} else if (screen == 'new') {
dis.dispatch({
action: 'view_create_room',
@@ -1957,7 +1975,10 @@ export default React.createClass({
if (this.state.view === VIEWS.SOFT_LOGOUT) {
const SoftLogout = sdk.getComponent('structures.auth.SoftLogout');
return (
-
+
);
}
diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js
index bd6a5912e2..8bfa458c28 100644
--- a/src/components/structures/auth/SoftLogout.js
+++ b/src/components/structures/auth/SoftLogout.js
@@ -15,6 +15,7 @@ limitations under the License.
*/
import React from 'react';
+import PropTypes from 'prop-types';
import {_t} from '../../../languageHandler';
import sdk from '../../../index';
import dis from '../../../dispatcher';
@@ -24,6 +25,7 @@ import {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
import SdkConfig from "../../../SdkConfig";
import MatrixClientPeg from "../../../MatrixClientPeg";
import {sendLoginRequest} from "../../../Login";
+import url from 'url';
const LOGIN_VIEW = {
LOADING: 1,
@@ -41,7 +43,11 @@ const FLOWS_TO_VIEWS = {
export default class SoftLogout extends React.Component {
static propTypes = {
- // Nothing.
+ // Query parameters from MatrixChat
+ realQueryParams: PropTypes.object, // {homeserver, identityServer, loginToken}
+
+ // Called when the SSO login completes
+ onTokenLoginCompleted: PropTypes.func,
};
constructor() {
@@ -67,6 +73,7 @@ export default class SoftLogout extends React.Component {
displayName,
loginView: LOGIN_VIEW.LOADING,
keyBackupNeeded: true, // assume we do while we figure it out (see componentWillMount)
+ ssoUrl: null,
busy: false,
password: "",
@@ -75,6 +82,12 @@ export default class SoftLogout extends React.Component {
}
componentDidMount(): void {
+ // We've ended up here when we don't need to - navigate to login
+ if (!Lifecycle.isSoftLogout()) {
+ dis.dispatch({action: "on_logged_in"});
+ return;
+ }
+
this._initLogin();
MatrixClientPeg.get().flagAllGroupSessionsForBackup().then(remaining => {
@@ -95,6 +108,14 @@ export default class SoftLogout extends React.Component {
};
async _initLogin() {
+ const queryParams = this.props.realQueryParams;
+ const hasAllParams = queryParams && queryParams['homeserver'] && queryParams['loginToken'];
+ if (hasAllParams) {
+ this.setState({loginView: LOGIN_VIEW.LOADING});
+ this.trySsoLogin();
+ return;
+ }
+
// Note: we don't use the existing Login class because it is heavily flow-based. We don't
// care about login flows here, unless it is the single flow we support.
const client = MatrixClientPeg.get();
@@ -102,6 +123,18 @@ export default class SoftLogout extends React.Component {
const chosenView = loginViews.filter(f => !!f)[0] || LOGIN_VIEW.UNSUPPORTED;
this.setState({loginView: chosenView});
+
+ if (chosenView === LOGIN_VIEW.CAS || chosenView === LOGIN_VIEW.SSO) {
+ const client = MatrixClientPeg.get();
+
+ const appUrl = url.parse(window.location.href, true);
+ appUrl.hash = ""; // Clear #/soft_logout off the URL
+ appUrl.query["homeserver"] = client.getHomeserverUrl();
+ appUrl.query["identityServer"] = client.getIdentityServerUrl();
+
+ const ssoUrl = client.getSsoLoginUrl(url.format(appUrl), chosenView === LOGIN_VIEW.CAS ? "cas" : "sso");
+ this.setState({ssoUrl});
+ }
}
onPasswordChange = (ev) => {
@@ -152,12 +185,55 @@ export default class SoftLogout extends React.Component {
});
};
+ async trySsoLogin() {
+ this.setState({busy: true});
+
+ const hsUrl = this.props.realQueryParams['homeserver'];
+ const isUrl = this.props.realQueryParams['identityServer'] || MatrixClientPeg.get().getIdentityServerUrl();
+ const loginType = "m.login.token";
+ const loginParams = {
+ token: this.props.realQueryParams['loginToken'],
+ device_id: MatrixClientPeg.get().getDeviceId(),
+ };
+
+ let credentials = null;
+ try {
+ credentials = await sendLoginRequest(hsUrl, isUrl, loginType, loginParams);
+ } catch (e) {
+ console.error(e);
+ this.setState({busy: false, loginView: LOGIN_VIEW.UNSUPPORTED});
+ return;
+ }
+
+ Lifecycle.hydrateSession(credentials).then(() => {
+ if (this.props.onTokenLoginCompleted) this.props.onTokenLoginCompleted();
+ }).catch((e) => {
+ console.error(e);
+ this.setState({busy: false, loginView: LOGIN_VIEW.UNSUPPORTED});
+ });
+ }
+
+ onSsoLogin = async (ev) => {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ this.setState({busy: true});
+ window.location.href = this.state.ssoUrl;
+ };
+
_renderSignInSection() {
if (this.state.loginView === LOGIN_VIEW.LOADING) {
const Spinner = sdk.getComponent("elements.Spinner");
return ;
}
+ let introText = null; // null is translated to something area specific in this function
+ if (this.state.keyBackupNeeded) {
+ introText = _t(
+ "Regain access to your account and recover encryption keys stored on this device. " +
+ "Without them, you won’t be able to read all of your secure messages on any device.");
+ }
+
if (this.state.loginView === LOGIN_VIEW.PASSWORD) {
const Field = sdk.getComponent("elements.Field");
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
@@ -167,12 +243,9 @@ export default class SoftLogout extends React.Component {
error = {this.state.errorText};
}
- let introText = _t("Enter your password to sign in and regain access to your account.");
- if (this.state.keyBackupNeeded) {
- introText = _t(
- "Regain access your account and recover encryption keys stored on this device. " +
- "Without them, you won’t be able to read all of your secure messages on any device.");
- }
+ if (!introText) {
+ introText = _t("Enter your password to sign in and regain access to your account.");
+ } // else we already have a message and should use it (key backup warning)
return (