Rename context-provider-command to pre-hook-command and refactor the code to be more readable.

This commit is contained in:
Adnan Hajdarevic 2019-12-05 22:14:08 +01:00
parent 3ec7da2b15
commit 54cfc6bcbd
2 changed files with 52 additions and 55 deletions

View File

@ -14,7 +14,9 @@ import (
"log" "log"
"math" "math"
"net" "net"
"net/http"
"net/textproto" "net/textproto"
"net/url"
"os" "os"
"reflect" "reflect"
"regexp" "regexp"
@ -423,11 +425,23 @@ func (h *HooksFiles) Set(value string) error {
return nil return nil
} }
// PreHookContext is a structure consisted of request context data that will be passed to the pre-hook command
type PreHookContext struct {
HookID string `json:"hookID"`
Method string `json:"method"`
Base64EncodedBody string `json:"base64EncodedBody"`
RemoteAddress string `json:"remoteAddress"`
URI string `json:"URI"`
Host string `json:"host"`
Headers http.Header `json:"headers"`
Query url.Values `json:"query"`
}
// Hook type is a structure containing details for a single hook // Hook type is a structure containing details for a single hook
type Hook struct { type Hook struct {
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
ExecuteCommand string `json:"execute-command,omitempty"` ExecuteCommand string `json:"execute-command,omitempty"`
ContextProviderCommand string `json:"context-provider-command,omitempty"` PreHookCommand string `json:"pre-hook-command,omitempty"`
CommandWorkingDirectory string `json:"command-working-directory,omitempty"` CommandWorkingDirectory string `json:"command-working-directory,omitempty"`
ResponseMessage string `json:"response-message,omitempty"` ResponseMessage string `json:"response-message,omitempty"`
ResponseHeaders ResponseHeaders `json:"response-headers,omitempty"` ResponseHeaders ResponseHeaders `json:"response-headers,omitempty"`

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/base64"
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
@ -16,7 +17,6 @@ import (
"time" "time"
"github.com/adnanh/webhook/hook" "github.com/adnanh/webhook/hook"
"github.com/codegangsta/negroni" "github.com/codegangsta/negroni"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/satori/go.uuid" "github.com/satori/go.uuid"
@ -222,7 +222,7 @@ func hookHandler(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body) body, err := ioutil.ReadAll(r.Body)
if err != nil { if err != nil {
log.Printf("[%s] error reading the request body. %+v\n", rid, err) log.Printf("[%s] error reading the request body: %+v\n", rid, err)
} }
// parse headers // parse headers
@ -234,37 +234,28 @@ func hookHandler(w http.ResponseWriter, r *http.Request) {
// parse context // parse context
var context map[string]interface{} var context map[string]interface{}
if matchedHook.ContextProviderCommand != "" { if matchedHook.PreHookCommand != "" {
// check the command exists // check the command exists
cmdPath, err := exec.LookPath(matchedHook.ContextProviderCommand) preHookCommandPath, err := exec.LookPath(matchedHook.PreHookCommand)
if err != nil { if err != nil {
// give a last chance, maybe it's a relative path // give a last chance, maybe it's a relative path
relativeToCwd := filepath.Join(matchedHook.CommandWorkingDirectory, matchedHook.ContextProviderCommand) preHookCommandPathRelativeToCurrentWorkingDirectory := filepath.Join(matchedHook.CommandWorkingDirectory, matchedHook.PreHookCommand)
// check the command exists // check the command exists
cmdPath, err = exec.LookPath(relativeToCwd) preHookCommandPath, err = exec.LookPath(preHookCommandPathRelativeToCurrentWorkingDirectory)
} }
if err != nil { if err != nil {
log.Printf("[%s] unable to locate context provider command: '%s', %+v\n", rid, matchedHook.ContextProviderCommand, err) log.Printf("[%s] unable to locate pre-hook command: '%s', %+v\n", rid, matchedHook.PreHookCommand, err)
// check if parameters specified in context-provider-command by mistake // check if parameters specified in pre-hook command by mistake
if strings.IndexByte(matchedHook.ContextProviderCommand, ' ') != -1 { if strings.IndexByte(matchedHook.PreHookCommand, ' ') != -1 {
s := strings.Fields(matchedHook.ContextProviderCommand)[0] s := strings.Fields(matchedHook.PreHookCommand)[0]
log.Printf("[%s] please use a wrapper script to provide arguments to context provider command for '%s'\n", rid, s) log.Printf("[%s] please use a wrapper script to provide arguments to pre-hook command for '%s'\n", rid, s)
} }
} else { } else {
contextProviderCommandStdin := struct { preHookCommandStdin := hook.PreHookContext{
HookID string `json:"hookID"`
Method string `json:"method"`
Body string `json:"body"`
RemoteAddress string `json:"remoteAddress"`
URI string `json:"URI"`
Host string `json:"host"`
Headers http.Header `json:"headers"`
Query url.Values `json:"query"`
}{
HookID: matchedHook.ID, HookID: matchedHook.ID,
Method: r.Method, Method: r.Method,
Body: string(body), Base64EncodedBody: base64.StdEncoding.EncodeToString(body),
RemoteAddress: r.RemoteAddr, RemoteAddress: r.RemoteAddr,
URI: r.RequestURI, URI: r.RequestURI,
Host: r.Host, Host: r.Host,
@ -272,39 +263,31 @@ func hookHandler(w http.ResponseWriter, r *http.Request) {
Query: r.URL.Query(), Query: r.URL.Query(),
} }
stdinJSON, err := json.Marshal(contextProviderCommandStdin) if preHookCommandStdinJSONString, err := json.Marshal(preHookCommandStdin); err != nil {
log.Printf("[%s] unable to encode pre-hook context as JSON string for the pre-hook command: %+v\n", rid, err)
if err != nil {
log.Printf("[%s] unable to encode context as JSON string for the context provider command: %+v\n", rid, err)
} else { } else {
cmd := exec.Command(cmdPath) preHookCommand := exec.Command(preHookCommandPath)
cmd.Dir = matchedHook.CommandWorkingDirectory preHookCommand.Dir = matchedHook.CommandWorkingDirectory
cmd.Env = append(os.Environ()) preHookCommand.Env = append(os.Environ())
stdin, err := cmd.StdinPipe()
if err != nil { if preHookCommandStdinPipe, err := preHookCommand.StdinPipe(); err != nil {
log.Printf("[%s] unable to acquire stdin pipe for the context provider command: %+v\n", rid, err) log.Printf("[%s] unable to acquire stdin pipe for the pre-hook command: %+v\n", rid, err)
} else { } else {
_, err := io.WriteString(stdin, string(stdinJSON)) _, err := io.WriteString(preHookCommandStdinPipe, string(preHookCommandStdinJSONString))
stdin.Close() preHookCommandStdinPipe.Close()
if err != nil { if err != nil {
log.Printf("[%s] unable to write to context provider command stdin: %+v\n", rid, err) log.Printf("[%s] unable to write to pre-hook command stdin: %+v\n", rid, err)
} else { } else {
log.Printf("[%s] executing context provider command %s (%s) using %s as cwd\n", rid, matchedHook.ContextProviderCommand, cmd.Path, cmd.Dir) log.Printf("[%s] executing pre-hook command %s (%s) using %s as cwd\n", rid, matchedHook.PreHookCommand, preHookCommand.Path, preHookCommand.Dir)
out, err := cmd.CombinedOutput()
if err != nil { if preHookCommandOutput, err := preHookCommand.CombinedOutput(); err != nil {
log.Printf("[%s] unable to execute context provider command: %+v\n", rid, err) log.Printf("[%s] unable to execute pre-hook command: %+v\n", rid, err)
} else { } else {
log.Printf("[%s] got context provider command output: %+v\n", rid, string(out)) JSONDecoder := json.NewDecoder(strings.NewReader(string(preHookCommandOutput)))
JSONDecoder.UseNumber()
decoder := json.NewDecoder(strings.NewReader(string(out))) if err := JSONDecoder.Decode(&context); err != nil {
decoder.UseNumber() log.Printf("[%s] unable to parse pre-hook command output: %+v\npre-hook command output was: %+v\n", rid, err, string(preHookCommandOutput))
err := decoder.Decode(&context)
if err != nil {
log.Printf("[%s] unable to parse context provider command output: %+v\n", rid, err)
} }
} }
} }