diff --git a/examples/trivial/index.js b/examples/trivial/index.js index 5752e6bd..6e48ac1b 100644 --- a/examples/trivial/index.js +++ b/examples/trivial/index.js @@ -24,7 +24,30 @@ var React = require("react"); // maps cannot pass through two stages). var MatrixReactSdk = require("../../src/index"); -React.render( - , +function routeUrl(location) { + if (location.hash.indexOf('#/register') == 0) { + var hashparts = location.hash.split('?'); + if (hashparts.length != 2) return; + var pairs = hashparts[1].split('&'); + var params = {}; + for (var i = 0; i < pairs.length; ++i) { + var parts = pairs[i].split('='); + if (parts.length != 2) continue; + params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); + } + window.matrixChat.resumeRegistration(params); + } +} + +window.onload = function() { + routeUrl(window.location); +} + +var onNewScreen = function(screen) { + window.location.hash = '#/'+screen; +} + +window.matrixChat = React.render( + , document.getElementById('matrixchat') ); diff --git a/skins/base/views/pages/MatrixChat.js b/skins/base/views/pages/MatrixChat.js index f2480ddc..e2123b15 100644 --- a/skins/base/views/pages/MatrixChat.js +++ b/skins/base/views/pages/MatrixChat.js @@ -54,7 +54,10 @@ module.exports = React.createClass({ ); } else if (this.state.screen == 'register') { return ( - + ); } else { return ( diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js index 1ac1c679..a687aee2 100644 --- a/src/controllers/pages/MatrixChat.js +++ b/src/controllers/pages/MatrixChat.js @@ -44,6 +44,11 @@ module.exports = { this.focusComposer = false; document.addEventListener("keydown", this.onKeyDown); window.addEventListener("focus", this.onFocus); + if (this.state.logged_in) { + this.notifyNewScreen(''); + } else { + this.notifyNewScreen('login'); + } }, componentWillUnmount: function() { @@ -63,7 +68,7 @@ module.exports = { switch (payload.action) { case 'logout': - this.setState({ + this.replaceState({ logged_in: false, ready: false }); @@ -76,15 +81,17 @@ module.exports = { break; case 'start_registration': if (this.state.logged_in) return; - this.setState({ + this.replaceState({ screen: 'register' }); + this.notifyNewScreen('register'); break; case 'start_login': if (this.state.logged_in) return; - this.setState({ + this.replaceState({ screen: 'login' }); + this.notifyNewScreen('login'); break; case 'view_room': this.focusComposer = true; @@ -115,10 +122,11 @@ module.exports = { onLoggedIn: function() { this.setState({ - screen: 'register', + screen: undefined, logged_in: true }); this.startMatrixClient(); + this.notifyNewScreen(''); }, startMatrixClient: function() { @@ -155,6 +163,30 @@ module.exports = { onFocus: function(ev) { dis.dispatch({action: 'focus_composer'}); + }, + + resumeRegistration(params) { + if (!params.hs_url) return false; + if (!params.is_url) return false; + if (!params.client_secret) return false; + if (!params.session_id) return false; + if (!params.sid) return false; + if (this.state.logged_in) return false; + + this.setState({ + screen: 'register', + register_client_secret: params.client_secret, + register_session_id: params.session_id, + register_hs_url: params.hs_url, + register_is_url: params.is_url, + register_id_sid: params.sid + }); + }, + + notifyNewScreen: function(screen) { + if (this.props.onNewScreen) { + this.props.onNewScreen(screen); + } } }; diff --git a/src/controllers/templates/Login.js b/src/controllers/templates/Login.js index 48ff6dc9..714fb272 100644 --- a/src/controllers/templates/Login.js +++ b/src/controllers/templates/Login.js @@ -125,7 +125,8 @@ module.exports = { } }, - showRegister: function() { + showRegister: function(ev) { + ev.preventDefault(); dis.dispatch({ action: 'start_registration' }); diff --git a/src/controllers/templates/Register.js b/src/controllers/templates/Register.js index c562a79e..3e7f07c7 100644 --- a/src/controllers/templates/Register.js +++ b/src/controllers/templates/Register.js @@ -36,6 +36,45 @@ module.exports = { }; }, + componentWillMount: function() { + this.readNewProps(); + }, + + componentWillReceiveProps: function() { + this.readNewProps(); + }, + + readNewProps: function() { + if (this.props.clientSecret && this.props.hsUrl && + this.props.isUrl && this.props.sessionId && + this.props.idSid) { + this.authSessionId = this.props.sessionId; + MatrixClientPeg.replaceUsingUrls( + this.props.hsUrl, + this.props.isUrl + ); + this.setState({ + hs_url: this.props.hsUrl, + is_url: this.props.isUrl + }); + this.savedParams = {client_secret: this.props.clientSecret}; + this.setState({busy: true}); + + var isLocation = document.createElement('a'); + isLocation.href = this.props.isUrl; + + var auth = { + type: 'm.login.email.identity', + threepid_creds: { + sid: this.props.idSid, + client_secret: this.savedParams.client_secret, + id_server: isLocation.host + } + }; + this.tryRegister(auth); + } + }, + componentDidUpdate: function() { // Just putting a script tag into the returned jsx doesn't work, annoyingly, // so we do this instead. @@ -85,13 +124,36 @@ module.exports = { } } - if (this.savedParams.email != '') { + if ( + this.savedParams.email != '' || + this.completedStages.indexOf('m.login.email.identity' > -1) + ) { return emailFlow; } else { return otherFlow; } }, + firstUncompletedStageIndex: function(flow) { + if (this.completedStages === undefined) return 0; + for (var i = 0; i < flow.stages.length; ++i) { + if (this.completedStages.indexOf(flow.stages[i]) == -1) { + return i; + } + } + }, + + numCompletedStages: function(flow) { + if (this.completedStages === undefined) return 0; + var nCompleted = 0; + for (var i = 0; i < flow.stages.length; ++i) { + if (this.completedStages.indexOf(flow.stages[i]) > -1) { + ++nCompleted; + } + } + return nCompleted; + }, + onInitialStageSubmit: function(ev) { ev.preventDefault(); MatrixClientPeg.replaceUsingUrls( @@ -126,10 +188,24 @@ module.exports = { var cli = MatrixClientPeg.get(); this.savedParams.client_secret = cli.generateClientSecret(); this.savedParams.send_attempt = 1; + + var nextLink = window.location.protocol + '//' + + window.location.host + + window.location.pathname + + '#/register?client_secret=' + + encodeURIComponent(this.savedParams.client_secret) + + "&hs_url=" + + encodeURIComponent(this.state.hs_url) + + "&is_url=" + + encodeURIComponent(this.state.is_url) + + "&session_id=" + + encodeURIComponent(this.authSessionId); + cli.requestEmailToken( this.savedParams.email, this.savedParams.client_secret, - this.savedParams.send_attempt + this.savedParams.send_attempt, + nextLink ).done(function(response) { self.setState({ busy: false, @@ -230,28 +306,41 @@ module.exports = { ).done(function(result) { self.onRegistered(result.user_id, result.access_token); }, function(error) { - if (error.httpStatus == 401) { + if (error.httpStatus == 401 && error.data.flows) { self.authParams = error.data.params; + self.authSessionId = error.data.session; + + self.completedStages = error.data.completed; + var flow = self.chooseFlow(error.data.flows); + + var flowStage = self.firstUncompletedStageIndex(flow); + var numDone = self.numCompletedStages(flow); + self.setState({ busy: false, flows: flow, - currentStep: 1, + currentStep: 1+numDone, totalSteps: flow.stages.length+1, - flowStage: 0 + flowStage: flowStage }); - self.startStage(flow.stages[0]); + self.startStage(flow.stages[flowStage]); } else { + var errorText = "Unable to contact the given Home Server"; + if (error.httpStatus == 401) { + errorText = "Authorisation failed!"; + } self.setStep("initial"); self.setState({ busy: false, - errorText: 'Unable to contact the given Home Server' + errorText: errorText }); } }); }, - showLogin: function() { + showLogin: function(ev) { + ev.preventDefault(); dis.dispatch({ action: 'start_login' });