Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95238b781f | ||
|
|
3ea7937b5b |
No files matched your search
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm"
|
name = "tesm"
|
||||||
version = "2.8.29"
|
version = "2.8.31"
|
||||||
description = "TESM -- Verwaltung und Ueberwachung von PoE-Endgeraeten und Aruba-Switchen"
|
description = "TESM -- Verwaltung und Ueberwachung von PoE-Endgeraeten und Aruba-Switchen"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
@@ -150,6 +150,22 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
globals().update(AMBER="", DIM="", BOLD="", RESET="")
|
globals().update(AMBER="", DIM="", BOLD="", RESET="")
|
||||||
|
|
||||||
root = Path(args.root)
|
root = Path(args.root)
|
||||||
|
|
||||||
|
# Gibt es diese Installation ueberhaupt noch? Wenn nicht, ist hier nichts
|
||||||
|
# zu melden -- auch kein Fehler.
|
||||||
|
#
|
||||||
|
# Der Hook unter /etc/update-motd.d bleibt liegen, wenn jemand eine
|
||||||
|
# Installation von Hand entfernt; einen Rueckbau bringt TESM nicht mit.
|
||||||
|
# Vorher druckte jeder dieser Hooks trotzdem seinen vollen Banner und
|
||||||
|
# darunter "Datenbank nicht lesbar". Auf dem Testserver standen so
|
||||||
|
# vierzehn Bloecke fuer vierzehn laengst geloeschte Probeinstallationen
|
||||||
|
# vor jeder Anmeldung -- und der echte Banner ging darin unter.
|
||||||
|
#
|
||||||
|
# Eine entfernte Installation ist keine kaputte. Eine Datenbank, die da
|
||||||
|
# ist und sich nicht lesen laesst, dagegen schon: die meldet sich weiter.
|
||||||
|
if not (root / "data" / "app.db").is_file():
|
||||||
|
return 0
|
||||||
|
|
||||||
# Kein isatty()-Test: dieses Skript schreibt beim Login nicht auf ein
|
# Kein isatty()-Test: dieses Skript schreibt beim Login nicht auf ein
|
||||||
# Terminal, sondern ueber run-parts in eine Datei. Der Betrachter ist
|
# Terminal, sondern ueber run-parts in eine Datei. Der Betrachter ist
|
||||||
# trotzdem ein echtes Terminal -- deshalb immer Farbe.
|
# trotzdem ein echtes Terminal -- deshalb immer Farbe.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "tesm-core"
|
name = "tesm-core"
|
||||||
version = "2.8.17"
|
version = "2.8.18"
|
||||||
description = "Gemeinsames Anwendungsgeruest (Auth, RBAC, Navigation, Design-System, Migrationen) fuer TESM und TESM-Lizenzserver"
|
description = "Gemeinsames Anwendungsgeruest (Auth, RBAC, Navigation, Design-System, Migrationen) fuer TESM und TESM-Lizenzserver"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
@@ -266,6 +266,35 @@ def _bitte_bestaetigen(permission: str) -> Any:
|
|||||||
return redirect(url_for("auth.reauth"))
|
return redirect(url_for("auth.reauth"))
|
||||||
|
|
||||||
|
|
||||||
|
def _heikel(permissions: tuple[str, ...], mode: str) -> str:
|
||||||
|
"""Welches Recht verlangt hier eine frische Bestaetigung? Sonst leer.
|
||||||
|
|
||||||
|
Bei ``mode="all"`` ist die Antwort einfach: jedes genannte Recht wird
|
||||||
|
gebraucht, also zaehlt jedes heikle darunter.
|
||||||
|
|
||||||
|
Bei ``mode="any"`` nicht. Diese Seiten nennen mehrere **unabhaengige**
|
||||||
|
Wege hinein, und welcher genommen wird, entscheidet das Konto. Der
|
||||||
|
Protokollverlauf etwa nennt "logs_history.read" und "logs_history.export":
|
||||||
|
lesen ist harmlos, mitnehmen nicht. Gezaehlt wurde aber ueber alle
|
||||||
|
genannten Rechte -- und so verlangte das blosse **Ansehen** des Verlaufs
|
||||||
|
nach fuenfzehn Minuten eine Passworteingabe, mit dem Hinweis, man greife
|
||||||
|
auf einen Datenexport zu. Das stimmte nicht, und wer es dreimal liest,
|
||||||
|
glaubt die Meldung beim vierten Mal auch dann nicht, wenn sie zutrifft.
|
||||||
|
|
||||||
|
Gefragt wird deshalb: haette dieses Konto die Seite auch ohne das heikle
|
||||||
|
Recht geoeffnet? Dann gibt es nichts zu bestaetigen. Die Ausfuhr selbst
|
||||||
|
haengt an ihrer eigenen Route, und die nennt nur ein Recht.
|
||||||
|
"""
|
||||||
|
heikle = [p for p in permissions if _verlangt_wiederanmeldung(p)]
|
||||||
|
if not heikle:
|
||||||
|
return ""
|
||||||
|
if mode == "any":
|
||||||
|
harmlos = [p for p in permissions if p not in heikle]
|
||||||
|
if any(current_user.has(p) for p in harmlos):
|
||||||
|
return ""
|
||||||
|
return heikle[0]
|
||||||
|
|
||||||
|
|
||||||
def permission_required(*permissions: str, mode: str = "all") -> Callable[..., Any]:
|
def permission_required(*permissions: str, mode: str = "all") -> Callable[..., Any]:
|
||||||
"""Erzwingt Rechte serverseitig.
|
"""Erzwingt Rechte serverseitig.
|
||||||
|
|
||||||
@@ -289,9 +318,9 @@ def permission_required(*permissions: str, mode: str = "all") -> Callable[..., A
|
|||||||
# in jeder Route einzeln. Vorher hing es daran, dass jemand an den
|
# in jeder Route einzeln. Vorher hing es daran, dass jemand an den
|
||||||
# Dekorator dachte: dieselbe Lizenz herunterzuladen fragte nach,
|
# Dekorator dachte: dieselbe Lizenz herunterzuladen fragte nach,
|
||||||
# sie per Mail zu verschicken nicht.
|
# sie per Mail zu verschicken nicht.
|
||||||
heikel = [p for p in permissions if _verlangt_wiederanmeldung(p)]
|
heikel = _heikel(permissions, mode)
|
||||||
if heikel and not _wiederanmeldung_frisch():
|
if heikel and not _wiederanmeldung_frisch():
|
||||||
return _bitte_bestaetigen(heikel[0])
|
return _bitte_bestaetigen(heikel)
|
||||||
return view(*args, **kwargs)
|
return view(*args, **kwargs)
|
||||||
|
|
||||||
wrapper._required_permissions = permissions # type: ignore[attr-defined]
|
wrapper._required_permissions = permissions # type: ignore[attr-defined]
|
||||||
|
|||||||
Reference in new issue
Block a user