clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

refactor(auth): make streamed request verification explicit

Dami committed d0a14b0
Add deferred NIP-98 verification and use it for file chunks, room attachments and Git requests. Preserve body validation after reading each stream and cover deferred validation and replay handling with ordinary tests.
commit
d0a14b01e65dc0ca2eb9b4f8d2fff7f59add59c6
parent
e8d32f37a63d7a5388d2d0a4bc2d170bbdf13d58
author
Dami <dami.etoile@gmail.com>
4 files changed, +41 -3
Minternal/daemon/room_attachments.go2+-
Minternal/daemon/services.go6+++++-
Mprotocol/auth/auth.go13++++++++++++-
Mprotocol/auth/auth_test.go23+++++++++++++++++++++++
M internal/daemon/room_attachments.go +1 -1
M internal/daemon/services.go +5 -1
M protocol/auth/auth.go +12 -1
@@ -38,6 +38,17 @@ func NewValidator(now func() time.Time) *Validator {
3838 // method and body supplied by the caller. Successfully verified event IDs are3939 // retained for the one-minute replay window.4040 func (v *Validator) VerifyNIP98(header, rawURL, method, body string) (nostr.Event, error) {41+ return v.verifyNIP98(header, rawURL, method, body, true)42+}43+44+// VerifyNIP98Deferred authenticates a proof before a streamed body is45+// read. Callers must check the payload tag against the resulting content hash46+// before accepting the body, such as with ValidateBlobPayload for uploads.47+func (v *Validator) VerifyNIP98Deferred(header, rawURL, method string) (nostr.Event, error) {48+ return v.verifyNIP98(header, rawURL, method, "", false)49+}50+51+func (v *Validator) verifyNIP98(header, rawURL, method, body string, checkPayload bool) (nostr.Event, error) {4152 e, err := decodeToken(header, "NIP-98")4253 if err != nil {4354 return nostr.Event{}, err
@@ -58,7 +69,7 @@ func (v *Validator) VerifyNIP98(header, rawURL, method, body string) (nostr.Even
5869 if strings.ToUpper(nostr.Tag(e, "method")) != strings.ToUpper(method) {5970 return nostr.Event{}, authError("token was signed for another method")6071 }61- if body != "" && nostr.Tag(e, "payload") != hashBytes([]byte(body)) {72+ if checkPayload && body != "" && nostr.Tag(e, "payload") != hashBytes([]byte(body)) {6273 return nostr.Event{}, authError("token payload hash does not match the body")6374 }6475 if err := v.mark(e.ID, now); err != nil {
M protocol/auth/auth_test.go +23 -0