github.com/go-playground/webhooks/v6@v6.3.0/github/github.go (about) 1 package github 2 3 import ( 4 "crypto/hmac" 5 "crypto/sha1" 6 "encoding/hex" 7 "encoding/json" 8 "errors" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "net/http" 13 ) 14 15 // parse errors 16 var ( 17 ErrEventNotSpecifiedToParse = errors.New("no Event specified to parse") 18 ErrInvalidHTTPMethod = errors.New("invalid HTTP Method") 19 ErrMissingGithubEventHeader = errors.New("missing X-GitHub-Event Header") 20 ErrMissingHubSignatureHeader = errors.New("missing X-Hub-Signature Header") 21 ErrEventNotFound = errors.New("event not defined to be parsed") 22 ErrParsingPayload = errors.New("error parsing payload") 23 ErrHMACVerificationFailed = errors.New("HMAC verification failed") 24 ) 25 26 // Event defines a GitHub hook event type 27 type Event string 28 29 // GitHub hook types 30 const ( 31 CheckRunEvent Event = "check_run" 32 CheckSuiteEvent Event = "check_suite" 33 CommitCommentEvent Event = "commit_comment" 34 CreateEvent Event = "create" 35 DeleteEvent Event = "delete" 36 DependabotAlertEvent Event = "dependabot_alert" 37 DeployKeyEvent Event = "deploy_key" 38 DeploymentEvent Event = "deployment" 39 DeploymentStatusEvent Event = "deployment_status" 40 ForkEvent Event = "fork" 41 GollumEvent Event = "gollum" 42 InstallationEvent Event = "installation" 43 InstallationRepositoriesEvent Event = "installation_repositories" 44 IntegrationInstallationEvent Event = "integration_installation" 45 IntegrationInstallationRepositoriesEvent Event = "integration_installation_repositories" 46 IssueCommentEvent Event = "issue_comment" 47 IssuesEvent Event = "issues" 48 LabelEvent Event = "label" 49 MemberEvent Event = "member" 50 MembershipEvent Event = "membership" 51 MilestoneEvent Event = "milestone" 52 MetaEvent Event = "meta" 53 OrganizationEvent Event = "organization" 54 OrgBlockEvent Event = "org_block" 55 PageBuildEvent Event = "page_build" 56 PingEvent Event = "ping" 57 ProjectCardEvent Event = "project_card" 58 ProjectColumnEvent Event = "project_column" 59 ProjectEvent Event = "project" 60 PublicEvent Event = "public" 61 PullRequestEvent Event = "pull_request" 62 PullRequestReviewEvent Event = "pull_request_review" 63 PullRequestReviewCommentEvent Event = "pull_request_review_comment" 64 PushEvent Event = "push" 65 ReleaseEvent Event = "release" 66 RepositoryEvent Event = "repository" 67 RepositoryVulnerabilityAlertEvent Event = "repository_vulnerability_alert" 68 SecurityAdvisoryEvent Event = "security_advisory" 69 StatusEvent Event = "status" 70 TeamEvent Event = "team" 71 TeamAddEvent Event = "team_add" 72 WatchEvent Event = "watch" 73 WorkflowDispatchEvent Event = "workflow_dispatch" 74 WorkflowJobEvent Event = "workflow_job" 75 WorkflowRunEvent Event = "workflow_run" 76 GitHubAppAuthorizationEvent Event = "github_app_authorization" 77 ) 78 79 // EventSubtype defines a GitHub Hook Event subtype 80 type EventSubtype string 81 82 // GitHub hook event subtypes 83 const ( 84 NoSubtype EventSubtype = "" 85 BranchSubtype EventSubtype = "branch" 86 TagSubtype EventSubtype = "tag" 87 PullSubtype EventSubtype = "pull" 88 IssueSubtype EventSubtype = "issues" 89 ) 90 91 // Option is a configuration option for the webhook 92 type Option func(*Webhook) error 93 94 // Options is a namespace var for configuration options 95 var Options = WebhookOptions{} 96 97 // WebhookOptions is a namespace for configuration option methods 98 type WebhookOptions struct{} 99 100 // Secret registers the GitHub secret 101 func (WebhookOptions) Secret(secret string) Option { 102 return func(hook *Webhook) error { 103 hook.secret = secret 104 return nil 105 } 106 } 107 108 // Webhook instance contains all methods needed to process events 109 type Webhook struct { 110 secret string 111 } 112 113 // New creates and returns a WebHook instance denoted by the Provider type 114 func New(options ...Option) (*Webhook, error) { 115 hook := new(Webhook) 116 for _, opt := range options { 117 if err := opt(hook); err != nil { 118 return nil, errors.New("Error applying Option") 119 } 120 } 121 return hook, nil 122 } 123 124 // Parse verifies and parses the events specified and returns the payload object or an error 125 func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) { 126 defer func() { 127 _, _ = io.Copy(ioutil.Discard, r.Body) 128 _ = r.Body.Close() 129 }() 130 131 if len(events) == 0 { 132 return nil, ErrEventNotSpecifiedToParse 133 } 134 if r.Method != http.MethodPost { 135 return nil, ErrInvalidHTTPMethod 136 } 137 138 event := r.Header.Get("X-GitHub-Event") 139 if event == "" { 140 return nil, ErrMissingGithubEventHeader 141 } 142 gitHubEvent := Event(event) 143 144 var found bool 145 for _, evt := range events { 146 if evt == gitHubEvent { 147 found = true 148 break 149 } 150 } 151 // event not defined to be parsed 152 if !found { 153 return nil, ErrEventNotFound 154 } 155 156 payload, err := ioutil.ReadAll(r.Body) 157 if err != nil || len(payload) == 0 { 158 return nil, ErrParsingPayload 159 } 160 161 // If we have a Secret set, we should check the MAC 162 if len(hook.secret) > 0 { 163 signature := r.Header.Get("X-Hub-Signature") 164 if len(signature) == 0 { 165 return nil, ErrMissingHubSignatureHeader 166 } 167 mac := hmac.New(sha1.New, []byte(hook.secret)) 168 _, _ = mac.Write(payload) 169 expectedMAC := hex.EncodeToString(mac.Sum(nil)) 170 171 if !hmac.Equal([]byte(signature[5:]), []byte(expectedMAC)) { 172 return nil, ErrHMACVerificationFailed 173 } 174 } 175 176 switch gitHubEvent { 177 case CheckRunEvent: 178 var pl CheckRunPayload 179 err = json.Unmarshal([]byte(payload), &pl) 180 return pl, err 181 case CheckSuiteEvent: 182 var pl CheckSuitePayload 183 err = json.Unmarshal([]byte(payload), &pl) 184 return pl, err 185 case CommitCommentEvent: 186 var pl CommitCommentPayload 187 err = json.Unmarshal([]byte(payload), &pl) 188 return pl, err 189 case CreateEvent: 190 var pl CreatePayload 191 err = json.Unmarshal([]byte(payload), &pl) 192 return pl, err 193 case DeployKeyEvent: 194 var pl DeployKeyPayload 195 err = json.Unmarshal([]byte(payload), &pl) 196 return pl, err 197 case DeleteEvent: 198 var pl DeletePayload 199 err = json.Unmarshal([]byte(payload), &pl) 200 return pl, err 201 case DependabotAlertEvent: 202 var pl DependabotAlertPayload 203 err = json.Unmarshal([]byte(payload), &pl) 204 return pl, err 205 case DeploymentEvent: 206 var pl DeploymentPayload 207 err = json.Unmarshal([]byte(payload), &pl) 208 return pl, err 209 case DeploymentStatusEvent: 210 var pl DeploymentStatusPayload 211 err = json.Unmarshal([]byte(payload), &pl) 212 return pl, err 213 case ForkEvent: 214 var pl ForkPayload 215 err = json.Unmarshal([]byte(payload), &pl) 216 return pl, err 217 case GollumEvent: 218 var pl GollumPayload 219 err = json.Unmarshal([]byte(payload), &pl) 220 return pl, err 221 case InstallationEvent, IntegrationInstallationEvent: 222 var pl InstallationPayload 223 err = json.Unmarshal([]byte(payload), &pl) 224 return pl, err 225 case InstallationRepositoriesEvent, IntegrationInstallationRepositoriesEvent: 226 var pl InstallationRepositoriesPayload 227 err = json.Unmarshal([]byte(payload), &pl) 228 return pl, err 229 case IssueCommentEvent: 230 var pl IssueCommentPayload 231 err = json.Unmarshal([]byte(payload), &pl) 232 return pl, err 233 case IssuesEvent: 234 var pl IssuesPayload 235 err = json.Unmarshal([]byte(payload), &pl) 236 return pl, err 237 case LabelEvent: 238 var pl LabelPayload 239 err = json.Unmarshal([]byte(payload), &pl) 240 return pl, err 241 case MemberEvent: 242 var pl MemberPayload 243 err = json.Unmarshal([]byte(payload), &pl) 244 return pl, err 245 case MembershipEvent: 246 var pl MembershipPayload 247 err = json.Unmarshal([]byte(payload), &pl) 248 return pl, err 249 case MetaEvent: 250 var pl MetaPayload 251 err = json.Unmarshal([]byte(payload), &pl) 252 return pl, err 253 case MilestoneEvent: 254 var pl MilestonePayload 255 err = json.Unmarshal([]byte(payload), &pl) 256 return pl, err 257 case OrganizationEvent: 258 var pl OrganizationPayload 259 err = json.Unmarshal([]byte(payload), &pl) 260 return pl, err 261 case OrgBlockEvent: 262 var pl OrgBlockPayload 263 err = json.Unmarshal([]byte(payload), &pl) 264 return pl, err 265 case PageBuildEvent: 266 var pl PageBuildPayload 267 err = json.Unmarshal([]byte(payload), &pl) 268 return pl, err 269 case PingEvent: 270 var pl PingPayload 271 err = json.Unmarshal([]byte(payload), &pl) 272 return pl, err 273 case ProjectCardEvent: 274 var pl ProjectCardPayload 275 err = json.Unmarshal([]byte(payload), &pl) 276 return pl, err 277 case ProjectColumnEvent: 278 var pl ProjectColumnPayload 279 err = json.Unmarshal([]byte(payload), &pl) 280 return pl, err 281 case ProjectEvent: 282 var pl ProjectPayload 283 err = json.Unmarshal([]byte(payload), &pl) 284 return pl, err 285 case PublicEvent: 286 var pl PublicPayload 287 err = json.Unmarshal([]byte(payload), &pl) 288 return pl, err 289 case PullRequestEvent: 290 var pl PullRequestPayload 291 err = json.Unmarshal([]byte(payload), &pl) 292 return pl, err 293 case PullRequestReviewEvent: 294 var pl PullRequestReviewPayload 295 err = json.Unmarshal([]byte(payload), &pl) 296 return pl, err 297 case PullRequestReviewCommentEvent: 298 var pl PullRequestReviewCommentPayload 299 err = json.Unmarshal([]byte(payload), &pl) 300 return pl, err 301 case PushEvent: 302 var pl PushPayload 303 err = json.Unmarshal([]byte(payload), &pl) 304 return pl, err 305 case ReleaseEvent: 306 var pl ReleasePayload 307 err = json.Unmarshal([]byte(payload), &pl) 308 return pl, err 309 case RepositoryEvent: 310 var pl RepositoryPayload 311 err = json.Unmarshal([]byte(payload), &pl) 312 return pl, err 313 case RepositoryVulnerabilityAlertEvent: 314 var pl RepositoryVulnerabilityAlertPayload 315 err = json.Unmarshal([]byte(payload), &pl) 316 return pl, err 317 case SecurityAdvisoryEvent: 318 var pl SecurityAdvisoryPayload 319 err = json.Unmarshal([]byte(payload), &pl) 320 return pl, err 321 case StatusEvent: 322 var pl StatusPayload 323 err = json.Unmarshal([]byte(payload), &pl) 324 return pl, err 325 case TeamEvent: 326 var pl TeamPayload 327 err = json.Unmarshal([]byte(payload), &pl) 328 return pl, err 329 case TeamAddEvent: 330 var pl TeamAddPayload 331 err = json.Unmarshal([]byte(payload), &pl) 332 return pl, err 333 case WatchEvent: 334 var pl WatchPayload 335 err = json.Unmarshal([]byte(payload), &pl) 336 return pl, err 337 case WorkflowDispatchEvent: 338 var pl WorkflowDispatchPayload 339 err = json.Unmarshal([]byte(payload), &pl) 340 return pl, err 341 case WorkflowJobEvent: 342 var pl WorkflowJobPayload 343 err = json.Unmarshal([]byte(payload), &pl) 344 return pl, err 345 case WorkflowRunEvent: 346 var pl WorkflowRunPayload 347 err = json.Unmarshal([]byte(payload), &pl) 348 return pl, err 349 case GitHubAppAuthorizationEvent: 350 var pl GitHubAppAuthorizationPayload 351 err = json.Unmarshal([]byte(payload), &pl) 352 return pl, err 353 default: 354 return nil, fmt.Errorf("unknown event %s", gitHubEvent) 355 } 356 }