package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
)
func verifyWebhookSignature(payload []byte, signature, secret string) bool {
// Remove 'sha256=' prefix from signature
receivedSignature := strings.TrimPrefix(signature, "sha256=")
// Calculate expected signature
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expectedSignature := hex.EncodeToString(mac.Sum(nil))
// Compare signatures using timing-safe comparison
return hmac.Equal([]byte(receivedSignature), []byte(expectedSignature))
}
func webhookHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
signature := r.Header.Get("X-Drippi-Signature")
secret := os.Getenv("DRIPPI_WEBHOOK_SECRET")
payload, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading request body", http.StatusBadRequest)
return
}
if !verifyWebhookSignature(payload, signature, secret) {
log.Println("Invalid webhook signature")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Process the webhook
var event map[string]interface{}
if err := json.Unmarshal(payload, &event); err != nil {
http.Error(w, "Error parsing JSON", http.StatusBadRequest)
return
}
log.Printf("Received webhook: %s", event["event"])
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "OK")
}
func main() {
http.HandleFunc("/webhook", webhookHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}