Konzept: Kunde kauft eine Lizenz -> Admin legt einen Kunden an (oder nutzt einen bestehenden) und weist ihm ein TICKET fuer eine Lizenz mit festen Eckdaten (Typ/Module/Laufzeit) zu -- das Ticket ist die dauerhafte, dem Kunden gehoerende Berechtigung, unabhaengig von der konkreten signierten Lizenzdatei darunter. Admin ODER Kunde (per Self-Service-Link, kein Login noetig) koennen aus einem offenen Ticket jederzeit eine Lizenz erstellen, widerrufen und erneut erstellen -- ein Kunde kann mehrere Tickets haben (z.B. mehrere Systeme). Neu: - license_tickets-Tabelle (id = unerratbares Token, customer_id, Typ/ Module/Laufzeit, status 'open'/'blocked'), licenses.ticket_id-Spalte. Rueckwirkende Migration erzeugt fuer jede bereits VOR diesem Feature direkt ausgestellte Lizenz automatisch ein passendes Ticket (sonst waeren z.B. POETESTs bereits aktivierte Produktivlizenz oder die Demo-Lizenzen im neuen, rein ticket-basierten Dashboard verschwunden) -- gegen eine echte Kopie der Live-Datenbank getestet. - /tickets/new (Ticket anlegen, admin), /tickets/<id> (Details, Lizenz aus Ticket erstellen -- reguraer laut Ticket-Typ ODER als Trial mit vollem Modulumfang unabhaengig vom Ticket-Typ --, Ticket sperren/ entsperren). - /self-service/<ticket_id>: oeffentlich erreichbar (kein Login), Zugriff ueber Besitz des unerratbaren Ticket-Tokens (192 Bit Zufall) als 'Magic Link' -- Kunde kann eigene Lizenz herunterladen, widerrufen und (mit den Ticket-Eckdaten) neu erstellen. Link wird auf der Ticket-Seite angezeigt und in die 'Lizenz per E-Mail senden'-Nachricht aufgenommen. - /licenses/<id>/delete (admin): raeumt widerrufene oder nie aktivierte Lizenzen auf, OHNE das zugehoerige Ticket anzutasten -- der Kunde (oder Admin) kann sich ueber das Ticket jederzeit eine neue mit denselben Eckdaten erzeugen. - Bugfix: wird fuer einen Fingerprint eine neue Lizenz aktiviert (z.B. Trial durch Enterprise ersetzt), werden jetzt automatisch alle ANDEREN fuer denselben Fingerprint noch 'active' vermerkten Lizenzen auf 'deactivated' gesetzt -- vorher blieben beide faelschlich gleichzeitig aktiv in der Uebersicht stehen. Bewusst nach Fingerprint gefiltert (ein Kunde darf mehrere Systeme mit je eigener Lizenz betreiben). - Dashboard zeigt jetzt Tickets statt roher Lizenzzeilen (inkl. aktueller Lizenz je Ticket), Kunden-Seite zeigt Ticket-Anzahl statt Lizenz-Anzahl mit Filter-Link aufs Dashboard. SCHEMA_VERSION 1 -> 2 (neue Tabelle + Spalte, ueber install.sh- Sicherheitsnetz mit Backup+Health-Check abgesichert). Verifiziert: Migration gegen eine echte Kopie der Live-Datenbank (POETESTs aktive Produktivlizenz + 3 Demo-Lizenzen) durchlaufen lassen -- alle 8 bestehenden Lizenzen haben danach ein Ticket, keine verwaist. Anschliessend alle neuen Seiten (Dashboard, Ticket-Anlage, Ticket-Detail, Self-Service) per Playwright gegen diese migrierte Kopie auf einem isolierten Scratch-Port durchgeklickt, keine Fehler. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
TESM-Lizenzserver
Master-Lizenzserver für TESM (TimEShepManager) — verwaltet Kunden und deren Lizenzen, statt Netzwerkgeräte. Ursprünglich als Teil des TESM-Hauptrepos gebaut (gleiche Codebasis: Login/Benutzer/Gruppen, LDAP/AD, NGINX- und Systemeinstellungen, Live-Log/Verlauf/Auditlog, Im-/Export-Grundgerüst, das komplette Rechtesystem) und in dieses eigene Repo ausgelagert.
Das Projekt ist ausschließlich für Linux ausgelegt (Zielsystem: eine Linux-VM, identisches Deployment-Muster wie TESM selbst).
Kernfunktionen
- Kunden-/Lizenzübersicht als Dashboard (Typ, Module, Ablaufdatum, Aktivierungsstatus, letzter Heartbeat)
- Lizenz-Ausstellung: Trial/Standard/Custom/Enterprise, frei wählbare Gültigkeitsdauer, bei Custom einzeln wählbare Module
- Ed25519-signierte Lizenzdateien (siehe
srv/tesm-license/licensing.py) — dieselbe Datei existiert byte-identisch im TESM-Repo, da Client (TESM) und Master (dieses Repo) exakt dasselbe Signier-/ Verifikationsprotokoll sprechen müssen - Online-Aktivierung/-Deaktivierung/-Heartbeat über eine schlanke
JSON-API (
/api/activate,/api/deactivate,/api/heartbeat, unauthentifiziert per Design — die Signatur der Anfrage selbst ist der Berechtigungsnachweis) - Offline-Fallback: dieselbe Aktivierungs-/Deaktivierungs-/Heartbeat- Logik auch als manuell kopierbarer Code für Kunden ohne Netzwerkzugriff auf den Lizenzserver
- E-Mail-Versand ausgestellter Lizenzen per Microsoft Graph (Client-Credentials-Flow, keine zusätzliche Abhängigkeit) inkl. Einrichtungsanleitung und Verbindungstest in der GUI
- Eigene Bootstrap-Lizenz des Masters selbst (
create_master_license.py, rein lokal, kein externer Super-Master nötig)
Installation
sudo ./install.sh
Richtet System-Pakete, die Flask-App (systemd: tesm-license.service)
sowie nginx als Reverse-Proxy unter /srv/tesm-license ein. Erkennt
selbstständig, ob dort bereits eine Installation existiert, und
aktualisiert sie entsprechend (In-Place bei unverändertem
Datenbank-Schema, sonst mit automatischem Backup + Health-Check +
Rückroll bei Fehlschlag — siehe Kommentarkopf in install.sh).
Nach der Erstinstallation:
sudo /srv/tesm-license/venv/bin/python3 /srv/tesm-license/create_admin.py
sudo /srv/tesm-license/venv/bin/python3 /srv/tesm-license/create_master_license.py
Update (von einem bereits installierten System aus)
sudo ./update.sh
# oder für eine bestimmte Version statt "latest":
TESM_RELEASE_TAG=v1.0.0 sudo -E ./update.sh
Lädt das aktuelle Gitea-Release herunter und übergibt an install.sh.
Zusammenspiel mit TESM
Eine TESM-Instanz aktiviert sich gegen genau einen Lizenzserver
(master_endpoint, in der Lizenzdatei hinterlegt). Ein Protokoll, zwei
Transportwege: online automatisch per HTTPS/JSON, offline als manuell
auszutauschender Code — beide Seiten nutzen dieselben Funktionen aus
licensing.py. Details zum kryptografischen Format und Ablauf siehe die
Docstrings in srv/tesm-license/licensing.py bzw. dem identischen Modul
im TESM-Repo.