furtka-gateway/control_plane/tokens.py
Robert Syrnicki 3a9d18fcd5 Scaffold gateway stack and single-tenant control plane
wg-easy + Traefik docker-compose stack (Phase 1) plus a stdlib-only
control-plane API for box registration, WireGuard peer provisioning via
wg-easy, and per-box route publish/unpublish backed by Traefik's file
provider (Phase 2, single-tenant mode). SQLite holds accounts/boxes/routes
so a later multi-tenant shared instance is the same schema with more rows,
not a reshape.

wg-easy's actual REST API was verified against its source rather than
assumed: it has no bearer-token auth (session-cookie login via
POST /api/auth/password) and no way to accept an externally-generated
public key (it always mints the keypair itself, private key included) —
both corrected from the original plan during implementation.
2026-08-24 11:50:25 +02:00

27 lines
795 B
Python

"""Bearer-token helpers shared by accounts.py/boxes.py.
Tokens are minted as ``"<row-id>.<secret>"`` so authenticating one is an
O(1) primary-key lookup followed by a single hash comparison, rather than
scanning every row and hashing each one looking for a match.
"""
import secrets
def generate_secret() -> str:
return secrets.token_urlsafe(32)
def issue(row_id: str) -> tuple[str, str]:
"""Return ``(bearer_token_to_hand_out, secret_to_hash_and_store)``."""
secret = generate_secret()
return f"{row_id}.{secret}", secret
def split(token: str) -> tuple[str, str] | None:
if not isinstance(token, str) or "." not in token:
return None
row_id, _, secret = token.partition(".")
if not row_id or not secret:
return None
return row_id, secret