"""Unified tracker auth primitives (ADR-0017, alpha issues 01/02/20). Two mechanisms live here: - **Hive peer HMAC** — gossip mutation endpoints require a signature computed as HMAC-SHA256(hive_secret, "." + raw_body). All trackers in a hive share one secret (``--hive-secret`` / MESHNET_HIVE_SECRET). Timestamps outside the skew window are rejected to blunt replay. - **Validator service token** — a dedicated bearer credential distinct from client API keys and admin sessions (``--validator-service-token`` / MESHNET_VALIDATOR_SERVICE_TOKEN), resolved to the ``validator`` role. Role resolution itself happens in the request handler (it needs the account store); these are the shared, dependency-free pieces. """ from __future__ import annotations import hmac import hashlib import time HIVE_SIGNATURE_HEADER = "X-Meshnet-Hive-Signature" HIVE_TIMESTAMP_HEADER = "X-Meshnet-Hive-Timestamp" HIVE_MAX_CLOCK_SKEW_SECONDS = 300.0 def _hive_digest(secret: str, timestamp: str, body: bytes) -> str: return hmac.new( secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256 ).hexdigest() def sign_hive_request(secret: str, body: bytes, *, timestamp: float | None = None) -> dict[str, str]: """Headers a tracker attaches when pushing gossip to a hive peer.""" ts = f"{timestamp if timestamp is not None else time.time():.3f}" return { HIVE_SIGNATURE_HEADER: _hive_digest(secret, ts, body), HIVE_TIMESTAMP_HEADER: ts, } def verify_hive_request( secret: str | None, headers, body: bytes, *, now: float | None = None, ) -> bool: """True only when the request carries a fresh, valid hive signature. Fails closed: no configured secret means no gossip is accepted. """ if not secret: return False signature = headers.get(HIVE_SIGNATURE_HEADER) timestamp = headers.get(HIVE_TIMESTAMP_HEADER) if not signature or not timestamp: return False try: ts_value = float(timestamp) except ValueError: return False current = now if now is not None else time.time() if abs(current - ts_value) > HIVE_MAX_CLOCK_SKEW_SECONDS: return False return hmac.compare_digest(signature, _hive_digest(secret, timestamp, body)) def is_validator_token(token: str | None, configured: str | None) -> bool: """Constant-time check of a presented bearer token against the configured validator service token.""" if not token or not configured: return False return hmac.compare_digest(token, configured)