Harden admin login Turnstile flow
This commit is contained in:
parent
e0fd5cea8c
commit
aec14bc97d
|
|
@ -14,6 +14,7 @@ export default function LoginPage() {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [turnstileToken, setTurnstileToken] = useState('');
|
const [turnstileToken, setTurnstileToken] = useState('');
|
||||||
const [turnstileReady, setTurnstileReady] = useState(false);
|
const [turnstileReady, setTurnstileReady] = useState(false);
|
||||||
|
const [turnstileWidgetRendered, setTurnstileWidgetRendered] = useState(false);
|
||||||
const turnstileRef = useRef<HTMLDivElement>(null);
|
const turnstileRef = useRef<HTMLDivElement>(null);
|
||||||
const widgetIdRef = useRef<string | null>(null);
|
const widgetIdRef = useRef<string | null>(null);
|
||||||
const tokenRef = useRef('');
|
const tokenRef = useRef('');
|
||||||
|
|
@ -57,6 +58,7 @@ export default function LoginPage() {
|
||||||
'error-callback': () => { setTurnstileToken(''); tokenRef.current = ''; setTurnstileReady(false); },
|
'error-callback': () => { setTurnstileToken(''); tokenRef.current = ''; setTurnstileReady(false); },
|
||||||
'expired-callback': () => { setTurnstileToken(''); tokenRef.current = ''; setTurnstileReady(false); },
|
'expired-callback': () => { setTurnstileToken(''); tokenRef.current = ''; setTurnstileReady(false); },
|
||||||
});
|
});
|
||||||
|
setTurnstileWidgetRendered(true);
|
||||||
}, [performLogin]);
|
}, [performLogin]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -69,6 +71,7 @@ export default function LoginPage() {
|
||||||
setTurnstileToken('');
|
setTurnstileToken('');
|
||||||
tokenRef.current = '';
|
tokenRef.current = '';
|
||||||
setTurnstileReady(false);
|
setTurnstileReady(false);
|
||||||
|
setTurnstileWidgetRendered(false);
|
||||||
setError('');
|
setError('');
|
||||||
if (widgetIdRef.current && (window as any).turnstile) {
|
if (widgetIdRef.current && (window as any).turnstile) {
|
||||||
(window as any).turnstile.reset(widgetIdRef.current);
|
(window as any).turnstile.reset(widgetIdRef.current);
|
||||||
|
|
@ -82,6 +85,11 @@ export default function LoginPage() {
|
||||||
// Invisible Turnstile flow:
|
// Invisible Turnstile flow:
|
||||||
// - If we don't have a token yet, execute Turnstile first.
|
// - If we don't have a token yet, execute Turnstile first.
|
||||||
// - If we already have a token, proceed with login.
|
// - If we already have a token, proceed with login.
|
||||||
|
if (TURNSTILE_SITE_KEY && !widgetIdRef.current) {
|
||||||
|
setError('Security check is still loading. Please wait a moment and try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (TURNSTILE_SITE_KEY && widgetIdRef.current && !tokenRef.current) {
|
if (TURNSTILE_SITE_KEY && widgetIdRef.current && !tokenRef.current) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
|
|
@ -95,6 +103,12 @@ export default function LoginPage() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If Turnstile is enabled, we must have a token at this point.
|
||||||
|
if (TURNSTILE_SITE_KEY && !tokenRef.current) {
|
||||||
|
setError('Security verification failed. Please try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await performLogin();
|
await performLogin();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ func (h *AdminHandler) AdminLogin(c *gin.Context) {
|
||||||
// Verify Turnstile token
|
// Verify Turnstile token
|
||||||
if h.turnstileSecret != "" {
|
if h.turnstileSecret != "" {
|
||||||
if strings.TrimSpace(req.TurnstileToken) == "" {
|
if strings.TrimSpace(req.TurnstileToken) == "" {
|
||||||
|
log.Warn().Str("email", req.Email).Msg("Admin login: missing Turnstile token")
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Security verification failed"})
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Security verification failed"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue