package main import ( "bytes" "fmt" "io/ioutil" "log" "net/http" "regexp" "strconv" "p83.nl/go/ekster/pkg/websub" ) type incomingHandler struct { Backend HubBackend } var ( urlRegex = regexp.MustCompile(`^/incoming/(\d+)$`) ) func (h *incomingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() err := r.ParseForm() if err != nil { http.Error(w, "could not parse form data", http.StatusBadRequest) return } log.Printf("%s %s\n", r.Method, r.URL) log.Println(r.URL.Query()) log.Println(r.PostForm) // find feed matches := urlRegex.FindStringSubmatch(r.URL.Path) feed, err := strconv.ParseInt(matches[1], 10, 64) if err != nil { fmt.Fprint(w, err) } if r.Method == http.MethodGet { values := r.URL.Query() // check if leaseStr := values.Get("hub.lease_seconds"); leaseStr != "" { // update lease_seconds leaseSeconds, err := strconv.ParseInt(leaseStr, 10, 64) if err != nil { http.Error(w, fmt.Sprintf("error in hub.lease_seconds format %q: %s", leaseSeconds, err), 400) return } err = h.Backend.FeedSetLeaseSeconds(feed, leaseSeconds) if err != nil { http.Error(w, fmt.Sprintf("error in while setting hub.lease_seconds: %s", err), 400) return } } verify := values.Get("hub.challenge") _, _ = fmt.Fprint(w, verify) return } if r.Method != http.MethodPost { http.Error(w, "Method not allowed", 405) return } // find secret secret := h.Backend.GetSecret(feed) if secret == "" { log.Printf("missing secret for feed %d\n", feed) http.Error(w, "Unknown", 400) return } feedContent, err := ioutil.ReadAll(r.Body) // match signature sig := r.Header.Get("X-Hub-Signature") if sig != "" { if err := websub.ValidateHubSignature(sig, feedContent, []byte(secret)); err != nil { log.Printf("could not validate signature: %+v", err) http.Error(w, fmt.Sprintf("could not validate signature: %s", err), 400) return } } ct := r.Header.Get("Content-Type") err = h.Backend.UpdateFeed(feed, ct, bytes.NewBuffer(feedContent)) if err != nil { http.Error(w, fmt.Sprintf("could not update feed: %s (%s)", ct, err), 400) return } return }