46 lines
1.6 KiB
Python
46 lines
1.6 KiB
Python
import base64
|
|
import hashlib
|
|
import hmac
|
|
import json
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
from backend.app.core.config import get_settings
|
|
|
|
|
|
settings = get_settings()
|
|
|
|
|
|
def hash_password(password: str) -> str:
|
|
secret = settings.secret_key.encode("utf-8")
|
|
return hashlib.sha256(secret + password.encode("utf-8")).hexdigest()
|
|
|
|
|
|
def verify_password(password: str, password_hash: str) -> bool:
|
|
return hmac.compare_digest(hash_password(password), password_hash or "")
|
|
|
|
|
|
def create_access_token(payload: dict) -> str:
|
|
data = dict(payload)
|
|
expire_at = datetime.now(timezone.utc) + timedelta(minutes=settings.jwt_expire_minutes)
|
|
data["exp"] = int(expire_at.timestamp())
|
|
body = json.dumps(data, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
|
|
body_b64 = base64.urlsafe_b64encode(body).decode("utf-8").rstrip("=")
|
|
signature = hmac.new(settings.secret_key.encode("utf-8"), body_b64.encode("utf-8"), hashlib.sha256).hexdigest()
|
|
return f"{body_b64}.{signature}"
|
|
|
|
|
|
def decode_access_token(token: str) -> dict | None:
|
|
try:
|
|
body_b64, signature = token.split(".", 1)
|
|
expected = hmac.new(settings.secret_key.encode("utf-8"), body_b64.encode("utf-8"), hashlib.sha256).hexdigest()
|
|
if not hmac.compare_digest(signature, expected):
|
|
return None
|
|
padded = body_b64 + "=" * (-len(body_b64) % 4)
|
|
payload = json.loads(base64.urlsafe_b64decode(padded.encode("utf-8")).decode("utf-8"))
|
|
exp = int(payload.get("exp", 0))
|
|
if exp <= int(datetime.now(timezone.utc).timestamp()):
|
|
return None
|
|
return payload
|
|
except Exception:
|
|
return None
|