From bbfb9291f8506487a5285e9ca57dd4f11287d2b2 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 11 Aug 2016 11:00:15 +0100 Subject: [PATCH] Refactor login token move the logic for handling login tokens into Lifecycle.loadSession This means it needs access to the (real) query parmeters, so it depends on corresponding changes in vector-web. --- src/Lifecycle.js | 63 +++++++++++++++++++----- src/components/structures/MatrixChat.js | 65 +++++++------------------ 2 files changed, 69 insertions(+), 59 deletions(-) diff --git a/src/Lifecycle.js b/src/Lifecycle.js index ec5dae8c57..bc7d24c707 100644 --- a/src/Lifecycle.js +++ b/src/Lifecycle.js @@ -15,6 +15,7 @@ limitations under the License. */ import q from 'q'; +import Matrix from 'matrix-js-sdk'; import MatrixClientPeg from './MatrixClientPeg'; import Notifier from './Notifier' @@ -29,20 +30,28 @@ import dis from './dispatcher'; * 0. if it looks like we are in the middle of a registration process, it does * nothing. * - * 1. if we have a guest access token in the query params, it uses that. + * 1. if we have a loginToken in the (real) query params, it uses that to log + * in. * - * 2. if an access token is stored in local storage (from a previous session), + * 2. if we have a guest access token in the fragment query params, it uses + * that. + * + * 3. if an access token is stored in local storage (from a previous session), * it uses that. * - * 3. it attempts to auto-register as a guest user. + * 4. it attempts to auto-register as a guest user. * - * If any of steps 1-3 are successful, it will call {setLoggedIn}, which in + * If any of steps 1-4 are successful, it will call {setLoggedIn}, which in * turn will raise on_logged_in and will_start_client events. * * It returns a promise which resolves when the above process completes. * - * @param {object} opts.queryParams: string->string map of the query-parameters - * extracted from the #-fragment of the starting URI. + * @param {object} opts.realQueryParams: string->string map of the + * query-parameters extracted from the real query-string of the starting + * URI. + * + * @param {object} opts.fragmentQueryParams: string->string map of the + * query-parameters extracted from the #-fragment of the starting URI. * * @param {boolean} opts.enableGuest: set to true to enable guest access tokens * and auto-guest registrations. @@ -55,12 +64,13 @@ import dis from './dispatcher'; * */ export function loadSession(opts) { - const queryParams = opts.queryParams || {}; + const realQueryParams = opts.realQueryParams || {}; + const fragmentQueryParams = opts.fragmentQueryParams || {}; let enableGuest = opts.enableGuest || false; const guestHsUrl = opts.guestHsUrl; const guestIsUrl = opts.guestIsUrl; - if (queryParams.client_secret && queryParams.sid) { + if (fragmentQueryParams.client_secret && fragmentQueryParams.sid) { // this happens during email validation: the email contains a link to the // IS, which in turn redirects back to vector. We let MatrixChat create a // Registration component which completes the next stage of registration. @@ -73,14 +83,22 @@ export function loadSession(opts) { enableGuest = false; } + if (realQueryParams.loginToken) { + if (!realQueryParams.homeserver) { + console.warn("Cannot log in with token: can't determine HS URL to use"); + } else { + return _loginWithToken(realQueryParams); + } + } + if (enableGuest && - queryParams.guest_user_id && - queryParams.guest_access_token + fragmentQueryParams.guest_user_id && + fragmentQueryParams.guest_access_token ) { console.log("Using guest access credentials"); setLoggedIn({ - userId: queryParams.guest_user_id, - accessToken: queryParams.guest_access_token, + userId: fragmentQueryParams.guest_user_id, + accessToken: fragmentQueryParams.guest_access_token, homeserverUrl: guestHsUrl, identityServerUrl: guestIsUrl, guest: true, @@ -100,6 +118,27 @@ export function loadSession(opts) { return q(); } +function _loginWithToken(queryParams) { + // create a temporary MatrixClient to do the login + var client = Matrix.createClient({ + baseUrl: queryParams.homeserver, + }); + + return client.loginWithToken(queryParams.loginToken).then(function(data) { + console.log("Logged in with token"); + setLoggedIn({ + userId: data.user_id, + accessToken: data.access_token, + homeserverUrl: queryParams.homeserver, + identityServerUrl: queryParams.identityServer, + guest: false, + }) + }, (err) => { + console.error("Failed to log in with login token: " + err + " " + + err.data); + }); +} + function _registerAsGuest(hsUrl, isUrl) { console.log("Doing guest login on %s", hsUrl); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index cb21c2aa91..ecd3ed1ab6 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -15,7 +15,6 @@ limitations under the License. */ var React = require('react'); var Matrix = require("matrix-js-sdk"); -var url = require('url'); var Favico = require('favico.js'); var MatrixClientPeg = require("../../MatrixClientPeg"); @@ -50,7 +49,15 @@ module.exports = React.createClass({ onNewScreen: React.PropTypes.func, registrationUrl: React.PropTypes.string, enableGuest: React.PropTypes.bool, - startingQueryParams: React.PropTypes.object + + // the queryParams extracted from the [real] query-string of the URI + realQueryParams: React.PropTypes.object, + + // the initial queryParams extracted from the hash-fragment of the URI + startingFragmentQueryParams: React.PropTypes.object, + + // called when the session load completes + onLoadCompleted: React.PropTypes.func, }, PageTypes: { @@ -89,8 +96,10 @@ module.exports = React.createClass({ getDefaultProps: function() { return { - startingQueryParams: {}, + realQueryParams: {}, + startingFragmentQueryParams: {}, config: {}, + onLoadCompleted: () => {}, }; }, @@ -171,7 +180,8 @@ module.exports = React.createClass({ this.handleResize(); Lifecycle.loadSession({ - queryParams: this.props.startingQueryParams, + realQueryParams: this.props.realQueryParams, + fragmentQueryParams: this.props.startingFragmentQueryParams, enableGuest: this.props.enableGuest, guestHsUrl: this.getCurrentHsUrl(), guestIsUrl: this.getCurrentIsUrl(), @@ -284,41 +294,6 @@ module.exports = React.createClass({ screen: 'forgot_password' }); this.notifyNewScreen('forgot_password'); - break; - case 'token_login': - if (this.state.logged_in) return; - - var self = this; - MatrixClientPeg.replaceUsingUrls( - payload.params.homeserver, - payload.params.identityServer - ); - - var client = MatrixClientPeg.get(); - client.loginWithToken(payload.params.loginToken).done(function(data) { - MatrixClientPeg.replaceUsingCreds({ - homeserverUrl: client.getHomeserverUrl(), - identityServerUrl: client.getIdentityServerUrl(), - userId: data.user_id, - accessToken: data.access_token, - guest: false, - }); - self.setState({ - screen: undefined, - logged_in: true - }); - - // We're left with the login token, hs and is url as query params - // in the url, a little nasty but let's redirect to clear them - var parsedUrl = url.parse(window.location.href); - parsedUrl.search = ""; - window.location.href = url.format(parsedUrl); - - }, function(error) { - self.notifyNewScreen('login'); - self.setState({errorText: 'Login failed.'}); - }); - break; case 'leave_room': var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -552,6 +527,7 @@ module.exports = React.createClass({ * Called when the sessionloader has finished */ _onLoadCompleted: function() { + this.props.onLoadCompleted(); this.setState({loading: false}); }, @@ -734,11 +710,6 @@ module.exports = React.createClass({ action: 'start_login', params: params }); - } else if (screen == 'token_login') { - dis.dispatch({ - action: 'token_login', - params: params - }); } else if (screen == 'forgot_password') { dis.dispatch({ action: 'start_password_recovery', @@ -994,8 +965,8 @@ module.exports = React.createClass({ // work out the HS URL prompts we should show for - // console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen + - // "; logged_in="+this.state.logged_in+"; ready="+this.state.ready); + console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen + + "; logged_in="+this.state.logged_in+"; ready="+this.state.ready); if (this.state.loading) { var Spinner = sdk.getComponent('elements.Spinner'); @@ -1099,7 +1070,7 @@ module.exports = React.createClass({ clientSecret={this.state.register_client_secret} sessionId={this.state.register_session_id} idSid={this.state.register_id_sid} - email={this.props.startingQueryParams.email} + email={this.props.startingFragmentQueryParams.email} username={this.state.upgradeUsername} guestAccessToken={this.state.guestAccessToken} defaultHsUrl={this.getDefaultHsUrl()}