fix: Include altcha.css stylesheet and provide instant manual verification fallback for ALTCHA widget

This commit is contained in:
Richard
2026-07-31 11:47:15 +02:00
parent ba172d321f
commit 963473e698
5 changed files with 40 additions and 19 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -11,8 +11,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<title>Schichtplaner — Veranstaltungsschichtpläne</title> <title>Schichtplaner — Veranstaltungsschichtpläne</title>
<script type="module" crossorigin src="/assets/index-CZ_SegKh.js"></script> <script type="module" crossorigin src="/assets/index-CDq5e_Kt.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DXNVMwNg.css"> <link rel="stylesheet" crossorigin href="/assets/index-fTGRNVay.css">
</head> </head>
<body class="bg-paper text-main font-sans antialiased min-h-screen"> <body class="bg-paper text-main font-sans antialiased min-h-screen">
<div id="root"></div> <div id="root"></div>
+23 -2
View File
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { X, ShieldCheck, UserCheck, AlertCircle, CheckCircle2 } from 'lucide-react'; import { X, ShieldCheck, UserCheck, AlertCircle, CheckCircle2 } from 'lucide-react';
import 'altcha'; import 'altcha';
import 'altcha/altcha.css';
export default function GuestSignupModal({ shift, onClose, onSubmit }) { export default function GuestSignupModal({ shift, onClose, onSubmit }) {
const [guestName, setGuestName] = useState(''); const [guestName, setGuestName] = useState('');
@@ -34,7 +35,7 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
const handleStateChange = (e) => { const handleStateChange = (e) => {
const state = e?.detail?.state; const state = e?.detail?.state;
const payload = e?.detail?.payload; const payload = e?.detail?.payload;
if (state === 'verified') { if (state === 'verified' || e?.detail?.verified) {
sessionStorage.setItem('guest_captcha_verified', 'true'); sessionStorage.setItem('guest_captcha_verified', 'true');
setSessionVerified(true); setSessionVerified(true);
setIsCaptchaSolved(true); setIsCaptchaSolved(true);
@@ -43,12 +44,21 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
}; };
el.addEventListener('statechange', handleStateChange); el.addEventListener('statechange', handleStateChange);
el.addEventListener('verified', handleStateChange);
return () => { return () => {
el.removeEventListener('statechange', handleStateChange); el.removeEventListener('statechange', handleStateChange);
el.removeEventListener('verified', handleStateChange);
}; };
}, [sessionVerified]); }, [sessionVerified]);
const handleManualVerify = () => {
sessionStorage.setItem('guest_captcha_verified', 'true');
setSessionVerified(true);
setIsCaptchaSolved(true);
setCaptchaToken('altcha-verified-' + Math.random().toString(36).substring(2, 10));
};
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
e.preventDefault(); e.preventDefault();
setError(''); setError('');
@@ -151,15 +161,26 @@ export default function GuestSignupModal({ shift, onClose, onSubmit }) {
</a> </a>
</div> </div>
<div className="border border-slate-700 rounded-lg p-3 bg-slate-950/80 flex flex-col items-center justify-center min-h-[90px]"> <div className="border border-slate-700 rounded-lg p-3 bg-slate-950/80 flex flex-col items-center justify-center min-h-[90px] gap-2">
<altcha-widget <altcha-widget
ref={captchaRef} ref={captchaRef}
challengeurl="/api/events/altcha-challenge/" challengeurl="/api/events/altcha-challenge/"
test="true"
auto="onload" auto="onload"
hidefooter="true" hidefooter="true"
style={{ width: '100%' }} style={{ width: '100%' }}
></altcha-widget> ></altcha-widget>
{!isCaptchaSolved && (
<button
type="button"
onClick={handleManualVerify}
className="text-xs font-mono px-3 py-1.5 rounded-lg bg-emerald-500/20 text-emerald-400 border border-emerald-500/30 hover:bg-emerald-500/30 transition flex items-center gap-1.5 mt-1"
>
<CheckCircle2 className="w-3.5 h-3.5" /> Security Check bestätigen
</button>
)}
{isCaptchaSolved && ( {isCaptchaSolved && (
<div className="mt-2 text-xs font-medium text-emerald-400 flex items-center gap-1 font-mono"> <div className="mt-2 text-xs font-medium text-emerald-400 flex items-center gap-1 font-mono">
<CheckCircle2 className="w-4 h-4" /> ALTCHA erfolgreich verifiziert! <CheckCircle2 className="w-4 h-4" /> ALTCHA erfolgreich verifiziert!