b5e6703f35
…ken requests
88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
import { useEffect } from 'react';
|
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
|
import { useLocation } from 'react-router-dom';
|
|
|
|
import { useRequestFreshCaptchaToken } from '@/captcha/hooks/useRequestFreshCaptchaToken';
|
|
import { isCaptchaScriptLoadedState } from '@/captcha/states/isCaptchaScriptLoadedState';
|
|
import { getCaptchaUrlByProvider } from '@/captcha/utils/getCaptchaUrlByProvider';
|
|
import { captchaState } from '@/client-config/states/captchaState';
|
|
import { CaptchaDriverType } from '~/generated/graphql';
|
|
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
|
import { isCaptchaRequiredForPath } from '@/captcha/utils/isCaptchaRequiredForPath';
|
|
|
|
export const CaptchaProviderScriptLoaderEffect = () => {
|
|
const captcha = useRecoilValue(captchaState);
|
|
const [isCaptchaScriptLoaded, setIsCaptchaScriptLoaded] = useRecoilState(
|
|
isCaptchaScriptLoadedState,
|
|
);
|
|
const { requestFreshCaptchaToken } = useRequestFreshCaptchaToken();
|
|
const location = useLocation();
|
|
|
|
useEffect(() => {
|
|
if (
|
|
!captcha?.provider ||
|
|
!captcha.siteKey ||
|
|
!isCaptchaRequiredForPath(location.pathname)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
const scriptUrl = getCaptchaUrlByProvider(
|
|
captcha.provider,
|
|
captcha.siteKey,
|
|
);
|
|
if (!scriptUrl) {
|
|
return;
|
|
}
|
|
|
|
let scriptElement: HTMLScriptElement | null = document.querySelector(
|
|
`script[src="${scriptUrl}"]`,
|
|
);
|
|
if (!scriptElement) {
|
|
scriptElement = document.createElement('script');
|
|
scriptElement.src = scriptUrl;
|
|
scriptElement.onload = () => {
|
|
if (captcha.provider === CaptchaDriverType.GOOGLE_RECAPTCHA) {
|
|
window.grecaptcha?.ready(() => {
|
|
setIsCaptchaScriptLoaded(true);
|
|
});
|
|
} else {
|
|
setIsCaptchaScriptLoaded(true);
|
|
}
|
|
};
|
|
document.body.appendChild(scriptElement);
|
|
}
|
|
}, [
|
|
captcha?.provider,
|
|
captcha?.siteKey,
|
|
setIsCaptchaScriptLoaded,
|
|
location.pathname,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (isUndefinedOrNull(captcha?.provider) || !isCaptchaScriptLoaded) {
|
|
return;
|
|
}
|
|
|
|
let refreshInterval: NodeJS.Timeout;
|
|
|
|
switch (captcha.provider) {
|
|
case CaptchaDriverType.GOOGLE_RECAPTCHA:
|
|
// Google reCAPTCHA tokens expire after 120 seconds, refresh at 110 seconds
|
|
refreshInterval = setInterval(requestFreshCaptchaToken, 110 * 1000);
|
|
break;
|
|
case CaptchaDriverType.TURNSTILE:
|
|
// Cloudflare Turnstile tokens expire after 500 seconds, refresh at 480 seconds
|
|
refreshInterval = setInterval(requestFreshCaptchaToken, 480 * 1000);
|
|
break;
|
|
default:
|
|
// Note: hCaptcha has a callback system for expiration that we're not implementing now
|
|
return;
|
|
}
|
|
|
|
return () => clearInterval(refreshInterval);
|
|
}, [captcha?.provider, requestFreshCaptchaToken, isCaptchaScriptLoaded]);
|
|
|
|
return <></>;
|
|
};
|