Skip to content

Commit 16896cd

Browse files
author
Dean Karn
authored
Merge pull request #29 from naiba/v3
Add gogs support
2 parents 5580947 + 3e1bb69 commit 16896cd

File tree

4 files changed

+172
-1
lines changed

4 files changed

+172
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# Folders
77
_obj
88
_test
9+
.idea
910

1011
# Architecture specific extensions/prefixes
1112
*.[568vq]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Installation
2424
Use go get.
2525

2626
```shell
27-
go get -u gopkg.in/go-playground/webhooks.v3
27+
go get -u gopkg.in/go-playground/webhooks.v3
2828
```
2929

3030
Then import the package into your own code.

gogs/gogs.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package gogs
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"net/http"
8+
9+
"crypto/hmac"
10+
"crypto/sha256"
11+
"encoding/hex"
12+
client "github.com/gogits/go-gogs-client"
13+
"gopkg.in/go-playground/webhooks.v3"
14+
)
15+
16+
// Webhook instance contains all methods needed to process events
17+
type Webhook struct {
18+
provider webhooks.Provider
19+
secret string
20+
eventFuncs map[Event]webhooks.ProcessPayloadFunc
21+
}
22+
23+
// Config defines the configuration to create a new Gogs Webhook instance
24+
type Config struct {
25+
Secret string
26+
}
27+
28+
// Event defines a Gogs hook event type
29+
type Event string
30+
31+
// Gogs hook types
32+
const (
33+
CreateEvent Event = "create"
34+
DeleteEvent Event = "delete"
35+
ForkEvent Event = "fork"
36+
PushEvent Event = "push"
37+
IssuesEvent Event = "issues"
38+
IssueCommentEvent Event = "issue_comment"
39+
PullRequestEvent Event = "pull_request"
40+
ReleaseEvent Event = "release"
41+
)
42+
43+
// New creates and returns a WebHook instance denoted by the Provider type
44+
func New(config *Config) *Webhook {
45+
return &Webhook{
46+
provider: webhooks.Gogs,
47+
secret: config.Secret,
48+
eventFuncs: map[Event]webhooks.ProcessPayloadFunc{},
49+
}
50+
}
51+
52+
// Provider returns the current hooks provider ID
53+
func (hook Webhook) Provider() webhooks.Provider {
54+
return hook.provider
55+
}
56+
57+
// RegisterEvents registers the function to call when the specified event(s) are encountered
58+
func (hook Webhook) RegisterEvents(fn webhooks.ProcessPayloadFunc, events ...Event) {
59+
60+
for _, event := range events {
61+
hook.eventFuncs[event] = fn
62+
}
63+
}
64+
65+
// ParsePayload parses and verifies the payload and fires off the mapped function, if it exists.
66+
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
67+
webhooks.DefaultLog.Info("Parsing Payload...")
68+
69+
event := r.Header.Get("X-Gogs-Event")
70+
if len(event) == 0 {
71+
webhooks.DefaultLog.Error("Missing X-Gogs-Event Header")
72+
http.Error(w, "400 Bad Request - Missing X-Gogs-Event Header", http.StatusBadRequest)
73+
return
74+
}
75+
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Gogs-Event:%s", event))
76+
77+
gogsEvent := Event(event)
78+
79+
fn, ok := hook.eventFuncs[gogsEvent]
80+
// if no event registered
81+
if !ok {
82+
webhooks.DefaultLog.Info(fmt.Sprintf("Webhook Event %s not registered, it is recommended to setup only events in gogs that will be registered in the webhook to avoid unnecessary traffic and reduce potential attack vectors.", event))
83+
return
84+
}
85+
86+
payload, err := ioutil.ReadAll(r.Body)
87+
if err != nil || len(payload) == 0 {
88+
webhooks.DefaultLog.Error("Issue reading Payload")
89+
http.Error(w, "Issue reading Payload", http.StatusInternalServerError)
90+
return
91+
}
92+
webhooks.DefaultLog.Debug(fmt.Sprintf("Payload:%s", string(payload)))
93+
94+
// If we have a Secret set, we should check the MAC
95+
if len(hook.secret) > 0 {
96+
webhooks.DefaultLog.Info("Checking secret")
97+
signature := r.Header.Get("X-Gogs-Signature")
98+
if len(signature) == 0 {
99+
webhooks.DefaultLog.Error("Missing X-Gogs-Signature required for HMAC verification")
100+
http.Error(w, "403 Forbidden - Missing X-Gogs-Signature required for HMAC verification", http.StatusForbidden)
101+
return
102+
}
103+
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Gogs-Signature:%s", signature))
104+
105+
mac := hmac.New(sha256.New, []byte(hook.secret))
106+
mac.Write(payload)
107+
108+
expectedMAC := hex.EncodeToString(mac.Sum(nil))
109+
110+
if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
111+
webhooks.DefaultLog.Debug(string(payload))
112+
http.Error(w, "403 Forbidden - HMAC verification failed", http.StatusForbidden)
113+
return
114+
}
115+
}
116+
117+
// Make headers available to ProcessPayloadFunc as a webhooks type
118+
hd := webhooks.Header(r.Header)
119+
120+
switch gogsEvent {
121+
case CreateEvent:
122+
var pe client.CreatePayload
123+
json.Unmarshal([]byte(payload), &pe)
124+
hook.runProcessPayloadFunc(fn, pe, hd)
125+
126+
case ReleaseEvent:
127+
var re client.ReleasePayload
128+
json.Unmarshal([]byte(payload), &re)
129+
hook.runProcessPayloadFunc(fn, re, hd)
130+
131+
case PushEvent:
132+
var pe client.PushPayload
133+
json.Unmarshal([]byte(payload), &pe)
134+
hook.runProcessPayloadFunc(fn, pe, hd)
135+
136+
case DeleteEvent:
137+
var de client.DeletePayload
138+
json.Unmarshal([]byte(payload), &de)
139+
hook.runProcessPayloadFunc(fn, de, hd)
140+
141+
case ForkEvent:
142+
var fe client.ForkPayload
143+
json.Unmarshal([]byte(payload), &fe)
144+
hook.runProcessPayloadFunc(fn, fe, hd)
145+
146+
case IssuesEvent:
147+
var ie client.IssuesPayload
148+
json.Unmarshal([]byte(payload), &ie)
149+
hook.runProcessPayloadFunc(fn, ie, hd)
150+
151+
case IssueCommentEvent:
152+
var ice client.IssueCommentPayload
153+
json.Unmarshal([]byte(payload), &ice)
154+
hook.runProcessPayloadFunc(fn, ice, hd)
155+
156+
case PullRequestEvent:
157+
var pre client.PullRequestPayload
158+
json.Unmarshal([]byte(payload), &pre)
159+
hook.runProcessPayloadFunc(fn, pre, hd)
160+
}
161+
}
162+
163+
func (hook Webhook) runProcessPayloadFunc(fn webhooks.ProcessPayloadFunc, results interface{}, header webhooks.Header) {
164+
go func(fn webhooks.ProcessPayloadFunc, results interface{}, header webhooks.Header) {
165+
fn(results, header)
166+
}(fn, results, header)
167+
}

webhooks.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ func (p Provider) String() string {
1919
return "Bitbucket"
2020
case GitLab:
2121
return "GitLab"
22+
case Gogs:
23+
return "Gogs"
2224
default:
2325
return "Unknown"
2426
}
@@ -29,6 +31,7 @@ const (
2931
GitHub Provider = iota
3032
Bitbucket
3133
GitLab
34+
Gogs
3235
)
3336

3437
// Webhook interface defines a webhook to receive events

0 commit comments

Comments
 (0)