diff --git a/bitbucket-server/bitbucketserver.go b/bitbucket-server/bitbucketserver.go index e23cbff..ad05a97 100644 --- a/bitbucket-server/bitbucketserver.go +++ b/bitbucket-server/bitbucketserver.go @@ -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 { @@ -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 } @@ -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) } diff --git a/bitbucket/bitbucket.go b/bitbucket/bitbucket.go index 2d1344e..8931365 100644 --- a/bitbucket/bitbucket.go +++ b/bitbucket/bitbucket.go @@ -85,20 +85,40 @@ 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 } @@ -106,7 +126,7 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) return nil, ErrUUIDVerificationFailed } - bitbucketEvent := Event(event) + bitbucketEvent := Event(eventType) var found bool for _, evt := range events { @@ -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) } diff --git a/docker/docker.go b/docker/docker.go index 84de0ec..ace65dc 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -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 } diff --git a/github/github.go b/github/github.go index be825a6..6a3f550 100644 --- a/github/github.go +++ b/github/github.go @@ -120,18 +120,39 @@ 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 } - event := r.Header.Get("X-GitHub-Event") - if event == "" { + payload, err := ioutil.ReadAll(r.Body) + if err != nil || len(payload) == 0 { + return nil, ErrParsingPayload + } + + return hook.ParsePayload( + payload, + r.Header.Get("X-GitHub-Event"), + 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 + } + + if eventType == "" { return nil, ErrMissingGithubEventHeader } - gitHubEvent := Event(event) + gitHubEvent := Event(eventType) var found bool for _, evt := range events { @@ -145,14 +166,8 @@ 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 - } - // If we have a Secret set, we should check the MAC if len(hook.secret) > 0 { - signature := r.Header.Get("X-Hub-Signature") if len(signature) == 0 { return nil, ErrMissingHubSignatureHeader } @@ -168,152 +183,115 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) switch gitHubEvent { case CheckRunEvent: var pl CheckRunPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case CheckSuiteEvent: var pl CheckSuitePayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case CommitCommentEvent: var pl CommitCommentPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case CreateEvent: var pl CreatePayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case DeleteEvent: var pl DeletePayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case DeploymentEvent: var pl DeploymentPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case DeploymentStatusEvent: var pl DeploymentStatusPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case ForkEvent: var pl ForkPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case GollumEvent: var pl GollumPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case InstallationEvent, IntegrationInstallationEvent: var pl InstallationPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case InstallationRepositoriesEvent: var pl InstallationRepositoriesPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case IssueCommentEvent: var pl IssueCommentPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case IssuesEvent: var pl IssuesPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case LabelEvent: var pl LabelPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case MemberEvent: var pl MemberPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case MembershipEvent: var pl MembershipPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case MilestoneEvent: var pl MilestonePayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case OrganizationEvent: var pl OrganizationPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case OrgBlockEvent: var pl OrgBlockPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PageBuildEvent: var pl PageBuildPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PingEvent: var pl PingPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case ProjectCardEvent: var pl ProjectCardPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case ProjectColumnEvent: var pl ProjectColumnPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case ProjectEvent: var pl ProjectPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PublicEvent: var pl PublicPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PullRequestEvent: var pl PullRequestPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PullRequestReviewEvent: var pl PullRequestReviewPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PullRequestReviewCommentEvent: var pl PullRequestReviewCommentPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PushEvent: var pl PushPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case ReleaseEvent: var pl ReleasePayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case RepositoryEvent: var pl RepositoryPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case RepositoryVulnerabilityAlertEvent: var pl RepositoryVulnerabilityAlertPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case SecurityAdvisoryEvent: var pl SecurityAdvisoryPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case StatusEvent: var pl StatusPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case TeamEvent: var pl TeamPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case TeamAddEvent: var pl TeamAddPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case WatchEvent: var pl WatchPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) default: return nil, fmt.Errorf("unknown event %s", gitHubEvent) } diff --git a/gitlab/gitlab.go b/gitlab/gitlab.go index e181817..8a489c0 100644 --- a/gitlab/gitlab.go +++ b/gitlab/gitlab.go @@ -83,38 +83,24 @@ 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 } - // If we have a Secret set, we should check the MAC - if len(hook.secret) > 0 { - signature := r.Header.Get("X-Gitlab-Token") - if signature != hook.secret { - return nil, ErrGitLabTokenVerificationFailed - } - } - - event := r.Header.Get("X-Gitlab-Event") - if len(event) == 0 { - return nil, ErrMissingGitLabEventHeader - } - - gitLabEvent := Event(event) - payload, err := ioutil.ReadAll(r.Body) if err != nil || len(payload) == 0 { return nil, ErrParsingPayload } - return eventParsing(gitLabEvent, events, payload) + return hook.ParsePayload( + payload, + r.Header.Get("X-Gitlab-Event"), + r.Header.Get("X-Gitlab-Token"), + events..., + ) } func eventParsing(gitLabEvent Event, events []Event, payload []byte) (interface{}, error) { - var found bool for _, evt := range events { if evt == gitLabEvent { @@ -130,57 +116,46 @@ func eventParsing(gitLabEvent Event, events []Event, payload []byte) (interface{ switch gitLabEvent { case PushEvents: var pl PushEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case TagEvents: var pl TagEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case ConfidentialIssuesEvents: var pl ConfidentialIssueEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case IssuesEvents: var pl IssueEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case CommentEvents: var pl CommentEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case MergeRequestEvents: var pl MergeRequestEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case WikiPageEvents: var pl WikiPageEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PipelineEvents: var pl PipelineEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case BuildEvents: var pl BuildEventPayload - err := json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case JobEvents: - var p1 JobEventPayload - err := json.Unmarshal([]byte(payload), &p1) - return p1, err + var pl JobEventPayload + return pl, json.Unmarshal(payload, &pl) case SystemHookEvents: var pl SystemHookPayload - err := json.Unmarshal([]byte(payload), &pl) - if err != nil { + if err := json.Unmarshal(payload, &pl); err != nil { return nil, err } switch pl.ObjectKind { @@ -197,3 +172,30 @@ func eventParsing(gitLabEvent Event, events []Event, payload []byte) (interface{ return nil, fmt.Errorf("unknown event %s", gitLabEvent) } } + +// ParsePayload verifies and parses the events from a payload and string +// metadata (event type and token), 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, token string, events ...Event) (interface{}, error) { + if len(events) == 0 { + return nil, ErrEventNotSpecifiedToParse + } + + // If we have a Secret set, we should check the MAC + if len(hook.secret) > 0 { + if token != hook.secret { + return nil, ErrGitLabTokenVerificationFailed + } + } + + if len(eventType) == 0 { + return nil, ErrMissingGitLabEventHeader + } + + gitLabEvent := Event(eventType) + + return eventParsing(gitLabEvent, events, payload) +} diff --git a/gogs/gogs.go b/gogs/gogs.go index 9575c22..f05babb 100644 --- a/gogs/gogs.go +++ b/gogs/gogs.go @@ -1,6 +1,9 @@ package gogs import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -8,10 +11,6 @@ import ( "io/ioutil" "net/http" - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - client "github.com/gogits/go-gogs-client" ) @@ -81,19 +80,40 @@ 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 } - event := r.Header.Get("X-Gogs-Event") - if len(event) == 0 { + payload, err := ioutil.ReadAll(r.Body) + if err != nil || len(payload) == 0 { + return nil, ErrParsingPayload + } + + return hook.ParsePayload( + payload, + r.Header.Get("X-Gogs-Event"), + r.Header.Get("X-Gogs-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 + } + + if len(eventType) == 0 { return nil, ErrMissingGogsEventHeader } - gogsEvent := Event(event) + gogsEvent := Event(eventType) var found bool for _, evt := range events { @@ -107,14 +127,8 @@ 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 - } - // If we have a Secret set, we should check the MAC if len(hook.secret) > 0 { - signature := r.Header.Get("X-Gogs-Signature") if len(signature) == 0 { return nil, ErrMissingGogsSignatureHeader } @@ -132,43 +146,35 @@ func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) switch gogsEvent { case CreateEvent: var pl client.CreatePayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case ReleaseEvent: var pl client.ReleasePayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PushEvent: var pl client.PushPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case DeleteEvent: var pl client.DeletePayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case ForkEvent: var pl client.ForkPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case IssuesEvent: var pl client.IssuesPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case IssueCommentEvent: var pl client.IssueCommentPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) case PullRequestEvent: var pl client.PullRequestPayload - err = json.Unmarshal([]byte(payload), &pl) - return pl, err + return pl, json.Unmarshal(payload, &pl) default: return nil, fmt.Errorf("unknown event %s", gogsEvent)