first commit
This commit is contained in:
commit
efa5080897
127 changed files with 18610 additions and 0 deletions
48
backend/app/api_keys_service.py
Normal file
48
backend/app/api_keys_service.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import re
|
||||
import secrets
|
||||
import uuid
|
||||
|
||||
from pwdlib import PasswordHash
|
||||
|
||||
KEY_PREFIX = "urmi_live_"
|
||||
KEY_RANDOM_BYTES = 24
|
||||
NAME_PATTERN = re.compile(r"^[A-Za-z0-9][A-Za-z0-9 _-]{1,59}$")
|
||||
|
||||
password_hash = PasswordHash.recommended()
|
||||
|
||||
|
||||
def validate_key_name(value: str) -> str:
|
||||
name = value.strip()
|
||||
if not NAME_PATTERN.match(name):
|
||||
raise ValueError("Key name must be 2–60 characters using letters, numbers, spaces, _ or -")
|
||||
return name
|
||||
|
||||
|
||||
def generate_api_token(key_id: uuid.UUID) -> str:
|
||||
return f"{KEY_PREFIX}{key_id.hex}_{secrets.token_urlsafe(KEY_RANDOM_BYTES)}"
|
||||
|
||||
|
||||
def parse_api_token(token: str) -> tuple[uuid.UUID, str] | None:
|
||||
if not token.startswith(KEY_PREFIX):
|
||||
return None
|
||||
rest = token[len(KEY_PREFIX) :]
|
||||
if "_" not in rest:
|
||||
return None
|
||||
key_hex, _secret = rest.split("_", 1)
|
||||
try:
|
||||
return uuid.UUID(hex=key_hex), token
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def token_prefix(token: str) -> str:
|
||||
visible = token[:16]
|
||||
return f"{visible}…"
|
||||
|
||||
|
||||
def hash_api_token(token: str) -> str:
|
||||
return password_hash.hash(token)
|
||||
|
||||
|
||||
def verify_api_token(token: str, stored_hash: str) -> bool:
|
||||
return password_hash.verify(token, stored_hash)
|
||||
Loading…
Add table
Add a link
Reference in a new issue