update
This commit is contained in:
178
AzA march 2026 - Kopie (18)/aza_firewall.py
Normal file
178
AzA march 2026 - Kopie (18)/aza_firewall.py
Normal file
@@ -0,0 +1,178 @@
|
||||
# -*- 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."
|
||||
)
|
||||
Reference in New Issue
Block a user