element-call/src/auth/useRecaptcha.js

107 lines
2.7 KiB
JavaScript
Raw Normal View History

2022-01-05 00:00:13 +00:00
import { randomString } from "matrix-js-sdk/src/randomstring";
import { useEffect, useCallback, useRef, useState } from "react";
const RECAPTCHA_SCRIPT_URL =
"https://www.recaptcha.net/recaptcha/api.js?onload=mxOnRecaptchaLoaded&render=explicit";
export function useRecaptcha(sitekey) {
const [recaptchaId] = useState(() => randomString(16));
2022-01-05 01:57:23 +00:00
const promiseRef = useRef();
2022-01-05 00:00:13 +00:00
useEffect(() => {
if (!sitekey) {
return;
}
const onRecaptchaLoaded = () => {
if (!document.getElementById(recaptchaId)) {
return;
}
window.grecaptcha.render(recaptchaId, {
sitekey,
size: "invisible",
callback: (response) => {
2022-01-05 01:57:23 +00:00
if (promiseRef.current) {
promiseRef.current.resolve(response);
}
},
"error-callback": (error) => {
if (promiseRef.current) {
promiseRef.current.reject(error);
2022-01-05 00:00:13 +00:00
}
},
});
};
if (
typeof window.grecaptcha !== "undefined" &&
typeof window.grecaptcha.render === "function"
) {
onRecaptchaLoaded();
} else {
window.mxOnRecaptchaLoaded = onRecaptchaLoaded;
if (!document.querySelector(`script[src="${RECAPTCHA_SCRIPT_URL}"]`)) {
const scriptTag = document.createElement("script");
scriptTag.src = RECAPTCHA_SCRIPT_URL;
scriptTag.async = true;
document.body.appendChild(scriptTag);
}
}
}, [recaptchaId, sitekey]);
const execute = useCallback(() => {
2022-01-07 19:31:53 +00:00
if (!sitekey) {
return Promise.resolve(null);
}
2022-01-05 00:00:13 +00:00
if (!window.grecaptcha) {
return Promise.reject(new Error("Recaptcha not loaded"));
}
2022-01-05 01:57:23 +00:00
return new Promise((resolve, reject) => {
const observer = new MutationObserver((mutationsList) => {
for (const item of mutationsList) {
2022-01-06 22:16:31 +00:00
if (item.target.style?.visibility !== "visible") {
2022-01-05 01:57:23 +00:00
reject(new Error("Recaptcha dismissed"));
observer.disconnect();
return;
}
}
});
promiseRef.current = {
resolve: (value) => {
resolve(value);
observer.disconnect();
},
reject: (error) => {
reject(error);
observer.disconnect();
},
};
2022-01-05 00:00:13 +00:00
window.grecaptcha.execute();
2022-01-05 01:57:23 +00:00
const iframe = document.querySelector(
'iframe[src*="recaptcha/api2/bframe"]'
);
if (iframe?.parentNode?.parentNode) {
observer.observe(iframe?.parentNode?.parentNode, {
attributes: true,
});
}
2022-01-05 00:00:13 +00:00
});
}, [recaptchaId]);
const reset = useCallback(() => {
if (window.grecaptcha) {
window.grecaptcha.reset();
}
}, [recaptchaId]);
return { execute, reset, recaptchaId };
}