From a193b9d6e9e5d4e064987958468ac97fd49edb21 Mon Sep 17 00:00:00 2001 From: alientim Date: Sun, 23 Aug 2026 22:43:17 +0200 Subject: [PATCH] licensing.py: optionales report-Feld fuer Sub-Lizenzserver-Meldungen Rein synchronisierende Aenderung (harte Invariante: licensing.py bleibt byte-identisch in beiden Repos). build_client_request() akzeptiert jetzt einen optionalen report-Parameter, der bei Heartbeats einer role='license_server'-Lizenz den eigenen Kunden-/Ticket-/Lizenzstand signiert mitschickt -- Kern des neuen Sub-Lizenzserver-Reportings auf dem Lizenzserver (siehe dortiges Release). Bestehende Aufrufer (TESM- Client-Heartbeats, activate/deactivate) uebergeben report nie -- das Feld fehlt dann wie bisher komplett in der Payload, keine Verhaltensaenderung. Co-Authored-By: Claude Sonnet 5 --- srv/tesm/VERSION | 2 +- srv/tesm/licensing.py | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/srv/tesm/VERSION b/srv/tesm/VERSION index c04c650..db6fb4a 100644 --- a/srv/tesm/VERSION +++ b/srv/tesm/VERSION @@ -1 +1 @@ -1.2.7 +1.2.8 diff --git a/srv/tesm/licensing.py b/srv/tesm/licensing.py index e9f2de3..b42933f 100644 --- a/srv/tesm/licensing.py +++ b/srv/tesm/licensing.py @@ -275,11 +275,24 @@ def system_fingerprint(): # gebunden ist, siehe Plan-Abschnitt "Warum das die Doppelnutzung wirksam # verhindert". -def build_client_request(action, license_file, nonce=None) -> dict: +def build_client_request(action, license_file, nonce=None, report=None) -> dict: """Vom CLIENT aufgerufen: erzeugt eine signierte Anfrage (action: "activate"/"deactivate"/"heartbeat"). Das Ergebnis ist unverändert für einen Online-API-Aufruf nutzbar; für den Offline-Fall wird es - zusätzlich mit encode_code() in einen kopierbaren Code umgewandelt.""" + zusätzlich mit encode_code() in einen kopierbaren Code umgewandelt. + + report: NUR für Heartbeats einer role="license_server"-Lizenz gedacht + (siehe Lizenzserver-app.py _build_own_issuance_report()) -- ein + optionaler Schnappschuss der eigenen Kunden/Tickets/Lizenzen dieses + Sub-Lizenzservers, den der Master beim Empfang in seine + reported_sub_*-Tabellen übernimmt, um einen Gesamtüberblick zu haben. + Bewusst Teil DIESER generischen, gemeinsam genutzten Funktion (nicht + ein eigenes Protokoll-Feature) -- ein normaler TESM-Client/eine + "customer"-Lizenz übergibt hier einfach nie einen Wert, das Feld fehlt + dann in der Payload wie bisher (keine Verhaltensänderung für alle + bestehenden Aufrufer). Wie jedes andere Feld wird auch report + mitsigniert -- ein Angreifer ohne den privaten Lizenzschlüssel kann + keine gefälschten Berichte unterschieben.""" if action not in ("activate", "deactivate", "heartbeat"): raise ValueError(f"Unbekannte Aktion: {action!r}") payload = { @@ -296,6 +309,8 @@ def build_client_request(action, license_file, nonce=None) -> dict: "nonce": nonce or uuid.uuid4().hex, "timestamp": _iso(time.time()), } + if report is not None: + payload["report"] = report signature = sign_payload(payload, license_file["license_privkey"]) return {**payload, "signature": signature}