Skip to content

Commit

Permalink
Abuse Protection for webhooks (#491)
Browse files Browse the repository at this point in the history
* First pass at supporting receiver based webhook abuse protection
* Adding client test for new status codes.
* adding options to set the GET and OPTIONS function handlers.
* adding docs for abuse protection
* don't drop encoding checking
* fix unit tests for unknown encoding
* allow nil event to be delivered if receiver wants

Signed-off-by: Scott Nichols <snichols@vmware.com>
  • Loading branch information
Scott Nichols authored May 19, 2020
1 parent 467aaaf commit 97abfeb
Show file tree
Hide file tree
Showing 12 changed files with 435 additions and 10 deletions.
13 changes: 8 additions & 5 deletions v2/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,12 @@ var (
WithShutdownTimeout = http.WithShutdownTimeout
//WithEncoding = http.WithEncoding
//WithStructuredEncoding = http.WithStructuredEncoding // TODO: expose new way
WithPort = http.WithPort
WithPath = http.WithPath
WithMiddleware = http.WithMiddleware
WithListener = http.WithListener
WithRoundTripper = http.WithRoundTripper
WithPort = http.WithPort
WithPath = http.WithPath
WithMiddleware = http.WithMiddleware
WithListener = http.WithListener
WithRoundTripper = http.WithRoundTripper
WithGetHandlerFunc = http.WithGetHandlerFunc
WithOptionsHandlerFunc = http.WithOptionsHandlerFunc
WithDefaultOptionsHandlerFunc = http.WithDefaultOptionsHandlerFunc
)
39 changes: 39 additions & 0 deletions v2/cmd/samples/http/receiver-protected/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"context"
"fmt"
"log"

cloudevents "github.com/cloudevents/sdk-go/v2"
)

func main() {
ctx := context.Background()
p, err := cloudevents.NewHTTP(
cloudevents.WithDefaultOptionsHandlerFunc([]string{"POST", "OPTIONS"}, 100, []string{"http://localhost:8181"}, true),
)
if err != nil {
log.Fatalf("failed to create protocol: %s", err.Error())
}

c, err := cloudevents.NewClient(p)
if err != nil {
log.Fatalf("failed to create client, %v", err)
}

log.Printf("will listen on :8080\n")
log.Fatalf("failed to start receiver: %s", c.StartReceiver(ctx, receive))
}

func receive(ctx context.Context, event cloudevents.Event) {
fmt.Printf("%s", event)
}

//
// Testing with:
//
// PORT=8181 go run ./cmd/tools/http/raw/
//
// curl http://localhost:8080 -v -X OPTIONS -H "Origin: http://example.com" -H "WebHook-Request-Origin: http://example.com" -H "WebHook-Request-Callback: http://localhost:8181/do-this?now=true"
//
34 changes: 34 additions & 0 deletions v2/cmd/tools/http/raw/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"fmt"
"log"
"net/http"
"net/http/httputil"

"github.com/kelseyhightower/envconfig"
)

type RawHTTP struct {
Port int `envconfig:"PORT" default:"8080"`
}

func (raw *RawHTTP) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
if reqBytes, err := httputil.DumpRequest(r, true); err == nil {
log.Printf("Raw HTTP Request:\n%+v", string(reqBytes))
_, _ = w.Write(reqBytes)
} else {
log.Printf("Failed to call DumpRequest: %s", err)
}
fmt.Println("------------------------------")
}

