🚧 WIP
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
"""Password hashing (Argon2id, spec section 43) and session tokens."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import secrets
|
||||
import uuid
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
from argon2 import PasswordHasher
|
||||
from argon2.exceptions import VerifyMismatchError
|
||||
|
||||
_hasher = PasswordHasher() # Argon2id by default
|
||||
|
||||
|
||||
def hash_password(password: str) -> str:
|
||||
return _hasher.hash(password)
|
||||
|
||||
|
||||
def verify_password(password_hash: str, password: str) -> bool:
|
||||
try:
|
||||
return _hasher.verify(password_hash, password)
|
||||
except VerifyMismatchError:
|
||||
return False
|
||||
except Exception:
|
||||
# Malformed hash etc. — never crash authentication on it.
|
||||
return False
|
||||
|
||||
|
||||
def generate_password(length: int = 24) -> str:
|
||||
"""Cryptographically random password for MQTT clients (spec section 11)."""
|
||||
alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789"
|
||||
return "".join(secrets.choice(alphabet) for _ in range(length))
|
||||
|
||||
|
||||
def generate_session_id() -> uuid.UUID:
|
||||
return uuid.uuid4()
|
||||
|
||||
|
||||
def session_expiry(ttl_seconds: int) -> datetime:
|
||||
return datetime.now(UTC) + timedelta(seconds=ttl_seconds)
|
||||
Reference in New Issue
Block a user