feat: mehrere Leitstand-Zugaenge gleichzeitig (LEITSTAND_ZUGAENGE)

Bisher gab es genau ein Nutzer/Passwort-Paar (LEITSTAND_USER/LEITSTAND_PASS).
Fuer einen zweiten Einsatzzweck/ein zweites Team am selben Leitstand (z.B.
Notdienst neben Praxis) reicht das nicht. LEITSTAND_ZUGAENGE in der .env
nimmt jetzt zusaetzliche "nutzer:passwort"-Paare (kommagetrennt) an - das
bestehende LEITSTAND_USER/LEITSTAND_PASS bleibt als erstes Konto gueltig,
config.leitstand_konten() buendelt alle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EbdWYnDtyMgxsq4eN1WnrQ
This commit is contained in:
Jeuner 2026-08-28 18:10:31 +02:00
parent 87621e5bec
commit 795dcf7eeb
3 changed files with 23 additions and 3 deletions

View file

@ -99,6 +99,9 @@ LEITSTAND_HOST=127.0.0.1
LEITSTAND_PORT=8088
LEITSTAND_USER=praxis
LEITSTAND_PASS=
# Weitere Konten zusaetzlich zum obigen - kommagetrennt "nutzer:passwort",
# z.B. fuer ein zweites Team/einen zweiten Einsatzzweck neben "praxis".
LEITSTAND_ZUGAENGE=
# Optional: geteiltes Geheimnis fuer signierte, 1h gueltige Testzugangslinks
# (z.B. per Chatbot-Kommando ausgegeben). Leer = Feature aus.

View file

@ -117,6 +117,22 @@ LEITSTAND_PORT = int(os.environ.get("LEITSTAND_PORT", "8088"))
# auf den Seiten stehen Transkripte und Aufnahmen von Patienten.
LEITSTAND_USER = os.environ.get("LEITSTAND_USER", "praxis")
LEITSTAND_PASS = os.environ.get("LEITSTAND_PASS", "")
# Weitere Konten zusaetzlich zum obigen (z.B. ein eigenes Konto fuer den
# Notdienst neben dem Praxis-Konto) - kommagetrennt "nutzer:passwort",
# z.B. "notdienst:Berg,spaeter:nochwas".
LEITSTAND_ZUGAENGE = os.environ.get("LEITSTAND_ZUGAENGE", "")
def leitstand_konten() -> dict[str, str]:
"""Alle gueltigen Leitstand-Logins als {nutzername: passwort}."""
konten = {}
if LEITSTAND_PASS:
konten[LEITSTAND_USER] = LEITSTAND_PASS
for eintrag in LEITSTAND_ZUGAENGE.split(","):
nutzer, _, passwort = eintrag.strip().partition(":")
if nutzer and passwort:
konten[nutzer] = passwort
return konten
# Geteiltes Geheimnis mit dilles-agent.php ("agent-one test"-Kommando auf
# dillenberg.net) fuer signierte, 1h gueltige Testzugangslinks - siehe

View file

@ -186,7 +186,8 @@ class Handler(BaseHTTPRequestHandler):
"""
self._zusatz_header: list[tuple[str, str]] = []
self._via_token = False # True nur bei Zugang per Testzugangs-Token, nicht Passwort
if not config.LEITSTAND_PASS:
konten = config.leitstand_konten()
if not konten:
return True
token = parse_qs(urlparse(self.path).query).get("zugang", [None])[0]
@ -209,8 +210,8 @@ class Handler(BaseHTTPRequestHandler):
except Exception:
return False
# compare_digest: Vergleichsdauer verrät nichts über das Passwort.
return (hmac.compare_digest(nutzer, config.LEITSTAND_USER)
and hmac.compare_digest(wort, config.LEITSTAND_PASS))
erwartet = konten.get(nutzer)
return erwartet is not None and hmac.compare_digest(wort, erwartet)
def _anmeldung_verlangen(self) -> None:
self.send_response(401)