Compare commits

..

4 Commits

Author SHA1 Message Date
c5fef8e42d AppendHeaders 2023-10-28 21:48:54 +01:00
e74c3a684e stop using deprecated ioutil 2023-10-28 21:47:35 +01:00
0f8b4d2e1e update gitignore 2023-10-28 21:46:58 +01:00
f3cdde5fe6 update makefile 2023-10-28 21:46:15 +01:00
11 changed files with 37 additions and 84 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
gohookr
test_output

View File

@@ -3,6 +3,10 @@ all: install
clean:
rm -rf gohookr
build:
go mod tidy
go build -o gohookr
install: build
cp gohookr /usr/local/bin/
cp gohookr.service /usr/lib/systemd/system/
@@ -10,10 +14,6 @@ install: build
systemctl daemon-reload
systemctl enable --now gohookr
build:
go mod tidy
go build -o gohookr
uninstall:
systemctl disable --now gohookr
rm -rf /usr/local/bin/gohookr /usr/lib/systemd/system/gohookr.service

View File

@@ -4,7 +4,8 @@
"test": {
"Script": {
"Program": "./example.sh",
"AppendPayload": true
"AppendPayload": true,
"AppendHeaders": true
},
"DisableSignatureVerification": true,
"Tests": [

View File

@@ -1,13 +0,0 @@
listenaddress: 127.0.0.1:8654
services:
test:
script:
program: "echo"
arguments:
- test
tests:
- program: ./example.sh
appendpayload: true
disablesignatureverification: false
signatureheader: test
secret: thisisasecret

View File

@@ -2,22 +2,33 @@ package config
import (
"fmt"
"net/http"
"os/exec"
"strings"
)
type Command struct {
Program string
Arguments []string
AppendPayload bool
AppendHeaders bool
}
func (c Command) Execute(payload string) ([]byte, error) {
func (c Command) Execute(payload string, header http.Header) ([]byte, error) {
arguments := make([]string, 0)
copy(c.Arguments, arguments)
if c.AppendPayload {
arguments = append(arguments, payload)
}
if c.AppendHeaders {
var header_builder strings.Builder;
header.Write(&header_builder);
arguments = append(arguments, header_builder.String())
}
return exec.Command(c.Program, arguments...).Output()
}

View File

@@ -1,12 +1,5 @@
package config
import (
"encoding/json"
"io/ioutil"
"gopkg.in/yaml.v3"
)
// The struct that represents the config.json file
type Config struct {
ListenAddress string
@@ -40,23 +33,3 @@ func (c Config) Validate() error {
return nil
}
func (c *Config) Load(config_filename string) error {
raw_config, err := ioutil.ReadFile(config_filename)
if err != nil {
return err
}
err = json.Unmarshal(raw_config, &c)
if err == nil {
return c.Validate()
}
err = yaml.Unmarshal(raw_config, &c)
if err == nil {
return c.Validate()
}
return err
}

2
example.sh Normal file → Executable file
View File

@@ -1,3 +1,3 @@
#!/usr/bin/bash
date >> test_output
echo "$1" >> test_output
echo "$1" "$2" >> test_output

5
go.mod
View File

@@ -2,7 +2,4 @@ module git.alv.cx/alvierahman90/gohookr
go 1.16
require (
github.com/gorilla/mux v1.8.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
require github.com/gorilla/mux v1.8.0

4
go.sum
View File

@@ -1,6 +1,2 @@
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

28
main.go
View File

@@ -4,9 +4,9 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
@@ -17,10 +17,9 @@ import (
var config_filename = "/etc/gohookr.json"
var checkSignature = true
func main() {
var c config.Config
func main() {
r := mux.NewRouter()
r.HandleFunc("/webhooks/{service}", webhookHandler)
@@ -32,28 +31,23 @@ func main() {
checkSignature = p != "true"
}
var err = c.Load(config_filename)
raw_config, err := os.ReadFile(config_filename)
if err != nil {
panic(err.Error())
}
fmt.Printf("CONFIG OK: %s\n", config_filename)
fmt.Printf("LISTENING AT: %s\n", c.ListenAddress)
for _, v := range os.Args {
if v == "checkConfig" {
return
if err := json.Unmarshal(raw_config, &c); err != nil {
panic(err.Error())
}
if err := c.Validate(); err != nil {
panic(err.Error())
}
log.Fatal(http.ListenAndServe(c.ListenAddress, r))
}
func webhookHandler(w http.ResponseWriter, r *http.Request) {
var c config.Config
var err = c.Load(config_filename)
if err != nil {
writeResponse(w, 500, "Unable to read config file")
}
// Check what service is specified in URL (/webhooks/{service}) and if it exists
serviceName := string(mux.Vars(r)["service"])
service, ok := c.Services[serviceName]
@@ -66,7 +60,7 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) {
// Read payload or return 500 if that doesn't work out
payload := ""
if p, err := ioutil.ReadAll(r.Body); err != nil {
if p, err := io.ReadAll(r.Body); err != nil {
writeResponse(w, 500, "Internal Server Error: Could not read payload")
fmt.Println("Error: Could not read payload")
return
@@ -93,12 +87,12 @@ func webhookHandler(w http.ResponseWriter, r *http.Request) {
go func() {
// Run tests, immediately stop if one fails
for _, test := range service.Tests {
if _, err := test.Execute(payload); err != nil {
if _, err := test.Execute(payload, r.Header); err != nil {
fmt.Printf("Test failed(%v) for service %v\n", test, serviceName)
return
}
}
stdout, err := service.Script.Execute(payload)
stdout, err := service.Script.Execute(payload, r.Header)
fmt.Println(string(stdout))
if err != nil {
fmt.Println(err.Error())

View File

@@ -15,17 +15,10 @@ make
Default config path is `/etc/gohookr.json`.
It can be overriden by setting environment variable `CONFIG`.
The config file will be re-read every request so service configs can be changed without restarting
the service (unless you want to change the listening port).
Check below for an example configuration, which should tell you most of the things you need to know
to configure gohookr.
You can test your config file by running
```
gohookr checkConfig
```
Currently gohookr must be restarted after config changes.
### Signature Verification
@@ -39,8 +32,7 @@ For GitHub it would be `sha256=`.
#### Disable Signature Verification
You can disable signature verification by setting `DisableSignatureVerification` for a service to
`true`.
You can disable signature verification by setting `DisableSignatureVerification` for a service to `true`.
You can disable signature verification for all services by setting environment variable
`NO_SIGNATURE_VERIFICATION` to `true`.
@@ -49,7 +41,8 @@ You can disable signature verification for all services by setting environment v
gohookr doesn't care what the command is as long as the `Program` is executable.
You can specify extra arguments with the `Arguments` field.
You can ask it to put the payload as the last argument by setting `AppendPayload` to true.
You can ask it to put the payload as the last (or second to last if `AppendHeaders` is set) argument by setting `AppendPayload` to true.
You can ask it to put the request headers as the last argument by setting `AppendHeaders` to true.
### Writing Tests