diff --git a/components/usage/config.json b/components/usage/config.json index 3afe1c7c648de3..ff036bb180539d 100644 --- a/components/usage/config.json +++ b/components/usage/config.json @@ -8,6 +8,9 @@ "services": { "grpc": { "address": ":9001" + }, + "http": { + "address": ":9002" } } } diff --git a/components/usage/go.mod b/components/usage/go.mod index a7feff0f6c341d..67ffc3ff28901f 100644 --- a/components/usage/go.mod +++ b/components/usage/go.mod @@ -27,7 +27,9 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/felixge/httpsnoop v1.0.1 // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/gorilla/handlers v1.5.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/hashicorp/golang-lru v0.5.1 // indirect diff --git a/components/usage/go.sum b/components/usage/go.sum index f63492d75bb309..6fae7ef405d2d9 100644 --- a/components/usage/go.sum +++ b/components/usage/go.sum @@ -78,6 +78,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -157,6 +159,8 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= +github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= diff --git a/components/usage/pkg/server/server.go b/components/usage/pkg/server/server.go index 3d75723551c9b8..0cad678a80473f 100644 --- a/components/usage/pkg/server/server.go +++ b/components/usage/pkg/server/server.go @@ -21,6 +21,7 @@ import ( "github.com/gitpod-io/gitpod/usage/pkg/controller" "github.com/gitpod-io/gitpod/usage/pkg/db" "github.com/gitpod-io/gitpod/usage/pkg/stripe" + "github.com/gorilla/handlers" "gorm.io/gorm" ) @@ -111,6 +112,9 @@ func Start(cfg Config) error { return fmt.Errorf("failed to register gRPC services: %w", err) } + h := stripe.NewWebhookHandler() + registerHttpHandlers(srv, h) + err = controller.RegisterMetrics(srv.MetricsRegistry()) if err != nil { return fmt.Errorf("failed to register controller metrics: %w", err) @@ -133,3 +137,7 @@ func registerGRPCServices(srv *baseserver.Server, conn *gorm.DB, stripeClient *s } return nil } + +func registerHttpHandlers(srv *baseserver.Server, h *stripe.WebhookHandler) { + srv.HTTPMux().Handle("/stripe/invoices/webhook", handlers.ContentTypeHandler(h, "application/json")) +} diff --git a/components/usage/pkg/stripe/webhook.go b/components/usage/pkg/stripe/webhook.go new file mode 100644 index 00000000000000..065213da65a305 --- /dev/null +++ b/components/usage/pkg/stripe/webhook.go @@ -0,0 +1,39 @@ +// Copyright (c) 2022 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package stripe + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/gitpod-io/gitpod/common-go/log" + "github.com/stripe/stripe-go/v72" +) + +type WebhookHandler struct{} + +func NewWebhookHandler() *WebhookHandler { + return &WebhookHandler{} +} + +func (h *WebhookHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + const maxBodyBytes = int64(65536) + + req.Body = http.MaxBytesReader(w, req.Body, maxBodyBytes) + + event := stripe.Event{} + err := json.NewDecoder(req.Body).Decode(&event) + if err != nil { + log.WithError(err).Error("Stripe webhook error while parsing event payload") + w.WriteHeader(http.StatusBadRequest) + return + } + + // TODO: verify webhook signature. + // Conditional on there being a secret configured. + + fmt.Fprintf(w, "event type: %s", event.Type) +}