Skip to content

Commit

Permalink
Merge pull request #29 from naiba/v3
Browse files Browse the repository at this point in the history
Add gogs support
  • Loading branch information
deankarn authored May 8, 2018
2 parents 5580947 + 3e1bb69 commit 16896cd
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# Folders
_obj
_test
.idea

# Architecture specific extensions/prefixes
*.[568vq]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Installation
Use go get.

```shell
go get -u gopkg.in/go-playground/webhooks.v3
go get -u gopkg.in/go-playground/webhooks.v3
```

Then import the package into your own code.
Expand Down
167 changes: 167 additions & 0 deletions gogs/gogs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package gogs

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"

"crypto/hmac"
"crypto/sha256"
"encoding/hex"
client "github.com/gogits/go-gogs-client"
"gopkg.in/go-playground/webhooks.v3"
)

// Webhook instance contains all methods needed to process events
type Webhook struct {
provider webhooks.Provider
secret string
eventFuncs map[Event]webhooks.ProcessPayloadFunc
}

// Config defines the configuration to create a new Gogs Webhook instance
type Config struct {
Secret string
}

// Event defines a Gogs hook event type
type Event string

// Gogs hook types
const (
CreateEvent Event = "create"
DeleteEvent Event = "delete"
ForkEvent Event = "fork"
PushEvent Event = "push"
IssuesEvent Event = "issues"
IssueCommentEvent Event = "issue_comment"
PullRequestEvent Event = "pull_request"
ReleaseEvent Event = "release"
)

// New creates and returns a WebHook instance denoted by the Provider type
func New(config *Config) *Webhook {
return &Webhook{
provider: webhooks.Gogs,
secret: config.Secret,
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...")

event := r.Header.Get("X-Gogs-Event")
if len(event) == 0 {
webhooks.DefaultLog.Error("Missing X-Gogs-Event Header")
http.Error(w, "400 Bad Request - Missing X-Gogs-Event Header", http.StatusBadRequest)
return
}
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Gogs-Event:%s", event))

gogsEvent := Event(event)

fn, ok := hook.eventFuncs[gogsEvent]
// if no event registered
if !ok {
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))
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)))

// If we have a Secret set, we should check the MAC
if len(hook.secret) > 0 {
webhooks.DefaultLog.Info("Checking secret")
signature := r.Header.Get("X-Gogs-Signature")
if len(signature) == 0 {
webhooks.DefaultLog.Error("Missing X-Gogs-Signature required for HMAC verification")
http.Error(w, "403 Forbidden - Missing X-Gogs-Signature required for HMAC verification", http.StatusForbidden)
return
}
webhooks.DefaultLog.Debug(fmt.Sprintf("X-Gogs-Signature:%s", signature))

mac := hmac.New(sha256.New, []byte(hook.secret))
mac.Write(payload)

expectedMAC := hex.EncodeToString(mac.Sum(nil))

if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
webhooks.DefaultLog.Debug(string(payload))
http.Error(w, "403 Forbidden - HMAC verification failed", http.StatusForbidden)
return
}
}

// Make headers available to ProcessPayloadFunc as a webhooks type
hd := webhooks.Header(r.Header)

switch gogsEvent {
case CreateEvent:
var pe client.CreatePayload
json.Unmarshal([]byte(payload), &pe)
hook.runProcessPayloadFunc(fn, pe, hd)

case ReleaseEvent:
var re client.ReleasePayload
json.Unmarshal([]byte(payload), &re)
hook.runProcessPayloadFunc(fn, re, hd)

case PushEvent:
var pe client.PushPayload
json.Unmarshal([]byte(payload), &pe)
hook.runProcessPayloadFunc(fn, pe, hd)

case DeleteEvent:
var de client.DeletePayload
json.Unmarshal([]byte(payload), &de)
hook.runProcessPayloadFunc(fn, de, hd)

case ForkEvent:
var fe client.ForkPayload
json.Unmarshal([]byte(payload), &fe)
hook.runProcessPayloadFunc(fn, fe, hd)

case IssuesEvent:
var ie client.IssuesPayload
json.Unmarshal([]byte(payload), &ie)
hook.runProcessPayloadFunc(fn, ie, hd)

case IssueCommentEvent:
var ice client.IssueCommentPayload
json.Unmarshal([]byte(payload), &ice)
hook.runProcessPayloadFunc(fn, ice, hd)

case PullRequestEvent:
var pre client.PullRequestPayload
json.Unmarshal([]byte(payload), &pre)
hook.runProcessPayloadFunc(fn, pre, 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)
}
3 changes: 3 additions & 0 deletions webhooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ func (p Provider) String() string {
return "Bitbucket"
case GitLab:
return "GitLab"
case Gogs:
return "Gogs"
default:
return "Unknown"
}
Expand All @@ -29,6 +31,7 @@ const (
GitHub Provider = iota
Bitbucket
GitLab
Gogs
)

// Webhook interface defines a webhook to receive events
Expand Down

0 comments on commit 16896cd

Please sign in to comment.