From 467ece7b7544b5f29c73cdd2f3f8aa851b2851e9 Mon Sep 17 00:00:00 2001 From: Allisson Azevedo Date: Fri, 5 Mar 2021 18:09:28 -0300 Subject: [PATCH] feat: Include X-Hub-Signature if webhook has a secret key (#16) --- .../000001_create_initial_schema.up.sql | 1 + entity.go | 1 + http/handler/delivery_attempt_test.go | 4 ++-- repository/delivery.go | 24 +++++++++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/db/migrations/000001_create_initial_schema.up.sql b/db/migrations/000001_create_initial_schema.up.sql index 0096830..f9bae39 100644 --- a/db/migrations/000001_create_initial_schema.up.sql +++ b/db/migrations/000001_create_initial_schema.up.sql @@ -45,6 +45,7 @@ CREATE TABLE IF NOT EXISTS delivery_attempts( id UUID PRIMARY KEY, webhook_id UUID NOT NULL, delivery_id UUID NOT NULL, + raw_request TEXT NOT NULL, raw_response TEXT NOT NULL, response_status_code SMALLINT NOT NULL, execution_duration SMALLINT NOT NULL, diff --git a/entity.go b/entity.go index bd8a64e..f840d1e 100644 --- a/entity.go +++ b/entity.go @@ -76,6 +76,7 @@ type DeliveryAttempt struct { ID ID `json:"id" db:"id"` WebhookID ID `json:"webhook_id" db:"webhook_id"` DeliveryID ID `json:"delivery_id" db:"delivery_id"` + RawRequest string `json:"raw_request" db:"raw_request"` RawResponse string `json:"raw_response" db:"raw_response"` ResponseStatusCode int `json:"response_status_code" db:"response_status_code"` ExecutionDuration int `json:"execution_duration" db:"execution_duration"` diff --git a/http/handler/delivery_attempt_test.go b/http/handler/delivery_attempt_test.go index 465293f..676bfa5 100644 --- a/http/handler/delivery_attempt_test.go +++ b/http/handler/delivery_attempt_test.go @@ -40,7 +40,7 @@ func TestDeliveryAttempt(t *testing.T) { Handler(router). Get("/v1/delivery-attempts"). Expect(t). - Body(`{"delivery_attempts":[{"id":"00000000-0000-0000-0000-000000000000","webhook_id":"00000000-0000-0000-0000-000000000000","delivery_id":"00000000-0000-0000-0000-000000000000","raw_response":"","response_status_code":0,"execution_duration":0,"success":false,"error":"","created_at":"0001-01-01T00:00:00Z"}],"limit":50,"offset":0}`). + Body(`{"delivery_attempts":[{"id":"00000000-0000-0000-0000-000000000000","webhook_id":"00000000-0000-0000-0000-000000000000","delivery_id":"00000000-0000-0000-0000-000000000000","raw_request":"", "raw_response":"","response_status_code":0,"execution_duration":0,"success":false,"error":"","created_at":"0001-01-01T00:00:00Z"}],"limit":50,"offset":0}`). Status(nethttp.StatusOK). End() @@ -60,7 +60,7 @@ func TestDeliveryAttempt(t *testing.T) { Handler(router). Get("/v1/delivery-attempts/97087247-d89d-410e-b915-740b4c6d9d99"). Expect(t). - Body(`{"id":"97087247-d89d-410e-b915-740b4c6d9d99","webhook_id":"cd9b7318-36c6-4534-be84-fe78042aeaf2","delivery_id":"b919ca2c-6b0f-4a22-a61f-8c882ee69323","raw_response":"","response_status_code":0,"execution_duration":0,"success":false,"error":"","created_at":"0001-01-01T00:00:00Z"}`). + Body(`{"id":"97087247-d89d-410e-b915-740b4c6d9d99","webhook_id":"cd9b7318-36c6-4534-be84-fe78042aeaf2","delivery_id":"b919ca2c-6b0f-4a22-a61f-8c882ee69323","raw_request":"", "raw_response":"","response_status_code":0,"execution_duration":0,"success":false,"error":"","created_at":"0001-01-01T00:00:00Z"}`). Status(nethttp.StatusOK). End() diff --git a/repository/delivery.go b/repository/delivery.go index b284d73..1168d70 100644 --- a/repository/delivery.go +++ b/repository/delivery.go @@ -3,7 +3,10 @@ package repository import ( "bytes" "context" + "crypto/hmac" + "crypto/sha256" "database/sql" + "encoding/hex" "net/http" "net/http/httputil" "time" @@ -15,6 +18,7 @@ import ( ) type dispatchResponse struct { + RawRequest string RawResponse string ResponseStatusCode int ExecutionDuration int @@ -34,6 +38,24 @@ func dispatchToURL(webhook *postmand.Webhook, delivery *postmand.Delivery) dispa return dr } request.Header.Set("Content-Type", webhook.ContentType) + if webhook.SecretToken != "" { + hash := hmac.New(sha256.New, []byte(webhook.SecretToken)) + _, err := hash.Write([]byte(delivery.Payload)) + if err != nil { + dr.Success = false + dr.Error = err.Error() + return dr + } + request.Header.Set("X-Hub-Signature", hex.EncodeToString(hash.Sum(nil))) + } + + // Create request dump + requestDump, err := httputil.DumpRequest(request, true) + if err != nil { + dr.Success = false + dr.Error = err.Error() + return dr + } // Make request start := time.Now() @@ -62,6 +84,7 @@ func dispatchToURL(webhook *postmand.Webhook, delivery *postmand.Delivery) dispa } // Update dispatch response + dr.RawRequest = string(requestDump) dr.RawResponse = string(responseDump) dr.ResponseStatusCode = response.StatusCode dr.ExecutionDuration = int(latency.Milliseconds()) @@ -202,6 +225,7 @@ func (d Delivery) Dispatch(ctx context.Context) (*postmand.DeliveryAttempt, erro ID: uuid.New(), WebhookID: webhook.ID, DeliveryID: delivery.ID, + RawRequest: dr.RawRequest, RawResponse: dr.RawResponse, ResponseStatusCode: dr.ResponseStatusCode, ExecutionDuration: dr.ExecutionDuration,