Auf einer echten, frisch installierten Ubuntu-24.04-VM (192.168.80.114,
Standard-Setup, Netz per DHCP) zeigten sich zwei reale Bugs:
1. Systemeinstellungen > Netzwerkeinstellungen: 'Kein unterstütztes
Backend erkannt' trotz laufendem Netz -- _detect_network_backend()
kannte nur NetworkManager und dhcpcd, nicht netplan/systemd-networkd,
den mit Abstand haeufigsten Fall auf einem normalen Ubuntu-Host.
Neues drittes Backend 'netplan' ergaenzt: Erkennung ueber
systemd-networkd + vorhandenes netplan-Binary, Moduserkennung ueber
das 'dynamic'-Flag des Kernels auf der aktuellen Adresse, Anwenden
ueber eine eigene Override-Datei (/etc/netplan/90-poe-manager.yaml,
gewinnt alphabetisch gegen z.B. cloud-inits 50-*.yaml) plus
Aufruf von netplan apply, Backup/Auto-Rollback wie bei den anderen
Backends.
Live verifiziert: Anwenden loeste echten DHCP-Lease-Renew aus, nach
Ablauf der 45s-Bestaetigungsfrist wurde die Override-Datei automatisch
wieder entfernt (Rollback funktioniert).
2. DHCP-Konfiguration: 'Keine IPv4-Adresse auf eth0 gefunden', obwohl
das Interface-Dropdown korrekt 'enp1s0' zeigte -- DHCP_DEFAULTS hatte
'eth0' hart kodiert (Annahme aus einer aelteren Testumgebung), was auf
Systemen mit Predictable Network Interface Names schlicht nicht
existiert. _load_dhcp_settings() korrigiert das jetzt: liegt der
gespeicherte/Default-Wert nicht unter den tatsaechlich vorhandenen
Schnittstellen, wird automatisch die erste echte vorgeschlagen.
Neue Abhaengigkeit PyYAML fuer das Schreiben der netplan-Override-Datei.
Live auf frischem Testsystem (Ubuntu 24.04, 192.168.80.114) verifiziert:
Skript brach beim Kopieren nach /srv/poe_manager mit 'rsync: command
not found' ab, weil rsync nirgends in der apt-get-install-Zeile stand.
Quelltext-Huerde wieder entfernt (auf Wunsch) - siehe vorherigen Commit,
hier nur der Revert von initSourceProtection() und der README-Erwaehnung.
SSH-Terminal-Login war komplett kaputt (von dir gemeldet + Screenshot):
- Root Cause: das Init-Payload vom Browser enthielt nie ein Passwort,
SSHClient.connect() bekam also weder Passwort noch Key noch Agent und
scheiterte sofort mit "No authentication methods available" - noch
bevor ueberhaupt eine interaktive Passwortabfrage moeglich gewesen
waere (die High-Level-API erledigt Host-Key-Pruefung UND
Authentifizierung in einem blockierenden Aufruf).
- Fix: Umstieg auf die Low-Level paramiko.Transport-API. Nach
Host-Key-Bestaetigung wird aktiv erfragt, welche Auth-Methoden der
Server anbietet (auth_none), und bei Bedarf interaktiv ueber das
Browser-Terminal nach Passwort/keyboard-interactive-Prompts gefragt
-- genau das Verhalten, das der bestehende Hinweistext im Modal schon
immer versprach, aber nie tatsaechlich implementiert war.
Host-Key-Verifikation dabei manuell nachgebaut (_verify_host_key_interactive)
inkl. hartem Ablehnen bei GEAENDERTEM (nicht nur unbekanntem) Host-Key,
wie ein echtes ssh-CLI bei einer moeglichen MITM-Situation.
- Waehrend der Live-Verifikation gegen ein echtes Geraet zwei weitere
Bugs gefunden und gefixt: ws.receive() wirft in diesem Setup
ConnectionClosed statt None zurueckzugeben (crashte
_terminal_read_line unbehandelt -> "Invalid frame header" beim
Client); _send_and_close() crashte ebenso, wenn der Client bereits weg
war. Beide jetzt defensiv abgefangen.
- Live gegen ein echtes Zielgeraet verifiziert (Host-Key-Bestaetigung,
Passwort-Prompt, erfolgreicher Login) sowie manuell von dir bestaetigt.
Kaputtes DOM in zwei Bearbeiten-Modals (von dir gemeldet: "Verbindung
testen" oeffnete beim Switch bearbeiten kein Fenster, obwohl es beim
Neuanlegen funktionierte):
- Root Cause: <div class="modal-overlay">...</div> stand direkt in
<tbody> (nur <tr> ist dort gueltig). Browser "foster-parenten"
ungueltigen Tbody-Inhalt aus der Tabelle heraus und zerreissen dabei
teils die Eltern-Kind-Beziehung zwischen <form> und seinen Buttons --
this.closest("form") lieferte dadurch null statt des Formulars.
Betroffen: editSwitchModal (switches.html), deviceOptionsModal
(settings_dhcp.html). Fix: beide Modal-Bloecke aus der Tabelle heraus
in eine eigene Schleife direkt danach verschoben (gleiches Muster wie
die bereits korrekten Neuanlegen-Modals).
- Per DOM-Inspektion verifiziert: this.closest("form") lieferte vorher
null, danach das korrekte Formular fuer alle Zeilen; End-to-End-Test
bestaetigt, dass sich das Terminal-Modal jetzt oeffnet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Hostname (Systemeinstellungen, neben Pruefintervall):
- hostnamectl set-hostname ueber die App, Validierung (RFC-1123-artiges
Label), kein Revert-Timer noetig (kappt die Erreichbarkeit nicht wie
eine IP-Aenderung). Live getestet inkl. Validierung und Revert.
DHCP: Range ist jetzt Pflicht, kein geratener Default mehr:
- dhcp_range_start/end/dns starten leer (Platzhaltertext statt fake-
echt aussehendem Default) - ein Zufalls-Range haette den Dienst sonst
unbemerkt mit einer zum echten Netz nicht passenden Konfiguration
starten lassen koennen.
- write_dhcp_file und dhcp_service_action=enable_restart verweigern sich
ohne eingetragene Range; _render_kea_config laesst "pools" ohne Range
komplett weg statt einen kaputten Pool-String zu erzeugen.
- Neues, separates dhcp_gateway-Feld (optional) fuer einen vom
automatisch erkannten Gateway abweichenden Router fuer die Clients.
Topbar-Ampel fuer den Kea-Dienst:
- Gruener/roter Punkt neben dem Pruefintervall-Timer, nur sichtbar mit
settings_dhcp.view (ein einzelner, kurzer systemctl-Aufruf pro Request,
nicht die volle Status-Erkennung). Live verifiziert (rot wenn gestoppt,
gruen wenn gestartet).
Reservierungstabelle zeigt jetzt pro Client, welche eigene DHCP-Option
greift (global oder Client-Override, mit Wert im Tooltip).
Text-Straffung: die laengsten Hint-Texte und Code-Kommentare in
Templates/app.py gekuerzt (u.a. groups.html, settings_dhcp.html,
account.html, devices/switches/users/credentials.html, zwei grosse
Migrations-/DHCP-Kommentarbloecke in app.py) - Kernaussagen erhalten,
Redundanz entfernt.
Quelltext-Huerde (KEINE echte Sicherheit, nur Abschreckung): Rechtsklick
und DevTools-/Quelltext-Shortcuts per JS blockiert. Klar dokumentiert
in Kommentar + README, dass der Browser HTML/CSS/JS immer vollstaendig
ausliefert und das in Sekunden umgehbar ist - echte Absicherung bleiben
ausschliesslich die serverseitigen Rechteprüfungen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bisher enthielt "Systemeinstellungen" nur das Pruefintervall. Jetzt
zusaetzlich Verwaltung der Netzwerkkonfiguration DIESES Hosts (getrennt
vom Kea-DHCP-*Server* fuer Clients):
- Backend-Erkennung (NetworkManager vs. dhcpcd via systemctl is-active).
Kein erkanntes Backend -> Seite bleibt rein lesend statt zu raten.
- Status-Anzeige: Interface, IP/Prefix, Gateway, DNS, Modus (DHCP/Statisch).
- Aenderung: Interface, Modus, bei Statisch IP/Prefix/Gateway, DNS
unabhaengig von Modus setzbar (IP per DHCP + feste DNS moeglich).
- Sicherheitsnetz analog "netplan try": Backup vor jeder Aenderung,
automatisches Rollback nach 45s ohne explizite Bestaetigung (nur
moeglich, wenn die Seite ueber die neue Config noch erreichbar ist) --
verhindert Aussperren durch einen Tippfehler bei IP/Gateway.
- Bugfix waehrend der Implementierung gefunden: der Auto-Revert-Timer
laeuft in einem Hintergrund-Thread ohne Request-Kontext: log_action()
griff auf current_user zu und warf dort einen AttributeError (die
Config wurde trotzdem korrekt zurueckgerollt, nur der Audit-Log-Eintrag
fehlte und ein Fehler landete im Server-Log). Fix: log_action_system()
ohne current_user-Abhaengigkeit fuer Code ausserhalb des Request-
Kontexts.
- Getestet: Backend-Erkennung + rein lesender Fallback live (WSL hat
weder NetworkManager noch dhcpcd aktiv, korrekt erkannt), Rechte-Gating,
Anwenden-/Rollback-Logik fuer beide Backends per gemocktem
subprocess.run verifiziert (inkl. echtem dhcpcd.conf-Rewrite und
vollständigem Anwenden-dann-Auto-Rollback-Durchlauf mit Audit-Log-
Eintrag).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Neuer Settings-Schluessel nav_child_order (JSON dict group_key ->
geordnete Liste der Kind-Keys), analog zu nav_order fuer die Top-Level-
Reihenfolge. _ordered_nav_items() liefert die komplette, ungefilterte
Navbar-Struktur inkl. angewandter Kind-Reihenfolge; inject_nav() filtert
das anschliessend weiterhin nach Berechtigung wie bisher.
- save_nav_order() verarbeitet zusaetzlich ein Feld
nav_child_order_<group_key> pro Gruppe mit Kindern.
- account.html: Navbar-Reihenfolge-Karte jetzt UNTER Profil/Passwort
aendern (vorher darueber), zeigt die komplette Navbar inkl.
eingerueckter, separat sortierbarer Unterpunkte pro Gruppe
(verschachtelte <ul>, moveNavItem() bewegt automatisch nur innerhalb
der eigenen Gruppe dank DOM-Nesting).
- Live per Playwright verifiziert: Zugangsdaten innerhalb Geraete nach
oben verschoben, gespeichert, Sidebar zeigt danach tatsaechlich die
neue Reihenfolge (Zugangsdaten vor Clients/Switche).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- permission_tree() bekommt einen dritten Parameter compact=false, der
nur im Dropdown der Hauptseite (Admin-/System-/editierbare Gruppen)
auf true gesetzt wird, nicht im "Neue Gruppe"-Modal.
- .permission-groups-row--compact verkleinert Zeilen-/Spalten-Padding
und die Einrueckung der Unterpunkte (32px statt 48px) NUR fuer diese
Instanzen - das Modal behaelt exakt sein bisheriges Aussehen.
- Modal und Dropdown nutzen weiterhin denselben Code/dieselbe Struktur
(permission_table()-Macro, Kill-Switch-Logik, JS-Gating), nur die
Abstaende unterscheiden sich ueber die Zusatzklasse.
- Verifiziert per Screenshot: Dropdown jetzt sichtbar kompakter (engere
Zellen, kuerzere Zeilen), Modal unveraendert; Gruppen anlegen-mit-
Rechten und Gruppen-Bearbeiten-Regression funktionieren weiterhin.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- addGroupModal, addCredentialModal, addOptionModal (DHCP), addSwitchModal,
deviceModal (Gerät anlegen), userModal (Benutzer anlegen) — bisher
unterschiedliche/keine explizite Breite, jetzt einheitlich 1000px für
ein konsistentes Erscheinungsbild. Bearbeiten-/Zuweisen-Modals bleiben
bei ihrer bisherigen (kleineren) Breite, da dort keine so breite
Rechtetabelle wie bei Neue Gruppe eingebettet ist.
- Live verifiziert: Modal-Breite tatsächlich 1000px (vorher lieferte ein
vergessener Flask-Neustart fälschlich 900px trotz bereits geänderter
Vorlage — Erinnerung: Template-Änderungen brauchen ohne
TEMPLATES_AUTO_RELOAD einen Neustart, anders als CSS/JS).
- Gruppen-Rechtetabelle bei 1440px (typische Breite dieser App) identisch
zum Neue-Gruppe-Modal nebeneinander, ohne Umbruch.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bugfix (von dir gemeldet, live auf Port 5000 gefunden):
- initConfirmables() in app.js rief beim bestätigten Absenden
form.requestSubmit() OHNE den ursprünglichen Submitter auf. Laut Spec
wird dann KEIN Submit-Button-Name/Value mitgeschickt. users.html trug
die Benutzer-ID als name/value des Löschen-Buttons selbst (statt eines
verstecken Inputs wie überall sonst) — dadurch kam "delete_user" nie
im Request an, der Klick tat scheinbar nichts. Fix: e.submitter beim
ersten Klick merken und an requestSubmit(submitter) weiterreichen
(behebt es grundsätzlich für alle Formulare dieser Art); zusätzlich
users.html auf das robustere hidden-input-Muster umgestellt wie
credentials/devices/groups. Mit echtem Playwright-Browserklick
(nicht nur curl) verifiziert.
Gruppen-Rechtetabelle, mehrere Korrekturrunden nach deinem Mockup:
- Bereichsname + Kill-Switch-Kästchen jetzt eng nebeneinander in der
Tabellen-Kopfzeile (nicht mehr an den Rand gestellt), R/W/E/D-Spalten
in derselben Zeile statt einer zweiten.
- Nur die von einem Bereich tatsächlich genutzten Spalten werden gezeigt
(GROUP_ROW_TYPES) — Logs zeigt nur R, Einstellungen nur R/W/E, nur
Geräte zeigt zusätzlich D.
- Bugfix: D-Spalte bei Geräte verschwand durch zu schmale Flex-Breite der
Spalte im Overflow, obwohl serverseitig korrekt gerendert — behoben
durch flex:0 0 auto statt fester Breite.
- Checkbox-Zentrierung robust per display:block+margin:auto statt sich
auf native Checkbox-Ränder zu verlassen (waren leicht asymmetrisch).
- Unterpunkte deutlich weiter eingerückt (34px) für klare Hierarchie.
- Sichtbares Ausgrauen (nicht nur natives disabled) der Unterpunkte,
solange der Bereich-Kill-Switch aus ist (JS setzt .permission-locked).
- Legende jetzt UNTER der Rechtetabelle statt darüber.
- Rechte lassen sich jetzt direkt beim Anlegen einer neuen Gruppe setzen
(Modal zeigt dieselbe Rechtetabelle, add_group-Route verarbeitet
mitgesendete permissions[] im selben Request) statt sie erst danach
über die Gruppentabelle nachzupflegen.
Alles inkl. Erstellen-mit-Rechten und Bearbeiten-Regression live per
Playwright verifiziert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Neue Helfer _list_network_interfaces() (echte Interfaces aus
/sys/class/net) und _detect_interface_network() (IPv4/Prefix per
"ip addr show", Gateway per "ip route show default") — Subnet/
Netzmaske/Router werden dadurch bei jeder Anzeige/Generierung live vom
System gelesen statt manuell gepflegt zu werden.
- dhcp_subnet/dhcp_netmask als manuelle Settings entfernt; Interface ist
jetzt ein Dropdown mit den tatsächlich vorhandenen Interfaces statt
Freitext, serverseitig zusätzlich gegen die echte Liste validiert.
- _dhcp_reservation_candidates()/_render_kea_config() nehmen jetzt das
erkannte Netz (ipaddress.IPv4Network) bzw. net_info entgegen statt
Subnet/Netzmaske aus der Konfiguration zu lesen; Router kommt vom
erkannten Gateway (Fallback: erster DNS-Eintrag, wie zuvor).
- UI zeigt das erkannte Netz (IP/Prefix, Subnet, Gateway) read-only an;
Schreiben/Vorschau werden blockiert bzw. liefern eine leere
Reservierungsliste, wenn die Erkennung fehlschlägt, statt eine mit
Sicherheit falsche Konfiguration zu erzeugen.
- Live getestet: Erkennung liefert korrekt das tatsächliche WSL-NAT-Netz
(172.25.64.0/20) samt Gateway; generierte Config besteht kea-dhcp4 -t;
ein Testgerät mit IP im erkannten Netz erscheint korrekt als
Reservierung, Geräte außerhalb werden weiterhin sauber übersprungen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Backend-Wechsel von isc-dhcp-server (seit 2022 EOL) auf Kea DHCP
(kea-dhcp4-server) — aktiv weiterentwickelt, bildet "globaler Wert, pro
Client überschreibbar" nativ über Kea-Reservation-Option-Data ab.
- Neue Tabellen dhcp_option_defs/dhcp_option_values: eigene/herstellerspezifische
Options mit Code/Name/Typ/Beschreibung, Wert global sowie optional pro
Client (device_mac="" für global, siehe Kommentar zur SQLite-NULL-
UNIQUE-Falle). UI dafür: Optionen-Tabelle + "Neue Option"-Modal +
Pro-Client-Overrides-Modal je Reservierung.
- Kea-JSON-Generator (_render_kea_config): option-def für jede eigene
Option, globale Werte im Top-Level option-data, Client-Overrides im
option-data der jeweiligen Reservierung.
- Reservierungen werden jetzt zusätzlich auf Zugehörigkeit zum
konfigurierten Subnet gefiltert (_dhcp_reservation_candidates) — beim
Live-Test gegen echtes Kea gefunden: Kea lehnt Reservierungen außerhalb
ihres Subnets als Konfigurationsfehler ab, das muss also schon bei der
Generierung berücksichtigt werden statt erst beim Laden zu crashen.
- Neue, einzeln bestätigte Aktionen: "kea-dhcp4-server installieren"
(apt-get), "Aktivieren & (neu) starten" sowie "Stoppen"
(systemctl) — bewusst getrennt von "Konfiguration speichern"/"In
Datei schreiben".
- Live gegen eine echte, frisch installierte Kea-3.0.3-Instanz verifiziert:
Installation erfolgreich, generierte Config besteht "kea-dhcp4 -t",
Dienst übernimmt sie beim Neustart fehlerfrei (DHCP4_CONFIG_COMPLETE),
globaler Options-Wert und Client-Override erscheinen korrekt getrennt.
Danach wieder gestoppt; Paket bleibt installiert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Neue Unterseite unter Einstellungen (eigenes Rechtepaar
settings_dhcp.view/settings_dhcp.edit, in PERMISSIONS/NAV_ITEMS/
_nav_key_visible integriert, Kill-Switch über settings_group.view
greift wie bei den anderen Einstellungen-Unterpunkten).
- Rein lesende Installations-/Status-Erkennung (shutil.which("dhcpd"),
systemctl is-active isc-dhcp-server) — die App installiert/startet nie
selbst einen DHCP-Dienst, sondern zeigt bei fehlender Installation den
passenden manuellen Befehl an.
- Konfigurierbare Netzwerkparameter (Interface/Subnet/Netzmaske/Range/
DNS/Domain/Lease-Zeiten/Ausgabepfad), gespeichert als dhcp_*-Schlüssel
in der bestehenden settings-Tabelle.
- Reservierungen werden aus aktiven Geräten mit gültiger MAC+IP generiert
(Hostname aus Gerätename abgeleitet, Kollisionen automatisch
durchnummeriert, Geräte ohne MAC/IP werden übersprungen).
- "In Datei schreiben" (nur mit settings_dhcp.edit) schreibt eine
separate Include-Datei statt der aktiven dhcpd.conf; kein automatischer
Dienst-Reload/-Restart durch die App.
- Live getestet: Status-Erkennung, Config speichern, Reservierungs-
Generierung inkl. Namenskollisionen, Datei-Schreiben in sicheren
Testpfad, View-only-Gating (Formular ausgeblendet, POST blockiert),
Kill-Switch über settings_group.view.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Neue Spalte switches.ssh_port (nullable INTEGER), Migration für
bestehende DBs in _ensure_schema(), Feld in create_db.py ergänzt.
- Formular (Anlegen/Bearbeiten): optionales SSH-Port-Feld, Validierung
1-65535, leer -> NULL (= Standard 22 überall, SWITCH_DEFAULT_SSH_PORT).
Switch-Liste zeigt den effektiven Port inkl. "(Standard)"-Hinweis.
- generate_ips.py liefert den effektiven Port (Fallback 22) als eigenes
Pipe-Feld an poe.sh; poe.sh übernimmt es in disable_poe/enable_poe und
reicht es als "ssh -p <port>" an die expect-Skripte durch (Default
weiterhin 22 falls Parameter fehlt).
- Web-Terminal (Verbindungstest) sendet den im Formular eingetragenen
Port statt hartkodiert 22.
- Live getestet: gültiger/leerer/ungültiger Port beim Anlegen, korrekte
Weitergabe durch generate_ips.py inkl. Feldreihenfolge, die poe.sh
'read' erwartet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- "Ändern" deckt jetzt ausnahmslos überall Löschen mit ab (auch bei
Clients) — es gibt kein eigenes *.delete-Recht mehr. Betroffen:
devices/switches/credentials/users/groups.
- "D" in der Rechtetabelle bedeutet ausschließlich Dashboard-Neustart
(devices.restart, PoE-Neustart über das Dashboard-Popup) und existiert
nur bei Clients. Automatische Neustarts bei Ausfall (poe.sh) bleiben
davon komplett unabhängig.
- Gruppen-Rechtetabelle transponiert: Kategorien jetzt als Zeilen,
Rechte R(ead)/W(rite)/E(dit)/D(ashboard-Neustart) nebeneinander als
Spalten statt untereinander. Deckt sich besser mit dem Legenden-Format
und braucht weniger vertikalen Platz.
- Neue, einmalig laufende Migration (_migrated_permission_delete_fold_v2)
überführt bestehende *.delete-Grants verlustfrei in *.edit, bevor die
veralteten Rechte-Zeilen entfernt werden.
- Routen (delete_device/delete_switch/delete_credential/delete_user/
delete_group) und die zugehörigen can_delete-Template-Variablen prüfen
jetzt einheitlich *.edit statt *.delete.
- README-Rechtesystem-Abschnitt und Legende an das neue Tabellen-Layout
angepasst.
- Live getestet: Kill-Switch, alle 5 Delete-Foldings (mit/ohne Recht),
devices.restart-Gating unabhängig von devices.edit, Eskalationsschutz
(Admin-Löschschutz, Systemgruppen-Schutz) — alles bestätigt korrekt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Kompletter Umbau des Permission-Systems weg von groben is_admin-Gates hin zu
einem zweistufigen, an die Sidebar-Struktur gespiegelten Rechtebaum:
Geräte (devices_group.view)
├─ Clients Lesen/Schreiben/Ändern/Löschen (+ PoE-Neustart)
├─ Switche Lesen/Schreiben/Ändern/Löschen
└─ Zugangsdaten Lesen/Schreiben/Ändern/Löschen (jetzt eigene Rechte,
vorher an switches.* gekoppelt)
Logs (logs_group.view)
├─ Live Lesen
└─ Änderungen Lesen
Einstellungen (settings_group.view)
├─ Benutzer Lesen/Schreiben/Ändern/Löschen
├─ Gruppen Lesen/Schreiben/Ändern/Löschen
├─ Systemeinstellungen Lesen/Ändern
└─ Im-/Export Lesen (Export)/Ändern (Import)
- User.has_permission() ist jetzt hierarchisch: das "Bereich anzeigen"-Recht
einer Top-Level-Gruppe wirkt als Kill-Switch für alle Kind-Rechte
darunter, auch wenn ein Kind-Recht einzeln noch gesetzt ist. Mit
Testgruppe verifiziert (devices.view ohne devices_group.view -> /devices
liefert 302, "Geräte" verschwindet komplett aus der Sidebar; nach
Zurücksetzen sofort wieder 200).
- devices.toggle entfällt, ist jetzt Teil von devices.edit (Ändern).
- Neue eigenständige credentials.*-Rechte statt Kopplung an switches.*.
- Benutzer- und Gruppenverwaltung sind jetzt ebenfalls granular/delegierbar
(users.*/groups.*) statt fest is_admin-exklusiv — dafür neue,
fest einprogrammierte Eskalationsschranken: Admin-Konten anlegen/ändern/
löschen sowie Admin-Zuweisung bleiben unabhängig von delegierten Rechten
echten Admins vorbehalten (mit Testgruppe verifiziert: Anlegen als Admin,
Bearbeiten/Löschen bestehender Admin-Konten und Zuweisen zu "admin"
wurden alle korrekt blockiert, normale Benutzerverwaltung funktioniert).
- "Admin" (virtuell) und "Benutzer" (Standardgruppe, neues is_system-Flag)
sind jetzt echte Systemgruppen: weder umbenennbar noch in ihren Rechten
änderbar, auch nicht durch Admins über die UI — Mitgliedschaft bleibt frei
verwaltbar. Mit direktem POST verifiziert: Umbenennen/Löschen/Rechte-Reset
von "Benutzer" werden blockiert, Mitgliederverwaltung funktioniert weiter.
- groups.html zeigt den Baum jetzt als 3 Zeilen (Geräte/Logs/Einstellungen)
mit eingerückten Unterpunkten statt einer flachen Liste von Kategorien mit
wiederholtem Bereichsnamen im Label.
- Migration in _ensure_schema() (Altrechte übertragen, neue Bereichs-Rechte
für bestehende Gruppen nachtragen) läuft jetzt über einen Einmal-Guard in
der settings-Tabelle — lief anfangs bei jedem Neustart erneut und hat
damit den Kill-Switch-Mechanismus untergraben (ein deaktiviertes
Bereichs-Recht wäre bei jedem Neustart automatisch wieder gesetzt worden,
solange irgendein Kind-Recht noch aktiv war); im Test entdeckt und behoben.
- create_db.py synchronisiert (is_system-Spalte, neuer Rechtesatz für
Frischinstallationen).
- README: Rechtesystem-Abschnitt komplett neu beschrieben (Baum, Kill-Switch,
Systemgruppen, Eskalationsschutz).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Vollständiges Audit aller Routen gegen das Rechtesystem durchgeführt. Die
Nav-Sichtbarkeit stufte "Live" (Live-Log) bereits korrekt als admin-only ein
(_nav_key_visible: logs_live -> user.is_admin), die zugehörigen Routen
/logs und /get_log prüften das aber nie tatsächlich — nur @login_required.
Jeder eingeloggte Benutzer, unabhängig von seinen Gruppen-Rechten, konnte
das Live-Log damit direkt per URL aufrufen, obwohl die Sidebar es korrekt
ausblendete.
- /logs: fehlende is_admin-Prüfung ergänzt (Flash + Redirect, konsistent zu
activity_log()/users()/groups()/settings()).
- /get_log: fehlende is_admin-Prüfung ergänzt (403, da per AJAX abgerufen).
Alle anderen neu hinzugekommenen Seiten (Benutzer, Gruppen, Systemein-
stellungen, Im-/Export, Änderungslog, Jetzt-prüfen-Trigger) waren bereits
korrekt und bewusst exklusiv auf is_admin geprüft — dort gibt es keine
sinnvolle granularere Rechte-Stufe unterhalb von Admin (Gruppenverwaltung
steuert das Rechtesystem selbst, Systemeinstellungen/Import-Export/manuelle
Prüfung wirken global). Zugangsdaten bleiben bewusst an switches.*-Rechte
gekoppelt (bestehende, dokumentierte Design-Entscheidung). README um eine
Übersicht ergänzt, welche Bereiche bewusst ohne granulare Rechte auskommen
und warum.
Mit Testbenutzer ohne jede Gruppenzugehörigkeit verifiziert: /logs liefert
jetzt 302 (Redirect), /get_log liefert 403 statt beide zuvor 200.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- section-head: Button ("+ Neue Zugangsdaten" etc.) rutscht bei langer
Beschreibung nicht mehr in die nächste Zeile — bleibt immer rechts oben,
der Beschreibungstext wickelt stattdessen innerhalb seiner eigenen Spalte.
- Suchfeld-Icon überlappte den Platzhaltertext: eine spätere, generische
Input-Regel mit gleicher Spezifität hat die padding-left-Regel des
Lupe-Icons überschrieben (reine Reihenfolge-im-Stylesheet-Sache) — Selektor
spezifischer gemacht.
- Live-Log: Neustart-bezogene Zeilen (manueller Neustart, automatischer
PoE-Restart bei Ausfall) werden jetzt orange markiert statt farblos.
- Aufgeklappte Nav-Gruppen bleiben über Seitenwechsel hinweg erhalten
(localStorage), zusätzlich zur automatischen Aufklappung der Gruppe der
aktuell aktiven Seite.
- Datei-Auswahl (Import) im Dark Mode gestylt (Text + Button), inkl.
color-scheme-bewusster Browser-Widgets.
- Manueller "Jetzt prüfen"-Trigger (Icon neben dem globalen Timer, nur
Admins): startet rpi-check.service neu -> frisches Logfile + sofortiger
Durchlauf, Countdown synchronisiert sich auf den manuellen Zeitpunkt.
- Dashboard und Live-Log aktualisieren sich jetzt per AJAX im Hintergrund
(kein voller Seiten-Reload mehr): neue Route /dashboard/tiles liefert das
Kachel-Fragment (_dashboard_tiles.html, von index.html eingebunden und vom
Live-Update nachgeladen), get_log() liefert den aktuellen Dateinamen als
Header mit, damit die Anzeige nach einem Service-Neustart aktuell bleibt.
- Root-Cause für "Intervall bleibt immer bei 300s": in der WSL-Testumgebung
lief poe_wrapper.py nur als manuell gestarteter Hintergrundprozess statt
als echter rpi-check.service — "systemctl restart" lief dadurch ins Leere.
Echten systemd-Service in WSL eingerichtet und Intervalländerung end-to-end
verifiziert (Log-Zeilenabstand folgt jetzt dem neu gesetzten Intervall).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Topbar zeigt rechts jetzt ausschließlich den "Nächste Prüfung"-Countdown,
konsistent auf jeder Seite (auch anonymes Dashboard) statt nur auf dem
Dashboard. Neuer Context-Processor inject_check_timer()/get_last_run_at()
liefert last_run/interval global, ohne dass jede Route das selbst
berechnen muss.
- "+ Neu ..."-Buttons (Devices, Switches, Zugangsdaten, Benutzer, Gruppen)
aus der Topbar entfernt und stattdessen in einen .section-head direkt
über der jeweiligen Tabelle verschoben, zusammen mit einer kurzen
Beschreibung der Seite (bisher nur bei Zugangsdaten/Gruppen vorhanden,
jetzt auch bei Geräte/Switche/Benutzer).
- Live-Log: eigene lokale Timer-Pill entfernt (redundant zum globalen
Timer), "Aktualisieren"-Button in denselben section-head verschoben.
Dashboard: Suchfeld aus der Topbar in den Seiteninhalt verschoben, lokale
Timer-Anzeige entfernt (übernimmt die globale Topbar-Pill), Reload-bei-
Intervallende-Logik bleibt als separater, unsichtbarer Scheduler erhalten.
- Neue generische Tabellen-Sortierung (app.js: initSortableTables): Klick
auf eine Spaltenüberschrift mit data-sort-key sortiert die Zeilen anhand
von data-sort-<key>-Attributen. Unterstützt auch Akkordeon-Tabellen mit
mehreren <tbody> (Gruppen: Haupt- + Detail-Zeile bleiben als Einheit
zusammen, die virtuelle "Admin"-Zeile bleibt über data-sort-pinned immer
oben). Angewendet auf Geräte, Switche, Zugangsdaten, Benutzer, Gruppen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Datei hatte CRLF-Zeilenenden (vermutlich aus einer Windows-Bearbeitung),
wodurch das Skript unter Linux/WSL mit "command not found: $'\r'" und
Syntaxfehlern abbrach. Auf LF normalisiert.
- Die Haupt-Check-Schleife las per `read` nur 7 Felder aus
generate_ips.py, das aber inzwischen 8 Felder liefert (MAC am Ende
angehängt) — dadurch landete die MAC-Adresse an $switch_pass
angehängt. `mac` als zusätzliche (ungenutzte) read-Variable ergänzt.
- PoE-Neustart wurde bei nicht erreichbaren Geräten ausgelöst, sobald ein
`port`-Wert gesetzt war — unabhängig davon, ob dem Gerät überhaupt ein
Switch zugeordnet ist. Das führte zu sinnlosen SSH-Versuchen mit leeren
Zugangsdaten (ssh @) und irreführenden "PoE deaktiviert/aktiviert"
Log-Einträgen für Geräte ohne Switch. Prüft jetzt zusätzlich, dass
switch_ip nicht leer ist, bevor ein Neustart versucht wird (gilt für
den regulären Check-Loop und den manuellen Neustart).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Live-Log-Bug behoben: _latest_log_file() sortierte nach Datei-ctime statt
nach Dateiname — auf manchen Dateisystemen (u.a. unter WSL2 auf einem
gemounteten Windows-Laufwerk) unzuverlässig und lieferte nicht immer das
tatsächlich neueste Logfile. Sortiert jetzt wie der Rest des Codes über
den chronologisch sortierbaren Dateinamen (rpi-YYYYMMDDHHMMSS.log).
- Navbar umstrukturiert in aufklappbare Gruppen mit Unterpunkten:
- "Geräte": Clients (bisherige Devices-Seite), Switche, Zugangsdaten
- "Einstellungen": Benutzer, Gruppen, Systemeinstellungen (Prüfintervall),
Im-/Export
- "Logs": Live, Änderungen (vormals Live-Log/Änderungslog)
Sichtbarkeit gilt jetzt auch pro Unterpunkt: eine Gruppe erscheint nur,
wenn mindestens ein Unterpunkt für den Benutzer sichtbar ist, und zeigt
dann auch nur die sichtbaren Unterpunkte.
- Im-/Export als eigene Unterseite mit Export/Import nebeneinander
(.settings-grid).
- Neue Seite "Mein Konto" (/account, erreichbar über ein Zahnrad-Symbol
neben dem eigenen Namen in der Sidebar) ersetzt das bisherige Profil-Modal:
Profil/Passwort/Profilbild als volle Seite, dazu für Admins die
Navbar-Reihenfolge (aus den Systemeinstellungen hierher verschoben).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Änderungslog: audit_log-Tabelle + last_modified_by/at an Devices und
Switches; log_action()/touch_record() in allen Verwaltungsrouten
(Devices, Switches, Zugangsdaten, Benutzer, Gruppen, Settings) verdrahtet.
Neue Admin-Seite "Änderungslog" unter /logs/aenderungen. PoE-Neustarts
werden bewusst nicht geloggt.
- Verschlüsseltes Import/Export für Devices/Switches/Zugangsdaten unter
Settings, passphrasenbasiert (PBKDF2 + Fernet), für Umzug auf neue
Umgebungen. Referenziert Zugangsdaten/Switche über Name/Hostname statt
interner ID für stabilen Re-Import.
- Eigenes Profil: Klick auf den Namen in der Sidebar öffnet ein Modal zum
Ändern von Vor-/Nachname, eigenem Passwort (mit Prüfung des aktuellen
Passworts) und Profilbild-Upload (Anzeige in Sidebar + Änderungslog).
- Anpassbare Navigation: Reihenfolge der Sidebar-Punkte ist unter Settings
per Auf-/Ab-Buttons konfigurierbar (settings.nav_order); "Devices"/
"Users"/"Settings" umbenannt zu "Geräte"/"Benutzer"/"Einstellungen";
"Live-Log" und "Änderungslog" zu aufklappbarer "Logs"-Gruppe
zusammengefasst. Jeder Benutzer sieht weiterhin nur, wofür er berechtigt
ist.
- create_db.py mit allen Schema-Erweiterungen synchronisiert (audit_log,
last_modified_by/at, avatar_filename) für Frischinstallationen.
- venv-Umgebung im WSL neu aufgesetzt (war fälschlich unter dem
Erstellungspfad venv-linux verankert und daher nicht aktivierbar).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Dashboard zeigt jetzt in beiden Zustaenden (mit/ohne Login) Kacheln statt
Tabelle; ohne Login nur aktive Geraete + Online/Offline/Gesamt, eingeloggt
alle Geraete + zusaetzliche Deaktiviert-Kachel
- Sortierung ueberall: erst alle Nicht-Online-Geraete, dann Online, jeweils
alphabetisch
- Neue Rechte devices.view / switches.view; Standardgruppe 'Benutzer' wird
automatisch angelegt (alle Ansichtsrechte) und jedem neuen Benutzer
zugeordnet; bestehende Benutzer ohne Gruppe werden migriert
- Gruppen-Seite zeigt zusaetzlich virtuelle 'Admin'-Karte (informativ) und
markiert die Standardgruppe (nicht loeschbar)
- 'Naechste Pruefung'-Countdown wird serverseitig aus dem tatsaechlichen
letzten Log-Eintrag geseedet statt bei jedem Reload neu zu starten
- Deployment-Doku korrigiert: Checkout getrennt von /srv/poe_manager, damit
kein verschachteltes srv/poe_manager/srv/poe_manager entsteht
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Neues, eigenständiges Frontend (Sidebar, zentriertes Logo in der Topbar,
Dark/Light-Theme, Karten-Dashboard, Toasts/Modals statt Bootstrap)
- Oeffentliches Kurz-Dashboard ohne Login (Status-Uebersicht)
- Browser-SSH-Terminal (paramiko, plattformunabhaengig) zum Testen von
Switch-Zugangsdaten inkl. interaktiver Host-Key-Bestaetigung
- Granulares Rechtesystem mit Gruppen (Devices/Switches-Berechtigungen)
- Aufgeraeumtes Backend mit konfigurierbaren Pfaden, auto-generierten
Secrets statt hart codierter Werte im Original
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>