feat: Wabenhain Honig-Shop Anwendung

Vollstaendige Next.js/Prisma-E-Commerce-Anwendung fuer eine Imkerei:
Shop, Warenkorb, Stripe-Checkout, Kundenkonto mit 2FA, Admin-Bereich
(Produkte, Ernten, Chargen, Bestellungen, Gutscheine, admin-editierbare
Website-Inhalte), i18n (DE/EN), Rate-Limiting/CSP/Audit-Log-Haertung,
PostgreSQL- und MySQL-Unterstuetzung ueber austauschbare Prisma-
Treiber-Adapter, Unit-/Komponenten-/E2E-Tests.
This commit is contained in:
Nick Szaunig committed 2026-08-17 14:30:28 +02:00
1 parent 5c76fcc266
commit c7927f2883
240 files changed
+26096 -137

No files matched your search

+40
View File
@@ -0,0 +1,40 @@
const VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
// Nur beim ersten Modul-Laden geprueft (nicht pro Request) — macht ein in
// Produktion vergessenes TURNSTILE_SECRET_KEY im Server-Log sichtbar, statt
// die CAPTCHA-Pruefung stillschweigend fuer alle Formulare zu ueberspringen.
if (process.env.NODE_ENV === "production" && !process.env.TURNSTILE_SECRET_KEY) {
console.warn(
"TURNSTILE_SECRET_KEY ist in Produktion nicht gesetzt — CAPTCHA-Pruefung auf Registrierung/Newsletter/Firmenanfrage ist deaktiviert."
);
}
/**
* Prueft ein Cloudflare-Turnstile-Token serverseitig gegen die Siteverify-
* API. Ohne konfigurierten TURNSTILE_SECRET_KEY wird die Pruefung
* uebersprungen (true) — analog zum Stripe/Google-Fallback ohne
* Zugangsdaten, damit die Formulare auch ohne CAPTCHA-Setup nutzbar bleiben.
*/
export async function verifyTurnstileToken(token: string | null, remoteIp?: string): Promise<boolean> {
const secret = process.env.TURNSTILE_SECRET_KEY;
if (!secret) return true;
if (!token) return false;
try {
const response = await fetch(VERIFY_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ secret, response: token, ...(remoteIp ? { remoteip: remoteIp } : {}) }),
});
const data = (await response.json()) as { success: boolean };
return data.success === true;
} catch {
// Anders als bei fehlendem Secret (bewusst nicht konfiguriert) ist hier
// ein Secret vorhanden — Turnstile wurde also aktiv gewuenscht. Ein
// Netzwerkfehler bei der Pruefung selbst darf dann nicht stillschweigend
// als "bestanden" gewertet werden, sonst waere die Pruefung durch simples
// Stoeren der Verbindung zu Cloudflare umgehbar. Das Rate-Limiting bleibt
// in diesem Fall die einzige Verteidigungslinie.
return false;
}
}