Vollstaendiger Neubau der Anwendung. Der vorherige Stand bleibt unveraendert im Zweig SONNET5 erhalten. Aufbau: apps/tesm (Anwendung), packages/tesm-core (gemeinsamer Kern), packages/tesm-licensing (Lizenzprotokoll), deploy (Installation, systemd, privilegierter Helfer), docs, tests. Der Lizenzserver liegt in seinem eigenen Repository; beide Repositorien bringen die gemeinsamen Pakete mit, damit sich jedes allein installieren laesst. Die wichtigsten Unterschiede zum Vorgaenger, jeweils an der Stelle im Code kommentiert, an der der Fehler entstanden ist: * Der Webprozess laeuft unprivilegiert. Alles, was Root braucht, geht ueber einen einzigen Helfer mit Positivlisten fuer jedes Argument. * CSRF-Schutz ueberhaupt -- der Vorgaenger hatte keinen. * Rechte werden serverseitig geprueft, nicht nur im Template ausgeblendet. * Die nginx-Site wird bei jedem Lauf inhaltlich verglichen und erneuert. * Jede erzeugte Konfiguration wird vor dem Uebernehmen geprueft (nginx, Kea). * Kein Hostname im Lizenz-Fingerabdruck. * Zwei Installationen auf einem Host stoeren sich nicht (eigener SITE_KEY). * Verschachtelte Datenbankverbindungen sind ein Fehler, kein Deadlock. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
33 lines
956 B
Python
33 lines
956 B
Python
"""Fehlerklassen des Lizenzprotokolls.
|
|
|
|
Alle Fehler sind bewusst so gebaut, dass sie *keine* Geheimnisse (Schluessel,
|
|
Signaturen, Payload-Inhalte) in ihrer Textform tragen -- sie landen in Logs und
|
|
teilweise in HTTP-Antworten.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
class LicensingError(Exception):
|
|
"""Basisklasse aller Protokollfehler."""
|
|
|
|
|
|
class InvalidLicenseFile(LicensingError):
|
|
"""Lizenzdatei ist strukturell kaputt, unvollstaendig oder falsch versioniert."""
|
|
|
|
|
|
class UntrustedIssuer(LicensingError):
|
|
"""Signatur ist in sich gueltig, der Aussteller aber nicht vertrauenswuerdig (Pinning)."""
|
|
|
|
|
|
class SignatureInvalid(LicensingError):
|
|
"""Signatur passt nicht zur Payload."""
|
|
|
|
|
|
class ReplayDetected(LicensingError):
|
|
"""Nonce wurde schon gesehen oder Zeitstempel liegt ausserhalb des Frischefensters."""
|
|
|
|
|
|
class ProtocolViolation(LicensingError):
|
|
"""Anfrage/Antwort verletzt das erwartete Format oder die erwartete Aktion."""
|