diff --git a/DEVLOG.md b/DEVLOG.md index 2f747a7..aa32b80 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -940,3 +940,17 @@ Keine Commits in dieser Session. - frontend/DEVLOG.md | 51 ++++++++++ --- +## 2026-05-24 12:48 – 12:49 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** timemaster + +### Commits +- 30828c6 feat: agent-02-kiosk Phase 2A - Auth endpoints (PIN/NFC/QR/List) + +### Geänderte Dateien +- DEVLOG.md | 16 +++ +- backend/app/routers/kiosk.py | 130 ++++++++++++++++++- +- backend/app/schemas/kiosk_auth.py | 38 ++++++ +- backend/app/services/kiosk_auth_service.py | 195 +++++++++++++++++++++++++++++ + +--- diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 4fb6540..b67da7f 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -33,6 +33,12 @@ class Settings(BaseSettings): first_superadmin_email: str = "" first_superadmin_password: str = "" + # CalDAV / outbound HTTP + # Kommaseparierte CIDR-Whitelist für interne CalDAV-Server (z.B. Nextcloud im LAN). + # Diese CIDRs sind vom SSRF-Schutz ausgenommen. + # Beispiel: CALDAV_ALLOWED_CIDRS=192.168.1.0/24,10.10.5.50/32 + caldav_allowed_cidrs: list[str] = [] + @model_validator(mode='after') def validate_secret_key(self): if self.app_env == 'production' and self.secret_key == 'change-me-in-production': diff --git a/backend/app/services/caldav_service.py b/backend/app/services/caldav_service.py index 27d0f7a..0c8526a 100644 --- a/backend/app/services/caldav_service.py +++ b/backend/app/services/caldav_service.py @@ -168,13 +168,38 @@ def _validate_caldav_url(url: str) -> None: raise ValueError(str(exc)) from exc +def _get_allowed_networks() -> list[ipaddress.IPv4Network | ipaddress.IPv6Network]: + """Gibt die konfigurierten Whitelist-Netzwerke zurück (CALDAV_ALLOWED_CIDRS).""" + from app.core.config import settings + networks = [] + for cidr in settings.caldav_allowed_cidrs: + cidr = cidr.strip() + if not cidr: + continue + try: + networks.append(ipaddress.ip_network(cidr, strict=False)) + except ValueError: + log.warning("Ungültiger CIDR in CALDAV_ALLOWED_CIDRS ignoriert: %r", cidr) + return networks + + def _check_ip_blocked(ip: ipaddress.IPv4Address | ipaddress.IPv6Address, hostname: str) -> None: - """Wirft ValueError wenn die IP in einem blockierten Netz liegt.""" + """Wirft ValueError wenn die IP in einem blockierten Netz liegt. + + Whitelist (CALDAV_ALLOWED_CIDRS) schlägt die Blockliste – + damit können interne Nextcloud-Server im LAN trotzdem genutzt werden. + """ + # Whitelist-Check zuerst: explizit erlaubte CIDRs überschreiben die Blockliste + for allowed in _get_allowed_networks(): + if ip in allowed: + return # explizit erlaubt → kein Fehler + for network in _BLOCKED_NETWORKS: if ip in network: raise ValueError( f"Host '{hostname}' ({ip}) liegt in einem privaten/reservierten " - f"Adressbereich ({network}) und darf nicht als CalDAV-Server genutzt werden." + f"Adressbereich ({network}) und darf nicht als CalDAV-Server genutzt werden. " + f"Tipp: Interne Server können per CALDAV_ALLOWED_CIDRS freigegeben werden." )