mediscan-api / apps /api /medbill_api /security.py
Vishwam2007's picture
Deploy MedBill backend
b802ed5
Raw History Blame Contribute Delete
2.07 kB
from __future__ import annotations
import base64
import hashlib
import hmac
import json
import os
import time
from typing import Any
def _b64encode(value: bytes) -> str:
return base64.urlsafe_b64encode(value).rstrip(b"=").decode("ascii")
def _b64decode(value: str) -> bytes:
return base64.urlsafe_b64decode(value + ("=" * (-len(value) % 4)))
def hash_password(password: str) -> str:
salt = os.urandom(16)
digest = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 240_000)
return f"{_b64encode(salt)}${_b64encode(digest)}"
def verify_password(password: str, password_hash: str) -> bool:
try:
salt_value, digest_value = password_hash.split("$", 1)
except ValueError:
return False
digest = hashlib.pbkdf2_hmac(
"sha256",
password.encode(),
_b64decode(salt_value),
240_000,
)
return hmac.compare_digest(digest, _b64decode(digest_value))
def create_token(payload: dict[str, Any], *, secret: str) -> str:
now = int(time.time())
body = {**payload, "iat": now, "exp": now + 60 * 60 * 24 * 7}
header = {"alg": "HS256", "typ": "JWT"}
signing_input = ".".join(
[
_b64encode(json.dumps(header, separators=(",", ":")).encode()),
_b64encode(json.dumps(body, separators=(",", ":")).encode()),
],
)
signature = hmac.new(secret.encode(), signing_input.encode(), hashlib.sha256).digest()
return f"{signing_input}.{_b64encode(signature)}"
def decode_token(token: str, *, secret: str) -> dict[str, Any] | None:
try:
header, payload, signature = token.split(".", 2)
signing_input = f"{header}.{payload}"
expected = hmac.new(secret.encode(), signing_input.encode(), hashlib.sha256).digest()
if not hmac.compare_digest(expected, _b64decode(signature)):
return None
data = json.loads(_b64decode(payload))
except (ValueError, json.JSONDecodeError):
return None
if int(data.get("exp", 0)) < int(time.time()):
return None
return data