83 lines
2.6 KiB
Go
83 lines
2.6 KiB
Go
package alert
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"hotalert/logging"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// DiscordWebhookAlerter is a struct that implements alerting on Discord via webhooks.
|
|
type DiscordWebhookAlerter struct {
|
|
// webhook is the Discord webhook URL.
|
|
webhook string
|
|
// messageTemplate is the message that is going to be posted when the alert conditions match.
|
|
messageTemplate string
|
|
// HttpClient is the http client used when executing requests.
|
|
HttpClient *http.Client
|
|
}
|
|
|
|
// DiscordWebhookAlerterOptions are the options for the DiscordWebhookAlerter
|
|
type DiscordWebhookAlerterOptions struct {
|
|
// Webhook is the discord webhook.
|
|
Webhook string `mapstructure:"webhook"`
|
|
// MessageTemplate is the message template that is going to be posted.
|
|
MessageTemplate string `mapstructure:"message"`
|
|
}
|
|
|
|
// Validate validates the DiscordWebhookAlerterOptions, returns an error on invalid options.
|
|
func (o *DiscordWebhookAlerterOptions) Validate() error {
|
|
if o.Webhook == "" || o.MessageTemplate == "" {
|
|
return errors.New("invalid configuration for webhook_discord")
|
|
}
|
|
if !strings.Contains(o.Webhook, "http://") && !strings.Contains(o.Webhook, "https://") {
|
|
return errors.New(fmt.Sprintf("invalid webhook schema for %s", o.Webhook))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewDiscordWebhookAlerter returns a new DiscordWebhookAlerter instance.
|
|
func NewDiscordWebhookAlerter(options DiscordWebhookAlerterOptions) (*DiscordWebhookAlerter, error) {
|
|
if err := options.Validate(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &DiscordWebhookAlerter{
|
|
webhook: options.Webhook,
|
|
messageTemplate: options.MessageTemplate,
|
|
HttpClient: http.DefaultClient,
|
|
}, nil
|
|
}
|
|
|
|
// PostAlert posts the alert on Discord via webhooks.
|
|
func (d *DiscordWebhookAlerter) PostAlert(ctx context.Context, matchedKeywords []string) {
|
|
alertMessage := strings.Replace(d.messageTemplate, "$keywords", strings.Join(matchedKeywords, ","), -1)
|
|
var postBody = map[string]interface{}{
|
|
"content": alertMessage,
|
|
"embeds": nil,
|
|
"attachments": nil,
|
|
}
|
|
|
|
postBodyBytes, err := json.Marshal(postBody)
|
|
if err != nil {
|
|
logging.SugaredLogger.Errorf("Failed to marshall postBody: %v", err)
|
|
return
|
|
}
|
|
|
|
postRequest, err := http.NewRequest("POST", d.webhook, bytes.NewBuffer(postBodyBytes))
|
|
if err != nil {
|
|
logging.SugaredLogger.Errorf("Failed to create alert request.")
|
|
return
|
|
}
|
|
postRequest.Header["Content-Type"] = []string{"application/json"}
|
|
_, err = d.HttpClient.Do(postRequest.WithContext(ctx))
|
|
if err != nil {
|
|
logging.SugaredLogger.Errorf("Failed to post alert to discord!")
|
|
return
|
|
}
|
|
logging.SugaredLogger.Infof("Alert posted:\nBEGIN\n%s\nEND", alertMessage)
|
|
}
|