Files
OCR/docengine/app/core/security.py

67 lines
2.3 KiB
Python

from __future__ import annotations
import uuid
from datetime import UTC, datetime, timedelta
from typing import Any
from jose import JWTError, jwt
from passlib.context import CryptContext
from app.core.config import settings
from app.core.aes import get_string_value
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
"""Hash a password using bcrypt."""
return pwd_context.hash(password)
def verify_password(plain_password: str, hashed_password: str) -> bool:
"""Verify a plain password against a hashed password."""
return pwd_context.verify(plain_password, hashed_password)
def create_access_token(data: dict[str, Any], expires_delta: timedelta | None = None) -> str:
"""Create a JWT access token."""
to_encode = data.copy()
expire = datetime.now(UTC) + (expires_delta or timedelta(minutes=settings.jwt_access_token_expire_minutes))
to_encode.update({"exp": expire, "type": "access"})
return jwt.encode(to_encode, settings.jwt_secret_key, algorithm=settings.jwt_algorithm)
def create_refresh_token(data: dict[str, Any], expires_delta: timedelta | None = None) -> str:
"""Create a JWT refresh token."""
to_encode = data.copy()
expire = datetime.now(UTC) + (expires_delta or timedelta(days=settings.jwt_refresh_token_expire_days))
to_encode.update({
"exp": expire,
"type": "refresh",
"jti": str(uuid.uuid4()),
})
return jwt.encode(to_encode, settings.jwt_secret_key, algorithm=settings.jwt_algorithm)
def decode_token(token: str) -> dict[str, Any]:
"""Decode and validate a JWT token."""
decrypted_token = get_string_value(
token,
settings.session_encryption_secret,
settings.session_encryption_secret_internal
)
final_token = decrypted_token if decrypted_token else token
try:
payload = jwt.decode(final_token, settings.jwt_secret_key, algorithms=[settings.jwt_algorithm])
return payload
except JWTError as e:
raise InvalidTokenError(str(e)) from e
class InvalidTokenError(Exception):
"""Raised when a JWT token is invalid or expired."""
def __init__(self, detail: str = "Invalid or expired token") -> None:
self.detail = detail
super().__init__(self.detail)