diff --git a/src/Signup.js b/src/Signup.js index 5b368b4811..4518955d95 100644 --- a/src/Signup.js +++ b/src/Signup.js @@ -293,8 +293,9 @@ class Register extends Signup { class Login extends Signup { - constructor(hsUrl, isUrl) { + constructor(hsUrl, isUrl, fallbackHsUrl) { super(hsUrl, isUrl); + this._fallbackHsUrl = fallbackHsUrl; this._currentFlowIndex = 0; this._flows = []; } @@ -359,6 +360,30 @@ class Login extends Signup { error.friendlyText = ( 'Incorrect username and/or password.' ); + if (self._fallbackHsUrl) { + // as per elsewhere, it would be much nicer to not replace the global + // client just to try an alternate HS + MatrixClientPeg.replaceUsingUrls( + self._fallbackHsUrl, + self._isUrl + ); + return MatrixClientPeg.get().login('m.login.password', loginParams).then(function(data) { + return q({ + homeserverUrl: self._fallbackHsUrl, + identityServerUrl: self._isUrl, + userId: data.user_id, + accessToken: data.access_token + }); + }, function(fallback_error) { + // We also have to put the default back again if it fails... + MatrixClientPeg.replaceUsingUrls( + this._hsUrl, + this._isUrl + ); + // throw the original error + throw error; + }); + } } else { error.friendlyText = ( diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 255f7c9b92..2f7a6ed8ec 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -103,6 +103,10 @@ module.exports = React.createClass({ return "https://matrix.org"; }, + getFallbackHsUrl: function() { + return this.props.config.fallback_hs_url; + }, + getCurrentIsUrl: function() { if (this.state.register_is_url) { return this.state.register_is_url; @@ -1183,6 +1187,7 @@ module.exports = React.createClass({ defaultIsUrl={this.props.config.default_is_url} customHsUrl={this.getCurrentHsUrl()} customIsUrl={this.getCurrentIsUrl()} + fallbackHsUrl={this.getFallbackHsUrl()} onForgotPasswordClick={this.onForgotPasswordClick} onLoginAsGuestClick={this.props.enableGuest && this.props.config && this.props.config.default_hs_url ? this._registerAsGuest.bind(this, true) : undefined} onCancelClick={ this.state.guestCreds ? this.onReturnToGuestClick : null } diff --git a/src/components/structures/login/Login.js b/src/components/structures/login/Login.js index d127c7ed78..aa0c42dc98 100644 --- a/src/components/structures/login/Login.js +++ b/src/components/structures/login/Login.js @@ -35,6 +35,10 @@ module.exports = React.createClass({displayName: 'Login', customIsUrl: React.PropTypes.string, defaultHsUrl: React.PropTypes.string, defaultIsUrl: React.PropTypes.string, + // Secondary HS which we try to log into if the user is using + // the default HS but login fails. Useful for migrating to a + // different home server without confusing users. + fallbackHsUrl: React.PropTypes.string, // login shouldn't know or care how registration is done. onRegisterClick: React.PropTypes.func.isRequired, @@ -105,7 +109,9 @@ module.exports = React.createClass({displayName: 'Login', hsUrl = hsUrl || this.state.enteredHomeserverUrl; isUrl = isUrl || this.state.enteredIdentityServerUrl; - var loginLogic = new Signup.Login(hsUrl, isUrl); + var fallbackHsUrl = hsUrl == this.props.defaultHsUrl ? this.props.fallbackHsUrl : null; + + var loginLogic = new Signup.Login(hsUrl, isUrl, fallbackHsUrl); this._loginLogic = loginLogic; loginLogic.getFlows().then(function(flows) {