alientimandClaude Opus 5 3295583591 Anmeldeseite: Wortmarke fuer beide, Karte ohne Wiederholung
* Die Wortmarke stand nur bei TESM -- sie hing an der Funktionszeile, und die
  hatte der Lizenzserver nicht. Jetzt zeigen beide die Marke; die Zeile
  darunter ist optional und beim Lizenzserver "LIZENZIEREN".
* Der Kartenkopf ist weg: eine Kachel mit zwei Buchstaben, die Ueberschrift
  "Anmelden" und der Anwendungsname darunter sagten dasselbe wie die Marke
  darueber und der Knopf darunter. Die Ueberschrift bleibt fuer die
  Titelzeile des Browsers.
* Marke und Karte stehen jetzt uebereinander im Fluss statt uebereinander
  gestapelt: auf einem flachen Fenster schnitt die Karte mitten durch den
  Schriftzug.
* Die Marke ist kuerzer und symmetrisch um die Mitte aufgebaut -- Schriftzug
  ueber text-anchor, Zacken spiegelbildlich, Linie links so lang wie der Punkt
  rechts. Volle Deckkraft, weil sie kein Wasserzeichen hinter der Karte mehr
  ist.
* Funktionszeile gekuerzt auf "UEBERWACHEN . BOOTEN . ANBINDEN" -- mit echtem
  Umlaut. "(PXE)" stand fuer etwas, das es noch nicht gibt.
* Der Farbverlauf im Hintergrund hat wieder Geometrie und Staerke der Fassung
  1.x. Der zweite Kreis lag auf --info und 10 %: ein kaltes Blau, das man auf
  dunklem Grund nicht sah und das nicht zur Marke gehoert.
* "Bitte melden Sie sich an." stand auf einer Seite aus Anmeldefeld,
  Passwortfeld und einem Knopf "Anmelden". Statt dessen erfaehrt jetzt der,
  dessen Sitzung gerade ablief, warum er wieder hier ist.

Dabei drei Dinge gefunden, die lautlos nichts taten:

* __version__ stand fest verdrahtet in drei __init__.py. Die Fusszeile zeigte
  vier Releases lang 2.0.2, waehrend die Anwendung 2.0.6 war. Die Nummer kommt
  jetzt aus den Metadaten des installierten Pakets; Quelle ist pyproject.toml.
* "gap: var(--sp-7)" -- die Skala kennt kein --sp-7 (1 bis 6, dann 8, 10, 12,
  16). Eine undefinierte Variable verwirft die ganze Deklaration ohne Meldung:
  der Abstand war "normal", und Marke und Karte stiessen auf den Pixel
  aneinander.
* Ein Test dagegen fand sofort ein zweites: --surface-0 wird dreimal benutzt
  und nirgends definiert. Die Schrift auf der Kachel "kritisch" blieb
  dunkelgrau auf Rot, die Dateivorschau hatte keinen Grund, und das Feld
  "Recht nicht vorhanden" in der Rechtematrix war durchsichtig -- also so hell
  wie die Karte, obwohl es dunkler sein sollte.

Version 2.0.7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:44:34 +02:00

TESM-Lizenzserver

Ausgabe und Verwaltung der Lizenzen für TESM: Kunde -> Ticket -> Lizenz, Aktivierung online und offline, Kundenportal, Selbstbedienung, Versand über MS Graph und eine Hierarchie aus Unter-Lizenzservern.

Dieses Repository enthält genau das, was zum Installieren und Betreiben des Lizenzservers gebraucht wird -- nichts darüber hinaus:

apps/tesm-license               die Anwendung
packages/tesm-core              gemeinsamer Kern (Anmeldung, Rechte, Sicherung, nginx, ...)
packages/tesm-licensing         Lizenzprotokoll, gemeinsame Hälfte
packages/tesm-licensing-server  Lizenzprotokoll, Serverhälfte: ausstellen, erneuern, antworten
deploy/                         install.sh, update.sh, release.sh, systemd, privilegierter Helfer
docs/                           Betrieb und Sicherheit

Die verwaltete Anwendung liegt hier nicht mit drin.

Wo sonst noch
alientim/tesm TESM selbst
alientim/TESM-DEV Entwicklung: beide Anwendungen, Tests, Architekturdoku

Zweige

Zweig Inhalt
main dieser Neubau (Version 2.0.0)
SONNET5 der Stand davor, unverändert aufbewahrt

Installation

sudo bash deploy/install.sh --app tesm-license --https --domain lizenz.firma.de
sudo -u tesm-license tesm-license-admin init-key
sudo -u tesm-license tesm-license-admin bootstrap
sudo -u tesm-license tesm-license-admin create-admin

