diff --git a/hook/hook.go b/hook/hook.go index 6fcda3e..0727911 100644 --- a/hook/hook.go +++ b/hook/hook.go @@ -4,11 +4,13 @@ import ( "crypto/hmac" "crypto/sha1" "crypto/sha256" + "encoding/base64" "encoding/hex" "encoding/json" "errors" "fmt" "io/ioutil" + "log" "net" "net/textproto" "reflect" @@ -263,9 +265,11 @@ func ExtractParameterAsString(s string, params interface{}) (string, bool) { // Argument type specifies the parameter key name and the source it should // be extracted from type Argument struct { - Source string `json:"source,omitempty"` - Name string `json:"name,omitempty"` - EnvName string `json:"envname,omitempty"` + Source string `json:"source,omitempty"` + Name string `json:"name,omitempty"` + EnvName string `json:"envname,omitempty"` + FileName string `json:"filename,omitempty"` + Base64Decode bool `json:"base64decode,omitempty"` } // Get Argument method returns the value for the Argument's key name @@ -380,6 +384,7 @@ type Hook struct { CaptureCommandOutput bool `json:"include-command-output-in-response,omitempty"` PassEnvironmentToCommand []Argument `json:"pass-environment-to-command,omitempty"` PassArgumentsToCommand []Argument `json:"pass-arguments-to-command,omitempty"` + PassFileToCommand []Argument `json:"pass-file-to-command,omitempty"` JSONStringParameters []Argument `json:"parse-parameters-as-json,omitempty"` TriggerRule *Rules `json:"trigger-rule,omitempty"` TriggerRuleMismatchHttpResponseCode int `json:"trigger-rule-mismatch-http-response-code,omitempty"` @@ -489,6 +494,52 @@ func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string return args, nil } +// FileParameter describes a pass-file-to-command instance to be stored as file +type FileParameter struct { + Filename string + Data []byte +} + +// ExtractCommandArgumentsForFile creates a list of arguments in key=value +// format, based on the PassFileToCommand property that is ready to be used +// with exec.Command(). +func (h *Hook) ExtractCommandArgumentsForFile(headers, query, payload *map[string]interface{}) ([]FileParameter, []error) { + var args = make([]FileParameter, 0) + var errors = make([]error, 0) + for i := range h.PassFileToCommand { + if arg, ok := h.PassFileToCommand[i].Get(headers, query, payload); ok { + + if h.PassFileToCommand[i].FileName == "" { + // if no filename is set, fall-back on the name + log.Printf("no filename specified, falling back to [%s]", EnvNamespace+h.PassFileToCommand[i].Name) + h.PassFileToCommand[i].FileName = EnvNamespace + h.PassFileToCommand[i].Name + } + + var fileContent []byte + if h.PassFileToCommand[i].Base64Decode { + dec, err := base64.StdEncoding.DecodeString(arg) + if err != nil { + log.Printf("error decoding string [%s]", err) + } + fileContent = []byte(dec) + } else { + fileContent = []byte(arg) + } + + args = append(args, FileParameter{Filename: h.PassFileToCommand[i].FileName, Data: fileContent}) + + } else { + errors = append(errors, &ArgumentError{h.PassFileToCommand[i]}) + } + } + + if len(errors) > 0 { + return args, errors + } + + return args, nil +} + // Hooks is an array of Hook objects type Hooks []Hook diff --git a/webhook.go b/webhook.go index 1034290..671794a 100644 --- a/webhook.go +++ b/webhook.go @@ -12,7 +12,7 @@ import ( "os/exec" "strings" - "github.com/adnanh/webhook/hook" + "./hook" "github.com/codegangsta/negroni" "github.com/gorilla/mux" @@ -333,6 +333,31 @@ func handleHook(h *hook.Hook, headers, query, payload *map[string]interface{}, b cmd.Env = append(os.Environ(), envs...) + var files []hook.FileParameter + files, errors = h.ExtractCommandArgumentsForFile(headers, query, payload) + + if errors != nil { + for _, err := range errors { + log.Printf("error extracting command arguments for file: %s\n", err) + } + } + + for i := range files { + var filename string + if h.CommandWorkingDirectory != "" { + filename = h.CommandWorkingDirectory + "/" + files[i].Filename + } else { + filename = files[i].Filename + } + + log.Printf("writing file %s", filename) + + err := ioutil.WriteFile(filename, files[i].Data, 0644) + if err != nil { + log.Printf("error writing file %s [%s]", filename, err) + } + } + log.Printf("executing %s (%s) with arguments %q and environment %s using %s as cwd\n", h.ExecuteCommand, cmd.Path, cmd.Args, envs, cmd.Dir) out, err := cmd.CombinedOutput()