Files

53 lines
1.9 KiB
Python
Raw Permalink Normal View History

import hmac
import hashlib
from datetime import datetime, timedelta, timezone
from typing import Optional, Dict, Any
import jwt
from app.core.config import settings
def verify_password(plain_password: str, stored_password: str) -> bool:
"""Constant-time password comparison to prevent timing attacks."""
if not plain_password or not stored_password:
return False
# Supports direct string comparison via hmac or sha256 hash
if stored_password.startswith("sha256$"):
_, salt, expected_hash = stored_password.split("$", 2)
calc_hash = hashlib.sha256((salt + plain_password).encode("utf-8")).hexdigest()
return hmac.compare_digest(calc_hash, expected_hash)
return hmac.compare_digest(plain_password, stored_password)
def hash_password(plain_password: str, salt: str = "merica_dlh_salt") -> str:
"""Generate salted sha256 password hash."""
calc_hash = hashlib.sha256((salt + plain_password).encode("utf-8")).hexdigest()
return f"sha256${salt}${calc_hash}"
def create_session_token(data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str:
"""Create a unified session JWT token signed with SECRET_KEY."""
to_encode = data.copy()
now = datetime.now(timezone.utc)
if expires_delta:
expire = now + expires_delta
else:
expire = now + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({
"exp": int(expire.timestamp()),
"iat": int(now.timestamp())
})
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
return encoded_jwt
def decode_session_token(token: str) -> Optional[Dict[str, Any]]:
"""Decode and validate a session JWT token."""
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
return payload
except Exception:
return None