init-key erzeugt den Signaturschlüssel dieses Servers. Sichern Sie ihn sofort. Ohne ihn lässt sich keine ausgestellte Lizenz mehr erneuern, und Kunden müssten einen Ausstellerwechsel bestätigen.

Zielzustand: Port 443 mit TLS, Port 80 leitet dorthin um -- ausser dem ACME-Pfad, der erreichbar bleiben muss, sonst kann Let's Encrypt nie erneuern. Sitzt ein eigener Reverse Proxy davor, der TLS beendet, läuft der Dienst ohne --https schlicht auf Port 80.

Der Lizenzserver darf neben TESM auf demselben Host laufen; nginx unterscheidet die beiden am Servernamen, und jede Installation hat ihren eigenen SITE_KEY für nginx-Site, logrotate, Zertifikate und Sitzungscookie.

Aktualisieren

sudo bash deploy/update.sh --app tesm-license

Vor jedem Update entsteht ein vollständiges Backup, danach läuft ein Health-Check mit automatischem Rollback.


Betrieb von der Kommandozeile

sudo -u tesm-license tesm-license-admin status
sudo -u tesm-license tesm-license-admin init-key       # Signaturschlüssel
sudo -u tesm-license tesm-license-admin bootstrap      # Grunddaten
sudo -u tesm-license tesm-license-admin create-admin
sudo -u tesm-license tesm-license-admin migrate-legacy # Altbestand übernehmen

migrate-legacy liest die SQLite-Datei eines alten Lizenzservers nur lesend, übernimmt dessen Signaturschlüssel und stellt die Lizenzen mit ihrer restlichen Laufzeit neu aus. Wird der Schlüssel nicht übernommen, müssen Kunden den Ausstellerwechsel einmal bestätigen.


Release bauen

git tag -a v2.0.0 -m "TESM-Lizenzserver 2.0.0" && git push origin v2.0.0
bash deploy/release.sh v2.0.0

Heraus kommt tesm-license-v2.0.0.tar.gz samt SHA-256. Der Name kommt aus dem Repository -- ein Lizenzserver-Release, das tesm-... heisst, verwechselt man genau einmal.


Lizenzprotokoll in Kurzform

  • Ed25519, getrennte Signaturkontexte je Nachrichtenart (tesm/license-file/v2\0) -- eine Signatur aus einem Kontext ist in einem anderen nicht verwendbar.
  • Kanonisches JSON, damit dieselbe Aussage genau eine Signatur hat.
  • Nonce gegen Wiedereinspielung, seq gegen das Zurückrollen auf eine ältere Lizenz.
  • Aussteller wird beim ersten Kontakt gemerkt (TOFU); ein Wechsel muss ausdrücklich bestätigt werden.
  • Der Fingerabdruck der Maschine enthält keinen Hostnamen -- Umbenennen brach im Vorgänger die Bindung.
  • Offline-Aktivierung über einen kurzen Code in beide Richtungen; die Lizenz bleibt auf dem Server als "Aktivierung offen" markiert, bis sie zurückkommt.
  • Keine Lizenz ohne master_endpoint: eine Ausstellung ohne Endpunkt wird abgelehnt statt eine Lizenz zu erzeugen, die sich nie aktivieren kann.

Dokumentation

docs/BETRIEB.md Installation, Update, HTTPS, Sicherung, Fehlersuche
docs/SICHERHEIT.md Anmeldung, Sitzungen, CSRF, Geheimnisse, Rechtetrennung

Aufbau und Entwurfsentscheidungen stehen in docs/ARCHITEKTUR.md im Entwicklungsrepository, ebenso die Tests.


Was diese Fassung anders macht

  • Keine doppelte licensing.py. Ein Paket, das beide Anwendungen installieren -- statt zweier Dateien, die byte-identisch bleiben sollen.
  • Kein root für die Anwendung. Ein einziger allowlisted Helfer mit Argumentprüfung.
  • CSRF-Schutz überhaupt. Der Vorgänger hatte keinen.
  • Rechte werden serverseitig geprüft, nicht nur im Template ausgeblendet.
  • Verschachtelte Datenbankverbindungen sind ein Fehler, kein Deadlock.
S
Description
TESM-Lizenzserver -- Master-Lizenzserver fuer TESM (Kunden-/Lizenzverwaltung, Aktivierungs-/Heartbeat-API)
Readme
3.7 MiB
2026-09-03 16:18:55 +02:00
Languages
Python 62.4%
HTML 21.3%
Shell 7.7%
CSS 5.5%
JavaScript 3.1%