package main import ( "bytes" "fmt" "net/smtp" "text/template" "github.com/jordan-wright/email" "gorm.io/gorm" ) type EmailTemplate struct { Subject string Body string } var emailTemplates = map[string]EmailTemplate{ "peer_created": { Subject: "New Peer Created: {{.Peer.IP}}", Body: "Peer {{.Peer.IP}} was created on server {{.Server.Name}}.\nPublic Key: {{.Peer.PublicKey}}", }, "peer_deleted": { Subject: "Peer Deleted: {{.Peer.IP}}", Body: "Peer {{.Peer.IP}} was deleted from server {{.Server.Name}}.", }, "policy_changed": { Subject: "Policy Updated for {{.Peer.IP}}", Body: "Policy updated for peer {{.Peer.IP}} on server {{.Server.Name}}.\nChanges: {{range .Policy.Changes}}{{.}} {{end}}", }, } func GetSMTPSettings() (settings SMTPSettings, err error) { err = db.First(&settings).Error if err == gorm.ErrRecordNotFound { return SMTPSettings{}, nil } return } func SaveSMTPSettings(settings SMTPSettings) error { var existing SMTPSettings if err := db.First(&existing).Error; err == gorm.ErrRecordNotFound { return db.Create(&settings).Error } return db.Model(&existing).Updates(settings).Error } func SendEmail(to, templateName string, data map[string]interface{}) error { settings, err := GetSMTPSettings() if err != nil { return err } if !settings.Enabled { return fmt.Errorf("SMTP is disabled") } template, ok := emailTemplates[templateName] if !ok { return fmt.Errorf("template %s not found", templateName) } subject, err := renderTemplate(template.Subject, data) if err != nil { return err } body, err := renderTemplate(template.Body, data) if err != nil { return err } e := email.NewEmail() e.From = fmt.Sprintf("%s <%s>", settings.FromName, settings.FromEmail) e.To = []string{to} e.Subject = subject e.Text = []byte(body) addr := fmt.Sprintf("%s:%d", settings.Server, settings.Port) if settings.UseAuth { return e.Send(addr, smtp.PlainAuth("", settings.Username, settings.Password, settings.Server)) } return e.Send(addr, nil) } func TestSMTP(settings SMTPSettings) error { e := email.NewEmail() e.From = fmt.Sprintf("%s <%s>", settings.FromName, settings.FromEmail) e.To = []string{settings.FromEmail} e.Subject = "WGRplane SMTP Test" e.Text = []byte("This is a test email from WGRplane.") addr := fmt.Sprintf("%s:%d", settings.Server, settings.Port) if settings.UseAuth { return e.Send(addr, smtp.PlainAuth("", settings.Username, settings.Password, settings.Server)) } return e.Send(addr, nil) } func renderTemplate(tmpl string, data map[string]interface{}) (string, error) { t, err := template.New("email").Parse(tmpl) if err != nil { return "", err } var buf bytes.Buffer if err := t.Execute(&buf, data); err != nil { return "", err } return buf.String(), nil } func NotifyPeerCreated(server *Server, peer *Peer) error { data := map[string]interface{}{ "Server": server, "Peer": peer, } return SendEmail(server.Endpoint, "peer_created", data) } func NotifyPeerDeleted(server *Server, peer *Peer) error { data := map[string]interface{}{ "Server": server, "Peer": peer, } return SendEmail(server.Endpoint, "peer_deleted", data) } func NotifyPolicyChanged(server *Server, peer *Peer, changes []string) error { data := map[string]interface{}{ "Server": server, "Peer": peer, "Policy": Policy{Action: "updated", Changes: changes}, } return SendEmail(server.Endpoint, "policy_changed", data) }