separated github from post handler

This commit is contained in:
Adnan Hajdarevic 2015-02-24 16:52:55 +01:00
parent 478d189de8
commit a5d79fddd9
2 changed files with 78 additions and 29 deletions

View file

@ -14,6 +14,7 @@ type Hook struct {
Command string `json:"command"` Command string `json:"command"`
Cwd string `json:"cwd"` Cwd string `json:"cwd"`
Secret string `json:"secret"` Secret string `json:"secret"`
Args []string `json:"args"`
Rule rules.Rule `json:"trigger-rule"` Rule rules.Rule `json:"trigger-rule"`
} }
@ -49,6 +50,14 @@ func (h *Hook) UnmarshalJSON(j []byte) error {
h.Secret = v.(string) h.Secret = v.(string)
} }
if v, ok := m["args"]; ok {
h.Args = make([]string, 0)
for i := range v.([]interface{}) {
h.Args = append(h.Args, v.([]interface{})[i].(string))
}
}
if v, ok := m["trigger-rule"]; ok { if v, ok := m["trigger-rule"]; ok {
rule := v.(map[string]interface{}) rule := v.(map[string]interface{})
@ -150,5 +159,9 @@ func (h *Hooks) SetDefaults() {
if h.list[i].Cwd == "" { if h.list[i].Cwd == "" {
h.list[i].Cwd = "." h.list[i].Cwd = "."
} }
if h.list[i].Args == nil {
h.list[i].Args = make([]string, 1)
}
} }
} }

View file

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url"
"os/exec" "os/exec"
"strings" "strings"
"time" "time"
@ -70,49 +71,84 @@ func rootHandler() string {
return fmt.Sprintf("webhook %s running for %s serving %d hook(s)\n", version, time.Since(appStart).String(), webhooks.Count()) return fmt.Sprintf("webhook %s running for %s serving %d hook(s)\n", version, time.Since(appStart).String(), webhooks.Count())
} }
func hookHandler(req *http.Request, params martini.Params) string { func githubHandler(id string, body []byte, signature string, params interface{}) {
defer req.Body.Close() if hook := webhooks.Match(id, params); hook != nil {
body, err := ioutil.ReadAll(req.Body) if hook.Secret != "" {
if err != nil { if signature == "" {
l4g.Warn("Error occurred while trying to read the request body: %s", err) l4g.Error("Hook %s got matched and contains the secret, but the request didn't contain any signature.", hook.ID)
return
}
mac := hmac.New(sha1.New, []byte(hook.Secret))
mac.Write(body)
expectedMAC := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
l4g.Error("Hook %s got matched and contains the secret, but the request contained invalid signature. Expected %s, got %s.", hook.ID, expectedMAC, signature)
return
}
}
cmd := exec.Command(hook.Command)
cmd.Dir = hook.Cwd
out, err := cmd.Output()
l4g.Info("Hook %s triggered successfully! Command output:\n%s\nError: %+v", hook.ID, out, err)
} }
}
payloadJSON := make(map[string]interface{}) func defaultPostHookHandler(id string, formValues url.Values) {
if hook := webhooks.Match(id, make(map[string]interface{})); hook != nil {
args := make([]string, 0)
args = append(args, hook.Command)
for i := range hook.Args {
if arg := formValues[hook.Args[i]]; len(arg) > 0 {
args = append(args, arg[0])
}
}
cmd := exec.Command(hook.Command)
cmd.Args = args
cmd.Dir = hook.Cwd
out, err := cmd.Output()
l4g.Info("Hook %s triggered successfully! Command output:\n%s\nError: %+v", hook.ID, out, err)
}
}
func hookHandler(req *http.Request, params martini.Params) string {
if req.Header.Get("Content-Type") == "application/json" { if req.Header.Get("Content-Type") == "application/json" {
defer req.Body.Close()
body, err := ioutil.ReadAll(req.Body)
if err != nil {
l4g.Warn("Error occurred while trying to read the request body: %s", err)
}
payloadJSON := make(map[string]interface{})
decoder := json.NewDecoder(strings.NewReader(string(body))) decoder := json.NewDecoder(strings.NewReader(string(body)))
decoder.UseNumber() decoder.UseNumber()
err := decoder.Decode(&payloadJSON) err = decoder.Decode(&payloadJSON)
if err != nil { if err != nil {
l4g.Warn("Error occurred while trying to parse the payload as JSON: %s", err) l4g.Warn("Error occurred while trying to parse the payload as JSON: %s", err)
} }
}
go func(id string, body []byte, signature string, params interface{}) { githubSignature := ""
if hook := webhooks.Match(id, params); hook != nil {
if hook.Secret != "" {
if signature == "" {
l4g.Error("Hook %s got matched and contains the secret, but the request didn't contain any signature.", hook.ID)
return
}
mac := hmac.New(sha1.New, []byte(hook.Secret)) if len(req.Header.Get("X-Hub-Signature")) > 5 {
mac.Write(body) githubSignature = req.Header.Get("X-Hub-Signature")[5:]
expectedMAC := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
l4g.Error("Hook %s got matched and contains the secret, but the request contained invalid signature. Expected %s, got %s.", hook.ID, expectedMAC, signature)
return
}
}
cmd := exec.Command(hook.Command, "", "", hook.Cwd)
out, _ := cmd.Output()
l4g.Info("Hook %s triggered successfully! Command output:\n%s", hook.ID, out)
} }
}(params["id"], body, req.Header.Get("X-Hub-Signature")[5:], payloadJSON)
if strings.Contains(req.Header.Get("User-Agent"), "Github") {
go githubHandler(params["id"], body, githubSignature, payloadJSON)
}
} else {
req.ParseForm()
go defaultPostHookHandler(params["id"], req.Form)
}
return "Got it, thanks. :-)" return "Got it, thanks. :-)"
} }