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")