forked from go-playground/webhooks
/
bitbucket.go
199 lines (180 loc) · 6.87 KB
/
bitbucket.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package bitbucket
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"gopkg.in/go-playground/webhooks.v4"
)
// Webhook instance contains all methods needed to process events
type Webhook struct {
provider webhooks.Provider
uuid string
eventFuncs map[Event]webhooks.ProcessPayloadFunc
}
// Config defines the configuration to create a new Bitbucket Webhook instance
type Config struct {
UUID string
}
// Event defines a Bitbucket hook event type
type Event string
// Bitbucket hook types
const (
RepoPushEvent Event = "repo:push"
RepoForkEvent Event = "repo:fork"
RepoUpdatedEvent Event = "repo:updated"
RepoCommitCommentCreatedEvent Event = "repo:commit_comment_created"
RepoCommitStatusCreatedEvent Event = "repo:commit_status_created"
RepoCommitStatusUpdatedEvent Event = "repo:commit_status_updated"
IssueCreatedEvent Event = "issue:created"
IssueUpdatedEvent Event = "issue:updated"
IssueCommentCreatedEvent Event = "issue:comment_created"
PullRequestCreatedEvent Event = "pullrequest:created"
PullRequestUpdatedEvent Event = "pullrequest:updated"
PullRequestApprovedEvent Event = "pullrequest:approved"
PullRequestUnapprovedEvent Event = "pullrequest:unapproved"
PullRequestMergedEvent Event = "pullrequest:fulfilled"
PullRequestDeclinedEvent Event = "pullrequest:rejected"
PullRequestCommentCreatedEvent Event = "pullrequest:comment_created"
PullRequestCommentUpdatedEvent Event = "pullrequest:comment_updated"
PullRequestCommentDeletedEvent Event = "pullrequest:comment_deleted"
)
// New creates and returns a WebHook instance denoted by the Provider type
func New(config *Config) *Webhook {
return &Webhook{
provider: webhooks.Bitbucket,
uuid: config.UUID,
eventFuncs: map[Event]webhooks.ProcessPayloadFunc{},
}
}
// Provider returns the current hooks provider ID
func (hook Webhook) Provider() webhooks.Provider {
return hook.provider
}
// RegisterEvents registers the function to call when the specified event(s) are encountered
func (hook Webhook) RegisterEvents(fn webhooks.ProcessPayloadFunc, events ...Event) {
for _, event := range events {
hook.eventFuncs[event] = fn
}
}
// ParsePayload parses and verifies the payload and fires off the mapped function, if it exists.
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
webhooks.DefaultLog.Info("Parsing Payload...")
uuid := r.Header.Get("X-Hook-UUID")
if uuid == "" {
webhooks.DefaultLog.Error("Missing X-Hook-UUID Header")
http.Error(w, "400 Bad Request - Missing X-Hook-UUID Header", http.StatusBadRequest)
return
}
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Hook-UUID:%s", uuid))
if len(hook.uuid) > 0 {
if uuid != hook.uuid {
webhooks.DefaultLog.Error(fmt.Sprintf("X-Hook-UUID %s does not match configured uuid of %s", uuid, hook.uuid))
http.Error(w, "403 Forbidden - X-Hook-UUID does not match", http.StatusForbidden)
return
}
} else {
webhooks.DefaultLog.Debug("hook uuid not defined - recommend setting for improved security")
}
event := r.Header.Get("X-Event-Key")
if event == "" {
webhooks.DefaultLog.Error("Missing X-Event-Key Header")
http.Error(w, "400 Bad Request - Missing X-Event-Key Header", http.StatusBadRequest)
return
}
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Event-Key:%s", event))
bitbucketEvent := Event(event)
fn, ok := hook.eventFuncs[bitbucketEvent]
// if no event registered
if !ok {
webhooks.DefaultLog.Info(fmt.Sprintf("Webhook Event %s not registered, it is recommended to setup only events in bitbucket that will be registered in the webhook to avoid unnecessary traffic and reduce potential attack vectors.", event))
return
}
payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 {
webhooks.DefaultLog.Error("Issue reading Payload")
http.Error(w, "Issue reading Payload", http.StatusInternalServerError)
return
}
webhooks.DefaultLog.Debug(fmt.Sprintf("Payload:%s", string(payload)))
hd := webhooks.Header(r.Header)
switch bitbucketEvent {
case RepoPushEvent:
var pl RepoPushPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case RepoForkEvent:
var pl RepoForkPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case RepoUpdatedEvent:
var pl RepoUpdatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case RepoCommitCommentCreatedEvent:
var pl RepoCommitCommentCreatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case RepoCommitStatusCreatedEvent:
var pl RepoCommitStatusCreatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case RepoCommitStatusUpdatedEvent:
var pl RepoCommitStatusUpdatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case IssueCreatedEvent:
var pl IssueCreatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case IssueUpdatedEvent:
var pl IssueUpdatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case IssueCommentCreatedEvent:
var pl IssueCommentCreatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestCreatedEvent:
var pl PullRequestCreatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestUpdatedEvent:
var pl PullRequestUpdatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestApprovedEvent:
var pl PullRequestApprovedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestUnapprovedEvent:
var pl PullRequestUnapprovedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestMergedEvent:
var pl PullRequestMergedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestDeclinedEvent:
var pl PullRequestDeclinedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestCommentCreatedEvent:
var pl PullRequestCommentCreatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestCommentUpdatedEvent:
var pl PullRequestCommentUpdatedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
case PullRequestCommentDeletedEvent:
var pl PullRequestCommentDeletedPayload
json.Unmarshal([]byte(payload), &pl)
hook.runProcessPayloadFunc(fn, pl, hd)
}
}
func (hook Webhook) runProcessPayloadFunc(fn webhooks.ProcessPayloadFunc, results interface{}, header webhooks.Header) {
go func(fn webhooks.ProcessPayloadFunc, results interface{}, header webhooks.Header) {
fn(results, header)
}(fn, results, header)
}