feat(hub): per-hub relay auth keys with automatic recovery

The public relay used to accept a shared auth key compiled into every
hub, so its bandwidth was open to anyone. The relay now issues a
per-hub credential it can meter and revoke, and hubs obtain one on
their own.

- --relay resolves an auth key at startup: HAPI_RELAY_AUTH env, then a
  key persisted in settings.json, then a fresh key from the relay's
  /issue endpoint. There is no shared-key fallback; if no key can be
  obtained the tunnel does not start and the hub says why.
- A persisted key rejected by the relay (HTTP 403 after revocation or a
  secret rotation) is discarded and replaced once, then the tunnel is
  restarted, so a revoked hub recovers without manual edits. Keys given
  explicitly through the environment are never overwritten.
- Issuance is rate-limited per public IP; HTTP 429 is reported with the
  retry hint instead of being retried blindly, which matters for users
  sharing a CGNAT or corporate egress address.
- The tunnel URL now comes from upstream tunwg's slog JSON on stderr
  (msg="listener started"), replacing the fork's custom --json event,
  and --log_level=0 keeps per-request logs out of the hub console.

Requires a relay running tunwg with TUNWG_AUTH_SECRET configured.
This commit is contained in:
weishu
2026-08-04 08:18:17 +08:00
parent cc8cc914bc
commit b67f4e56e5
8 changed files with 276 additions and 35 deletions
+1 -1
View File
@@ -16,7 +16,7 @@
* - HAPI_PUBLIC_URL: Public URL for external access (e.g., Telegram Mini App)
* - CORS_ORIGINS: Comma-separated CORS origins
* - HAPI_RELAY_API: Relay API domain for tunwg (default: relay.hapi.run)
* - HAPI_RELAY_AUTH: Relay auth key for tunwg (default: hapi)
* - HAPI_RELAY_AUTH: Relay auth key override (default: per-hub key issued by the relay)
* - HAPI_RELAY_FORCE_TCP: Force TCP relay mode when UDP is unavailable (true/1)
* - VAPID_SUBJECT: Contact email or URL for Web Push (defaults to mailto:admin@hapi.run)
* - HAPI_HOME: Data directory (default: ~/.hapi)