Skip to content

Commit 2aa5fdc

Browse files
author
奶爸
committed
add gogs support
1 parent b6e930d commit 2aa5fdc

File tree

2 files changed

+176
-1
lines changed

2 files changed

+176
-1
lines changed

gogs/gogs.go

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

webhooks.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,19 @@ 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
}
2527
}
2628

2729
// webhooks available providers
2830
const (
29-
GitHub Provider = iota
31+
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)