package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io" "net/http" "os" "os/exec" "gitea.urkob.com/urko/gitea-webhook-listener/kit/config" ) func main() { cfg, err := config.LoadConfig(".configs/app.yml") if err != nil { panic(err) } http.HandleFunc("/payload", handlePayload(cfg.Secret, cfg.BinaryPath, cfg.ScriptPath)) http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), nil) } func handlePayload(secret, binaryPath, scriptPath string) func(w http.ResponseWriter, r *http.Request) { return (func(w http.ResponseWriter, r *http.Request) { // Read the request body body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "Failed to read request body", http.StatusBadRequest) return } defer r.Body.Close() // Verify the signature if !verifySignature(body, r.Header.Get("X-Hub-Signature-256"), []byte(secret)) { http.Error(w, "Signatures didn't match", http.StatusUnauthorized) return } // Parse the JSON payload var payload interface{} err = json.Unmarshal(body, &payload) if err != nil { http.Error(w, "Failed to parse JSON payload", http.StatusBadRequest) return } // TODO: Do something with the payload fmt.Fprintf(w, "I got some JSON: %v", payload) if err := execute(binaryPath, scriptPath); err != nil { panic(err) } }) } func execute(binaryPath, scriptPath string) error { cmd := exec.Command(binaryPath, scriptPath) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { return fmt.Errorf("cmd.Run %w", err) } return nil } func verifySignature(payload []byte, signature string, secret []byte) bool { // Compute the expected signature mac := hmac.New(sha256.New, secret) mac.Write(payload) expectedSignature := hex.EncodeToString(mac.Sum(nil)) // Compare the expected signature with the actual signature return hmac.Equal([]byte(signature), []byte("sha256="+expectedSignature)) }