From a9fc56ff47676fa49c884248b5a7baa042a40dd7 Mon Sep 17 00:00:00 2001 From: alientim Date: Sun, 23 Aug 2026 10:34:53 +0200 Subject: [PATCH] Eigenstaendiges Repo: install.sh/update.sh auf tesm-license umgestellt, README + .gitignore Ausgelagert aus dem TESM-Hauptrepo (srv/tesm-license/, install-license.sh, update-license.sh, zugehoerige systemd-/nginx-Vorlagen) per git-filter-repo, komplette bisherige Historie erhalten. install-license.sh und update-license.sh wurden zu install.sh/update.sh (jetzt die einzigen Skripte in diesem Repo, keine Namenskollision mit TESM mehr noetig). update.sh zeigt jetzt auf dieses eigene Repo/Release-Paket (tesm-license-vX.Y.Z.tar.gz) statt auf das gemeinsame TESM-Paket. Co-Authored-By: Claude Sonnet 5 --- .gitignore | 17 +++++++++++++ README.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ install.sh | 16 ++++++------ update.sh | 36 +++++++++++++++----------- 4 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 .gitignore create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b45d2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Virtuelle Umgebung (Linux — das Projekt ist ausschließlich für Linux ausgelegt) +/srv/tesm-license/venv/ +__pycache__/ +*.pyc + +# Logfiles +*.log + +# Secrets — niemals committen +/srv/tesm-license/sqlite.db +/srv/tesm-license/fernet.key +/srv/tesm-license/secret.key +/srv/tesm-license/license.json +/srv/tesm-license/master_signing_key.json + +# Laufzeit-Uploads — werden bei Bedarf automatisch angelegt +/srv/tesm-license/static/uploads/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..be344cb --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +# TESM-Lizenzserver + +Master-Lizenzserver für [TESM (TimEShepManager)](https://gitea.int.eertmoed.net/alientim/tesm) — +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 + +```bash +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: + +```bash +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) + +```bash +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](https://gitea.int.eertmoed.net/alientim/tesm). diff --git a/install.sh b/install.sh index c9445be..0886d73 100644 --- a/install.sh +++ b/install.sh @@ -1,16 +1,16 @@ #!/bin/bash # ============================================================================ # TESM-Lizenzserver — Installer/Updater -# Fork von install.sh (TESM selbst), auf /srv/tesm-license statt /srv/tesm -# beschränkt -- deployt NUR den Master-Lizenzserver-Teil dieses Repos -# (srv/tesm-license/), lässt srv/tesm/ komplett unangetastet. Für dasselbe -# Sicherheitsnetz (Backup + Health-Check + automatischer Rückroll) wie bei -# TESM, siehe dortigen Kommentarkopf für die ausführliche Begründung -- -# hier nur die Kurzfassung je Schritt. +# Richtet System-Pakete und die Flask-App (systemd + nginx) unter +# /srv/tesm-license ein. Ursprünglich als Teil des TESM-Hauptrepos gebaut +# (Fork von dessen install.sh) und später in dieses eigenständige Repo +# ausgelagert -- Backup + Health-Check + automatischer Rückroll bei einem +# fehlgeschlagenen Update funktionieren identisch zu TESMs eigenem +# Installer, hier nur die Kurzfassung je Schritt. # # Auszuführen als root, nachdem dieses Repo/Release-Paket z.B. nach -# /root/tesm entpackt wurde: -# sudo ./install-license.sh +# /root/tesm-license entpackt wurde: +# sudo ./install.sh # ============================================================================ set -e diff --git a/update.sh b/update.sh index 90bbd89..6fb9db4 100644 --- a/update.sh +++ b/update.sh @@ -1,24 +1,30 @@ #!/bin/bash # ============================================================================ # TESM-Lizenzserver — Update/Reinstall (Bootstrapper) -# Fork von update.sh (TESM selbst) -- lädt dasselbe gepackte Gitea-Release -# herunter (das Repo enthält beide Apps: srv/tesm/ UND srv/tesm-license/) -# und übergibt an install-license.sh aus dem Paket, statt install.sh. +# Lädt ein gepacktes Gitea-Release per HTTP herunter (kein "git clone" +# nötig) und übergibt die eigentliche Installations-/Update-Logik an +# install.sh aus dem Paket -- das erkennt selbstständig, ob unter +# /srv/tesm-license schon eine Installation existiert, und aktualisiert +# sie entsprechend (In-Place bei unverändertem Datenbank-Schema, sonst mit +# automatischem Backup + Migrations-Sicherheitsnetz samt Rückroll- +# Möglichkeit -- siehe install.sh für Details). # # Auszuführen als root auf dem Zielsystem: -# sudo ./update-license.sh +# sudo ./update.sh # Optional übersteuerbar (z.B. für eine bestimmte Version statt "latest"): -# TESM_RELEASE_TAG=v1.0.0 sudo -E ./update-license.sh +# TESM_RELEASE_TAG=v1.0.0 sudo -E ./update.sh +# Für ein privates Repo wird ein Zugriffstoken benötigt: +# TESM_GITEA_USER=alientim TESM_GITEA_TOKEN= sudo -E ./update.sh # ============================================================================ set -e GITEA_BASE="${TESM_GITEA_BASE:-https://gitea.int.eertmoed.net}" REPO_OWNER="${TESM_REPO_OWNER:-alientim}" -REPO_NAME="${TESM_REPO_NAME:-tesm}" +REPO_NAME="${TESM_REPO_NAME:-tesm-license}" RELEASE_TAG="${TESM_RELEASE_TAG:-latest}" GITEA_USER="${TESM_GITEA_USER:-}" GITEA_TOKEN="${TESM_GITEA_TOKEN:-}" -PACKAGE_NAME="tesm-${RELEASE_TAG}.tar.gz" +PACKAGE_NAME="tesm-license-${RELEASE_TAG}.tar.gz" DOWNLOAD_URL="${GITEA_BASE}/${REPO_OWNER}/${REPO_NAME}/releases/download/${RELEASE_TAG}/${PACKAGE_NAME}" WORK_DIR="/tmp/tesm-license-update-$(date +%s)" @@ -30,7 +36,7 @@ YELLOW='\033[1;33m' NC='\033[0m' if [ "$(id -u)" -ne 0 ]; then - echo "Bitte als root ausführen (sudo ./update-license.sh)." >&2 + echo "Bitte als root ausführen (sudo ./update.sh)." >&2 exit 1 fi @@ -38,10 +44,10 @@ echo -e "${YELLOW}============================================================== echo -e "${YELLOW} TESM-Lizenzserver Update/Reinstall — Release \"${RELEASE_TAG}\"${NC}" echo -e "${YELLOW}============================================================================${NC}" echo -echo "Lädt das Release-Paket herunter (enthält TESM und den Lizenzserver" -echo "zusammen) und übergibt Installation/Update an install-license.sh" -echo "daraus -- deployt ausschließlich srv/tesm-license/, lässt eine" -echo "eventuell auf demselben Host vorhandene TESM-Installation unberührt." +echo "Lädt das Release-Paket herunter und übergibt Installation/Update an" +echo "install.sh daraus -- das erkennt selbst, ob es sich um eine frische" +echo "Installation oder ein Update einer bestehenden handelt, und sichert" +echo "die Datenbank bei einer Schema-Änderung automatisch vorsorglich ab." echo read -r -p "Fortfahren? [y/N] " confirm @@ -64,10 +70,12 @@ mkdir -p "$WORK_DIR/pkg" tar xzf "$PACKAGE_FILE" -C "$WORK_DIR/pkg" --strip-components=1 echo -e "${GREEN}✔${NC} Paket entpackt." -echo -e "${RED}→${NC} Starte install-license.sh aus dem Paket..." -bash "$WORK_DIR/pkg/install-license.sh" +echo -e "${RED}→${NC} Starte install.sh aus dem Paket..." +bash "$WORK_DIR/pkg/install.sh" echo echo -e "${GREEN}============================================================================${NC}" echo -e "${GREEN} TESM-Lizenzserver Update/Reinstall (Release \"${RELEASE_TAG}\") abgeschlossen.${NC}" echo -e "${GREEN}============================================================================${NC}" +echo "Siehe Ausgabe von install.sh oben für Details (In-Place-Update, frische" +echo "Installation, oder Migrationsergebnis inkl. eventuellem Rückroll-Hinweis)."