diff --git a/src/SignupStages.js b/src/SignupStages.js index 2b0d163a08..72e789e6a6 100644 --- a/src/SignupStages.js +++ b/src/SignupStages.js @@ -53,66 +53,24 @@ class RecaptchaStage extends Stage { constructor(matrixClient, signupInstance) { super(RecaptchaStage.TYPE, matrixClient, signupInstance); this.defer = q.defer(); // resolved with the captcha response - this.publicKey = null; // from the HS - this.divId = null; // from the UI component } - // called when the UI component has loaded the recaptcha
so we can - // render to it. + // called when the recaptcha has been completed. onReceiveData(data) { - if (!data || !data.divId) { + if (!data || !data.response) { return; } - this.divId = data.divId; - this._attemptRender(); + this.defer.resolve({ + auth: { + type: 'm.login.recaptcha', + response: data.response, + } + }); } complete() { - var publicKey; - var serverParams = this.signupInstance.getServerData().params; - if (serverParams && serverParams["m.login.recaptcha"]) { - publicKey = serverParams["m.login.recaptcha"].public_key; - } - if (!publicKey) { - return q.reject({ - message: "This server has not supplied enough information for Recaptcha " + - "authentication", - isFatal: true - }); - } - this.publicKey = publicKey; - this._attemptRender(); return this.defer.promise; } - - _attemptRender() { - if (!global.grecaptcha) { - console.error("grecaptcha not loaded!"); - return; - } - if (!this.publicKey) { - console.error("No public key for recaptcha!"); - return; - } - if (!this.divId) { - console.error("No div ID specified!"); - return; - } - console.log("Rendering to %s", this.divId); - var self = this; - global.grecaptcha.render(this.divId, { - sitekey: this.publicKey, - callback: function(response) { - console.log("Received captcha response"); - self.defer.resolve({ - auth: { - type: 'm.login.recaptcha', - response: response - } - }); - } - }); - } } RecaptchaStage.TYPE = "m.login.recaptcha"; diff --git a/src/components/structures/login/Registration.js b/src/components/structures/login/Registration.js index 0f1b6d331f..6d25efef6c 100644 --- a/src/components/structures/login/Registration.js +++ b/src/components/structures/login/Registration.js @@ -228,12 +228,9 @@ module.exports = React.createClass({ }); }, - onCaptchaLoaded: function(divIdName) { + onCaptchaResponse: function(response) { this.registerLogic.tellStage("m.login.recaptcha", { - divId: divIdName - }); - this.setState({ - busy: false // requires user input + response: response }); }, @@ -267,8 +264,15 @@ module.exports = React.createClass({ ); break; case "Register.STEP_m.login.recaptcha": + var publicKey; + var serverParams = this.registerLogic.getServerData().params; + if (serverParams && serverParams["m.login.recaptcha"]) { + publicKey = serverParams["m.login.recaptcha"].public_key; + } registerStep = ( - + ); break; default: diff --git a/src/components/views/login/CaptchaForm.js b/src/components/views/login/CaptchaForm.js index fdbe6f1db1..0e5922f464 100644 --- a/src/components/views/login/CaptchaForm.js +++ b/src/components/views/login/CaptchaForm.js @@ -26,28 +26,34 @@ module.exports = React.createClass({ displayName: 'CaptchaForm', propTypes: { - onCaptchaLoaded: React.PropTypes.func.isRequired // called with div id name + sitePublicKey: React.PropTypes.string, + + // called with the captcha response + onCaptchaResponse: React.PropTypes.func, }, getDefaultProps: function() { return { - onCaptchaLoaded: function() { - console.error("Unhandled onCaptchaLoaded"); - } + onCaptchaResponse: () => {}, + }; + }, + + getInitialState: function() { + return { + errorText: null, }; }, componentDidMount: function() { // Just putting a script tag into the returned jsx doesn't work, annoyingly, // so we do this instead. - var self = this; - if (this.refs.recaptchaContainer) { + if (global.grecaptcha) { + // already loaded + this._onCaptchaLoaded(); + } else { console.log("Loading recaptcha script..."); var scriptTag = document.createElement('script'); - window.mx_on_recaptcha_loaded = function() { - console.log("Loaded recaptcha script."); - self.props.onCaptchaLoaded(DIV_ID); - }; + window.mx_on_recaptcha_loaded = () => {this._onCaptchaLoaded()}; scriptTag.setAttribute( 'src', global.location.protocol+"//www.google.com/recaptcha/api.js?onload=mx_on_recaptcha_loaded&render=explicit" ); @@ -55,13 +61,54 @@ module.exports = React.createClass({ } }, + _renderRecaptcha: function(divId) { + if (!global.grecaptcha) { + console.error("grecaptcha not loaded!"); + throw new Error("Recaptcha did not load successfully"); + } + + var publicKey = this.props.sitePublicKey; + if (!publicKey) { + console.error("No public key for recaptcha!"); + throw new Error( + "This server has not supplied enough information for Recaptcha " + + "authentication"); + } + + console.log("Rendering to %s", divId); + global.grecaptcha.render(divId, { + sitekey: publicKey, + callback: this.props.onCaptchaResponse, + }); + }, + + _onCaptchaLoaded: function() { + console.log("Loaded recaptcha script."); + try { + this._renderRecaptcha(DIV_ID); + } catch (e) { + this.setState({ + errorText: e.toString(), + }) + } + }, + render: function() { - // FIXME: Tight coupling with the div id and SignupStages.js + let error = null; + if (this.state.errorText) { + error = ( +
+ {this.state.errorText} +
+ ); + } + return (
This Home Server would like to make sure you are not a robot
+ {error}
); } -}); \ No newline at end of file +});