11package main
22
33import (
4+ "bytes"
5+ "crypto/hmac"
6+ "crypto/sha256"
7+ "encoding/base64"
8+ "encoding/json"
49 "fmt"
510 "io"
611 "log"
@@ -10,6 +15,28 @@ import (
1015 "github.com/gin-gonic/gin"
1116)
1217
18+ func verifyPayload (jsonBody string , headers http.Header ) bool {
19+ secret := os .Getenv ("HOOKDECK_WEBHOOK_SECRET" )
20+ if secret == "" {
21+ log .Println ("No HOOKDECK_WEBHOOK_SECRET found in environment variables. Skipping verification." )
22+ return true
23+ }
24+
25+ hmacHeader := headers .Get ("x-hookdeck-signature" )
26+ hmacHeader2 := headers .Get ("x-hookdeck-signature-2" )
27+
28+ hash := hmac .New (sha256 .New , []byte (secret ))
29+ hash .Write ([]byte (jsonBody ))
30+ expectedHash := base64 .StdEncoding .EncodeToString (hash .Sum (nil ))
31+
32+ if expectedHash == hmacHeader ||
33+ (hmacHeader2 != "" && expectedHash == hmacHeader2 ) {
34+ return true
35+ }
36+
37+ return false
38+ }
39+
1340func main () {
1441 r := gin .Default ()
1542 r .POST ("/*path" , func (c * gin.Context ) {
@@ -23,7 +50,24 @@ func main() {
2350 return
2451 }
2552
26- log .Printf ("webhook_received: %v" , jsonBody )
53+ verified := verifyPayload (jsonBody , c .Request .Header )
54+
55+ if ! verified {
56+ c .JSON (http .StatusUnauthorized , gin.H {
57+ "message" : "invalid payload" ,
58+ })
59+ return
60+ }
61+
62+ var prettyJSON bytes.Buffer
63+ if err := json .Indent (& prettyJSON , []byte (jsonBody ), "" , " " ); err != nil {
64+ log .Printf ("Failed to format JSON: %v" , err )
65+ c .JSON (http .StatusInternalServerError , gin.H {
66+ "message" : "failed to format JSON" ,
67+ })
68+ return
69+ }
70+ log .Printf ("webhook_received: %v" , prettyJSON .String ())
2771
2872 c .JSON (http .StatusOK , gin.H {
2973 "status" : "ACCEPTED" ,
@@ -32,7 +76,7 @@ func main() {
3276
3377 port := os .Getenv ("PORT" )
3478 if port == "" {
35- port = "3030 "
79+ port = "3032 "
3680 }
3781
3882 fmt .Printf ("🪝 Server running at http://localhost:%s" , port )
0 commit comments