from passlib.context import CryptContext from settings import settings import jwt import datetime import logging password_context = CryptContext(schemes=["sha256_crypt"], deprecated="auto") logger = logging.getLogger(__name__) def hash_password(password: str) -> str: """Hashes a plain text password.""" return password_context.hash(password) def verify_password(plain_password: str, hashed_password: str) -> bool: """Verifies a plain text password against a hashed password.""" return password_context.verify(plain_password, hashed_password) def sign_jwt(row: dict) -> str: """Signs a JWT token with the given payload.""" exp = datetime.datetime.now( datetime.timezone.utc) + datetime.timedelta(hours=1) payload = { "id": row["id"], "exp": exp } return jwt.encode( payload, key=settings.jwt_secret, algorithm=settings.jwt_algorithm ) def decode_jwt(token: str | None) -> dict | None: """Decodes a JWT token and returns the payload.""" if not token or not token.startswith("Bearer "): logger.warning( "No token provided or token does not start with 'Bearer '") return None try: payload = jwt.decode( token.replace("Bearer ", ""), key=settings.jwt_secret, algorithms=[settings.jwt_algorithm] ) return payload except jwt.ExpiredSignatureError: logger.warning("Token has expired") return None except jwt.InvalidTokenError: logger.warning("Invalid token") return None logger.warning("Unexpected error in token decoding") return None