Inclui console handoff Desk↔Console (Spec 019), melhorias DNS Viewer (037), OpenPanel/Nextcloud/VM116 deploy notes, contracts stack e sidebar actualizado. Co-authored-by: Cursor <cursoragent@cursor.com>
35 lines
894 B
Python
35 lines
894 B
Python
"""Short-lived single-use tokens for Desk → Console SSO (Spec 019/035)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import secrets
|
|
import time
|
|
from threading import Lock
|
|
|
|
_HANDOFF: dict[str, dict] = {}
|
|
_LOCK = Lock()
|
|
TTL_SEC = 120
|
|
|
|
|
|
def create_handoff(username: str, role: str) -> tuple[str, int]:
|
|
token = secrets.token_urlsafe(32)
|
|
exp = time.time() + TTL_SEC
|
|
with _LOCK:
|
|
_purge_expired_locked()
|
|
_HANDOFF[token] = {"username": username, "role": role, "exp": exp}
|
|
return token, TTL_SEC
|
|
|
|
|
|
def consume_handoff(token: str) -> dict | None:
|
|
with _LOCK:
|
|
rec = _HANDOFF.pop(token.strip(), None)
|
|
_purge_expired_locked()
|
|
if not rec or rec["exp"] < time.time():
|
|
return None
|
|
return rec
|
|
|
|
|
|
def _purge_expired_locked() -> None:
|
|
now = time.time()
|
|
for key in [k for k, v in _HANDOFF.items() if v["exp"] < now]:
|
|
del _HANDOFF[key]
|