package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"math"
"net/http"
"strconv"
"time"
)
func verifyWebhookSignature(payload, signature, timestamp, secret string) bool {
// Check timestamp tolerance (5 minutes)
ts, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
return false
}
currentTime := time.Now().Unix()
if math.Abs(float64(currentTime-ts)) > 300 {
return false
}
// Compute expected signature
data := fmt.Sprintf("%s.%s", timestamp, payload)
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(data))
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
// Constant-time comparison
return hmac.Equal([]byte(expected), []byte(signature))
}
func webhookHandler(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
payload := string(body)
signature := r.Header.Get("X-Kyren-Signature")
timestamp := r.Header.Get("X-Kyren-Timestamp")
if !verifyWebhookSignature(payload, signature, timestamp, webhookSecret) {
http.Error(w, "Invalid signature", http.StatusBadRequest)
return
}
// Process the event...
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}