github.com/go-playground/webhooks/v6@v6.3.0/gogs/gogs.go (about) 1 package gogs 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net/http" 10 11 "crypto/hmac" 12 "crypto/sha256" 13 "encoding/hex" 14 15 client "github.com/gogits/go-gogs-client" 16 ) 17 18 // parse errors 19 var ( 20 ErrEventNotSpecifiedToParse = errors.New("no Event specified to parse") 21 ErrInvalidHTTPMethod = errors.New("invalid HTTP Method") 22 ErrMissingGogsEventHeader = errors.New("missing X-Gogs-Event Header") 23 ErrMissingGogsSignatureHeader = errors.New("missing X-Gogs-Signature Header") 24 ErrEventNotFound = errors.New("event not defined to be parsed") 25 ErrParsingPayload = errors.New("error parsing payload") 26 ErrHMACVerificationFailed = errors.New("HMAC verification failed") 27 ) 28 29 // Option is a configuration option for the webhook 30 type Option func(*Webhook) error 31 32 // Options is a namespace var for configuration options 33 var Options = WebhookOptions{} 34 35 // WebhookOptions is a namespace for configuration option methods 36 type WebhookOptions struct{} 37 38 // Secret registers the GitLab secret 39 func (WebhookOptions) Secret(secret string) Option { 40 return func(hook *Webhook) error { 41 hook.secret = secret 42 return nil 43 } 44 } 45 46 // Webhook instance contains all methods needed to process events 47 type Webhook struct { 48 secret string 49 } 50 51 // Event defines a Gogs hook event type 52 type Event string 53 54 // Gogs hook types 55 const ( 56 CreateEvent Event = "create" 57 DeleteEvent Event = "delete" 58 ForkEvent Event = "fork" 59 PushEvent Event = "push" 60 IssuesEvent Event = "issues" 61 IssueCommentEvent Event = "issue_comment" 62 PullRequestEvent Event = "pull_request" 63 ReleaseEvent Event = "release" 64 ) 65 66 // New creates and returns a WebHook instance denoted by the Provider type 67 func New(options ...Option) (*Webhook, error) { 68 hook := new(Webhook) 69 for _, opt := range options { 70 if err := opt(hook); err != nil { 71 return nil, errors.New("Error applying Option") 72 } 73 } 74 return hook, nil 75 } 76 77 // Parse verifies and parses the events specified and returns the payload object or an error 78 func (hook Webhook) Parse(r *http.Request, events ...Event) (interface{}, error) { 79 defer func() { 80 _, _ = io.Copy(ioutil.Discard, r.Body) 81 _ = r.Body.Close() 82 }() 83 84 if len(events) == 0 { 85 return nil, ErrEventNotSpecifiedToParse 86 } 87 if r.Method != http.MethodPost { 88 return nil, ErrInvalidHTTPMethod 89 } 90 91 event := r.Header.Get("X-Gogs-Event") 92 if len(event) == 0 { 93 return nil, ErrMissingGogsEventHeader 94 } 95 96 gogsEvent := Event(event) 97 98 var found bool 99 for _, evt := range events { 100 if evt == gogsEvent { 101 found = true 102 break 103 } 104 } 105 // event not defined to be parsed 106 if !found { 107 return nil, ErrEventNotFound 108 } 109 110 payload, err := ioutil.ReadAll(r.Body) 111 if err != nil || len(payload) == 0 { 112 return nil, ErrParsingPayload 113 } 114 115 // If we have a Secret set, we should check the MAC 116 if len(hook.secret) > 0 { 117 signature := r.Header.Get("X-Gogs-Signature") 118 if len(signature) == 0 { 119 return nil, ErrMissingGogsSignatureHeader 120 } 121 122 mac := hmac.New(sha256.New, []byte(hook.secret)) 123 _, _ = mac.Write(payload) 124 125 expectedMAC := hex.EncodeToString(mac.Sum(nil)) 126 127 if !hmac.Equal([]byte(signature), []byte(expectedMAC)) { 128 return nil, ErrHMACVerificationFailed 129 } 130 } 131 132 switch gogsEvent { 133 case CreateEvent: 134 var pl client.CreatePayload 135 err = json.Unmarshal([]byte(payload), &pl) 136 return pl, err 137 138 case ReleaseEvent: 139 var pl client.ReleasePayload 140 err = json.Unmarshal([]byte(payload), &pl) 141 return pl, err 142 143 case PushEvent: 144 var pl client.PushPayload 145 err = json.Unmarshal([]byte(payload), &pl) 146 return pl, err 147 148 case DeleteEvent: 149 var pl client.DeletePayload 150 err = json.Unmarshal([]byte(payload), &pl) 151 return pl, err 152 153 case ForkEvent: 154 var pl client.ForkPayload 155 err = json.Unmarshal([]byte(payload), &pl) 156 return pl, err 157 158 case IssuesEvent: 159 var pl client.IssuesPayload 160 err = json.Unmarshal([]byte(payload), &pl) 161 return pl, err 162 163 case IssueCommentEvent: 164 var pl client.IssueCommentPayload 165 err = json.Unmarshal([]byte(payload), &pl) 166 return pl, err 167 168 case PullRequestEvent: 169 var pl client.PullRequestPayload 170 err = json.Unmarshal([]byte(payload), &pl) 171 return pl, err 172 173 default: 174 return nil, fmt.Errorf("unknown event %s", gogsEvent) 175 } 176 }