2016-10-11 17:04:55 +00:00
|
|
|
/*
|
|
|
|
Copyright 2016 OpenMarket Ltd
|
2017-02-13 16:15:00 +00:00
|
|
|
Copyright 2017 Vector Creations Ltd
|
2016-10-11 17:04:55 +00:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import React from 'react';
|
|
|
|
|
|
|
|
import sdk from '../../../index';
|
|
|
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
|
|
|
|
|
|
|
/* This file contains a collection of components which are used by the
|
|
|
|
* InteractiveAuthDialog to prompt the user to enter the information needed
|
|
|
|
* for an auth stage. (The intention is that they could also be used for other
|
|
|
|
* components, such as the registration flow).
|
|
|
|
*
|
|
|
|
* Call getEntryComponentForLoginType() to get a component suitable for a
|
|
|
|
* particular login type. Each component requires the same properties:
|
|
|
|
*
|
|
|
|
* loginType: the login type of the auth stage being attempted
|
|
|
|
* authSessionId: session id from the server
|
|
|
|
* stageParams: params from the server for the stage being attempted
|
|
|
|
* errorText: error message from a previous attempt to authenticate
|
|
|
|
* submitAuthDict: a function which will be called with the new auth dict
|
|
|
|
*
|
|
|
|
* Each component may also provide the following functions (beyond the standard React ones):
|
|
|
|
* onSubmitClick: handle a 'submit' button click
|
|
|
|
* focus: set the input focus appropriately in the form.
|
|
|
|
*/
|
|
|
|
|
|
|
|
export const PasswordAuthEntry = React.createClass({
|
|
|
|
displayName: 'PasswordAuthEntry',
|
|
|
|
|
|
|
|
statics: {
|
|
|
|
LOGIN_TYPE: "m.login.password",
|
|
|
|
},
|
|
|
|
|
|
|
|
propTypes: {
|
|
|
|
submitAuthDict: React.PropTypes.func.isRequired,
|
|
|
|
errorText: React.PropTypes.string,
|
2017-02-13 18:52:33 +00:00
|
|
|
// is the auth logic currently waiting for something to
|
|
|
|
// happen?
|
|
|
|
busy: React.PropTypes.bool,
|
2016-10-11 17:04:55 +00:00
|
|
|
},
|
|
|
|
|
2017-02-13 16:03:21 +00:00
|
|
|
getInitialState: function() {
|
|
|
|
return {
|
2017-02-13 18:52:33 +00:00
|
|
|
passwordValid: false,
|
2017-02-13 16:03:21 +00:00
|
|
|
};
|
2016-10-11 17:04:55 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
focus: function() {
|
|
|
|
if (this.refs.passwordField) {
|
|
|
|
this.refs.passwordField.focus();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-02-13 18:52:33 +00:00
|
|
|
_onSubmit: function(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
if (this.props.busy) return;
|
|
|
|
|
2016-10-11 17:04:55 +00:00
|
|
|
this.props.submitAuthDict({
|
|
|
|
type: PasswordAuthEntry.LOGIN_TYPE,
|
|
|
|
user: MatrixClientPeg.get().credentials.userId,
|
|
|
|
password: this.refs.passwordField.value,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-01-20 14:22:27 +00:00
|
|
|
_onPasswordFieldChange: function(ev) {
|
2016-10-11 17:04:55 +00:00
|
|
|
// enable the submit button iff the password is non-empty
|
2017-02-13 16:03:21 +00:00
|
|
|
this.setState({
|
2017-02-13 18:52:33 +00:00
|
|
|
passwordValid: Boolean(this.refs.passwordField.value),
|
2017-02-13 16:03:21 +00:00
|
|
|
});
|
2016-10-11 17:04:55 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
render: function() {
|
|
|
|
let passwordBoxClass = null;
|
|
|
|
|
|
|
|
if (this.props.errorText) {
|
|
|
|
passwordBoxClass = 'error';
|
|
|
|
}
|
|
|
|
|
2017-02-13 18:52:33 +00:00
|
|
|
let submitButtonOrSpinner;
|
|
|
|
if (this.props.busy) {
|
|
|
|
const Loader = sdk.getComponent("elements.Spinner");
|
|
|
|
submitButtonOrSpinner = <Loader />;
|
|
|
|
} else {
|
|
|
|
submitButtonOrSpinner = (
|
|
|
|
<input type="submit"
|
|
|
|
className="mx_Dialog_primary"
|
|
|
|
disabled={!this.state.passwordValid}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-10-11 17:04:55 +00:00
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<p>To continue, please enter your password.</p>
|
|
|
|
<p>Password:</p>
|
2017-02-13 16:03:21 +00:00
|
|
|
<form onSubmit={this._onSubmit}>
|
|
|
|
<input
|
|
|
|
ref="passwordField"
|
|
|
|
className={passwordBoxClass}
|
|
|
|
onChange={this._onPasswordFieldChange}
|
|
|
|
type="password"
|
|
|
|
/>
|
|
|
|
<div className="mx_button_row">
|
2017-02-13 18:52:33 +00:00
|
|
|
{submitButtonOrSpinner}
|
2017-02-13 16:03:21 +00:00
|
|
|
</div>
|
|
|
|
</form>
|
2016-10-11 17:04:55 +00:00
|
|
|
<div className="error">
|
|
|
|
{this.props.errorText}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
export const RecaptchaAuthEntry = React.createClass({
|
|
|
|
displayName: 'RecaptchaAuthEntry',
|
|
|
|
|
|
|
|
statics: {
|
|
|
|
LOGIN_TYPE: "m.login.recaptcha",
|
|
|
|
},
|
|
|
|
|
|
|
|
propTypes: {
|
|
|
|
submitAuthDict: React.PropTypes.func.isRequired,
|
|
|
|
stageParams: React.PropTypes.object.isRequired,
|
|
|
|
errorText: React.PropTypes.string,
|
|
|
|
},
|
|
|
|
|
|
|
|
_onCaptchaResponse: function(response) {
|
|
|
|
this.props.submitAuthDict({
|
|
|
|
type: RecaptchaAuthEntry.LOGIN_TYPE,
|
|
|
|
response: response,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
render: function() {
|
|
|
|
const CaptchaForm = sdk.getComponent("views.login.CaptchaForm");
|
|
|
|
var sitePublicKey = this.props.stageParams.public_key;
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<CaptchaForm sitePublicKey={sitePublicKey}
|
|
|
|
onCaptchaResponse={this._onCaptchaResponse}
|
|
|
|
/>
|
|
|
|
<div className="error">
|
|
|
|
{this.props.errorText}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
export const FallbackAuthEntry = React.createClass({
|
|
|
|
displayName: 'FallbackAuthEntry',
|
|
|
|
|
|
|
|
propTypes: {
|
|
|
|
authSessionId: React.PropTypes.string.isRequired,
|
|
|
|
loginType: React.PropTypes.string.isRequired,
|
|
|
|
submitAuthDict: React.PropTypes.func.isRequired,
|
|
|
|
errorText: React.PropTypes.string,
|
|
|
|
},
|
|
|
|
|
|
|
|
componentWillMount: function() {
|
|
|
|
// we have to make the user click a button, as browsers will block
|
|
|
|
// the popup if we open it immediately.
|
|
|
|
this._popupWindow = null;
|
|
|
|
window.addEventListener("message", this._onReceiveMessage);
|
|
|
|
},
|
|
|
|
|
|
|
|
componentWillUnmount: function() {
|
|
|
|
window.removeEventListener("message", this._onReceiveMessage);
|
|
|
|
if (this._popupWindow) {
|
|
|
|
this._popupWindow.close();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
onSubmitClick: function() {
|
|
|
|
var url = MatrixClientPeg.get().getFallbackAuthUrl(
|
|
|
|
this.props.loginType,
|
|
|
|
this.props.authSessionId
|
|
|
|
);
|
|
|
|
this._popupWindow = window.open(url);
|
|
|
|
},
|
|
|
|
|
|
|
|
_onReceiveMessage: function(event) {
|
|
|
|
if (
|
|
|
|
event.data === "authDone" &&
|
|
|
|
event.origin === MatrixClientPeg.get().getHomeserverUrl()
|
|
|
|
) {
|
|
|
|
this.props.submitAuthDict({});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
render: function() {
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
Click "Submit" to authenticate
|
|
|
|
<div className="error">
|
|
|
|
{this.props.errorText}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const AuthEntryComponents = [
|
|
|
|
PasswordAuthEntry,
|
|
|
|
RecaptchaAuthEntry,
|
|
|
|
];
|
|
|
|
|
|
|
|
export function getEntryComponentForLoginType(loginType) {
|
|
|
|
for (var c of AuthEntryComponents) {
|
|
|
|
if (c.LOGIN_TYPE == loginType) {
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FallbackAuthEntry;
|
2017-01-20 14:22:27 +00:00
|
|
|
}
|