Fix grecaptcha throwing useless error sometimes

pull/21833/head
Dariusz Niemczyk 2021-07-19 15:41:44 +02:00
parent 863f4d4f9f
commit 9de5ebd4de
No known key found for this signature in database
GPG Key ID: 0AD2F70C94CA5B03
2 changed files with 54 additions and 30 deletions

View File

@ -90,6 +90,7 @@ declare global {
mxUIStore: UIStore; mxUIStore: UIStore;
mxSetupEncryptionStore?: SetupEncryptionStore; mxSetupEncryptionStore?: SetupEncryptionStore;
mxRoomScrollStateStore?: RoomScrollStateStore; mxRoomScrollStateStore?: RoomScrollStateStore;
mxOnRecaptchaLoaded?: () => void;
} }
interface Document { interface Document {
@ -185,4 +186,19 @@ declare global {
parameterDescriptors?: AudioParamDescriptor[]; parameterDescriptors?: AudioParamDescriptor[];
} }
); );
// eslint-disable-next-line no-var
var grecaptcha:
| undefined
| {
reset: (id: string) => void;
render: (
divId: string,
options: {
sitekey: string;
callback: () => void;
}
) => string;
isReady: () => boolean;
};
} }

View File

@ -15,39 +15,40 @@ limitations under the License.
*/ */
import React, { createRef } from 'react'; import React, { createRef } from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import CountlyAnalytics from "../../../CountlyAnalytics"; import CountlyAnalytics from "../../../CountlyAnalytics";
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
const DIV_ID = 'mx_recaptcha'; const DIV_ID = 'mx_recaptcha';
interface ICaptchaFormProps {
sitePublicKey: string
onCaptchaResponse: () => void
}
interface ICaptchaFormState {
errorText: string | null
}
/** /**
* A pure UI component which displays a captcha form. * A pure UI component which displays a captcha form.
*/ */
@replaceableComponent("views.auth.CaptchaForm") @replaceableComponent("views.auth.CaptchaForm")
export default class CaptchaForm extends React.Component { export default class CaptchaForm extends React.Component<ICaptchaFormProps, ICaptchaFormState> {
static propTypes = {
sitePublicKey: PropTypes.string,
// called with the captcha response
onCaptchaResponse: PropTypes.func,
};
static defaultProps = { static defaultProps = {
onCaptchaResponse: () => { }, onCaptchaResponse: () => { },
}; };
constructor(props) { private _captchaWidgetId: string | null = null;
super(props); private _recaptchaContainer: React.RefObject<HTMLDivElement> = createRef();
this.state = { state = {
errorText: null, errorText: null,
}; };
this._captchaWidgetId = null; constructor(props: ICaptchaFormProps) {
super(props);
this._recaptchaContainer = createRef();
CountlyAnalytics.instance.track("onboarding_grecaptcha_begin"); CountlyAnalytics.instance.track("onboarding_grecaptcha_begin");
} }
@ -55,15 +56,15 @@ export default class CaptchaForm extends React.Component {
componentDidMount() { componentDidMount() {
// Just putting a script tag into the returned jsx doesn't work, annoyingly, // Just putting a script tag into the returned jsx doesn't work, annoyingly,
// so we do this instead. // so we do this instead.
if (global.grecaptcha) { if (this.isRecaptchaReady()) {
// already loaded // already loaded
this._onCaptchaLoaded(); this._onCaptchaLoaded();
} else { } else {
console.log("Loading recaptcha script..."); console.log("Loading recaptcha script...");
window.mx_on_recaptcha_loaded = () => {this._onCaptchaLoaded();}; window.mxOnRecaptchaLoaded = () => { this._onCaptchaLoaded(); };
const scriptTag = document.createElement('script'); const scriptTag = document.createElement('script');
scriptTag.setAttribute( scriptTag.setAttribute(
'src', `https://www.recaptcha.net/recaptcha/api.js?onload=mx_on_recaptcha_loaded&render=explicit`, 'src', `https://www.recaptcha.net/recaptcha/api.js?onload=mxOnRecaptchaLoaded&render=explicit`,
); );
this._recaptchaContainer.current.appendChild(scriptTag); this._recaptchaContainer.current.appendChild(scriptTag);
} }
@ -73,8 +74,15 @@ export default class CaptchaForm extends React.Component {
this._resetRecaptcha(); this._resetRecaptcha();
} }
_renderRecaptcha(divId) { // Borrowed directly from: https://github.com/codeep/react-recaptcha-google/commit/e118fa5670fa268426969323b2e7fe77698376ba
if (!global.grecaptcha) { private isRecaptchaReady() {
return typeof window !== "undefined" &&
typeof global.grecaptcha !== "undefined" &&
typeof global.grecaptcha.render === 'function';
}
private _renderRecaptcha(divId) {
if (!this.isRecaptchaReady()) {
console.error("grecaptcha not loaded!"); console.error("grecaptcha not loaded!");
throw new Error("Recaptcha did not load successfully"); throw new Error("Recaptcha did not load successfully");
} }
@ -94,13 +102,13 @@ export default class CaptchaForm extends React.Component {
}); });
} }
_resetRecaptcha() { private _resetRecaptcha() {
if (this._captchaWidgetId !== null) { if (this._captchaWidgetId !== null) {
global.grecaptcha.reset(this._captchaWidgetId); global.grecaptcha.reset(this._captchaWidgetId);
} }
} }
_onCaptchaLoaded() { private _onCaptchaLoaded() {
console.log("Loaded recaptcha script."); console.log("Loaded recaptcha script.");
try { try {
this._renderRecaptcha(DIV_ID); this._renderRecaptcha(DIV_ID);