-
Notifications
You must be signed in to change notification settings - Fork 42
/
travis_hook.go
98 lines (89 loc) · 2.86 KB
/
travis_hook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package git
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
)
// TravisHook is webhook for travis-ci.org
type TravisHook struct{}
// DoesHandle satisfies hookHandler.
func (t TravisHook) DoesHandle(h http.Header) bool {
return h.Get("Travis-Repo-Slug") != ""
}
// Handle satisfies hookHandler.
func (t TravisHook) Handle(w http.ResponseWriter, r *http.Request, repo *Repo) (int, error) {
if r.Method != "POST" {
return http.StatusMethodNotAllowed, errors.New("the request had an invalid method")
}
if err := t.handleSignature(r, repo.Hook.Secret); err != nil {
return http.StatusBadRequest, err
}
if err := r.ParseForm(); err != nil {
return http.StatusBadRequest, err
}
payload := r.FormValue("payload")
if payload == "" {
return http.StatusBadRequest, fmt.Errorf("Payload required")
}
data := &travisPayload{}
if err := json.Unmarshal([]byte(payload), data); err != nil {
return http.StatusBadRequest, err
}
// ignored webhooks
err := hookIgnoredError{hookType: hookName(t)}
if data.Type != "push" || data.StatusMessage != "Passed" {
err.err = fmt.Errorf("Ignoring payload with wrong status or type")
return 200, err
}
if repo.Branch != "" && data.Branch != repo.Branch {
err.err = fmt.Errorf("Ignoring push for branch %s", data.Branch)
return 200, err
}
// attempt pull
if err := repo.Pull(); err != nil {
return http.StatusInternalServerError, err
}
if err := repo.checkoutCommit(data.Commit); err != nil {
return http.StatusInternalServerError, err
}
return 200, nil
}
type travisPayload struct {
ID int `json:"id"`
Number string `json:"number"`
Status int `json:"status"`
Result int `json:"result"`
StatusMessage string `json:"status_message"`
ResultMessage string `json:"result_message"`
StartedAt time.Time `json:"started_at"`
FinishedAt time.Time `json:"finished_at"`
Duration int `json:"duration"`
BuildURL string `json:"build_url"`
Branch string `json:"branch"`
Type string `json:"type"`
State string `json:"state"`
Commit string `json:"commit"`
}
// Check for an authorization signature in the request. Reject if not present. If validation required, check the sha
func (t TravisHook) handleSignature(r *http.Request, secret string) error {
signature := r.Header.Get("Authorization")
if signature == "" {
return errors.New("request sent no authorization signature")
}
if secret == "" {
Logger().Print("Unable to verify request signature. Secret not set in caddyfile!\n")
return nil
}
content := r.Header.Get("Travis-Repo-Slug") + secret
hash := sha256.Sum256([]byte(content))
expectedMac := hex.EncodeToString(hash[:])
if signature != expectedMac {
fmt.Println(signature, expectedMac)
return errors.New("Invalid authorization header")
}
return nil
}