/* Test der Zugangs-Sperre (19.08.2026). Stellt den echten Fehlerfall nach: Frueher teilten sich ALLE Besucher einen einzigen Fehlversuchs-Zaehler, weil req.ip die Cloudflare-IP war statt der des Besuchers. Ohne echten Server -- gateAuthHandler wird direkt mit nachgebauten req/res aufgerufen. */ process.env.SITE_ACCESS_SECRET = "test-geheimnis-nur-fuer-diesen-test"; process.env.SITE_ACCESS_CODE_DOGI = "RichtigerCode"; process.env.SITE_ACCESS_CODE_VANVAN = "VanVanCode"; const { gateAuthHandler } = await import("./gate.js"); function anfrage(code, besucherIp) { return { headers: { "cf-connecting-ip": besucherIp }, ip: "172.71.0.1", // immer DIESELBE Cloudflare-IP - genau das war der Ausloeser body: { code }, }; } function antwort() { const r = { statusCode: 200, daten: null, cookies: {}, status(c) { r.statusCode = c; return r; }, json(d) { r.daten = d; return r; }, cookie(n, w) { r.cookies[n] = w; return r; }, }; return r; } async function versuch(code, ip) { const res = antwort(); await gateAuthHandler(anfrage(code, ip), res); return res; } let fehler = 0; function pruefe(bedingung, text) { console.log(` ${bedingung ? "OK " : "FEHL"} ${text}`); if (!bedingung) fehler++; } console.log("=== 1. Richtiger Code wird angenommen ==="); let r = await versuch("RichtigerCode", "5.5.5.5"); pruefe(r.daten?.ok === true, "richtiger Code -> ok"); pruefe(!!r.cookies.dogi_session, "Sitzungs-Cookie wird gesetzt"); pruefe(r.cookies.dogi_role === "dogi", "Rolle 'dogi' erkannt"); console.log("\n=== 2. VanVan kommt ebenfalls rein ==="); r = await versuch("VanVanCode", "5.5.5.6"); pruefe(r.daten?.ok === true && r.cookies.dogi_role === "vanvan", "VanVan-Code -> ok, Rolle 'vanvan'"); console.log("\n=== 3. Falscher Code wird abgewiesen ==="); r = await versuch("Quatsch", "5.5.5.7"); pruefe(r.daten?.ok === false && r.statusCode === 401, "falscher Code -> 401"); console.log("\n=== 4. Sperre nach 5 Fehlversuchen (Angreifer-IP 9.9.9.9) ==="); for (let i = 0; i < 5; i++) await versuch("falsch" + i, "9.9.9.9"); r = await versuch("nochmal", "9.9.9.9"); pruefe(r.statusCode === 429, "gesperrte IP -> 429 (statt irrefuehrend 401)"); pruefe(/Zu viele Fehlversuche/.test(r.daten?.error || ""), "ehrliche Meldung statt 'Falscher Zugangscode'"); pruefe(/Minute/.test(r.daten?.error || ""), "Restzeit wird genannt"); console.log(` Meldung: "${r.daten?.error}"`); console.log("\n=== 5. DER EIGENTLICHE BUG: sperrt das auch Dogi aus? ==="); r = await versuch("RichtigerCode", "5.5.5.5"); pruefe(r.daten?.ok === true, "Dogi kommt trotz fremder Sperre rein (frueher: NEIN)"); console.log("\n=== 6. Auch der RICHTIGE Code bleibt fuer die gesperrte IP gesperrt ==="); r = await versuch("RichtigerCode", "9.9.9.9"); pruefe(r.statusCode === 429, "gesperrte IP kommt auch mit richtigem Code nicht rein"); console.log("\n=== 7. Ohne Cloudflare-Header: Rueckfall auf req.ip ==="); const res7 = antwort(); await gateAuthHandler({ headers: {}, ip: "10.0.0.5", body: { code: "RichtigerCode" } }, res7); pruefe(res7.daten?.ok === true, "funktioniert auch ohne Cloudflare-Header"); console.log("\n=== 8. Gefaelschter Header wird nicht blind uebernommen ==="); const res8 = antwort(); await gateAuthHandler({ headers: { "cf-connecting-ip": "kein-ip-wert; DROP TABLE" }, ip: "10.0.0.6", body: { code: "RichtigerCode" } }, res8); pruefe(res8.daten?.ok === true, "unsinniger Header -> sauberer Rueckfall, kein Absturz"); console.log(fehler === 0 ? "\n=> ALLE TESTS BESTANDEN" : `\n=> ${fehler} TESTS FEHLGESCHLAGEN`); process.exit(fehler === 0 ? 0 : 1);