Ergänzung Datenschutzerklärung und Impressum, Fristenformular in Einstellungen

This commit is contained in:
2026-08-10 06:44:11 +02:00
parent 8ffbda875e
commit 777e3e5447
25 changed files with 1310 additions and 139 deletions

View File

@@ -59,6 +59,50 @@ def normalize_email(email: str) -> str:
return email.strip().lower()
# --------------------------------------------------------------------------
# Schluessel fuer die Missbrauchsbremse
# --------------------------------------------------------------------------
#
# Die Zaehler brauchen einen Schluessel je Absender - IP-Adresse oder
# E-Mail-Adresse. Beides im Klartext abzulegen waere unnoetig: Fuer das
# Hochzaehlen genuegt ein Wert, der gleich bleibt; lesbar muss er nicht
# sein.
#
# Deshalb ein Streuwert mit einem zufaelligen, installationsweiten
# Zusatz. Das ist Pseudonymisierung, keine Anonymisierung - wer die
# Datenbank samt Zusatz hat, koennte eine vermutete Adresse
# nachrechnen. Es verhindert aber, dass beim Blick in die Tabelle
# Adressen mitgelesen werden, und die Werte verschwinden ohnehin nach
# 24 Stunden.
_bucket_salt: str | None = None
def _salt(db: Session) -> bytes:
"""Zufallszusatz, beim ersten Bedarf erzeugt und dann bestaendig."""
global _bucket_salt
if _bucket_salt is None:
from app.models import Setting
row = db.get(Setting, "ratelimit_salt")
if row is None:
value = secrets.token_hex(16)
db.add(Setting(key="ratelimit_salt", value=value))
db.flush()
else:
value = row.value
_bucket_salt = value
return _bucket_salt.encode()[:32]
def bucket_key(db: Session, prefix: str, value: str) -> str:
"""Erzeugt einen Zaehlerschluessel, ohne den Wert selbst abzulegen."""
digest = hashlib.blake2s(
value.encode("utf-8"), key=_salt(db), digest_size=16
).hexdigest()
return f"{prefix}:{digest}"
def check_rate_limit(
db: Session, bucket: str, *, limit: int, window_minutes: int
) -> bool: