<commit_before>package github

// this file was modified heavily from this https://github.com/google/go-github/blob/master/github/activity_events.go
// Portions Copyright 2013 The go-github AUTHORS. All rights reserved.

// we are using our protobuf generated events instead of the ones in their package so that we can marshal into protobuf protocol

import (
	"crypto/hmac"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"hash"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

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"
	// signatureHeader is the GitHub header key used to pass the HMAC hexdigest.
	signatureHeader = "X-Hub-Signature"
	// eventTypeHeader is the Github header key used to pass the event type.
	eventTypeHeader = "X-Github-Event"
)

var (
	// eventTypeMapping maps webhooks types to their corresponding go-github struct types.
	eventTypeMapping = map[string]string{
		"commit_comment":                        "CommitCommentEvent",
		"create":                                "CreateEvent",
		"delete":                                "DeleteEvent",
		"deployment":                            "DeploymentEvent",
		"deployment_status":                     "DeploymentStatusEvent",
		"fork":                                  "ForkEvent",
		"gollum":                                "GollumEvent",
		"integration_installation":              "IntegrationInstallationEvent",
		"integration_installation_repositories": "IntegrationInstallationRepositoriesEvent",
		"issue_comment":                         "IssueCommentEvent",
		"issues":                                "IssuesEvent",
		"label":                                 "LabelEvent",
		"member":                                "MemberEvent",
		"membership":                            "MembershipEvent",
		"milestone":                             "MilestoneEvent",
		"organization":                          "OrganizationEvent",
		"page_build":                            "PageBuildEvent",
		"ping":                                  "Ping",
		"public":                                "PublicEvent",
		"pull_request_review_comment":           "PullRequestReviewCommentEvent",
		"pull_request":                          "PullRequestEvent",
		"pull_request_review":                   "PullRequestReviewEvent",
		"push":                                  "PushEvent",
		"repository":                            "RepositoryEvent",
		"release":                               "ReleaseEvent",
		"status":                                "StatusEvent",
		"team_add":                              "TeamAddEvent",
		"watch":                                 "WatchEvent",
	}
)

// 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, error) {
	expectedMAC := genMAC(message, key, hashFunc)
	if !hmac.Equal(messageMAC, expectedMAC) {
		return false, fmt.Errorf("expected %x but was %x", expectedMAC, messageMAC)
	}
	return true, nil
}

// 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
// and returns the (JSON) payload.
// secretKey is the GitHub Webhook secret message.
//
// 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, secretKey []byte) (payload []byte, err error) {
	defer r.Body.Close()
	payload, err = ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}

	sig := r.Header.Get(signatureHeader)
	if err := validateSignature(sig, payload, secretKey); err != nil {
		return nil, err
	}
	return payload, nil
}

// 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.
// secretKey is the GitHub Webhook secret message.
//
// GitHub docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
func validateSignature(signature string, payload, secretKey []byte) error {
	messageMAC, hashFunc, err := messageMAC(signature)
	if err != nil {
		return err
	}
	if ok, err := checkMAC(payload, messageMAC, secretKey, hashFunc); !ok {
		return errors.New("payload signature check failed. %v", err)
	}
	return nil
}

// WebHookType returns the event type of webhook request r.
func WebHookType(r *http.Request) string {
	return r.Header.Get(eventTypeHeader)
}

// ParseWebHook parses the event payload. For recognized event types, a
// value of the corresponding struct type will be returned (as returned
// by Event.Payload()). 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) {<commit_msg>use fmt.Errorf instead of errors.New for messgae<commit_after>package github

// this file was modified heavily from this https://github.com/google/go-github/blob/master/github/activity_events.go
// Portions Copyright 2013 The go-github AUTHORS. All rights reserved.

// we are using our protobuf generated events instead of the ones in their package so that we can marshal into protobuf protocol

import (
	"crypto/hmac"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"hash"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

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"
	// signatureHeader is the GitHub header key used to pass the HMAC hexdigest.
	signatureHeader = "X-Hub-Signature"
	// eventTypeHeader is the Github header key used to pass the event type.
	eventTypeHeader = "X-Github-Event"
)

var (
	// eventTypeMapping maps webhooks types to their corresponding go-github struct types.
	eventTypeMapping = map[string]string{
		"commit_comment":                        "CommitCommentEvent",
		"create":                                "CreateEvent",
		"delete":                                "DeleteEvent",
		"deployment":                            "DeploymentEvent",
		"deployment_status":                     "DeploymentStatusEvent",
		"fork":                                  "ForkEvent",
		"gollum":                                "GollumEvent",
		"integration_installation":              "IntegrationInstallationEvent",
		"integration_installation_repositories": "IntegrationInstallationRepositoriesEvent",
		"issue_comment":                         "IssueCommentEvent",
		"issues":                                "IssuesEvent",
		"label":                                 "LabelEvent",
		"member":                                "MemberEvent",
		"membership":                            "MembershipEvent",
		"milestone":                             "MilestoneEvent",
		"organization":                          "OrganizationEvent",
		"page_build":                            "PageBuildEvent",
		"ping":                                  "Ping",
		"public":                                "PublicEvent",
		"pull_request_review_comment":           "PullRequestReviewCommentEvent",
		"pull_request":                          "PullRequestEvent",
		"pull_request_review":                   "PullRequestReviewEvent",
		"push":                                  "PushEvent",
		"repository":                            "RepositoryEvent",
		"release":                               "ReleaseEvent",
		"status":                                "StatusEvent",
		"team_add":                              "TeamAddEvent",
		"watch":                                 "WatchEvent",
	}
)

// 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, error) {
	expectedMAC := genMAC(message, key, hashFunc)
	if !hmac.Equal(messageMAC, expectedMAC) {
		return false, fmt.Errorf("expected %x but was %x", expectedMAC, messageMAC)
	}
	return true, nil
}

// 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
// and returns the (JSON) payload.
// secretKey is the GitHub Webhook secret message.
//
// 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, secretKey []byte) (payload []byte, err error) {
	defer r.Body.Close()
	payload, err = ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}

	sig := r.Header.Get(signatureHeader)
	if err := validateSignature(sig, payload, secretKey); err != nil {
		return nil, err
	}
	return payload, nil
}

// 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.
// secretKey is the GitHub Webhook secret message.
//
// GitHub docs: https://developer.github.com/webhooks/securing/#validating-payloads-from-github
func validateSignature(signature string, payload, secretKey []byte) error {
	messageMAC, hashFunc, err := messageMAC(signature)
	if err != nil {
		return err
	}
	if ok, err := checkMAC(payload, messageMAC, secretKey, hashFunc); !ok {
		return fmt.Errorf("payload signature check failed. %v", err)
	}
	return nil
}

// WebHookType returns the event type of webhook request r.
func WebHookType(r *http.Request) string {
	return r.Header.Get(eventTypeHeader)
}

// ParseWebHook parses the event payload. For recognized event types, a
// value of the corresponding struct type will be returned (as returned
// by Event.Payload()). 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) {
{'fraction_non_alphanumeric': 0.1128696054967961, 'fraction_numerical': 0.007874623639311356, 'mean_word_length': 2.5191524042379787, 'pattern_counts': {'":': 56, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1151448', 'n_tokens_mistral': 3883, 'n_tokens_neox': 3657, 'n_words': 1112}