/
artifactory_webhook.go
120 lines (103 loc) · 3.05 KB
/
artifactory_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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package artifactory
import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/gorilla/mux"
"github.com/influxdata/telegraf"
)
type ArtifactoryWebhook struct {
Path string
Secret string
acc telegraf.Accumulator
log telegraf.Logger
}
func (awh *ArtifactoryWebhook) Register(router *mux.Router, acc telegraf.Accumulator, log telegraf.Logger) {
router.HandleFunc(awh.Path, awh.eventHandler).Methods("POST")
awh.log = log
awh.log.Infof("Started webhooks_artifactory on %s", awh.Path)
awh.acc = acc
}
func (awh *ArtifactoryWebhook) eventHandler(rw http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
rw.WriteHeader(http.StatusBadRequest)
return
}
if awh.Secret != "" && !checkSignature(awh.Secret, data, r.Header.Get("x-jfrog-event-auth")) {
awh.log.Error("Failed to check the artifactory webhook auth signature")
rw.WriteHeader(http.StatusBadRequest)
return
}
bodyFields := make(map[string]interface{})
err = json.Unmarshal(data, &bodyFields)
if err != nil {
rw.WriteHeader(http.StatusBadRequest)
}
et := fmt.Sprintf("%v", bodyFields["event_type"])
ed := fmt.Sprintf("%v", bodyFields["domain"])
ne, err := awh.NewEvent(data, et, ed)
if err != nil {
rw.WriteHeader(http.StatusBadRequest)
}
if ne != nil {
nm := ne.NewMetric()
awh.acc.AddFields("artifactory_webhooks", nm.Fields(), nm.Tags(), nm.Time())
}
rw.WriteHeader(http.StatusOK)
}
type newEventError struct {
s string
}
func (e *newEventError) Error() string {
return e.s
}
func (awh *ArtifactoryWebhook) NewEvent(data []byte, et string, ed string) (Event, error) {
awh.log.Debugf("New %v domain %v event received", ed, et)
switch ed {
case "artifact":
if et == "deployed" || et == "deleted" {
return generateEvent(data, &ArtifactDeploymentOrDeletedEvent{})
} else if et == "moved" || et == "copied" {
return generateEvent(data, &ArtifactMovedOrCopiedEvent{})
} else {
return nil, &newEventError{"Not a recognized event type"}
}
case "artifact_property":
return generateEvent(data, &ArtifactPropertiesEvent{})
case "docker":
return generateEvent(data, &DockerEvent{})
case "build":
return generateEvent(data, &BuildEvent{})
case "release_bundle":
return generateEvent(data, &ReleaseBundleEvent{})
case "distribution":
return generateEvent(data, &DistributionEvent{})
case "destination":
return generateEvent(data, &DestinationEvent{})
}
return nil, &newEventError{"Not a recognized event type"}
}
func generateEvent(data []byte, event Event) (Event, error) {
err := json.Unmarshal(data, event)
if err != nil {
return nil, err
}
return event, nil
}
func checkSignature(secret string, data []byte, signature string) bool {
return hmac.Equal([]byte(signature), []byte(generateSignature(secret, data)))
}
func generateSignature(secret string, data []byte) string {
mac := hmac.New(sha1.New, []byte(secret))
if _, err := mac.Write(data); err != nil {
return err.Error()
}
result := mac.Sum(nil)
return "sha1=" + hex.EncodeToString(result)
}