fix(security): harden TLS, timeouts, validation, logging, and token generation
- Default TLS verification on, opt-in UPKEEP_INSECURE_SKIP_VERIFY - Alert webhooks use 10s timeout client, close response bodies - URL input validates http/https scheme for HTTP monitors - Stdlib logs route to stderr instead of discard - Panic on crypto/rand failure in token generation - Cluster startup warnings for non-HTTPS and missing secret - Replace demo SMTP creds with obvious placeholders - Color-coded log entries and scroll hints in logs tab
This commit is contained in:
+29
-9
@@ -7,8 +7,11 @@ import (
|
||||
"go-upkeep/internal/models"
|
||||
"net/http"
|
||||
"net/smtp"
|
||||
"time"
|
||||
)
|
||||
|
||||
var alertClient = &http.Client{Timeout: 10 * time.Second}
|
||||
|
||||
type Provider interface {
|
||||
Send(title, message string) error
|
||||
}
|
||||
@@ -24,7 +27,9 @@ func GetProvider(cfg models.AlertConfig) Provider {
|
||||
return &WebhookProvider{URL: cfg.Settings["url"]}
|
||||
case "email":
|
||||
port := "25"
|
||||
if p, ok := cfg.Settings["port"]; ok { port = p }
|
||||
if p, ok := cfg.Settings["port"]; ok {
|
||||
port = p
|
||||
}
|
||||
return &EmailProvider{
|
||||
Host: cfg.Settings["host"],
|
||||
Port: port,
|
||||
@@ -40,40 +45,55 @@ func GetProvider(cfg models.AlertConfig) Provider {
|
||||
|
||||
// --- DISCORD ---
|
||||
type DiscordProvider struct{ URL string }
|
||||
|
||||
func (d *DiscordProvider) Send(title, message string) error {
|
||||
payload := map[string]string{"content": fmt.Sprintf("**%s**\n%s", title, message)}
|
||||
jsonValue, _ := json.Marshal(payload)
|
||||
_, err := http.Post(d.URL, "application/json", bytes.NewBuffer(jsonValue))
|
||||
return err
|
||||
resp, err := alertClient.Post(d.URL, "application/json", bytes.NewBuffer(jsonValue))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- SLACK ---
|
||||
type SlackProvider struct{ URL string }
|
||||
|
||||
func (s *SlackProvider) Send(title, message string) error {
|
||||
payload := map[string]string{"text": fmt.Sprintf("*%s*\n%s", title, message)}
|
||||
jsonValue, _ := json.Marshal(payload)
|
||||
_, err := http.Post(s.URL, "application/json", bytes.NewBuffer(jsonValue))
|
||||
return err
|
||||
resp, err := alertClient.Post(s.URL, "application/json", bytes.NewBuffer(jsonValue))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- GENERIC WEBHOOK ---
|
||||
type WebhookProvider struct{ URL string }
|
||||
|
||||
func (w *WebhookProvider) Send(title, message string) error {
|
||||
// Sends a standard JSON payload
|
||||
payload := map[string]string{
|
||||
"title": title,
|
||||
"message": message,
|
||||
"status": "alert",
|
||||
}
|
||||
jsonValue, _ := json.Marshal(payload)
|
||||
_, err := http.Post(w.URL, "application/json", bytes.NewBuffer(jsonValue))
|
||||
return err
|
||||
resp, err := alertClient.Post(w.URL, "application/json", bytes.NewBuffer(jsonValue))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- EMAIL ---
|
||||
type EmailProvider struct {
|
||||
Host, Port, User, Pass, To, From string
|
||||
}
|
||||
|
||||
func (e *EmailProvider) Send(title, message string) error {
|
||||
auth := smtp.PlainAuth("", e.User, e.Pass, e.Host)
|
||||
msg := []byte("To: " + e.To + "\r\n" +
|
||||
@@ -81,4 +101,4 @@ func (e *EmailProvider) Send(title, message string) error {
|
||||
"\r\n" +
|
||||
message + "\r\n")
|
||||
return smtp.SendMail(e.Host+":"+e.Port, auth, e.From, []string{e.To}, msg)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user