133 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
| package github
 | |
| 
 | |
| import (
 | |
| 	"crypto/hmac"
 | |
| 	"crypto/sha1"
 | |
| 	"encoding/hex"
 | |
| 	"encoding/json"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"net/http"
 | |
| 
 | |
| 	"github.com/gorilla/mux"
 | |
| 	"github.com/influxdata/telegraf"
 | |
| )
 | |
| 
 | |
| type GithubWebhook struct {
 | |
| 	Path   string
 | |
| 	Secret string
 | |
| 	acc    telegraf.Accumulator
 | |
| }
 | |
| 
 | |
| func (gh *GithubWebhook) Register(router *mux.Router, acc telegraf.Accumulator) {
 | |
| 	router.HandleFunc(gh.Path, gh.eventHandler).Methods("POST")
 | |
| 	log.Printf("I! Started the webhooks_github on %s\n", gh.Path)
 | |
| 	gh.acc = acc
 | |
| }
 | |
| 
 | |
| func (gh *GithubWebhook) eventHandler(w http.ResponseWriter, r *http.Request) {
 | |
| 	defer r.Body.Close()
 | |
| 	eventType := r.Header.Get("X-Github-Event")
 | |
| 	data, err := ioutil.ReadAll(r.Body)
 | |
| 	if err != nil {
 | |
| 		w.WriteHeader(http.StatusBadRequest)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if gh.Secret != "" && !checkSignature(gh.Secret, data, r.Header.Get("X-Hub-Signature")) {
 | |
| 		log.Printf("E! Fail to check the github webhook signature\n")
 | |
| 		w.WriteHeader(http.StatusBadRequest)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	e, err := NewEvent(data, eventType)
 | |
| 	if err != nil {
 | |
| 		w.WriteHeader(http.StatusBadRequest)
 | |
| 		return
 | |
| 	}
 | |
| 	if e != nil {
 | |
| 		p := e.NewMetric()
 | |
| 		gh.acc.AddFields("github_webhooks", p.Fields(), p.Tags(), p.Time())
 | |
| 	}
 | |
| 
 | |
| 	w.WriteHeader(http.StatusOK)
 | |
| }
 | |
| 
 | |
| func generateEvent(data []byte, event Event) (Event, error) {
 | |
| 	err := json.Unmarshal(data, event)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return event, nil
 | |
| }
 | |
| 
 | |
| type newEventError struct {
 | |
| 	s string
 | |
| }
 | |
| 
 | |
| func (e *newEventError) Error() string {
 | |
| 	return e.s
 | |
| }
 | |
| 
 | |
| func NewEvent(data []byte, name string) (Event, error) {
 | |
| 	log.Printf("D! New %v event received", name)
 | |
| 	switch name {
 | |
| 	case "commit_comment":
 | |
| 		return generateEvent(data, &CommitCommentEvent{})
 | |
| 	case "create":
 | |
| 		return generateEvent(data, &CreateEvent{})
 | |
| 	case "delete":
 | |
| 		return generateEvent(data, &DeleteEvent{})
 | |
| 	case "deployment":
 | |
| 		return generateEvent(data, &DeploymentEvent{})
 | |
| 	case "deployment_status":
 | |
| 		return generateEvent(data, &DeploymentStatusEvent{})
 | |
| 	case "fork":
 | |
| 		return generateEvent(data, &ForkEvent{})
 | |
| 	case "gollum":
 | |
| 		return generateEvent(data, &GollumEvent{})
 | |
| 	case "issue_comment":
 | |
| 		return generateEvent(data, &IssueCommentEvent{})
 | |
| 	case "issues":
 | |
| 		return generateEvent(data, &IssuesEvent{})
 | |
| 	case "member":
 | |
| 		return generateEvent(data, &MemberEvent{})
 | |
| 	case "membership":
 | |
| 		return generateEvent(data, &MembershipEvent{})
 | |
| 	case "page_build":
 | |
| 		return generateEvent(data, &PageBuildEvent{})
 | |
| 	case "ping":
 | |
| 		return nil, nil
 | |
| 	case "public":
 | |
| 		return generateEvent(data, &PublicEvent{})
 | |
| 	case "pull_request":
 | |
| 		return generateEvent(data, &PullRequestEvent{})
 | |
| 	case "pull_request_review_comment":
 | |
| 		return generateEvent(data, &PullRequestReviewCommentEvent{})
 | |
| 	case "push":
 | |
| 		return generateEvent(data, &PushEvent{})
 | |
| 	case "release":
 | |
| 		return generateEvent(data, &ReleaseEvent{})
 | |
| 	case "repository":
 | |
| 		return generateEvent(data, &RepositoryEvent{})
 | |
| 	case "status":
 | |
| 		return generateEvent(data, &StatusEvent{})
 | |
| 	case "team_add":
 | |
| 		return generateEvent(data, &TeamAddEvent{})
 | |
| 	case "watch":
 | |
| 		return generateEvent(data, &WatchEvent{})
 | |
| 	}
 | |
| 	return nil, &newEventError{"Not a recognized event type"}
 | |
| }
 | |
| 
 | |
| func checkSignature(secret string, data []byte, signature string) bool {
 | |
| 	return hmac.Equal([]byte(signature), []byte(generateSignature(secret, data)))
 | |
| }
 | |
| 
 | |
| func generateSignature(secret string, data []byte) string {
 | |
| 	mac := hmac.New(sha1.New, []byte(secret))
 | |
| 	mac.Write(data)
 | |
| 	result := mac.Sum(nil)
 | |
| 	return "sha1=" + hex.EncodeToString(result)
 | |
| }
 |