-
Notifications
You must be signed in to change notification settings - Fork 235
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from naiba/v3
Add gogs support
- Loading branch information
Showing
4 changed files
with
172 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
# Folders | ||
_obj | ||
_test | ||
.idea | ||
|
||
# Architecture specific extensions/prefixes | ||
*.[568vq] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters