package alert // Copyright (c) 2025 Robert Strutts // License: MIT // GIT: https://git.mysnippetsofcode.com/bobs/execguard import ( "execguard/core/sys_database" "execguard/core/configure" "database/sql" "log" "os" "os/exec" "time" "context" "strings" ) var ( config configure.Config mailPath string ) func SetGlobalConfig(c configure.Config) { config = c } func SetGlobalMail(m string) { mailPath = m } func SendAlert(message string, db *sql.DB, log *log.Logger) { if config.AlertEmail == "" { return } if !sys_database.IsAllowed(db, log, mailPath) { log.Printf("%s not allowed...blocked email, sorry.", mailPath) return // Prevent system crash! } if _, err := os.Stat(mailPath); err != nil { log.Printf("Mail command not found: %v", err) return } time.Sleep(time.Duration(300) * time.Millisecond) // Must give time for Block to get over with... ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() // Ensure the context is canceled to avoid leaks cmd := exec.CommandContext(ctx, mailPath, "-s", "ExecGuard Alert", config.AlertEmail) cmd.Env = []string{"PATH=/usr/bin:/bin"} // Set a minimal PATH cmd.Stdin = strings.NewReader(message) output, err := cmd.CombinedOutput() if ctx.Err() == context.DeadlineExceeded { log.Printf("sendAlert timeout after 15s for message: %q", message) } if err != nil { log.Printf("Failed to send alert: %v, output: %s", err, output) } }