func main() {
var env RawHTTP
if err := envconfig.Process("", &env); err != nil {
log.Fatalf("Failed to process env var: %s", err)
}
log.Printf("Starting listening on :%d\n", env.Port)
log.Println(http.ListenAndServe(fmt.Sprintf(":%d", env.Port), &env))
}
6 changes: 5 additions & 1 deletion v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ require (
github.com/cucumber/messages-go/v10 v10.0.3
github.com/google/go-cmp v0.4.0
github.com/google/uuid v1.1.1
github.com/gorilla/mux v1.6.2
github.com/gorilla/mux v1.7.3
github.com/hashicorp/golang-lru v0.5.3 // indirect
github.com/kelseyhightower/envconfig v1.4.0
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac
github.com/nats-io/nats-streaming-server v0.17.0 // indirect
github.com/nats-io/nats.go v1.9.1
github.com/nats-io/stan.go v0.6.0
github.com/onsi/ginkgo v1.10.2 // indirect
github.com/onsi/gomega v1.7.0 // indirect
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.0.0 // indirect
github.com/stretchr/testify v1.5.1
github.com/valyala/bytebufferpool v1.0.0
go.opencensus.io v0.22.0
Expand Down
22 changes: 22 additions & 0 deletions v2/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQh
github.com/aslakhellesoy/gox v1.0.100/go.mod h1:AJl542QsKKG96COVsv0N74HHzVQgDIQPceVUh1aeU2M=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
Expand Down Expand Up @@ -77,6 +79,7 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
Expand Down Expand Up @@ -121,6 +124,8 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
Expand All @@ -137,11 +142,14 @@ github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/raft v1.1.1 h1:HJr7UE1x/JrJSc9Oy6aDBHtNHUUBHjcQjTgvUVihoZs=
github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
Expand All @@ -167,6 +175,10 @@ github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
Expand All @@ -191,8 +203,12 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.2 h1:uqH7bpe+ERSiDa34FDOF7RikN6RzXgduUF8yarlZp94=
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
Expand All @@ -210,21 +226,27 @@ github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOi
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
Expand Down
121 changes: 121 additions & 0 deletions v2/protocol/http/abuse_protection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package http

import (
"context"
cecontext "github.com/cloudevents/sdk-go/v2/context"
"go.uber.org/zap"
"net/http"
"strconv"
"strings"
)

type WebhookConfig struct {
AllowedMethods []string // defaults to POST
AllowedRate *int
AutoACKCallback bool
AllowedOrigins []string
}

const (
DefaultAllowedRate = 1000
)

// TODO: implement rate limiting.
// Throttling is indicated by requests being rejected using HTTP status code 429 Too Many Requests.
// TODO: use this if Webhook Request Origin has been turned on.
// Inbound requests should be rejected if Allowed Origins is required by SDK.

func (p *Protocol) OptionsHandler(rw http.ResponseWriter, req *http.Request) {
if req.Method != http.MethodOptions || p.WebhookConfig == nil {
rw.WriteHeader(http.StatusMethodNotAllowed)
return
}

headers := make(http.Header)

// The spec does not say we need to validate the origin, just the request origin.
// After the handshake, we will validate the origin.
if origin, ok := p.ValidateRequestOrigin(req); !ok {
rw.WriteHeader(http.StatusBadRequest)
return
} else {
headers.Set("WebHook-Allowed-Origin", origin)
}

allowedRateRequired := false
if _, ok := req.Header[http.CanonicalHeaderKey("WebHook-Request-Rate")]; ok {
// must send WebHook-Allowed-Rate
allowedRateRequired = true
}

if p.WebhookConfig.AllowedRate != nil {
headers.Set("WebHook-Allowed-Rate", strconv.Itoa(*p.WebhookConfig.AllowedRate))
} else if allowedRateRequired {
headers.Set("WebHook-Allowed-Rate", strconv.Itoa(DefaultAllowedRate))
}

if len(p.WebhookConfig.AllowedMethods) > 0 {
headers.Set("Allow", strings.Join(p.WebhookConfig.AllowedMethods, ", "))
} else {
headers.Set("Allow", http.MethodPost)
}

cb := req.Header.Get("WebHook-Request-Callback")
if cb != "" {
if p.WebhookConfig.AutoACKCallback {
go func() {
reqAck, err := http.NewRequest(http.MethodPost, cb, nil)
if err != nil {
cecontext.LoggerFrom(req.Context()).Errorw("OPTIONS handler failed to create http request attempting to ack callback.", zap.Error(err), zap.String("callback", cb))
return
}

// Write out the headers.
for k := range headers {
reqAck.Header.Set(k, headers.Get(k))
}

_, err = http.DefaultClient.Do(reqAck)
if err != nil {
cecontext.LoggerFrom(req.Context()).Errorw("OPTIONS handler failed to ack callback.", zap.Error(err), zap.String("callback", cb))
return
}
}()
return
} else {
cecontext.LoggerFrom(req.Context()).Infof("ACTION REQUIRED: Please validate web hook request callback: %q", cb)
// TODO: what to do pending https://github.com/cloudevents/spec/issues/617
return
}
}

// Write out the headers.
for k := range headers {
rw.Header().Set(k, headers.Get(k))
}
}

func (p *Protocol) ValidateRequestOrigin(req *http.Request) (string, bool) {
return p.validateOrigin(req.Header.Get("WebHook-Request-Origin"))
}

func (p *Protocol) ValidateOrigin(req *http.Request) (string, bool) {
return p.validateOrigin(req.Header.Get("Origin"))
}

func (p *Protocol) validateOrigin(ro string) (string, bool) {
cecontext.LoggerFrom(context.TODO()).Infow("Validating origin.", zap.String("origin", ro))

for _, ao := range p.WebhookConfig.AllowedOrigins {
if ao == "*" {
return ao, true
}
// TODO: it is not clear what the rules for allowed hosts are.
// Need to find docs for this. For now, test for prefix.
if strings.HasPrefix(ro, ao) {
return ao, true
}
}

return ro, false
}
43 changes: 43 additions & 0 deletions v2/protocol/http/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,46 @@ func WithClient(client nethttp.Client) Option {
return nil
}
}

// WithGetHandlerFunc sets the http GET handler func
func WithGetHandlerFunc(fn nethttp.HandlerFunc) Option {
return func(p *Protocol) error {
if p == nil {
return fmt.Errorf("http GET handler func can not set nil protocol")
}
p.GetHandlerFn = fn
return nil
}
}

// WithOptionsHandlerFunc sets the http OPTIONS handler func
func WithOptionsHandlerFunc(fn nethttp.HandlerFunc) Option {
return func(p *Protocol) error {
if p == nil {
return fmt.Errorf("http OPTIONS handler func can not set nil protocol")
}
p.OptionsHandlerFn = fn
return nil
}
}

// WithDefaultOptionsHandlerFunc sets the options handler to be the built in handler and configures the options.
// methods: the supported methods reported to OPTIONS caller.
// rate: the rate limit reported to OPTIONS caller.
// origins: the prefix of the accepted origins, or "*".
// callback: preform the callback to ACK the OPTIONS request.
func WithDefaultOptionsHandlerFunc(methods []string, rate int, origins []string, callback bool) Option {
return func(p *Protocol) error {
if p == nil {
return fmt.Errorf("http OPTIONS handler func can not set nil protocol")
}
p.OptionsHandlerFn = p.DeleteHandlerFn
p.WebhookConfig = &WebhookConfig{
AllowedMethods: methods,
AllowedRate: &rate,
AllowedOrigins: origins,
AutoACKCallback: callback,
}
return nil
}
}
Loading

0 comments on commit 97abfeb

Please sign in to comment.