Version 2.7.2: Umlaute in der Oberflaeche, Einbindungen an der Sitzung

This commit is contained in:
alientim committed 2026-09-11 23:24:28 +02:00
1 parent 11a55b20f8
commit dcb4f57eeb
83 files changed
+1224 -658

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "tesm-licensing"
version = "2.7.1"
version = "2.7.2"
description = "Ed25519-basiertes Lizenz- und Aktivierungsprotokoll fuer TESM und TESM-Lizenzserver"
requires-python = ">=3.11"
dependencies = ["cryptography>=42"]
@@ -42,7 +42,7 @@ def _b64d(value: str, *, field: str) -> bytes:
try:
return base64.b64decode(value, validate=True)
except (binascii.Error, ValueError, TypeError) as exc: # pragma: no cover - defensiv
raise ValueError(f"{field} ist kein gueltiges Base64") from exc
raise ValueError(f"{field} ist kein gültiges Base64") from exc
@@ -96,7 +96,7 @@ def decode_code(code: str) -> dict[str, Any]:
try:
data = json.loads(base64.urlsafe_b64decode(cleaned.encode("ascii")).decode("utf-8"))
except (binascii.Error, ValueError, UnicodeDecodeError) as exc:
raise ValueError("Code ist unlesbar oder beschaedigt") from exc
raise ValueError("Code ist unlesbar oder beschädigt") from exc
if not isinstance(data, dict):
raise ValueError("Code enthaelt kein Objekt")
raise ValueError("Code enthält kein Objekt")
return data
@@ -161,7 +161,7 @@ def split_bundle(bundle: Mapping[str, Any]) -> tuple[dict[str, Any], str]:
eingebettetem ``license_privkey``.
"""
if not isinstance(bundle, Mapping):
raise InvalidLicenseFile("Lizenzdatei enthaelt kein Objekt")
raise InvalidLicenseFile("Lizenzdatei enthält kein Objekt")
inner = bundle.get("license")
if isinstance(inner, Mapping):
@@ -194,10 +194,10 @@ def verify_license(
missing = [name for name in _PAYLOAD_FIELDS if name not in document]
if missing:
raise InvalidLicenseFile(f"Lizenzdokument unvollstaendig: {', '.join(missing)}")
raise InvalidLicenseFile(f"Lizenzdokument unvollständig: {', '.join(missing)}")
if int(document.get("fmt") or 0) != FORMAT_VERSION:
raise InvalidLicenseFile(
f"Nicht unterstuetzte Formatversion: {document.get('fmt')!r}"
f"Nicht unterstützte Formatversion: {document.get('fmt')!r}"
f" (erwartet {FORMAT_VERSION})"
)
if document.get("type") not in LICENSE_TYPES:
@@ -207,17 +207,17 @@ def verify_license(
master_pubkey = str(document.get("master_pubkey") or "")
if key_id(master_pubkey) != str(document.get("master_key_id") or ""):
raise InvalidLicenseFile("master_key_id passt nicht zum eingebetteten Schluessel")
raise InvalidLicenseFile("master_key_id passt nicht zum eingebetteten Schlüssel")
payload = {k: v for k, v in document.items() if k != "signature"}
if not verify(
payload, str(document.get("signature") or ""), master_pubkey, SIG_CONTEXT_LICENSE
):
raise SignatureInvalid("Signatur der Lizenzdatei ist ungueltig")
raise SignatureInvalid("Signatur der Lizenzdatei ist ungültig")
if trusted_master_keys and master_pubkey not in set(trusted_master_keys):
raise UntrustedIssuer(
"Die Lizenz wurde nicht von einem vertrauenswuerdigen Lizenzserver ausgestellt"
"Die Lizenz wurde nicht von einem vertrauenswürdigen Lizenzserver ausgestellt"
)
@@ -236,7 +236,7 @@ def license_status(
lifetime = bool(document.get("lifetime"))
warnings: list[str] = []
if not issuer_pinned:
warnings.append("Aussteller nicht gepinnt -- nur innere Konsistenz geprueft")
warnings.append("Aussteller nicht gepinnt – nur innere Konsistenz geprüft")
issued_at: datetime | None = None
expires_at: datetime | None = None
@@ -248,7 +248,7 @@ def license_status(
try:
parsed = parse_iso(str(raw))
except ValueError:
warnings.append(f"Feld {name} ist kein gueltiges Datum")
warnings.append(f"Feld {name} ist kein gültiges Datum")
continue
if name == "issued_at":
issued_at = parsed
@@ -77,7 +77,7 @@ def build_client_request(
if action not in ACTIONS:
raise ProtocolViolation(f"Unbekannte Aktion: {action!r}")
if not client_private_key:
raise ProtocolViolation("Kein Client-Schluessel vorhanden -- Lizenz unvollstaendig importiert")
raise ProtocolViolation("Kein Client-Schlüssel vorhanden | Lizenz unvollständig importiert")
payload: dict[str, Any] = {
"fmt": FORMAT_VERSION,
@@ -130,22 +130,22 @@ def verify_master_response(
if not isinstance(response, Mapping):
raise ProtocolViolation("Antwort ist kein Objekt")
if int(response.get("fmt") or 0) != FORMAT_VERSION:
raise ProtocolViolation("Nicht unterstuetzte Protokollversion")
raise ProtocolViolation("Nicht unterstützte Protokollversion")
payload = {k: v for k, v in response.items() if k != "signature"}
if not verify(
payload, str(response.get("signature") or ""), master_public_key, SIG_CONTEXT_RESPONSE
):
raise SignatureInvalid("Signatur der Antwort ist ungueltig")
raise SignatureInvalid("Signatur der Antwort ist ungültig")
if str(response.get("license_id") or "") != expected_license_id:
raise ProtocolViolation("Antwort gehoert zu einer anderen Lizenz")
raise ProtocolViolation("Antwort gehört zu einer anderen Lizenz")
if str(response.get("fingerprint") or "") != expected_fingerprint:
raise ProtocolViolation("Antwort gehoert zu einer anderen Maschine")
raise ProtocolViolation("Antwort gehört zu einer anderen Maschine")
if str(response.get("action") or "") != expected_action:
raise ProtocolViolation("Antwort gehoert zu einer anderen Aktion")
raise ProtocolViolation("Antwort gehört zu einer anderen Aktion")
if str(response.get("nonce") or "") != expected_nonce:
raise ReplayDetected("Antwort gehoert nicht zu dieser Anfrage")
raise ReplayDetected("Antwort gehört nicht zu dieser Anfrage")
if str(response.get("status") or "") not in RESPONSE_STATES:
raise ProtocolViolation("Unbekannter Antwortstatus")
@@ -156,4 +156,4 @@ def verify_master_response(
if not isinstance(update, Mapping):
raise ProtocolViolation("license_update ist kein Objekt")
if int(update.get("seq") or 0) < int(current_seq or 0):
raise ReplayDetected("license_update ist aelter als die installierte Lizenz")
raise ReplayDetected("license_update ist älter als die installierte Lizenz")