Logpy-AgentOne/pipe/audit.py
Jeuner 989d3ba85b feat: Leitstand-Fixes, Sicher-Modus, Notfall-Alarm, Audit-Log + Loeschfristen
- Audio-Wiedergabe im Leitstand brach durch Auto-Refresh (setInterval) ab,
  Karten-DOM wurde per innerHTML neu gebaut waehrend ein <audio> lief.
  takt() pausiert jetzt, solange eine Aufnahme abgespielt wird. Zusaetzlich
  HTTP-Range-Unterstuetzung fuer /audio/ nachgeruestet (war vorher immer
  volle Datei statt 206 Partial Content).
- Sicher-Modus: Rufnummern per Klick blurren, fuer Screenshots/Aufnahmen.
- Notfall-Alarm: pulsierender Karten-Rahmen + Banner + minuetlicher Ton,
  solange ein Notfall nicht im letzten Stapel (Erledigt) liegt.
- Favicon.
- Neues unveraenderliches audit.log (append-only, macOS uappnd-Flag) als
  Nachweis fuer den Umgang mit Anrufdaten - protokoll.schreibe() spiegelt
  jetzt jedes Ereignis dorthin, zusaetzlich zum rotierenden verlauf.log.
- pipe.loeschen: loescht erledigte Anrufe nach LOESCHFRIST_TAGE (lokal +
  Nextcloud), unbearbeitete Anrufe (nicht im letzten Stapel) bleiben immer
  unangetastet. Gedacht fuer taeglichen Cron-Lauf.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015vtvcyNkapuDh583643hNs
2026-08-24 19:13:09 +02:00

50 lines
1.7 KiB
Python

"""Unveraenderliches Ereignisprotokoll - Nachweis fuer den Umgang mit
Anrufdaten (u.a. Loeschungen nach Ablauf der Aufbewahrungsfrist).
Anders als protokoll.log (das fuers Leitstand-UI auf die letzten 2000 Zeilen
gekuerzt wird) wird diese Datei nie gekuerzt oder ueberschrieben - nur
angehaengt. Zusaetzlich technisch gegen nachtraegliches Aendern/Loeschen
abgesichert: macOS' uappnd-Flag (append-only) laesst nur noch Anhaengen zu,
selbst der eigene Prozess kann die Datei danach nicht mehr kuerzen oder
umschreiben, ohne das Flag vorher explizit aufzuheben (`chflags nouappnd`).
Auf anderen Betriebssystemen (kein chflags) ist das Log weiterhin
append-only per Konvention, nur ohne das zusaetzliche OS-Siegel.
"""
from __future__ import annotations
import json
import subprocess
from datetime import datetime
from . import config
DATEI = config.TELEFON / "audit.log"
_gesichert = False
def _absichern() -> None:
"""Setzt das append-only-Flag einmal pro Prozesslaufzeit. Wirft nie."""
global _gesichert
if _gesichert:
return
_gesichert = True
try:
subprocess.run(["chflags", "uappnd", str(DATEI)],
check=False, capture_output=True)
except Exception:
pass
def schreibe(art: str, text: str, **felder) -> None:
"""Haengt ein Ereignis unveraenderlich an. Wirft nie."""
try:
DATEI.parent.mkdir(parents=True, exist_ok=True)
if not DATEI.exists():
DATEI.touch()
eintrag = {"zeit": datetime.now().isoformat(timespec="seconds"),
"art": art, "text": text, **felder}
with DATEI.open("a", encoding="utf-8") as f:
f.write(json.dumps(eintrag, ensure_ascii=False) + "\n")
_absichern()
except Exception:
pass