Support registration & login with phone number (#742)

* WIP msisdn sign in

* A mostly working country picker

* Fix bug where you'dbe logged out after registering

Stop the guest sync, otherwise it gets 401ed for using a guest
access token for a non-guest, causing us to beliebe we've been
logged out.

* Use InteractiveAuth component for registration

* Fix tests

* Remove old signup code

* Signup -> Login

Now that Signup contains no code whatsoever related to signing up,
rename it to Login. Get rid of the Signup class.

* Stray newline

* Fix more merge failing

* Get phone country & number to the right place

* More-or-less working msisdn auth component

* Send the bind_msisdn param on registration

* Refinements to country dropdown

Rendering the whole lot when the component was rendered just makes
the page load really slow, so just show 2 at a time and rely on
type-to-search.

Make type-to-search always display an exact iso2 match first

* Propagate initial inputs to the phone input

* Support msisdn login

* semicolon

* Fix PropTypes

* Oops, use the 1qst element of the array

Not the array of object keys which has no particular order

* Make dropdown/countrydropdown controlled

* Unused line

* Add note on DOM layout

* onOptionChange is required

* More docs

* Add missing propTypes

* Don't resume promise on error

* Use React.Children to manipulate children

* Make catch less weird

* Fix null dereference

Assuming [0] of an empty list == undefined doesn't work if you're
then taking a property of it.
This commit is contained in:
David Baker
2017-03-09 10:59:22 +00:00
committed by GitHub
parent 676c5c21c1
commit 0269562383
12 changed files with 2032 additions and 30 deletions

View File

@@ -16,6 +16,8 @@ limitations under the License.
*/
import React from 'react';
import url from 'url';
import classnames from 'classnames';
import sdk from '../../../index';
@@ -255,6 +257,137 @@ export const EmailIdentityAuthEntry = React.createClass({
},
});
export const MsisdnAuthEntry = React.createClass({
displayName: 'MsisdnAuthEntry',
statics: {
LOGIN_TYPE: "m.login.msisdn",
},
propTypes: {
inputs: React.PropTypes.shape({
phoneCountry: React.PropTypes.string,
phoneNumber: React.PropTypes.string,
}),
fail: React.PropTypes.func,
clientSecret: React.PropTypes.func,
submitAuthDict: React.PropTypes.func.isRequired,
matrixClient: React.PropTypes.object,
submitAuthDict: React.PropTypes.func,
},
getInitialState: function() {
return {
token: '',
requestingToken: false,
};
},
componentWillMount: function() {
this._sid = null;
this._msisdn = null;
this._tokenBox = null;
this.setState({requestingToken: true});
this._requestMsisdnToken().catch((e) => {
this.props.fail(e);
}).finally(() => {
this.setState({requestingToken: false});
}).done();
},
/*
* Requests a verification token by SMS.
*/
_requestMsisdnToken: function() {
return this.props.matrixClient.requestRegisterMsisdnToken(
this.props.inputs.phoneCountry,
this.props.inputs.phoneNumber,
this.props.clientSecret,
1, // TODO: Multiple send attempts?
).then((result) => {
this._sid = result.sid;
this._msisdn = result.msisdn;
});
},
_onTokenChange: function(e) {
this.setState({
token: e.target.value,
});
},
_onFormSubmit: function(e) {
e.preventDefault();
if (this.state.token == '') return;
this.setState({
errorText: null,
});
this.props.matrixClient.submitMsisdnToken(
this._sid, this.props.clientSecret, this.state.token
).then((result) => {
if (result.success) {
const idServerParsedUrl = url.parse(
this.props.matrixClient.getIdentityServerUrl(),
)
this.props.submitAuthDict({
type: MsisdnAuthEntry.LOGIN_TYPE,
threepid_creds: {
sid: this._sid,
client_secret: this.props.clientSecret,
id_server: idServerParsedUrl.host,
},
});
} else {
this.setState({
errorText: "Token incorrect",
});
}
}).catch((e) => {
this.props.fail(e);
console.log("Failed to submit msisdn token");
}).done();
},
render: function() {
if (this.state.requestingToken) {
const Loader = sdk.getComponent("elements.Spinner");
return <Loader />;
} else {
const enableSubmit = Boolean(this.state.token);
const submitClasses = classnames({
mx_InteractiveAuthEntryComponents_msisdnSubmit: true,
mx_UserSettings_button: true, // XXX button classes
});
return (
<div>
<p>A text message has been sent to +<i>{this._msisdn}</i></p>
<p>Please enter the code it contains:</p>
<div className="mx_InteractiveAuthEntryComponents_msisdnWrapper">
<form onSubmit={this._onFormSubmit}>
<input type="text"
className="mx_InteractiveAuthEntryComponents_msisdnEntry"
value={this.state.token}
onChange={this._onTokenChange}
/>
<br />
<input type="submit" value="Submit"
className={submitClasses}
disabled={!enableSubmit}
/>
</form>
<div className="error">
{this.state.errorText}
</div>
</div>
</div>
);
}
},
});
export const FallbackAuthEntry = React.createClass({
displayName: 'FallbackAuthEntry',
@@ -313,6 +446,7 @@ const AuthEntryComponents = [
PasswordAuthEntry,
RecaptchaAuthEntry,
EmailIdentityAuthEntry,
MsisdnAuthEntry,
];
export function getEntryComponentForLoginType(loginType) {