mirror of
https://github.com/adnanh/webhook.git
synced 2025-05-14 09:34:43 +00:00
added parse-parameters-as-json property to hooks, fixed some bugs in old code
This commit is contained in:
parent
bddb523b67
commit
688483d6d1
3 changed files with 108 additions and 15 deletions
114
hook/hook.go
114
hook/hook.go
|
@ -34,10 +34,12 @@ func CheckPayloadSignature(payload []byte, secret string, signature string) (str
|
||||||
return expectedMAC, hmac.Equal([]byte(signature), []byte(expectedMAC))
|
return expectedMAC, hmac.Equal([]byte(signature), []byte(expectedMAC))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractParameter extracts value from interface{} based on the passed string
|
// ReplaceParameter replaces parameter value with the passed value in the passed map
|
||||||
func ExtractParameter(s string, params interface{}) (string, bool) {
|
// (please note you should pass pointer to the map, because we're modifying it)
|
||||||
|
// based on the passed string
|
||||||
|
func ReplaceParameter(s string, params interface{}, value interface{}) bool {
|
||||||
if params == nil {
|
if params == nil {
|
||||||
return "", false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if paramsValue := reflect.ValueOf(params); paramsValue.Kind() == reflect.Slice {
|
if paramsValue := reflect.ValueOf(params); paramsValue.Kind() == reflect.Slice {
|
||||||
|
@ -46,29 +48,80 @@ func ExtractParameter(s string, params interface{}) (string, bool) {
|
||||||
if p := strings.SplitN(s, ".", 2); len(p) > 1 {
|
if p := strings.SplitN(s, ".", 2); len(p) > 1 {
|
||||||
index, err := strconv.ParseUint(p[0], 10, 64)
|
index, err := strconv.ParseUint(p[0], 10, 64)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil || paramsValueSliceLength <= int(index) {
|
||||||
return "", false
|
return false
|
||||||
} else if paramsValueSliceLength <= int(index) {
|
|
||||||
return "", false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExtractParameter(p[1], params.([]interface{})[index])
|
return ReplaceParameter(p[1], params.([]interface{})[index], value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if p := strings.SplitN(s, ".", 2); len(p) > 1 {
|
if p := strings.SplitN(s, ".", 2); len(p) > 1 {
|
||||||
if pValue, ok := params.(map[string]interface{})[p[0]]; ok {
|
if pValue, ok := params.(map[string]interface{})[p[0]]; ok {
|
||||||
return ExtractParameter(p[1], pValue)
|
return ReplaceParameter(p[1], pValue, value)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if pValue, ok := params.(map[string]interface{})[p[0]]; ok {
|
if _, ok := (*params.(*map[string]interface{}))[p[0]]; ok {
|
||||||
return fmt.Sprintf("%v", pValue), true
|
(*params.(*map[string]interface{}))[p[0]] = value
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetParameter extracts interface{} value based on the passed string
|
||||||
|
func GetParameter(s string, params interface{}) (interface{}, bool) {
|
||||||
|
if params == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if paramsValue := reflect.ValueOf(params); paramsValue.Kind() == reflect.Slice {
|
||||||
|
if paramsValueSliceLength := paramsValue.Len(); paramsValueSliceLength > 0 {
|
||||||
|
|
||||||
|
if p := strings.SplitN(s, ".", 2); len(p) > 1 {
|
||||||
|
index, err := strconv.ParseUint(p[0], 10, 64)
|
||||||
|
|
||||||
|
if err != nil || paramsValueSliceLength <= int(index) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetParameter(p[1], params.([]interface{})[index])
|
||||||
|
}
|
||||||
|
|
||||||
|
index, err := strconv.ParseUint(s, 10, 64)
|
||||||
|
|
||||||
|
if err != nil || paramsValueSliceLength <= int(index) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return params.([]interface{})[index], true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if p := strings.SplitN(s, ".", 2); len(p) > 1 {
|
||||||
|
if pValue, ok := params.(map[string]interface{})[p[0]]; ok {
|
||||||
|
return GetParameter(p[1], pValue)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if pValue, ok := params.(map[string]interface{})[p[0]]; ok {
|
||||||
|
return pValue, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractParameterAsString extracts value from interface{} as string based on the passed string
|
||||||
|
func ExtractParameterAsString(s string, params interface{}) (string, bool) {
|
||||||
|
if pValue, ok := GetParameter(s, params); ok {
|
||||||
|
return fmt.Sprintf("%v", pValue), true
|
||||||
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +147,7 @@ func (ha *Argument) Get(headers, query, payload *map[string]interface{}) (string
|
||||||
}
|
}
|
||||||
|
|
||||||
if source != nil {
|
if source != nil {
|
||||||
return ExtractParameter(ha.Name, *source)
|
return ExtractParameterAsString(ha.Name, *source)
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", false
|
return "", false
|
||||||
|
@ -107,9 +160,44 @@ type Hook struct {
|
||||||
CommandWorkingDirectory string `json:"command-working-directory"`
|
CommandWorkingDirectory string `json:"command-working-directory"`
|
||||||
ResponseMessage string `json:"response-message"`
|
ResponseMessage string `json:"response-message"`
|
||||||
PassArgumentsToCommand []Argument `json:"pass-arguments-to-command"`
|
PassArgumentsToCommand []Argument `json:"pass-arguments-to-command"`
|
||||||
|
JSONStringParameters []Argument `json:"parse-parameters-as-json"`
|
||||||
TriggerRule *Rules `json:"trigger-rule"`
|
TriggerRule *Rules `json:"trigger-rule"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseJSONParameters decodes specified arguments to JSON objects and replaces the
|
||||||
|
// string with the newly created object
|
||||||
|
func (h *Hook) ParseJSONParameters(headers, query, payload *map[string]interface{}) {
|
||||||
|
for i := range h.JSONStringParameters {
|
||||||
|
if arg, ok := h.JSONStringParameters[i].Get(headers, query, payload); ok {
|
||||||
|
var newArg map[string]interface{}
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(strings.NewReader(string(arg)))
|
||||||
|
decoder.UseNumber()
|
||||||
|
|
||||||
|
err := decoder.Decode(&newArg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error parsing argument as JSON payload %+v\n", err)
|
||||||
|
} else {
|
||||||
|
var source *map[string]interface{}
|
||||||
|
|
||||||
|
switch h.JSONStringParameters[i].Source {
|
||||||
|
case SourceHeader:
|
||||||
|
source = headers
|
||||||
|
case SourcePayload:
|
||||||
|
source = payload
|
||||||
|
case SourceQuery:
|
||||||
|
source = query
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplaceParameter(h.JSONStringParameters[i].Name, source, newArg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("couldn't retrieve argument for %+v\n", h.JSONStringParameters[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ExtractCommandArguments creates a list of arguments, based on the
|
// ExtractCommandArguments creates a list of arguments, based on the
|
||||||
// PassArgumentsToCommand property that is ready to be used with exec.Command()
|
// PassArgumentsToCommand property that is ready to be used with exec.Command()
|
||||||
func (h *Hook) ExtractCommandArguments(headers, query, payload *map[string]interface{}) []string {
|
func (h *Hook) ExtractCommandArguments(headers, query, payload *map[string]interface{}) []string {
|
||||||
|
|
|
@ -37,6 +37,7 @@ var extractParameterTests = []struct {
|
||||||
{"a", map[string]interface{}{"a": "z"}, "z", true},
|
{"a", map[string]interface{}{"a": "z"}, "z", true},
|
||||||
{"a.b", map[string]interface{}{"a": map[string]interface{}{"b": "z"}}, "z", true},
|
{"a.b", map[string]interface{}{"a": map[string]interface{}{"b": "z"}}, "z", true},
|
||||||
{"a.b.c", map[string]interface{}{"a": map[string]interface{}{"b": map[string]interface{}{"c": "z"}}}, "z", true},
|
{"a.b.c", map[string]interface{}{"a": map[string]interface{}{"b": map[string]interface{}{"c": "z"}}}, "z", true},
|
||||||
|
{"a.b.0", map[string]interface{}{"a": map[string]interface{}{"b": []interface{}{"x", "y", "z"}}}, "x", true},
|
||||||
{"a.1.b", map[string]interface{}{"a": []interface{}{map[string]interface{}{"b": "y"}, map[string]interface{}{"b": "z"}}}, "z", true},
|
{"a.1.b", map[string]interface{}{"a": []interface{}{map[string]interface{}{"b": "y"}, map[string]interface{}{"b": "z"}}}, "z", true},
|
||||||
{"a.1.b.c", map[string]interface{}{"a": []interface{}{map[string]interface{}{"b": map[string]interface{}{"c": "y"}}, map[string]interface{}{"b": map[string]interface{}{"c": "z"}}}}, "z", true},
|
{"a.1.b.c", map[string]interface{}{"a": []interface{}{map[string]interface{}{"b": map[string]interface{}{"c": "y"}}, map[string]interface{}{"b": map[string]interface{}{"c": "z"}}}}, "z", true},
|
||||||
// failures
|
// failures
|
||||||
|
@ -51,7 +52,7 @@ var extractParameterTests = []struct {
|
||||||
|
|
||||||
func TestExtractParameter(t *testing.T) {
|
func TestExtractParameter(t *testing.T) {
|
||||||
for _, tt := range extractParameterTests {
|
for _, tt := range extractParameterTests {
|
||||||
value, ok := ExtractParameter(tt.s, tt.params)
|
value, ok := ExtractParameterAsString(tt.s, tt.params)
|
||||||
if ok != tt.ok || value != tt.value {
|
if ok != tt.ok || value != tt.value {
|
||||||
t.Errorf("failed to extract parameter %q:\nexpected {value:%#v, ok:%#v},\ngot {value:%#v, ok:%#v}", tt.s, tt.value, tt.ok, value, ok)
|
t.Errorf("failed to extract parameter %q:\nexpected {value:%#v, ok:%#v},\ngot {value:%#v, ok:%#v}", tt.s, tt.value, tt.ok, value, ok)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "2.2.2"
|
version = "2.3.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -170,6 +170,10 @@ func hookHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hook.ParseJSONParameters(&headers, &query, &payload)
|
||||||
|
|
||||||
|
fmt.Printf("%+v", payload)
|
||||||
|
|
||||||
// handle hook
|
// handle hook
|
||||||
go handleHook(hook, &headers, &query, &payload, &body)
|
go handleHook(hook, &headers, &query, &payload, &body)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue