validator edits
This commit is contained in:
75
packages/tracker/meshnet_tracker/auth.py
Normal file
75
packages/tracker/meshnet_tracker/auth.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""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, "<timestamp>." + 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)
|
||||
Reference in New Issue
Block a user