2021-07-28 15:20:06 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/hmac"
|
|
|
|
"crypto/sha256"
|
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
|
2022-01-21 21:08:05 +00:00
|
|
|
"git.alv.cx/alvierahman90/gohookr/config"
|
2021-07-28 15:20:06 +00:00
|
|
|
"github.com/gorilla/mux"
|
|
|
|
)
|
|
|
|
|
2021-07-29 06:54:22 +00:00
|
|
|
var config_filename = "/etc/gohookr.json"
|
2021-07-29 07:29:37 +00:00
|
|
|
var checkSignature = true
|
2021-08-04 11:04:01 +00:00
|
|
|
var c config.Config
|
2021-07-28 15:20:06 +00:00
|
|
|
|
|
|
|
func main() {
|
|
|
|
r := mux.NewRouter()
|
2021-07-29 06:54:22 +00:00
|
|
|
r.HandleFunc("/webhooks/{service}", webhookHandler)
|
2021-07-28 15:20:06 +00:00
|
|
|
|
2021-08-04 10:51:40 +00:00
|
|
|
if p, ok := os.LookupEnv("CONFIG"); ok {
|
|
|
|
config_filename = p
|
|
|
|
}
|
|
|
|
|
|
|
|
if p, ok := os.LookupEnv("NO_SIGNATURE_CHECK"); ok {
|
|
|
|
checkSignature = p != "true"
|
|
|
|
}
|
|
|
|
|
2023-10-28 20:47:35 +00:00
|
|
|
raw_config, err := os.ReadFile(config_filename)
|
2021-07-29 08:41:24 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err.Error())
|
|
|
|
}
|
2021-08-04 11:04:01 +00:00
|
|
|
|
2021-09-01 17:57:21 +00:00
|
|
|
if err := json.Unmarshal(raw_config, &c); err != nil {
|
|
|
|
panic(err.Error())
|
|
|
|
}
|
|
|
|
|
2021-08-04 11:04:01 +00:00
|
|
|
if err := c.Validate(); err != nil {
|
2021-07-29 08:41:24 +00:00
|
|
|
panic(err.Error())
|
2021-07-28 15:20:06 +00:00
|
|
|
}
|
|
|
|
|
2021-08-04 11:04:01 +00:00
|
|
|
log.Fatal(http.ListenAndServe(c.ListenAddress, r))
|
2021-07-28 15:20:06 +00:00
|
|
|
}
|
|
|
|
|
2021-07-29 06:54:22 +00:00
|
|
|
func webhookHandler(w http.ResponseWriter, r *http.Request) {
|
2021-08-06 13:53:22 +00:00
|
|
|
// Check what service is specified in URL (/webhooks/{service}) and if it exists
|
|
|
|
serviceName := string(mux.Vars(r)["service"])
|
|
|
|
service, ok := c.Services[serviceName]
|
|
|
|
if !ok {
|
|
|
|
writeResponse(w, 404, "Service Not Found")
|
|
|
|
fmt.Printf("Service not found: %v\n", serviceName)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fmt.Printf("Got webhook for: %v\n", serviceName)
|
|
|
|
|
|
|
|
// Read payload or return 500 if that doesn't work out
|
2021-07-28 15:20:06 +00:00
|
|
|
payload := ""
|
2023-10-28 20:47:35 +00:00
|
|
|
if p, err := io.ReadAll(r.Body); err != nil {
|
2021-07-28 15:20:06 +00:00
|
|
|
writeResponse(w, 500, "Internal Server Error: Could not read payload")
|
2021-08-06 13:53:22 +00:00
|
|
|
fmt.Println("Error: Could not read payload")
|
2021-07-28 15:20:06 +00:00
|
|
|
return
|
|
|
|
} else {
|
|
|
|
payload = string(p)
|
|
|
|
}
|
|
|
|
|
2021-07-29 06:23:43 +00:00
|
|
|
// Verify that signature provided matches signature calculated using secretsss
|
2021-07-28 15:20:06 +00:00
|
|
|
signature := r.Header.Get(service.SignatureHeader)
|
2021-08-04 21:12:59 +00:00
|
|
|
calculatedSignature := fmt.Sprintf(
|
|
|
|
"%v%v",
|
|
|
|
service.SignaturePrefix,
|
|
|
|
getSha256HMACSignature([]byte(service.Secret), payload),
|
|
|
|
)
|
|
|
|
fmt.Printf("signature = %v\n", signature)
|
|
|
|
fmt.Printf("calcuatedSignature = %v\n", calculatedSignature)
|
2021-08-14 00:06:29 +00:00
|
|
|
if checkSignature && !service.DisableSignatureVerification && signature != calculatedSignature {
|
2021-07-28 15:20:06 +00:00
|
|
|
writeResponse(w, 400, "Bad Request: Signatures do not match")
|
2021-08-06 13:53:22 +00:00
|
|
|
fmt.Println("Signatures do not match!")
|
2021-07-28 15:20:06 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-08-06 13:53:22 +00:00
|
|
|
// Run tests and script as goroutine to prevent timing out
|
2023-10-28 20:48:54 +00:00
|
|
|
go func() {
|
2021-08-04 21:17:43 +00:00
|
|
|
// Run tests, immediately stop if one fails
|
|
|
|
for _, test := range service.Tests {
|
2023-10-28 20:48:54 +00:00
|
|
|
if _, err := test.Execute(payload, r.Header); err != nil {
|
2021-08-06 13:53:22 +00:00
|
|
|
fmt.Printf("Test failed(%v) for service %v\n", test, serviceName)
|
2021-08-04 21:17:43 +00:00
|
|
|
return
|
|
|
|
}
|
2021-07-29 06:30:50 +00:00
|
|
|
}
|
2023-10-28 20:48:54 +00:00
|
|
|
stdout, err := service.Script.Execute(payload, r.Header)
|
2021-08-04 21:18:53 +00:00
|
|
|
fmt.Println(string(stdout))
|
2021-08-04 21:17:43 +00:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err.Error())
|
|
|
|
}
|
|
|
|
}()
|
2021-07-29 06:30:50 +00:00
|
|
|
|
2021-08-04 21:17:43 +00:00
|
|
|
writeResponse(w, 200, "OK")
|
|
|
|
return
|
2021-07-28 15:20:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func writeResponse(w http.ResponseWriter, responseCode int, responseString string) {
|
|
|
|
w.WriteHeader(responseCode)
|
|
|
|
w.Write([]byte(fmt.Sprintf("%v %v", responseCode, responseString)))
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSha256HMACSignature(secret []byte, data string) string {
|
|
|
|
h := hmac.New(sha256.New, secret)
|
|
|
|
io.WriteString(h, data)
|
|
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
|
|
}
|