srv/tesm-license/, install-license.sh, update-license.sh sowie die
zugehoerigen systemd-/nginx-Vorlagen leben ab sofort im eigenstaendigen
Repo https://gitea.int.eertmoed.net/alientim/tesm-license (komplette
bisherige Historie per git-filter-repo mit uebernommen, dort als v1.0.0
getaggt/released). Grund: eigener Release-/Versionszyklus getrennt von
TESM selbst, sauberere Trennung zwischen Kundenprodukt und interner
Lizenzierungs-Infrastruktur.
Betrifft nur dieses Repo -- die bereits laufende Installation auf
192.168.82.51 (TESM-Lizenzserver) ist unveraendert, zukuenftige Updates
dort laufen ueber das neue Repo/update.sh.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fork von install.sh/update.sh/tesm.service/nginx-Site (TESM selbst),
beschraenkt auf /srv/tesm-license -- deployt ausschliesslich den in Phase 2
gebauten Master-Lizenzserver, laesst eine evtl. auf demselben Host
vorhandene TESM-Installation komplett unberuehrt (eigener Pfad-/Env-Var-
Namespace, siehe app.py). Gleiches Backup+Health-Check+Rueckroll-
Sicherheitsnetz wie bei TESMs eigenem Installer.
Teil von Phase 3 (Infrastruktur), siehe Plan toasty-twirling-hickey.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Neue ldap_fileshare_mappings-Tabelle (AD-Gruppe -> Freigabe-UNC+Label),
verwaltet in Einstellungen -> LDAP wie die bestehende App-Gruppenzuordnung
(inkl. AD-Gruppen-Dropdown per "Gruppen laden", UNC-Backslash/Slash-
Normalisierung).
- Login-Gate: optionale "Erforderliche AD-Gruppe fuer Login" (Dropdown,
gleiches Lade-Muster) -- ohne Mitgliedschaft scheitert der Login wie bei
falschen Zugangsdaten, ohne Hinweis auf den eigentlichen Grund.
- Sessionabhaengiges Mounten: beim LDAP-Login werden alle per AD-Gruppe
zugeordneten Freigaben mit den eigenen (nie gespeicherten) Zugangsdaten
per mount.cifs unter /mnt/tesm-shares/<session-token>/ gemountet, beim
Logout wieder ausgehaengt. Passwort läuft ausschliesslich ueber die
PASSWD-Umgebungsvariable von mount.cifs. Aufraeum-Sweep (30 Min-Takt,
12h-Schwelle) und Cleanup-on-Startup als Sicherheitsnetz.
- Zwei unabhaengige Gates: TESM-Rechtesystem (fileshare.view/.create/.edit,
neue PERMISSIONS-Gruppe fileshare_group) UND AD-Gruppenmitgliedschaft
muessen beide zutreffen, sonst wird nicht gemountet und der Menuepunkt
"Dateifreigaben" bleibt verborgen.
- Neuer Dateibrowser (/fileshare, .../download, .../upload, .../mkdir,
.../delete, .../rename) mit Breadcrumbs, Upload/Download, Anlegen/
Umbenennen/Loeschen -- Pfadaufloesung ausschliesslich ueber
os.path.realpath-Vergleich gegen die eigene Mount-Root (Path-Traversal-
Schutz), zusaetzlich secure_filename() fuer Datei-/Ordnernamen.
- KRITISCHER Bugfix waehrend Live-Test gefunden: generate_ips.py importiert
app.py als Hilfsmodul (u.a. aus poe.sh/tesm-check.service heraus, alle
paar Sekunden) -- das fuehrte Modul-Level-Code erneut aus und hat aktive
Fileshare-Mounts anderer Sitzungen sofort wieder ausgehaengt. Neues
TESM_WEB_PROCESS-Env-Flag (nur in tesm.service gesetzt) schuetzt
Cleanup-on-Startup und den Sweep-Thread davor, bei einem reinen
Modul-Import erneut zu laufen.
- install.sh: cifs-utils ergaenzt (liefert mount.cifs).
- SCHEMA_VERSION 1 -> 2, VERSION 1.0.10 -> 1.1.0.
Live auf Testbox (192.168.82.51) und POETEST (192.168.80.202) getestet:
Login-Gate (erlauben/verbieten/reset), Rechte-Gate (Mount+Menuepunkt nur
mit fileshare.view), vollstaendiger Datei-Workflow (Upload/Download/
Umbenennen/Anlegen/Loeschen) gegen eine echte SMB-Freigabe, Path-Traversal
gegen alle 5 Routen (serverseitig verifiziert, kein Escape), sauberes
Unmount bei /logout.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Umbenennung: Einstellungen -> SSL/TLS heisst jetzt Einstellungen -> NGINX
(Route /settings/ssl -> /settings/nginx, Recht settings_ssl.* ->
settings_nginx.*, Icon "server" statt "shield") -- die Seite verwaltet
den kompletten Reverse-Proxy, nicht mehr nur SSL.
Neu:
- Domain (server_name) und HTTP-/HTTPS-Port sind jetzt einstellbar, nicht
mehr hart "_" bzw. 80/443. Aendert man den HTTP-Port weg von 80, wird
automatisch zusaetzlich ein minimaler Nur-ACME-Block auf Port 80
mitgeschrieben, da Let's Encrypt (HTTP-01) protokollbedingt immer Port 80
braucht, unabhaengig vom konfigurierten HTTP-Port.
- "RAW-Konfiguration"-Button zeigt die komplette aktuelle nginx-Config im
selben Popup-Stil wie das Live-Log (Wiederverwendung von
window.openRawLogModal, kein neuer Code dafuer noetig).
- Let's Encrypt: Zertifikat per certbot anfordern (certonly --webroot,
bewusst NICHT das certbot-nginx-Plugin -- das wuerde die App-eigene,
komplett selbstgeschriebene Config direkt editieren und bei der
naechsten Aenderung ueber diese Seite wieder verlieren). Automatische
Verlaengerung laeuft ueber certbots eigenen systemd-Timer/Cron
(Standard-Paketverhalten), ein Deploy-Hook
(/etc/letsencrypt/renewal-hooks/deploy/tesm-reload-nginx.sh, wird wie
die logrotate-Config bei jedem App-Start neu geschrieben) laedt nginx
nach jeder Verlaengerung neu. Fehlgeschlagene Anforderung (kein
oeffentlicher DNS-Eintrag o.ae.) wird sauber abgefangen und als
Fehlermeldung angezeigt, ohne etwas zu veraendern -- live mit einer
ungueltigen Test-Domain verifiziert.
- Zertifikatsquelle (Upload vs. Let's Encrypt) wird als eigenes Setting
(ssl_source) verfolgt, das Anwenden/Anzeigen/Entfernen beruecksichtigt
beide Quellen jeweils passend (Entfernen einer LE-verwalteten
Installation laeuft ueber "certbot delete", nicht ueber rohes
Datei-Loeschen, damit certbots eigene Renewal-Konfiguration nicht
verwaist).
- certbot zu install.sh's Paketliste hinzugefuegt.
Flask/gunicorn bindet jetzt an 127.0.0.1 statt 0.0.0.0 (tesm.service) --
direkter Zugriff auf Port 5000 aus dem Netz ist damit nicht mehr moeglich,
nur noch ueber den nginx-Reverse-Proxy (der ohnehin nur ueber 127.0.0.1
zugreift). Beantwortet die Nachfrage, ob Flask unerreichbar gemacht werden
kann.
Live auf Testsystem-Update-Restart verifiziert: Domain/Port-Aenderung
(HTTP-Port 8080 inkl. automatischem Zusatz-Block auf Port 80),
RAW-Config-Anzeige, Zertifikat-Upload, Let's-Encrypt-Fehlschlag sauber
abgefangen, Rueckbau auf Standardwerte (_, 80, 443, kein SSL) ueber
denselben Anwenden/Bestaetigen-Sicherheitsnetz-Pfad wie zuvor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
tesm.service startete die App bisher direkt per 'python3 app.py', was
Flasks eingebauten Werkzeug-Entwicklungsserver nutzt -- der meldet bei
jedem Start 'WARNING: This is a development server. Do not use it in a
production deployment.' und ist bewusst nicht für Dauerbetrieb gebaut.
Umgestellt auf Gunicorn, mit zwei bewusst gesetzten Einschraenkungen:
- '--workers 1': die App haelt laufende Wartungs-Jobs/Import-Vorschauen
nur im Arbeitsspeicher DES EINEN Prozesses (_maintenance_jobs,
_pending_imports, ...) -- mehrere Worker-Prozesse wuerden diesen
Zustand auf mehrere, sich nicht kennende Prozesse verteilen.
- '--worker-class gthread --threads 16' statt eines async-Workers: das
Browser-SSH-Terminal (flask-sock) belegt pro offener WebSocket-
Verbindung einen blockierenden Thread.
- '--timeout 0': deaktiviert Gunicorns eigenen 30s-Worker-Timeout, der
sonst auch eine offene, aber gerade inaktive SSH-Terminal-Verbindung
killen wuerde.
Live auf POETEST verifiziert: keine WARNING-Zeile mehr, genau 1 Master-
+ 1 Worker-Prozess, alle Kernseiten weiterhin 200, und als kritischer
Regressionstest das WebSocket-SSH-Terminal Ende-zu-Ende gegen einen
echten Host erfolgreich getestet (Host-Key/Passwort-Prompt/Login/Shell).
Dabei einen unabhaengigen Altlast-Fehler in POETESTs venv gefunden und
allgemein in install.sh gefixt: './venv/bin/pip' hat eine zur
Venv-Erstellung fest einprogrammierte Shebang-Zeile -- nach der
historischen Umbenennung 'poe_manager' -> 'tesm' zeigte sie auf einen
nicht mehr existierenden Pfad und schlug mit 'cannot execute: required
file not found' fehl. 'python3 -m pip' umgeht das, da nur der (korrekt
referenzierte) venv-Python-Interpreter selbst gebraucht wird -- betrifft
sonst auch jedes kuenftige In-Place-Update auf einem aehnlich
gewachsenen Host.
- 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>