52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
import hashlib
|
|
import logging
|
|
import secrets
|
|
from typing import Any
|
|
|
|
import jwt
|
|
from argon2 import PasswordHasher
|
|
from argon2.exceptions import InvalidHashError, VerificationError, VerifyMismatchError
|
|
|
|
from config import cfg
|
|
from schemas.dto import KeyPair
|
|
from schemas.jwt import JWTPayload
|
|
from schemas.providers import ProvidersType
|
|
|
|
ctx = PasswordHasher()
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def hash_password(plain_password: str) -> ...:
|
|
return ctx.hash(plain_password)
|
|
|
|
|
|
def verify_password(hashed_password: str, plain_password: str) -> bool:
|
|
try:
|
|
ctx.verify(hashed_password, plain_password)
|
|
return True
|
|
except (VerifyMismatchError, VerificationError, InvalidHashError):
|
|
return False
|
|
except Exception:
|
|
logger.exception("unexpected error while comparing password and hash")
|
|
return False
|
|
|
|
|
|
def generate_jwt(payload: dict[str, Any]) -> str:
|
|
return jwt.encode(payload, cfg.private_key, "RS256")
|
|
|
|
|
|
def decode_jwt(token: str) -> dict[str, Any]:
|
|
return jwt.decode(token, cfg.public_key, "RS256")
|
|
|
|
|
|
def generate_pair(user_id: int, iss: ProvidersType) -> KeyPair:
|
|
payload = JWTPayload(sub=user_id, iss=iss)
|
|
access_token = generate_jwt(payload.model_dump())
|
|
refresh_token = secrets.token_urlsafe(32)
|
|
|
|
return KeyPair(access_token=access_token, refresh_token=refresh_token)
|
|
|
|
|
|
def hash_refresh_token(token: str):
|
|
return hashlib.sha256(token.encode()).hexdigest()
|