Files
aza/backup backup backup backup/backup 24.2.26 - Kopie/aza_firewall.py
2026-03-30 07:59:11 +02:00

179 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
AZA Desktop Windows-Firewall-Handling.
Minimale lokale Regel fuer Backend auf 127.0.0.1:8000.
"""
import os
import sys
import subprocess
_RULE_NAME = "AZA Desktop - Lokale Kommunikation"
_BACKEND_PORT = 8000
def add_firewall_rule_if_needed() -> tuple[bool, str]:
"""
Legt eine minimale Windows-Firewall-Regel fuer das lokale AZA-Backend an.
Nur fuer aza_desktop.exe, TCP 8000, Remote 127.0.0.1 (localhost).
Gibt (erfolg, meldung) zurueck.
"""
if sys.platform != "win32":
return True, ""
exe_path = ""
if getattr(sys, "frozen", False):
exe_path = sys.executable
else:
# Dev: Basis-Pfad ermitteln
base = os.path.dirname(os.path.abspath(__file__))
for _ in range(5):
candidate = os.path.join(base, "aza_desktop.exe")
if os.path.isfile(candidate):
exe_path = candidate
break
parent = os.path.dirname(base)
if parent == base:
break
base = parent
if not exe_path or not os.path.isfile(exe_path):
return False, "aza_desktop.exe nicht gefunden"
exe_path = os.path.normpath(exe_path)
# Regel loeschen falls vorhanden (idempotent)
try:
subprocess.run(
[
"netsh", "advfirewall", "firewall", "delete", "rule",
f"name={_RULE_NAME}",
],
capture_output=True,
timeout=10,
creationflags=subprocess.CREATE_NO_WINDOW if hasattr(subprocess, "CREATE_NO_WINDOW") else 0,
)
except Exception:
pass
# Regel anlegen
try:
result = subprocess.run(
[
"netsh", "advfirewall", "firewall", "add", "rule",
f"name={_RULE_NAME}",
"dir=in",
"action=allow",
f"program={exe_path}",
f"localport={_BACKEND_PORT}",
"protocol=tcp",
"remoteip=127.0.0.1",
],
capture_output=True,
text=True,
timeout=10,
creationflags=subprocess.CREATE_NO_WINDOW if hasattr(subprocess, "CREATE_NO_WINDOW") else 0,
)
if result.returncode == 0:
return True, "Firewall-Regel angelegt"
err = (result.stderr or result.stdout or "").strip()
return False, err or f"Rueckcode {result.returncode}"
except subprocess.TimeoutExpired:
return False, "Zeitueberschreitung"
except Exception as e:
return False, str(e)
def check_firewall_rule() -> dict:
"""
Prueft ohne Adminrechte, ob die erwartete Firewall-Regel existiert.
Gibt dict mit keys: exists, program_ok, port_ok, protocol_ok, remote_ok, detail
"""
result = {
"exists": False,
"program_ok": None,
"port_ok": None,
"protocol_ok": None,
"remote_ok": None,
"detail": "",
}
if sys.platform != "win32":
result["detail"] = "Nur unter Windows relevant"
return result
try:
proc = subprocess.run(
[
"netsh", "advfirewall", "firewall", "show", "rule",
f"name={_RULE_NAME}", "verbose",
],
capture_output=True,
text=True,
timeout=10,
creationflags=(
subprocess.CREATE_NO_WINDOW
if hasattr(subprocess, "CREATE_NO_WINDOW")
else 0
),
)
except Exception as e:
result["detail"] = f"Pruefung nicht moeglich: {e}"
return result
stdout = proc.stdout or ""
if proc.returncode != 0 or _RULE_NAME not in stdout:
result["detail"] = "Regel nicht vorhanden"
return result
result["exists"] = True
lower = stdout.lower()
if "tcp" in lower:
result["protocol_ok"] = True
else:
result["protocol_ok"] = False
if str(_BACKEND_PORT) in stdout:
result["port_ok"] = True
else:
result["port_ok"] = False
if "127.0.0.1" in stdout or "localsubnet" in lower:
result["remote_ok"] = True
else:
result["remote_ok"] = False
if "aza_desktop" in lower:
result["program_ok"] = True
else:
result["program_ok"] = False
problems = []
if not result["protocol_ok"]:
problems.append("Protokoll")
if not result["port_ok"]:
problems.append("Port")
if not result["remote_ok"]:
problems.append("Remote-IP")
if not result["program_ok"]:
problems.append("Programm")
if problems:
result["detail"] = "Regel vorhanden, Details abweichend: " + ", ".join(problems)
else:
result["detail"] = "Regel korrekt (TCP 8000, localhost, programmgebunden)"
return result
def get_firewall_hint_text() -> str:
"""Ruiger Hinweistext fuer den Nutzer bei Firewall-Popup oder Backend-Problem."""
return (
"Windows hat eine Rueckfrage zur lokalen Netzwerkkommunikation von AZA angezeigt.\n\n"
"AZA verwendet lokal laufende Komponenten auf diesem Computer. "
"Die Rueckfrage betrifft die interne Kommunikation der App.\n\n"
"Fuer den lokalen Betrieb von AZA koennen Sie fortfahren bzw. "
"den Zugriff fuer private Netzwerke erlauben."
)