diff options
| author | Gab Virebent <gabriel1@virebent.art> | 2026-07-01 17:41:47 +0200 |
|---|---|---|
| committer | Gab Virebent <gabriel1@virebent.art> | 2026-07-01 17:41:47 +0200 |
| commit | 71e4fd1593b1d708e4f41f5e5119689435ff956e (patch) | |
| tree | 4eb1791d00ffd39eb38300cd0681539389c19122 /internal/handler/submit.go | |
| parent | c6bb0b76e72e1211a756823763846b9f528f5f4a (diff) | |
| download | nymdrop-71e4fd1593b1d708e4f41f5e5119689435ff956e.tar.gz nymdrop-71e4fd1593b1d708e4f41f5e5119689435ff956e.tar.xz nymdrop-71e4fd1593b1d708e4f41f5e5119689435ff956e.zip | |
Add client-side proof of work and fix X25519 WebCrypto API usage
Self-contained hashcash-style PoW on /submit: client finds a nonce so
SHA-256("<unix-ts>:<nonce>") has enough leading zero bits, sent as an
X-Nymdrop-Pow header; server verifies and rejects expired or replayed
stamps, no challenge round-trip required. Difficulty tunable via
--pow-difficulty without a rebuild.
Also fixes a latent bug in the browser crypto: X25519 was being
requested as ECDH with namedCurve "X25519", which is not a valid
WebCrypto combination and always throws. Modern WebCrypto exposes
X25519 as its own algorithm identifier.
Diffstat (limited to 'internal/handler/submit.go')
| -rw-r--r-- | internal/handler/submit.go | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/internal/handler/submit.go b/internal/handler/submit.go index 15251cf..2822488 100644 --- a/internal/handler/submit.go +++ b/internal/handler/submit.go @@ -2,15 +2,17 @@ package handler import ( "net/http" + "nymdrop/internal/pow" "nymdrop/internal/relay" ) type Submit struct { relay *relay.Relay + pow *pow.Verifier } -func NewSubmit(r *relay.Relay) *Submit { - return &Submit{relay: r} +func NewSubmit(r *relay.Relay, p *pow.Verifier) *Submit { + return &Submit{relay: r, pow: p} } func (s *Submit) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -19,6 +21,14 @@ func (s *Submit) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + // Proof-of-work computed client-side (X-Nymdrop-Pow: "<unix-ts>:<nonce>"). + // Rejects unproven, expired, and replayed stamps before touching the relay. + if err := s.pow.Verify(r.Header.Get("X-Nymdrop-Pow")); err != nil { + // Generic error — don't reveal which check failed. + http.Error(w, "error", http.StatusBadRequest) + return + } + r.Body = http.MaxBytesReader(w, r.Body, 10*1024*1024) defer r.Body.Close() |
