Update docs and screenshots
CI / backend (pull_request) Canceled after 0s
CI / shell (pull_request) Canceled after 0s
CI / frontend (pull_request) Canceled after 0s
CI / arm64-smoke (pull_request) Canceled after 0s
CI / backend (push) Canceled after 0s
CI / shell (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / arm64-smoke (push) Canceled after 0s
CI / backend (pull_request) Canceled after 0s
CI / shell (pull_request) Canceled after 0s
CI / frontend (pull_request) Canceled after 0s
CI / arm64-smoke (pull_request) Canceled after 0s
CI / backend (push) Canceled after 0s
CI / shell (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / arm64-smoke (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
"""Authentication services."""
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import secrets
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
from argon2 import PasswordHasher
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class SessionData:
|
||||
session_id: str
|
||||
csrf_token: str
|
||||
expires_at: datetime
|
||||
role: str
|
||||
username: str
|
||||
|
||||
|
||||
class AuthService:
|
||||
def __init__(self) -> None:
|
||||
self._hasher = PasswordHasher()
|
||||
self._sessions: dict[str, SessionData] = {}
|
||||
|
||||
def hash_password(self, password: str) -> str:
|
||||
return self._hasher.hash(password)
|
||||
|
||||
def verify_password(self, password: str, password_hash: str) -> bool:
|
||||
try:
|
||||
return self._hasher.verify(password_hash, password)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def create_session(self, username: str, role: str) -> SessionData:
|
||||
session_id = secrets.token_hex(24)
|
||||
csrf_token = secrets.token_hex(16)
|
||||
expires_at = datetime.now(UTC) + timedelta(hours=12)
|
||||
session = SessionData(
|
||||
session_id=session_id,
|
||||
csrf_token=csrf_token,
|
||||
expires_at=expires_at,
|
||||
role=role,
|
||||
username=username,
|
||||
)
|
||||
self._sessions[session_id] = session
|
||||
return session
|
||||
|
||||
def get_session(self, session_id: str | None) -> SessionData | None:
|
||||
if session_id is None:
|
||||
return None
|
||||
session = self._sessions.get(session_id)
|
||||
if session is None:
|
||||
return None
|
||||
if session.expires_at < datetime.now(UTC):
|
||||
self._sessions.pop(session_id, None)
|
||||
return None
|
||||
return session
|
||||
|
||||
Reference in New Issue
Block a user