Guard invalid Turnstile site key
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 46s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 46s
This commit is contained in:
@@ -57,6 +57,7 @@ const buildDateRangeParams = (dateRange: DateRange) => new URLSearchParams({
|
||||
|
||||
export type LoginConfig = {
|
||||
captchaRequired: boolean;
|
||||
captchaConfigured: boolean;
|
||||
turnstileSiteKey: string;
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ const securityUnavailableMessage = 'Não foi possível carregar a verificação
|
||||
const securityConfigurationMessage = 'Verificação de segurança indisponível. Entre em contato com o administrador.';
|
||||
const securityRequiredMessage = 'Conclua a verificação de segurança para continuar.';
|
||||
const securityFailedMessage = 'Não foi possível validar a verificação de segurança. Atualize a página e tente novamente.';
|
||||
const turnstileSiteKeyPattern = /^[0-9]x[0-9A-Za-z_-]{20,}$/;
|
||||
|
||||
const Login = () => {
|
||||
const [email, setEmail] = useState('');
|
||||
@@ -41,8 +42,9 @@ const Login = () => {
|
||||
const captchaContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const captchaWidgetIdRef = useRef<string | null>(null);
|
||||
const navigate = useNavigate();
|
||||
const captchaEnabled = Boolean(captchaRequired && turnstileSiteKey);
|
||||
const securityMisconfigured = captchaRequired && !turnstileSiteKey;
|
||||
const hasValidSiteKey = turnstileSiteKeyPattern.test(turnstileSiteKey);
|
||||
const captchaEnabled = Boolean(captchaRequired && hasValidSiteKey);
|
||||
const securityMisconfigured = captchaRequired && !hasValidSiteKey;
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
@@ -53,9 +55,9 @@ const Login = () => {
|
||||
if (!isMounted) return;
|
||||
|
||||
setCaptchaRequired(config.captchaRequired);
|
||||
setTurnstileSiteKey(config.turnstileSiteKey);
|
||||
setTurnstileSiteKey(config.turnstileSiteKey.trim());
|
||||
setCaptchaReady(!config.captchaRequired);
|
||||
if (config.captchaRequired && !config.turnstileSiteKey) {
|
||||
if (config.captchaRequired && !config.captchaConfigured) {
|
||||
setError(securityConfigurationMessage);
|
||||
}
|
||||
} catch {
|
||||
@@ -77,31 +79,37 @@ const Login = () => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!turnstileSiteKey || !captchaContainerRef.current || captchaWidgetIdRef.current) return;
|
||||
if (!hasValidSiteKey || !captchaContainerRef.current || captchaWidgetIdRef.current) return;
|
||||
|
||||
const siteKey = turnstileSiteKey;
|
||||
|
||||
const renderCaptcha = () => {
|
||||
if (!window.turnstile || !captchaContainerRef.current || captchaWidgetIdRef.current) return;
|
||||
|
||||
captchaWidgetIdRef.current = window.turnstile.render(captchaContainerRef.current, {
|
||||
sitekey: siteKey,
|
||||
theme: 'dark',
|
||||
callback: (token) => {
|
||||
setCaptchaToken(token);
|
||||
setCaptchaReady(true);
|
||||
},
|
||||
'expired-callback': () => {
|
||||
setCaptchaToken('');
|
||||
setCaptchaReady(true);
|
||||
},
|
||||
'error-callback': () => {
|
||||
setCaptchaToken('');
|
||||
setCaptchaReady(false);
|
||||
setError(securityUnavailableMessage);
|
||||
},
|
||||
});
|
||||
setCaptchaReady(true);
|
||||
try {
|
||||
captchaWidgetIdRef.current = window.turnstile.render(captchaContainerRef.current, {
|
||||
sitekey: siteKey,
|
||||
theme: 'dark',
|
||||
callback: (token) => {
|
||||
setCaptchaToken(token);
|
||||
setCaptchaReady(true);
|
||||
},
|
||||
'expired-callback': () => {
|
||||
setCaptchaToken('');
|
||||
setCaptchaReady(true);
|
||||
},
|
||||
'error-callback': () => {
|
||||
setCaptchaToken('');
|
||||
setCaptchaReady(false);
|
||||
setError(securityUnavailableMessage);
|
||||
},
|
||||
});
|
||||
setCaptchaReady(true);
|
||||
} catch {
|
||||
setCaptchaToken('');
|
||||
setCaptchaReady(false);
|
||||
setError(securityConfigurationMessage);
|
||||
}
|
||||
};
|
||||
|
||||
if (window.turnstile) {
|
||||
@@ -128,7 +136,7 @@ const Login = () => {
|
||||
document.head.appendChild(script);
|
||||
|
||||
return () => script.removeEventListener('load', renderCaptcha);
|
||||
}, [turnstileSiteKey]);
|
||||
}, [hasValidSiteKey, turnstileSiteKey]);
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
Reference in New Issue
Block a user