taler-mailbox

Service for asynchronous wallet-to-wallet payment messages
Log | Files | Refs | Submodules | README | LICENSE

commit 23fcb61d382136146c6aa10723e41789caeb6565
parent 78a90d5d629d3aa8ca85d6c5aa4ee6dd5f76642e
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Tue, 22 Apr 2025 14:20:13 +0200

fix etag handling and binary body parsing

Diffstat:
Mpkg/rest/mailbox.go | 34++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/pkg/rest/mailbox.go b/pkg/rest/mailbox.go @@ -28,6 +28,7 @@ import ( "log" "net/http" "os" + "strconv" "strings" "time" @@ -187,20 +188,20 @@ func (m *Mailbox) getMessagesResponse(w http.ResponseWriter, r *http.Request) { func (m *Mailbox) sendMessageResponse(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) var entry InboxEntry - var body = make ([]byte, m.MessageBodyBytes) + var body = make([]byte, m.MessageBodyBytes) if r.Body == nil { http.Error(w, "No request body", 400) return } - if r.ContentLength != m.MessageBodyBytes { + if r.ContentLength != m.MessageBodyBytes { w.WriteHeader(http.StatusBadRequest) return - } - _, err := r.Body.Read(body) - if err != nil { + } + _, err := r.Body.Read(body) + if err != nil { w.WriteHeader(http.StatusBadRequest) return - } + } tx := m.Db.Where("h_mailbox = ?", vars["h_mailbox"]) // FIXME max messages from config // FIXME unclear if this is how the API is defined @@ -208,7 +209,7 @@ func (m *Mailbox) sendMessageResponse(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusTooManyRequests) return } - err = m.Db.First(&entry, "h_mailbox = ? AND body = ?", vars["h_mailbox"], body).Error + err = m.Db.First(&entry, "h_mailbox = ? AND body = ?", vars["h_mailbox"], body).Error // FIXME actual cost cost, _ := talerutil.ParseAmount("KUDOS:1") if err != nil { @@ -258,15 +259,20 @@ func (m *Mailbox) deleteMessagesResponse(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusInternalServerError) return } - etag_expected := r.Header.Get("If-Match") - if etag_expected == "" { + etag_hdr := r.Header.Get("If-Match") + if etag_hdr == "" { http.Error(w, "If-Match header missing", 400) return } - if strings.Contains(etag_expected, ",") { + if strings.Contains(etag_hdr, ",") { http.Error(w, "If-Match contains multiple values", 400) return } + etag_expected, err := strconv.Atoi(etag_hdr) + if err != nil { + http.Error(w, "If-Match contains malformed etag number", 400) + return + } pkey, err := gnunetutil.DecodeStringToBinary(vars["mailbox"], 32) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -303,7 +309,11 @@ func (m *Mailbox) deleteMessagesResponse(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusInternalServerError) return } - if len(entries) < msg.Count { + if entries[0].ID != uint(etag_expected) { + w.WriteHeader(http.StatusPreconditionFailed) + return + } + if len(entries) != msg.Count { w.WriteHeader(http.StatusNotFound) return } @@ -360,7 +370,7 @@ func (m *Mailbox) Initialize(cfgfile string) { if m.Cfg.Section("mailbox").Key("production").MustBool(false) { fmt.Println("Production mode enabled") } - m.MessageBodyBytes = m.Cfg.Section("mailbox").Key("message_body_bytes").MustInt64(256) + m.MessageBodyBytes = m.Cfg.Section("mailbox").Key("message_body_bytes").MustInt64(256) psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", m.Cfg.Section("mailbox-pq").Key("host").MustString("localhost"), m.Cfg.Section("mailbox-pq").Key("port").MustInt64(5432),