feat(relay): optional proof-of-work for registration

GET /v1/register/challenge issues a stateless challenge (version, difficulty,
expiry and a random nonce, HMAC-signed with a per-process key). The client
finds a counter so that SHA-256(domain || challenge || identity_key ||
counter) has the requested number of leading zero bits and sends it in the
X-Sepot-Pow header of POST /v1/register. Verification is one HMAC and one
SHA-256; used challenges are kept in memory until they expire.

SEPOT_REGISTER_POW=off|optional|required (default optional): in optional
mode registrations with a valid solution get a separate, more generous
per-IP bucket (SEPOT_RL_REGISTER_POW_*), registrations without one keep the
existing limit; both share the global cap. required answers 428 without a
valid solution. Difficulty: SEPOT_REGISTER_POW_BITS (18), raised by one bit
per doubling of the registration rate over SEPOT_REGISTER_POW_ADAPT_PER_MIN
up to SEPOT_REGISTER_POW_MAX_BITS (22). server-info advertises the mode.

The paused-registration 503 now carries Retry-After.
This commit is contained in:
Julius Joska
2026-10-23 11:44:47 +02:00
parent 45f169c20d
commit 10ca35e352
7 changed files with 674 additions and 17 deletions
+2
View File
@@ -29,6 +29,8 @@ serde_json = "1"
base64 = "0.22"
# TURN údaje pro hovory: coturn ověřuje HMAC-SHA1 (REST schéma use-auth-secret)
hmac = "0.12"
# Proof-of-work registrace (pow.rs); už v grafu závislostí přes libsignal
sha2 = "0.10"
sha1 = "0.10"
hex = "0.4"
chrono = "0.4"