Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow parsing non-HTTP payloads (#1) #80

Open
wants to merge 1 commit into
base: v5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 46 additions & 48 deletions bitbucket-server/bitbucketserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,26 +83,48 @@ func New(options ...Option) (*Webhook, error) {
return hook, nil
}

// Parse verifies and parses the events specified and returns the payload object or an error
func (hook *Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) {
defer func() {
_, _ = io.Copy(ioutil.Discard, r.Body)
_ = r.Body.Close()
}()

if len(events) == 0 {
return nil, ErrEventNotSpecifiedToParse
}

if r.Method != http.MethodPost {
return nil, ErrInvalidHTTPMethod
}

event := r.Header.Get("X-Event-Key")
payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 {
return nil, ErrParsingPayload
}

return hook.ParsePayload(
payload,
r.Header.Get("X-Event-Key"),
r.Header.Get("X-Hub-Signature"),
events...,
)
}

// ParsePayload verifies and parses the events from a payload and string
// metadata (event type and signature), and returns the payload object or an
// error.
//
// Similar to Parse (which uses this method under the hood), this is useful in
// cases where payloads are not represented as HTTP requests - for example are
// put on a queue for pull processing.
func (hook Webhook) ParsePayload(payload []byte, eventType, signature string, events ...Event) (interface{}, error) {
if len(events) == 0 {
return nil, ErrEventNotSpecifiedToParse
}

event := eventType
if event == "" {
return nil, ErrMissingEventKeyHeader
}

bitbucketEvent := Event(event)
bitbucketEvent := Event(eventType)

var found bool
for _, evt := range events {
Expand All @@ -120,13 +142,7 @@ func (hook *Webhook) Parse(r *http.Request, events ...Event) (interface{}, error
return DiagnosticsPingPayload{}, nil
}

payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 {
return nil, ErrParsingPayload
}

if len(hook.secret) > 0 {
signature := r.Header.Get("X-Hub-Signature")
if len(signature) == 0 {
return nil, ErrMissingHubSignatureHeader
}
Expand All @@ -142,76 +158,58 @@ func (hook *Webhook) Parse(r *http.Request, events ...Event) (interface{}, error
switch bitbucketEvent {
case RepositoryReferenceChangedEvent:
var pl RepositoryReferenceChangedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepositoryModifiedEvent:
var pl RepositoryModifiedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepositoryForkedEvent:
var pl RepositoryForkedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepositoryCommentAddedEvent:
var pl RepositoryCommentAddedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepositoryCommentEditedEvent:
var pl RepositoryCommentEditedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepositoryCommentDeletedEvent:
var pl RepositoryCommentDeletedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestOpenedEvent:
var pl PullRequestOpenedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestModifiedEvent:
var pl PullRequestModifiedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestMergedEvent:
var pl PullRequestMergedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestDeclinedEvent:
var pl PullRequestDeclinedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestDeletedEvent:
var pl PullRequestDeletedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestReviewerUpdatedEvent:
var pl PullRequestReviewerUpdatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestReviewerApprovedEvent:
var pl PullRequestReviewerApprovedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestReviewerUnapprovedEvent:
var pl PullRequestReviewerUnapprovedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestReviewerNeedsWorkEvent:
var pl PullRequestReviewerNeedsWorkPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestCommentAddedEvent:
var pl PullRequestCommentAddedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestCommentEditedEvent:
var pl PullRequestCommentEditedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestCommentDeletedEvent:
var pl PullRequestCommentDeletedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
default:
return nil, fmt.Errorf("unknown event %s", bitbucketEvent)
}
Expand Down
93 changes: 45 additions & 48 deletions bitbucket/bitbucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,28 +85,48 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
_ = r.Body.Close()
}()

if len(events) == 0 {
return nil, ErrEventNotSpecifiedToParse
}
if r.Method != http.MethodPost {
return nil, ErrInvalidHTTPMethod
}

uuid := r.Header.Get("X-Hook-UUID")
payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 {
return nil, ErrParsingPayload
}

return hook.ParsePayload(
payload,
r.Header.Get("X-Event-Key"),
r.Header.Get("X-Hook-UUID"),
events...,
)
}

// ParsePayload verifies and parses the events from a payload and string
// metadata (event type and UUID), and returns the payload object or an
// error.
//
// Similar to Parse (which uses this method under the hood), this is useful in
// cases where payloads are not represented as HTTP requests - for example are
// put on a queue for pull processing.
func (hook Webhook) ParsePayload(payload []byte, eventType, uuid string, events ...Event) (interface{}, error) {
if len(events) == 0 {
return nil, ErrEventNotSpecifiedToParse
}

if hook.uuid != "" && uuid == "" {
return nil, ErrMissingHookUUIDHeader
}

event := r.Header.Get("X-Event-Key")
if event == "" {
if eventType == "" {
return nil, ErrMissingEventKeyHeader
}

if len(hook.uuid) > 0 && uuid != hook.uuid {
return nil, ErrUUIDVerificationFailed
}

bitbucketEvent := Event(event)
bitbucketEvent := Event(eventType)

var found bool
for _, evt := range events {
Expand All @@ -120,84 +140,61 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return nil, ErrEventNotFound
}

payload, err := ioutil.ReadAll(r.Body)
if err != nil || len(payload) == 0 {
return nil, ErrParsingPayload
}

switch bitbucketEvent {
case RepoPushEvent:
var pl RepoPushPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepoForkEvent:
var pl RepoForkPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepoUpdatedEvent:
var pl RepoUpdatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepoCommitCommentCreatedEvent:
var pl RepoCommitCommentCreatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepoCommitStatusCreatedEvent:
var pl RepoCommitStatusCreatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case RepoCommitStatusUpdatedEvent:
var pl RepoCommitStatusUpdatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case IssueCreatedEvent:
var pl IssueCreatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case IssueUpdatedEvent:
var pl IssueUpdatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case IssueCommentCreatedEvent:
var pl IssueCommentCreatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestCreatedEvent:
var pl PullRequestCreatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestUpdatedEvent:
var pl PullRequestUpdatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestApprovedEvent:
var pl PullRequestApprovedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestUnapprovedEvent:
var pl PullRequestUnapprovedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestMergedEvent:
var pl PullRequestMergedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestDeclinedEvent:
var pl PullRequestDeclinedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestCommentCreatedEvent:
var pl PullRequestCommentCreatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestCommentUpdatedEvent:
var pl PullRequestCommentUpdatedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
case PullRequestCommentDeletedEvent:
var pl PullRequestCommentDeletedPayload
err = json.Unmarshal([]byte(payload), &pl)
return pl, err
return pl, json.Unmarshal(payload, &pl)
default:
return nil, fmt.Errorf("unknown event %s", bitbucketEvent)
}
Expand Down
15 changes: 12 additions & 3 deletions docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,20 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error)
return nil, ErrParsingPayload
}

return hook.ParsePayload(payload, events...)
}

// ParsePayload verifies and parses the Build event from a payload, and returns
// the payload object or an error.
//
// Similar to Parse (which uses this method under the hood), this is useful in
// cases where payloads are not represented as HTTP requests - for example are
// put on a queue for pull processing.
func (hook Webhook) ParsePayload(payload []byte, events ...Event) (interface{}, error) {
var pl BuildPayload
err = json.Unmarshal([]byte(payload), &pl)
if err != nil {
if err := json.Unmarshal(payload, &pl); err != nil {
return nil, ErrParsingPayload
}
return pl, err

return pl, nil
}
Loading