Terminplaner: Empfaenger-Kappe ueber Betriebe (G01, Freitext in G04/G06)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-04 10:03:39 +00:00
1 parent c35711caad
commit 4d96565240
5 files changed
+257 -18

No files matched your search

+27 -3
View File
@@ -13,8 +13,11 @@ import { pruefeNow, pruefeText } from './util.js'
* Buchung, ein Treffer bekommt seine Mails immer.
* Oeffentliche Schnittstelle (routes/publicTermine.js): darfAnfrage / darfAnfrageSite (lesende Abrufe und Token-Aufrufe
* je IP und je siteKey), darfBuchungsversuch (je IP), darfHaltung (je siteKey), darfWiderrufsversuch (je IP) und darfG01
* (Bestaetigungsmails je Adresse und Funktion). IPv6-Adressen zaehlen je /64 (ipSchluessel): ein Anschluss bekommt meist
* (Bestaetigungsmails je Adresse). IPv6-Adressen zaehlen je /64 (ipSchluessel): ein Anschluss bekommt meist
* ein ganzes /64, die Adresse darin wechselt beliebig.
* Empfaenger-Kappe: eine fremde Adresse bekommt ueber alle Betriebe (Funktionen) zusammen hoechstens 3 Mails je Stunde und
* 10 je Tag, die ein Gast oder ein Betrieb ausloest (darfG01 beim Gast-Formular, darfEmpfaenger fuer den Freitext des
* Betriebs in G04/G06, mails.js anGast); beide teilen dieselben Zaehler.
*
* Speicher: zwei getrennte Maps mit je hoechstens 10 000 Schluesseln. Die Zaehler je IP (Schluessel mit 'ip:') haben
* beliebig viele, von Angreifern frei waehlbare Schluessel; sie duerfen die langlebigen Zaehler je Adresse, Funktion
@@ -46,6 +49,9 @@ const HALTUNGEN_JE_SITE = 25
const WIDERRUFE_JE_IP = 10
/** G01 (Bestaetigungsmail, auch "zu viele"): je Adresse und Funktion und Tag. */
const G01_JE_ADRESSE = 5
/** Empfaenger-Kappe ueber alle Funktionen: je (normalisierter) Adresse und Stunde, je Adresse und Tag. */
const EMPFAENGER_JE_STUNDE = 3
const EMPFAENGER_JE_TAG = 10
/**
* Eine Map schluessel -> { start, ende (ms), n }; die Einfuegereihenfolge ist die Reihenfolge der Fensterbeginne.
@@ -195,9 +201,27 @@ export function darfWiderrufsversuch(ip, now) {
return zaehle(`ip:widerruf:${ipSchluessel(ip)}`, WIDERRUFE_JE_IP, STUNDE_MS, now)
}
/** Darf an diese (normalisierte) Adresse eine G01 gehen? Hoechstens 5 je Adresse und Funktion und Tag (gehalten wie "zu viele"). */
/** Die zwei Regeln der Empfaenger-Kappe (Stunde und Tag) fuer eine normalisierte Adresse, ueber alle Funktionen. */
const empfaengerRegeln = (adresse) => [
{ schluessel: `empfaenger-h:${adresse}`, max: EMPFAENGER_JE_STUNDE, fensterMs: STUNDE_MS },
{ schluessel: `empfaenger-d:${adresse}`, max: EMPFAENGER_JE_TAG, fensterMs: TAG_MS },
]
/**
* Darf an diese (normalisierte: klein, getrimmt) Adresse eine G01 gehen? Hoechstens 5 je Adresse und Funktion und Tag
* (gehalten wie "zu viele") und die Empfaenger-Kappe ueber alle Funktionen (3 je Stunde, 10 je Tag). Alles oder nichts:
* eine abgelehnte Anfrage erhoeht keinen Zaehler.
*/
export function darfG01(featureId, adresse, now) {
return zaehle(`g01:${featureId}:${adresse}`, G01_JE_ADRESSE, TAG_MS, now)
return zaehleAlle([{ schluessel: `g01:${featureId}:${adresse}`, max: G01_JE_ADRESSE, fensterMs: TAG_MS }, ...empfaengerRegeln(adresse)], now)
}
/**
* Darf an diese (normalisierte) Adresse eine Mail mit Freitext des Betriebs gehen (G04, G06)? Dieselben Zaehler wie
* darfG01 (3 je Stunde, 10 je Tag ueber alle Funktionen), aber ohne die Regel je Funktion.
*/
export function darfEmpfaenger(adresse, now) {
return zaehleAlle(empfaengerRegeln(adresse), now)
}
/** Leert alle Zaehler (Tests). */