added support for x-hub-signature

This commit is contained in:
Adnan Hajdarevic 2015-01-20 18:57:16 +01:00
parent 450852e1be
commit 3c4c025233
2 changed files with 22 additions and 17 deletions

View file

@ -45,6 +45,10 @@ func (h *Hook) UnmarshalJSON(j []byte) error {
h.Cwd = v.(string) h.Cwd = v.(string)
} }
if v, ok := m["secret"]; ok {
h.Secret = v.(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{})
@ -126,7 +130,7 @@ func New(hookFile string) (*Hooks, error) {
func (h *Hooks) Match(id string, params interface{}) *Hook { func (h *Hooks) Match(id string, params interface{}) *Hook {
for i := range h.list { for i := range h.list {
if h.list[i].ID == id { if h.list[i].ID == id {
if h.list[i].Rule != nil && h.list[i].Rule.Evaluate(params) { if h.list[i].Rule == nil || (h.list[i].Rule != nil && h.list[i].Rule.Evaluate(params)) {
return &h.list[i] return &h.list[i]
} }
} }

View file

@ -1,12 +1,14 @@
package main package main
import ( import (
"encoding/hex"
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os/exec" "os/exec"
"strings"
"time" "time"
"github.com/adnanh/webhook/hooks" "github.com/adnanh/webhook/hooks"
@ -14,13 +16,13 @@ import (
"github.com/go-martini/martini" "github.com/go-martini/martini"
"crypto/hmac" "crypto/hmac"
"crypto/sha256" "crypto/sha1"
l4g "code.google.com/p/log4go" l4g "code.google.com/p/log4go"
) )
const ( const (
version string = "1.0.1" version string = "1.0.2"
) )
var ( var (
@ -69,24 +71,25 @@ func rootHandler() string {
} }
func hookHandler(req *http.Request, params martini.Params) string { func hookHandler(req *http.Request, params martini.Params) string {
p := make(map[string]interface{}) 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{})
if req.Header.Get("Content-Type") == "application/json" { if req.Header.Get("Content-Type") == "application/json" {
decoder := json.NewDecoder(req.Body) decoder := json.NewDecoder(strings.NewReader(string(body)))
decoder.UseNumber() decoder.UseNumber()
err := decoder.Decode(&p) 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)
} }
} }
body, err := ioutil.ReadAll(req.Body)
if err != nil {
l4g.Warn("Error occurred while trying to read the request body: %s", err)
}
go func(id string, body []byte, signature string, params interface{}) { go func(id string, body []byte, signature string, params interface{}) {
if hook := webhooks.Match(id, params); hook != nil { if hook := webhooks.Match(id, params); hook != nil {
if hook.Secret != "" { if hook.Secret != "" {
@ -95,13 +98,11 @@ func hookHandler(req *http.Request, params martini.Params) string {
return return
} }
mac := hmac.New(sha256.New, []byte(hook.Secret)) mac := hmac.New(sha1.New, []byte(hook.Secret))
mac.Write(body) mac.Write(body)
expectedMAC := mac.Sum(nil) expectedMAC := hex.EncodeToString(mac.Sum(nil))
l4g.Info("Expected %s, got %s.", expectedMAC, signature) if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
if !hmac.Equal([]byte(signature), expectedMAC) {
l4g.Error("Hook %s got matched, but the request contained invalid signature. Expected %s, got %s.", hook.ID, expectedMAC, signature) l4g.Error("Hook %s got matched, but the request contained invalid signature. Expected %s, got %s.", hook.ID, expectedMAC, signature)
return return
} }
@ -111,7 +112,7 @@ func hookHandler(req *http.Request, params martini.Params) string {
out, _ := cmd.Output() out, _ := cmd.Output()
l4g.Info("Hook %s triggered successfully! Command output:\n%s", hook.ID, out) l4g.Info("Hook %s triggered successfully! Command output:\n%s", hook.ID, out)
} }
}(params["id"], body, req.Header.Get("X-Hub-Signature"), p) }(params["id"], body, req.Header.Get("X-Hub-Signature")[5:], payloadJSON)
return "Got it, thanks. :-)" return "Got it, thanks. :-)"
} }