summaryrefslogtreecommitdiff
path: root/vendor/github.com/google/go-github/v43/github/messages.go
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-24 17:58:01 -0600
committermo khan <mo@mokhan.ca>2025-07-24 17:58:01 -0600
commit72296119fc9755774719f8f625ad03e0e0ec457a (patch)
treeed236ddee12a20fb55b7cfecf13f62d3a000dcb5 /vendor/github.com/google/go-github/v43/github/messages.go
parenta920a8cfe415858bb2777371a77018599ffed23f (diff)
parenteaa1bd3b8e12934aed06413d75e7482ac58d805a (diff)
Merge branch 'the-spice-must-flow' into 'main'
Add SpiceDB Authorization See merge request gitlab-org/software-supply-chain-security/authorization/sparkled!19
Diffstat (limited to 'vendor/github.com/google/go-github/v43/github/messages.go')
-rw-r--r--vendor/github.com/google/go-github/v43/github/messages.go304
1 files changed, 304 insertions, 0 deletions
diff --git a/vendor/github.com/google/go-github/v43/github/messages.go b/vendor/github.com/google/go-github/v43/github/messages.go
new file mode 100644
index 0000000..c1e8161
--- /dev/null
+++ b/vendor/github.com/google/go-github/v43/github/messages.go
@@ -0,0 +1,304 @@
+// Copyright 2016 The go-github AUTHORS. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file provides functions for validating payloads from GitHub Webhooks.
+// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
+
+package github
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+ "io/ioutil"
+ "mime"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+const (
+ // sha1Prefix is the prefix used by GitHub before the HMAC hexdigest.
+ sha1Prefix = "sha1"
+ // sha256Prefix and sha512Prefix are provided for future compatibility.
+ sha256Prefix = "sha256"
+ sha512Prefix = "sha512"
+ // SHA1SignatureHeader is the GitHub header key used to pass the HMAC-SHA1 hexdigest.
+ SHA1SignatureHeader = "X-Hub-Signature"
+ // SHA256SignatureHeader is the GitHub header key used to pass the HMAC-SHA256 hexdigest.
+ SHA256SignatureHeader = "X-Hub-Signature-256"
+ // EventTypeHeader is the GitHub header key used to pass the event type.
+ EventTypeHeader = "X-Github-Event"
+ // DeliveryIDHeader is the GitHub header key used to pass the unique ID for the webhook event.
+ DeliveryIDHeader = "X-Github-Delivery"
+)
+
+var (
+ // eventTypeMapping maps webhooks types to their corresponding go-github struct types.
+ eventTypeMapping = map[string]string{
+ "branch_protection_rule": "BranchProtectionRuleEvent",
+ "check_run": "CheckRunEvent",
+ "check_suite": "CheckSuiteEvent",
+ "commit_comment": "CommitCommentEvent",
+ "content_reference": "ContentReferenceEvent",
+ "create": "CreateEvent",
+ "delete": "DeleteEvent",
+ "deploy_key": "DeployKeyEvent",
+ "deployment": "DeploymentEvent",
+ "deployment_status": "DeploymentStatusEvent",
+ "discussion": "DiscussionEvent",
+ "fork": "ForkEvent",
+ "github_app_authorization": "GitHubAppAuthorizationEvent",
+ "gollum": "GollumEvent",
+ "installation": "InstallationEvent",
+ "installation_repositories": "InstallationRepositoriesEvent",
+ "issue_comment": "IssueCommentEvent",
+ "issues": "IssuesEvent",
+ "label": "LabelEvent",
+ "marketplace_purchase": "MarketplacePurchaseEvent",
+ "member": "MemberEvent",
+ "membership": "MembershipEvent",
+ "meta": "MetaEvent",
+ "milestone": "MilestoneEvent",
+ "organization": "OrganizationEvent",
+ "org_block": "OrgBlockEvent",
+ "package": "PackageEvent",
+ "page_build": "PageBuildEvent",
+ "ping": "PingEvent",
+ "project": "ProjectEvent",
+ "project_card": "ProjectCardEvent",
+ "project_column": "ProjectColumnEvent",
+ "public": "PublicEvent",
+ "pull_request": "PullRequestEvent",
+ "pull_request_review": "PullRequestReviewEvent",
+ "pull_request_review_comment": "PullRequestReviewCommentEvent",
+ "pull_request_target": "PullRequestTargetEvent",
+ "push": "PushEvent",
+ "repository": "RepositoryEvent",
+ "repository_dispatch": "RepositoryDispatchEvent",
+ "repository_vulnerability_alert": "RepositoryVulnerabilityAlertEvent",
+ "release": "ReleaseEvent",
+ "secret_scanning_alert": "SecretScanningAlertEvent",
+ "star": "StarEvent",
+ "status": "StatusEvent",
+ "team": "TeamEvent",
+ "team_add": "TeamAddEvent",
+ "user": "UserEvent",
+ "watch": "WatchEvent",
+ "workflow_dispatch": "WorkflowDispatchEvent",
+ "workflow_job": "WorkflowJobEvent",
+ "workflow_run": "WorkflowRunEvent",
+ }
+)
+
+// genMAC generates the HMAC signature for a message provided the secret key
+// and hashFunc.
+func genMAC(message, key []byte, hashFunc func() hash.Hash) []byte {
+ mac := hmac.New(hashFunc, key)
+ mac.Write(message)
+ return mac.Sum(nil)
+}
+
+// checkMAC reports whether messageMAC is a valid HMAC tag for message.
+func checkMAC(message, messageMAC, key []byte, hashFunc func() hash.Hash) bool {
+ expectedMAC := genMAC(message, key, hashFunc)
+ return hmac.Equal(messageMAC, expectedMAC)
+}
+
+// messageMAC returns the hex-decoded HMAC tag from the signature and its
+// corresponding hash function.
+func messageMAC(signature string) ([]byte, func() hash.Hash, error) {
+ if signature == "" {
+ return nil, nil, errors.New("missing signature")
+ }
+ sigParts := strings.SplitN(signature, "=", 2)
+ if len(sigParts) != 2 {
+ return nil, nil, fmt.Errorf("error parsing signature %q", signature)
+ }
+
+ var hashFunc func() hash.Hash
+ switch sigParts[0] {
+ case sha1Prefix:
+ hashFunc = sha1.New
+ case sha256Prefix:
+ hashFunc = sha256.New
+ case sha512Prefix:
+ hashFunc = sha512.New
+ default:
+ return nil, nil, fmt.Errorf("unknown hash type prefix: %q", sigParts[0])
+ }
+
+ buf, err := hex.DecodeString(sigParts[1])
+ if err != nil {
+ return nil, nil, fmt.Errorf("error decoding signature %q: %v", signature, err)
+ }
+ return buf, hashFunc, nil
+}
+
+// ValidatePayload validates an incoming GitHub Webhook event request body
+// and returns the (JSON) payload.
+// The Content-Type header of the payload can be "application/json" or "application/x-www-form-urlencoded".
+// If the Content-Type is neither then an error is returned.
+// secretToken is the GitHub Webhook secret token.
+// If your webhook does not contain a secret token, you can pass nil or an empty slice.
+// This is intended for local development purposes only and all webhooks should ideally set up a secret token.
+//
+// Example usage:
+//
+// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+// // read signature from request
+// signature := ""
+// payload, err := github.ValidatePayloadFromBody(r.Header.Get("Content-Type"), r.Body, signature, s.webhookSecretKey)
+// if err != nil { ... }
+// // Process payload...
+// }
+func ValidatePayloadFromBody(contentType string, readable io.Reader, signature string, secretToken []byte) (payload []byte, err error) {
+ var body []byte // Raw body that GitHub uses to calculate the signature.
+
+ switch contentType {
+ case "application/json":
+ var err error
+ if body, err = ioutil.ReadAll(readable); err != nil {
+ return nil, err
+ }
+
+ // If the content type is application/json,
+ // the JSON payload is just the original body.
+ payload = body
+
+ case "application/x-www-form-urlencoded":
+ // payloadFormParam is the name of the form parameter that the JSON payload
+ // will be in if a webhook has its content type set to application/x-www-form-urlencoded.
+ const payloadFormParam = "payload"
+
+ var err error
+ if body, err = ioutil.ReadAll(readable); err != nil {
+ return nil, err
+ }
+
+ // If the content type is application/x-www-form-urlencoded,
+ // the JSON payload will be under the "payload" form param.
+ form, err := url.ParseQuery(string(body))
+ if err != nil {
+ return nil, err
+ }
+ payload = []byte(form.Get(payloadFormParam))
+
+ default:
+ return nil, fmt.Errorf("webhook request has unsupported Content-Type %q", contentType)
+ }
+
+ // Only validate the signature if a secret token exists. This is intended for
+ // local development only and all webhooks should ideally set up a secret token.
+ if len(secretToken) > 0 {
+ if err := ValidateSignature(signature, body, secretToken); err != nil {
+ return nil, err
+ }
+ }
+
+ return payload, nil
+}
+
+// ValidatePayload validates an incoming GitHub Webhook event request
+// and returns the (JSON) payload.
+// The Content-Type header of the payload can be "application/json" or "application/x-www-form-urlencoded".
+// If the Content-Type is neither then an error is returned.
+// secretToken is the GitHub Webhook secret token.
+// If your webhook does not contain a secret token, you can pass nil or an empty slice.
+// This is intended for local development purposes only and all webhooks should ideally set up a secret token.
+//
+// Example usage:
+//
+// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+// payload, err := github.ValidatePayload(r, s.webhookSecretKey)
+// if err != nil { ... }
+// // Process payload...
+// }
+//
+func ValidatePayload(r *http.Request, secretToken []byte) (payload []byte, err error) {
+ signature := r.Header.Get(SHA256SignatureHeader)
+ if signature == "" {
+ signature = r.Header.Get(SHA1SignatureHeader)
+ }
+
+ contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
+ if err != nil {
+ return nil, err
+ }
+
+ return ValidatePayloadFromBody(contentType, r.Body, signature, secretToken)
+}
+
+// ValidateSignature validates the signature for the given payload.
+// signature is the GitHub hash signature delivered in the X-Hub-Signature header.
+// payload is the JSON payload sent by GitHub Webhooks.
+// secretToken is the GitHub Webhook secret token.
+//
+// GitHub API docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
+func ValidateSignature(signature string, payload, secretToken []byte) error {
+ messageMAC, hashFunc, err := messageMAC(signature)
+ if err != nil {
+ return err
+ }
+ if !checkMAC(payload, messageMAC, secretToken, hashFunc) {
+ return errors.New("payload signature check failed")
+ }
+ return nil
+}
+
+// WebHookType returns the event type of webhook request r.
+//
+// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/events/github-event-types
+func WebHookType(r *http.Request) string {
+ return r.Header.Get(EventTypeHeader)
+}
+
+// DeliveryID returns the unique delivery ID of webhook request r.
+//
+// GitHub API docs: https://docs.github.com/en/developers/webhooks-and-events/events/github-event-types
+func DeliveryID(r *http.Request) string {
+ return r.Header.Get(DeliveryIDHeader)
+}
+
+// ParseWebHook parses the event payload. For recognized event types, a
+// value of the corresponding struct type will be returned (as returned
+// by Event.ParsePayload()). An error will be returned for unrecognized event
+// types.
+//
+// Example usage:
+//
+// func (s *GitHubEventMonitor) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+// payload, err := github.ValidatePayload(r, s.webhookSecretKey)
+// if err != nil { ... }
+// event, err := github.ParseWebHook(github.WebHookType(r), payload)
+// if err != nil { ... }
+// switch event := event.(type) {
+// case *github.CommitCommentEvent:
+// processCommitCommentEvent(event)
+// case *github.CreateEvent:
+// processCreateEvent(event)
+// ...
+// }
+// }
+//
+func ParseWebHook(messageType string, payload []byte) (interface{}, error) {
+ eventType, ok := eventTypeMapping[messageType]
+ if !ok {
+ return nil, fmt.Errorf("unknown X-Github-Event in message: %v", messageType)
+ }
+
+ event := Event{
+ Type: &eventType,
+ RawPayload: (*json.RawMessage)(&payload),
+ }
+ return event.ParsePayload()
+}