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.
pull/21833/head
Richard van der Hoff 2016-08-11 11:00:15 +01:00
parent 6802db05bd
commit bbfb9291f8
2 changed files with 69 additions and 59 deletions

View File

@ -15,6 +15,7 @@ limitations under the License.
*/ */
import q from 'q'; import q from 'q';
import Matrix from 'matrix-js-sdk';
import MatrixClientPeg from './MatrixClientPeg'; import MatrixClientPeg from './MatrixClientPeg';
import Notifier from './Notifier' 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 * 0. if it looks like we are in the middle of a registration process, it does
* nothing. * 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. * 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. * turn will raise on_logged_in and will_start_client events.
* *
* It returns a promise which resolves when the above process completes. * It returns a promise which resolves when the above process completes.
* *
* @param {object} opts.queryParams: string->string map of the query-parameters * @param {object} opts.realQueryParams: string->string map of the
* extracted from the #-fragment of the starting URI. * 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 * @param {boolean} opts.enableGuest: set to true to enable guest access tokens
* and auto-guest registrations. * and auto-guest registrations.
@ -55,12 +64,13 @@ import dis from './dispatcher';
* *
*/ */
export function loadSession(opts) { export function loadSession(opts) {
const queryParams = opts.queryParams || {}; const realQueryParams = opts.realQueryParams || {};
const fragmentQueryParams = opts.fragmentQueryParams || {};
let enableGuest = opts.enableGuest || false; let enableGuest = opts.enableGuest || false;
const guestHsUrl = opts.guestHsUrl; const guestHsUrl = opts.guestHsUrl;
const guestIsUrl = opts.guestIsUrl; 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 // 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 // IS, which in turn redirects back to vector. We let MatrixChat create a
// Registration component which completes the next stage of registration. // Registration component which completes the next stage of registration.
@ -73,14 +83,22 @@ export function loadSession(opts) {
enableGuest = false; 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 && if (enableGuest &&
queryParams.guest_user_id && fragmentQueryParams.guest_user_id &&
queryParams.guest_access_token fragmentQueryParams.guest_access_token
) { ) {
console.log("Using guest access credentials"); console.log("Using guest access credentials");
setLoggedIn({ setLoggedIn({
userId: queryParams.guest_user_id, userId: fragmentQueryParams.guest_user_id,
accessToken: queryParams.guest_access_token, accessToken: fragmentQueryParams.guest_access_token,
homeserverUrl: guestHsUrl, homeserverUrl: guestHsUrl,
identityServerUrl: guestIsUrl, identityServerUrl: guestIsUrl,
guest: true, guest: true,
@ -100,6 +118,27 @@ export function loadSession(opts) {
return q(); 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) { function _registerAsGuest(hsUrl, isUrl) {
console.log("Doing guest login on %s", hsUrl); console.log("Doing guest login on %s", hsUrl);

View File

@ -15,7 +15,6 @@ limitations under the License.
*/ */
var React = require('react'); var React = require('react');
var Matrix = require("matrix-js-sdk"); var Matrix = require("matrix-js-sdk");
var url = require('url');
var Favico = require('favico.js'); var Favico = require('favico.js');
var MatrixClientPeg = require("../../MatrixClientPeg"); var MatrixClientPeg = require("../../MatrixClientPeg");
@ -50,7 +49,15 @@ module.exports = React.createClass({
onNewScreen: React.PropTypes.func, onNewScreen: React.PropTypes.func,
registrationUrl: React.PropTypes.string, registrationUrl: React.PropTypes.string,
enableGuest: React.PropTypes.bool, 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: { PageTypes: {
@ -89,8 +96,10 @@ module.exports = React.createClass({
getDefaultProps: function() { getDefaultProps: function() {
return { return {
startingQueryParams: {}, realQueryParams: {},
startingFragmentQueryParams: {},
config: {}, config: {},
onLoadCompleted: () => {},
}; };
}, },
@ -171,7 +180,8 @@ module.exports = React.createClass({
this.handleResize(); this.handleResize();
Lifecycle.loadSession({ Lifecycle.loadSession({
queryParams: this.props.startingQueryParams, realQueryParams: this.props.realQueryParams,
fragmentQueryParams: this.props.startingFragmentQueryParams,
enableGuest: this.props.enableGuest, enableGuest: this.props.enableGuest,
guestHsUrl: this.getCurrentHsUrl(), guestHsUrl: this.getCurrentHsUrl(),
guestIsUrl: this.getCurrentIsUrl(), guestIsUrl: this.getCurrentIsUrl(),
@ -284,41 +294,6 @@ module.exports = React.createClass({
screen: 'forgot_password' screen: 'forgot_password'
}); });
this.notifyNewScreen('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; break;
case 'leave_room': case 'leave_room':
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
@ -552,6 +527,7 @@ module.exports = React.createClass({
* Called when the sessionloader has finished * Called when the sessionloader has finished
*/ */
_onLoadCompleted: function() { _onLoadCompleted: function() {
this.props.onLoadCompleted();
this.setState({loading: false}); this.setState({loading: false});
}, },
@ -734,11 +710,6 @@ module.exports = React.createClass({
action: 'start_login', action: 'start_login',
params: params params: params
}); });
} else if (screen == 'token_login') {
dis.dispatch({
action: 'token_login',
params: params
});
} else if (screen == 'forgot_password') { } else if (screen == 'forgot_password') {
dis.dispatch({ dis.dispatch({
action: 'start_password_recovery', action: 'start_password_recovery',
@ -994,8 +965,8 @@ module.exports = React.createClass({
// work out the HS URL prompts we should show for // work out the HS URL prompts we should show for
// console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen + console.log("rendering; loading="+this.state.loading+"; screen="+this.state.screen +
// "; logged_in="+this.state.logged_in+"; ready="+this.state.ready); "; logged_in="+this.state.logged_in+"; ready="+this.state.ready);
if (this.state.loading) { if (this.state.loading) {
var Spinner = sdk.getComponent('elements.Spinner'); var Spinner = sdk.getComponent('elements.Spinner');
@ -1099,7 +1070,7 @@ module.exports = React.createClass({
clientSecret={this.state.register_client_secret} clientSecret={this.state.register_client_secret}
sessionId={this.state.register_session_id} sessionId={this.state.register_session_id}
idSid={this.state.register_id_sid} idSid={this.state.register_id_sid}
email={this.props.startingQueryParams.email} email={this.props.startingFragmentQueryParams.email}
username={this.state.upgradeUsername} username={this.state.upgradeUsername}
guestAccessToken={this.state.guestAccessToken} guestAccessToken={this.state.guestAccessToken}
defaultHsUrl={this.getDefaultHsUrl()} defaultHsUrl={this.getDefaultHsUrl()}