Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import base64 | |
| import hashlib | |
| import hmac | |
| import secrets | |
| PBKDF2_ROUNDS = 210_000 | |
| def _b64(data: bytes) -> str: | |
| return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=") | |
| def _unb64(value: str) -> bytes: | |
| padding = "=" * (-len(value) % 4) | |
| return base64.urlsafe_b64decode(value + padding) | |
| def hash_secret(secret: str) -> str: | |
| salt = secrets.token_bytes(16) | |
| digest = hashlib.pbkdf2_hmac("sha256", secret.encode("utf-8"), salt, PBKDF2_ROUNDS) | |
| return f"pbkdf2_sha256${PBKDF2_ROUNDS}${_b64(salt)}${_b64(digest)}" | |
| def verify_secret(secret: str, stored_hash: str) -> bool: | |
| try: | |
| algorithm, rounds_text, salt_text, digest_text = stored_hash.split("$", 3) | |
| if algorithm != "pbkdf2_sha256": | |
| return False | |
| rounds = int(rounds_text) | |
| salt = _unb64(salt_text) | |
| expected = _unb64(digest_text) | |
| except (ValueError, TypeError): | |
| return False | |
| actual = hashlib.pbkdf2_hmac("sha256", secret.encode("utf-8"), salt, rounds) | |
| return hmac.compare_digest(actual, expected) | |
| def generate_api_key() -> str: | |
| return "rcg_" + secrets.token_urlsafe(32) | |
| def key_prefix(secret: str) -> str: | |
| return secret[:12] | |
| def generate_csrf_token() -> str: | |
| return secrets.token_urlsafe(24) | |