Nur noch, was zum Installieren und Betreiben des Lizenzservers noetig ist

Entfernt: Tests, Architekturdokumentation und die Anwendung TESM. Beides liegt
im Entwicklungsrepository alientim/TESM-DEV.

Neu: packages/tesm-licensing-server -- die Serverhaelfte des Lizenzprotokolls
(issue_license, resign_license, build_master_response, verify_client_request,
Schluesselerzeugung). Sie war bisher Teil von tesm-licensing und lag damit auch
in jeder Client-Installation. Die gemeinsame Haelfte bleibt in tesm-licensing
und wird von beiden Seiten benutzt.

install.sh installiert diese Serverhaelfte ausschliesslich fuer
--app tesm-license und bricht ab, wenn sie fehlt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 18:37:12 +02:00
co-authored by Claude Opus 5
parent f7805a2180
commit 6ac2ed0a62
24 changed files with 344 additions and 4336 deletions
+2 -1
View File
@@ -20,6 +20,7 @@ from pathlib import Path
from typing import Any
import tesm_licensing as lic
import tesm_licensing_server as licsrv
from tesm_core import audit
from tesm_core.cli_web import add_web_setup, run_web_setup
from tesm_core.db import Database
@@ -73,7 +74,7 @@ def cmd_bootstrap(args: argparse.Namespace) -> int:
"address": str(extension.settings.get(conn, "vendor_address") or ""),
"logo_base64": "",
}
bundle, _ = lic.issue_license(
bundle, _ = licsrv.issue_license(
customer={"name": args.name, "contact_email": vendor["email"]},
license_type="enterprise",
modules=[],
@@ -29,6 +29,7 @@ from datetime import datetime, timedelta, timezone
from typing import Any
import tesm_licensing as lic
import tesm_licensing_server as licsrv
from tesm_core import audit
from tesm_core.db import Database
@@ -72,7 +73,7 @@ def _signed_response(
detail: str = "",
license_update: dict[str, Any] | None = None,
) -> Outcome:
response = lic.build_master_response(
response = licsrv.build_master_response(
str(request["action"]),
license_id=str(request["license_id"]),
fingerprint=str(request["fingerprint"]),
@@ -124,7 +125,7 @@ def _verify(
)
try:
lic.verify_client_request(
licsrv.verify_client_request(
request,
str(row["license_pubkey"]),
expected_action=expected_action,
@@ -11,6 +11,7 @@ from datetime import datetime, timezone
from typing import Any, Iterable, Sequence
import tesm_licensing as lic
import tesm_licensing_server as licsrv
from tesm_core.db import Database
TICKET_TYPES = lic.LICENSE_TYPES
@@ -458,7 +459,7 @@ def issue_from_ticket(
customer = get_customer(conn, int(ticket["customer_id"]))
assert customer is not None
bundle, license_pub = lic.issue_license(
bundle, license_pub = licsrv.issue_license(
customer={
"name": str(customer["name"]),
"contact_email": str(customer["contact_email"] or ""),
@@ -600,7 +601,7 @@ def resign_license(
if row is None:
raise IssuanceError("Diese Lizenz existiert nicht.")
document = json.loads(str(row["license_document"]))
updated = lic.resign_license(
updated = licsrv.resign_license(
document, master_private_key_b64=master_private_key, changes=changes
)
conn.execute(
@@ -33,6 +33,7 @@ from pathlib import Path
from typing import Any
import tesm_licensing as lic
import tesm_licensing_server as licsrv
from tesm_core.db import Database
from tesm_core.keystore import Keystore
@@ -124,7 +125,7 @@ def read_legacy_key(root: Path) -> tuple[str, str]:
public = str(data.get("public") or data.get("public_key") or "")
if not private or not public:
raise LegacyImportError("Der alte Signaturschluessel ist unvollstaendig.")
if lic.public_from_private(private) != public:
if licsrv.public_from_private(private) != public:
raise LegacyImportError(
"Im alten Signaturschluessel passen privater und oeffentlicher Teil nicht "
"zueinander. Die Datei ist beschaedigt."
@@ -291,7 +292,7 @@ def import_all(
)
continue
bundle, license_public = lic.issue_license(
bundle, license_public = licsrv.issue_license(
customer={
"name": str(customer["name"]),
"contact_email": str(customer["contact_email"] or ""),
@@ -24,6 +24,7 @@ from datetime import datetime, timezone
from pathlib import Path
import tesm_licensing as lic
import tesm_licensing_server as licsrv
from tesm_core.keystore import check_private_file, write_private_file
logger = logging.getLogger(__name__)
@@ -59,7 +60,7 @@ def load(path: Path) -> MasterKey:
public = str(data.get("public_key") or "")
if not private or not public:
raise MasterKeyError("Der Signaturschluessel ist unvollstaendig.")
if lic.public_from_private(private) != public:
if licsrv.public_from_private(private) != public:
raise MasterKeyError(
"Der oeffentliche Teil des Signaturschluessels passt nicht zum privaten. "
"Die Datei ist beschaedigt oder wurde manipuliert."
@@ -77,7 +78,7 @@ def ensure(path: Path) -> MasterKey:
"""
if path.is_file():
return load(path)
private, public = lic.generate_keypair()
private, public = licsrv.generate_keypair()
payload = {
"private_key": private,
"public_key": public,