From abf54765d83470538cf3dc087e7e2189abf35bcc Mon Sep 17 00:00:00 2001 From: Jeuner <62662523+Jeuners@users.noreply.github.com> Date: Tue, 25 Aug 2026 02:11:41 +0200 Subject: [PATCH] fix: Rufnummern bei Testzugang serverseitig maskieren, nicht nur per CSS blurren CSS-Blur (Sicher-Modus) verdeckt nur die Anzeige - im Seitenquelltext, DevTools oder Netzwerk-Tab standen die echten Rufnummern trotzdem drin, weil sie ganz normal im JSON von /api/anrufe und /api/verlauf ankamen. Bei Testzugang (per Token statt Passwort, self._via_token) werden nummer/ rueckrufnummer jetzt vor dem Senden durch einen Platzhalter ersetzt (_maskiere_anrufe), im Verlauf-Log werden eingebettete Ziffernfolgen ab 9 Stellen ersetzt (_maskiere_verlauf, gleiche Heuristik wie das bestehende Frontend-telBlur, nur serverseitig und wirklich ersetzend statt nur verdeckend). Die echten Werte verlassen den Server in diesem Modus nicht mehr. Getestet: 13 unmaskierte Rufnummern im Verlauf bei Passwort-Zugriff, 0 bei Token-Zugriff; _maskiere_anrufe() isoliert verifiziert. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_015vtvcyNkapuDh583643hNs --- pipe/server.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/pipe/server.py b/pipe/server.py index 19e2d5d..1148102 100644 --- a/pipe/server.py +++ b/pipe/server.py @@ -229,6 +229,30 @@ def verlauf(anzahl: int = 150) -> list[dict]: return alle[-anzahl:] +# Bei Testzugang (kein Passwort, oeffentlicher Link) werden Rufnummern nicht +# nur im Frontend per CSS geblurred (das verdeckt nur die Anzeige - im +# Seitenquelltext/DevTools/Netzwerk-Tab stehen sie trotzdem echt drin), +# sondern schon hier serverseitig ersetzt. Die echten Werte verlassen den +# Server in diesem Modus gar nicht erst. +_MASKE = "•••• •••• •••" + + +def _maskiere_anrufe(anrufe_liste: list[dict]) -> list[dict]: + for a in anrufe_liste: + if a.get("nummer"): + a["nummer"] = _MASKE + if a.get("rueckrufnummer"): + a["rueckrufnummer"] = _MASKE + return anrufe_liste + + +def _maskiere_verlauf(eintraege: list[dict]) -> list[dict]: + for e in eintraege: + if e.get("text"): + e["text"] = re.sub(r"\d{9,}", "•••••••••", e["text"]) + return eintraege + + class Handler(BaseHTTPRequestHandler): def log_message(self, *_): # kein Zugriffslog auf der Konsole pass @@ -307,9 +331,15 @@ class Handler(BaseHTTPRequestHandler): daten["testzugang"] = getattr(self, "_via_token", False) self._json(daten) elif pfad == "/api/anrufe": - self._json({"stapel": stapel.erlaubt(), "anrufe": anrufe()}) + liste = anrufe() + if getattr(self, "_via_token", False): + liste = _maskiere_anrufe(liste) + self._json({"stapel": stapel.erlaubt(), "anrufe": liste}) elif pfad == "/api/verlauf": - self._json(verlauf(150)) + eintraege = verlauf(150) + if getattr(self, "_via_token", False): + eintraege = _maskiere_verlauf(eintraege) + self._json(eintraege) elif pfad == "/api/modell": self._json({"aktuell": modellwahl.aktuelle_id(), "optionen": modellwahl.AUSWAHL}) elif pfad.startswith("/audio/"):