From 43fb7aa0be85307db0537ac132c3dbebe8da3ea5 Mon Sep 17 00:00:00 2001 From: Yu-Hsin Yang <cindy02017@gmail.com> Date: Mon, 3 Jun 2024 21:46:02 +0200 Subject: [PATCH] Beautify webhook messages --- alert/alert.go | 95 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/alert/alert.go b/alert/alert.go index b748b04..f8ad6f7 100644 --- a/alert/alert.go +++ b/alert/alert.go @@ -13,9 +13,21 @@ import ( "time" ) +type Field struct { + Title string `json:"title"` + Value string `json:"value"` + Short bool `json:"short"` +} + +type Attachment struct { + Color string `json:"color"` + Fields []Field `json:"fields"` +} + // Payload struct to hold the JSON structure for our message type Payload struct { Text string `json:"text"` + Attachments []Attachment `json:"attachments,omitempty"` } type Config struct { @@ -33,11 +45,11 @@ type Canary struct { type HTTPCanary struct { Canary + UserAgent string RemoteIP string RemotePort uint16 LocalIP string LocalPort uint16 - UserAgent string FullUrl string Referer string } @@ -69,15 +81,14 @@ func Initialize(slackhook string, silenceSeconds uint16, doSyslog bool) { } // Send a slack message -func PostSlackHook(message string) { +func PostSlackHook(message string, attachments []Attachment) { if time.Since(lastNotifTime).Seconds() < float64(config.silenceSeconds) { lastNotifTime = time.Now() return } lastNotifTime = time.Now() - - toSend := fmt.Sprintf("TokenAlert `%s`", message) - payload := Payload{Text: toSend} + + payload := Payload{Text: message, Attachments: attachments} // Marshal the payload into JSON jsonData, err := json.Marshal(payload) @@ -110,35 +121,62 @@ func PostSlackHook(message string) { } // Format the canary alert message -func formatSlackMessage(canary interface{}) string { +func formatSlackMessage(canary interface{}, remoteIP string) (string, []Attachment) { v := reflect.ValueOf(canary) t := v.Type() - var message strings.Builder - message.WriteString("*Canary Alert*\n\n") - - for i := 0; i < v.NumField(); i++ { - field := v.Field(i) - typeField := t.Field(i) - if typeField.Name == "Canary" { - for j := 0; j < field.NumField(); j++ { - subField := field.Field(j) - subTypeField := field.Type().Field(j) - message.WriteString(fmt.Sprintf("*%s*: `%v`\n", subTypeField.Name, subField.Interface())) - } - } else { - message.WriteString(fmt.Sprintf("*%s*: `%v`\n", typeField.Name, field.Interface())) - } + // Choose color depending on the alert level + var color string + switch v.FieldByName("Level").Interface() { + case "low": + color = "#36a64f" + case "medium": + color = "#ffcc00" + case "high": + color = "#ff0000" + default: + color = "#000000" } - return message.String() + + + var message strings.Builder + + message.WriteString("**Canary Alert**") + + var fields []Field + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + typeField := t.Field(i) + if typeField.Name == "Canary" { + for j := 0; j < field.NumField(); j++ { + subField := field.Field(j) + subTypeField := field.Type().Field(j) + fields = append(fields, Field{Title: subTypeField.Name, Value: fmt.Sprintf("%v", subField.Interface()), Short: true}) + } + } else { + fields = append(fields, Field{Title: typeField.Name, Value: fmt.Sprintf("%v", field.Interface()), Short: true}) + } + } + + // Append the ipinfo URL + fields = append(fields, Field{Title: "CheckRemoteIPInfo", Value: fmt.Sprintf("http://ipinfo.io/%s", remoteIP)}) + + attachments := []Attachment{ + { + Color: color, + Fields: fields, + }, + } + + return message.String(), attachments } -func (h HTTPCanary) FormatSlackMessage() string { - return formatSlackMessage(h) +func (h HTTPCanary) FormatSlackMessage() (string, []Attachment){ + return formatSlackMessage(h, h.RemoteIP) } -func (d DNSCanary) FormatSlackMessage() string { - return formatSlackMessage(d) +func (d DNSCanary) FormatSlackMessage() (string, []Attachment) { + return formatSlackMessage(d, d.RemoteIP) } // Handler for HTTP canary alerts @@ -164,9 +202,6 @@ func HTTPAlert(canaryinfo HTTPCanary, alertType string) { } if alertType == "slack" || alertType == "all" { - //Slack alert if configured - // PostSlackHook(fmt.Sprintf("``` %+v ```", canaryinfo)) - // Slack alert if configured PostSlackHook(canaryinfo.FormatSlackMessage()) } @@ -192,8 +227,6 @@ func DNSAlert(canaryinfo DNSCanary, alertType string) { } if alertType == "slack" || alertType == "all" { - //Slack alert if configured - // PostSlackHook(fmt.Sprintf("``` %+v ```", canaryinfo)) // Slack alert if configured PostSlackHook(canaryinfo.FormatSlackMessage()) } -- GitLab