-
Notifications
You must be signed in to change notification settings - Fork 8
/
webhook.go
80 lines (64 loc) · 1.83 KB
/
webhook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package hooks
import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"net/url"
"github.com/reviewboard/rb-gateway/repositories/events"
)
type Webhook struct {
// A unique ID for the webhook.
Id string `json:"id"`
// The URL that the webhook will request.
Url string `json:"url"`
// A secret used for generating an HMAC-SHA1 signature for the payload.
Secret string `json:"secret"`
// Whether or not the webhook is enabled.
Enabled bool `json:"enabled"`
// A sorted list of events that this webhook applies to.
Events []string `json:"events"`
// A sorted list of repository names that this webhook applies to.
Repos []string `json:"repos"`
}
// Return an HMAC-SHA1 signature of the payload using the hook's secret.
func (hook Webhook) SignPayload(payload []byte) string {
hmac := hmac.New(sha1.New, []byte(hook.Secret))
hmac.Write(payload)
return hex.EncodeToString(hmac.Sum(nil))
}
// Validate a hook.
func (hook Webhook) Validate(repos map[string]struct{}) error {
if len(hook.Events) == 0 {
return errors.New("Hook has no events.")
} else {
for _, event := range hook.Events {
if !events.IsValidEvent(event) {
return fmt.Errorf(`Invalid event: "%s".`, event)
}
}
}
if len(hook.Repos) == 0 {
return errors.New("Hook has no repositories.")
} else {
for _, repo := range hook.Repos {
if _, ok := repos[repo]; !ok {
return fmt.Errorf(`Invalid repository: "%s".`, repo)
}
}
}
url, err := url.Parse(hook.Url)
if err != nil {
return fmt.Errorf("Invalid URL: %s", err.Error())
}
if url.Scheme != "http" && url.Scheme != "https" {
return fmt.Errorf(`Invalid URL scheme "%s": only HTTP and HTTPS are supported.`,
url.Scheme)
}
if len(hook.Secret) < 20 {
return fmt.Errorf(`Secret is too short (%d bytes); secrets must be at least 20 bytes.`,
len(hook.Secret))
}
return nil
}