From 5af03eedb9cbced2723487362ac8f8c91aad8186 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 31 Oct 2026 17:43:04 +0100 Subject: [PATCH] fix(satellite): Geheimnisse aus FritzBox-Antworten erreichen ARIA nicht MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lesende TR-064-Aktionen geben teils Geheimnisse zurueck (GetSecurityKeys → WLAN-Schluessel, Kennwoerter, PINs). Die gingen bisher im Ergebnis an ARIA und damit ans Sprachmodell. Felder mit Passphrase/Password/PreSharedKey/ WEPKey/Secret/PIN werden jetzt als '•••• (verborgen)' geliefert. Schickt ARIA den Platzhalter in einer Set-Aktion zurueck, lehnt der Satellit ab — sonst setzte die Box ihn als neuen Schluessel. Co-Authored-By: Claude Opus 5.5 --- satellite/satellite.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/satellite/satellite.py b/satellite/satellite.py index 23363dc..fd85d32 100644 --- a/satellite/satellite.py +++ b/satellite/satellite.py @@ -1404,6 +1404,13 @@ def _fb_call(ip: str, user: str, pw: str, params: dict) -> dict: "erneut mit confirmed=true aufrufen.")} args = params.get("args") if isinstance(params.get("args"), dict) else {} args = {(k if k.startswith("New") else "New" + k): v for k, v in args.items()} + hidden = [k for k, v in args.items() if "(verborgen)" in str(v)] + if hidden: + # Sonst setzte die Box den Platzhalter als neuen Schluessel/Kennwort + return {"ok": False, "error": ( + f"{', '.join(hidden)}: das ist nur der Platzhalter fuer ein verborgenes Geheimnis, " + "nicht der echte Wert — so nicht senden. Geheimnisse aendert Stefan selbst " + "(FritzBox-Oberflaeche) oder er nennt den neuen Wert ausdruecklich.")} logger.info("[fritzbox] %s %s %s args=%s", ip, svc["short"], action, list(args)) r = _tr064(ip, user, pw, svc["type"], svc["control"], action, args) if not r.get("ok") and r.get("upnp_error") in _FB_2FA_CODES: @@ -1419,7 +1426,15 @@ def _fb_call(ip: str, user: str, pw: str, params: dict) -> dict: r = _tr064(ip, user, pw, svc["type"], svc["control"], action, args) if not r.get("ok"): return r - return {"ok": True, "result": {"ip": ip, "service": svc["short"], "action": action, **r["fields"]}} + # Geheimnisse, die die Box auf Lese-Anfragen herausgibt (WLAN-Schluessel, + # Kennwoerter, PINs), gehen NICHT an ARIA — ihre Antworten landen beim + # Sprachmodell. Stefan sieht sie in der FritzBox-Oberflaeche. + fields = {k: ("•••• (verborgen)" if _FB_SECRET_FIELD.search(k) and v else v) for k, v in r["fields"].items()} + return {"ok": True, "result": {"ip": ip, "service": svc["short"], "action": action, **fields}} + + +_FB_SECRET_FIELD = re.compile(r"Passphrase|Password|PreSharedKey|WEPKey|KeyPassphrase|Secret|PIN|Passwd|SharedKey", + re.IGNORECASE) FB_BACKUP_DIR = os.environ.get("FB_BACKUP_DIR", "/data/fritzbox-backups")