github.com/crowdsecurity/crowdsec@v1.6.1/cmd/notification-email/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "time" 8 9 "github.com/crowdsecurity/crowdsec/pkg/protobufs" 10 "github.com/hashicorp/go-hclog" 11 plugin "github.com/hashicorp/go-plugin" 12 mail "github.com/xhit/go-simple-mail/v2" 13 "gopkg.in/yaml.v2" 14 ) 15 16 var baseLogger hclog.Logger = hclog.New(&hclog.LoggerOptions{ 17 Name: "email-plugin", 18 Level: hclog.LevelFromString("INFO"), 19 Output: os.Stderr, 20 JSONFormat: true, 21 }) 22 23 var AuthStringToType map[string]mail.AuthType = map[string]mail.AuthType{ 24 "none": mail.AuthNone, 25 "crammd5": mail.AuthCRAMMD5, 26 "login": mail.AuthLogin, 27 "plain": mail.AuthPlain, 28 } 29 30 var EncryptionStringToType map[string]mail.Encryption = map[string]mail.Encryption{ 31 "ssltls": mail.EncryptionSSLTLS, 32 "starttls": mail.EncryptionSTARTTLS, 33 "none": mail.EncryptionNone, 34 } 35 36 type PluginConfig struct { 37 Name string `yaml:"name"` 38 LogLevel *string `yaml:"log_level"` 39 40 SMTPHost string `yaml:"smtp_host"` 41 SMTPPort int `yaml:"smtp_port"` 42 SMTPUsername string `yaml:"smtp_username"` 43 SMTPPassword string `yaml:"smtp_password"` 44 SenderEmail string `yaml:"sender_email"` 45 SenderName string `yaml:"sender_name"` 46 ReceiverEmails []string `yaml:"receiver_emails"` 47 EmailSubject string `yaml:"email_subject"` 48 EncryptionType string `yaml:"encryption_type"` 49 AuthType string `yaml:"auth_type"` 50 HeloHost string `yaml:"helo_host"` 51 ConnectTimeout string `yaml:"connect_timeout"` 52 SendTimeout string `yaml:"send_timeout"` 53 } 54 55 type EmailPlugin struct { 56 ConfigByName map[string]PluginConfig 57 } 58 59 func (n *EmailPlugin) Configure(ctx context.Context, config *protobufs.Config) (*protobufs.Empty, error) { 60 d := PluginConfig{ 61 SMTPPort: 25, 62 SenderName: "Crowdsec", 63 EmailSubject: "Crowdsec notification", 64 EncryptionType: "ssltls", 65 AuthType: "login", 66 SenderEmail: "crowdsec@crowdsec.local", 67 HeloHost: "localhost", 68 } 69 70 if err := yaml.Unmarshal(config.Config, &d); err != nil { 71 return nil, err 72 } 73 74 if d.Name == "" { 75 return nil, fmt.Errorf("name is required") 76 } 77 78 if d.SMTPHost == "" { 79 return nil, fmt.Errorf("SMTP host is not set") 80 } 81 82 if d.ReceiverEmails == nil || len(d.ReceiverEmails) == 0 { 83 return nil, fmt.Errorf("receiver emails are not set") 84 } 85 86 n.ConfigByName[d.Name] = d 87 baseLogger.Debug(fmt.Sprintf("Email plugin '%s' use SMTP host '%s:%d'", d.Name, d.SMTPHost, d.SMTPPort)) 88 return &protobufs.Empty{}, nil 89 } 90 91 func (n *EmailPlugin) Notify(ctx context.Context, notification *protobufs.Notification) (*protobufs.Empty, error) { 92 if _, ok := n.ConfigByName[notification.Name]; !ok { 93 return nil, fmt.Errorf("invalid plugin config name %s", notification.Name) 94 } 95 cfg := n.ConfigByName[notification.Name] 96 97 logger := baseLogger.Named(cfg.Name) 98 99 if cfg.LogLevel != nil && *cfg.LogLevel != "" { 100 logger.SetLevel(hclog.LevelFromString(*cfg.LogLevel)) 101 } 102 103 logger.Debug("got notification") 104 105 server := mail.NewSMTPClient() 106 server.Host = cfg.SMTPHost 107 server.Port = cfg.SMTPPort 108 server.Username = cfg.SMTPUsername 109 server.Password = cfg.SMTPPassword 110 server.Encryption = EncryptionStringToType[cfg.EncryptionType] 111 server.Authentication = AuthStringToType[cfg.AuthType] 112 server.Helo = cfg.HeloHost 113 114 var err error 115 116 if cfg.ConnectTimeout != "" { 117 server.ConnectTimeout, err = time.ParseDuration(cfg.ConnectTimeout) 118 if err != nil { 119 logger.Warn(fmt.Sprintf("invalid connect timeout '%s', using default '10s'", cfg.ConnectTimeout)) 120 server.ConnectTimeout = 10 * time.Second 121 } 122 } 123 124 if cfg.SendTimeout != "" { 125 server.SendTimeout, err = time.ParseDuration(cfg.SendTimeout) 126 if err != nil { 127 logger.Warn(fmt.Sprintf("invalid send timeout '%s', using default '10s'", cfg.SendTimeout)) 128 server.SendTimeout = 10 * time.Second 129 } 130 } 131 132 logger.Debug("making smtp connection") 133 smtpClient, err := server.Connect() 134 if err != nil { 135 return &protobufs.Empty{}, err 136 } 137 logger.Debug("smtp connection done") 138 139 email := mail.NewMSG() 140 email.SetFrom(fmt.Sprintf("%s <%s>", cfg.SenderName, cfg.SenderEmail)). 141 AddTo(cfg.ReceiverEmails...). 142 SetSubject(cfg.EmailSubject) 143 email.SetBody(mail.TextHTML, notification.Text) 144 145 err = email.Send(smtpClient) 146 if err != nil { 147 return &protobufs.Empty{}, err 148 } 149 logger.Info(fmt.Sprintf("sent email to %v", cfg.ReceiverEmails)) 150 return &protobufs.Empty{}, nil 151 } 152 153 func main() { 154 var handshake = plugin.HandshakeConfig{ 155 ProtocolVersion: 1, 156 MagicCookieKey: "CROWDSEC_PLUGIN_KEY", 157 MagicCookieValue: os.Getenv("CROWDSEC_PLUGIN_KEY"), 158 } 159 160 plugin.Serve(&plugin.ServeConfig{ 161 HandshakeConfig: handshake, 162 Plugins: map[string]plugin.Plugin{ 163 "email": &protobufs.NotifierPlugin{ 164 Impl: &EmailPlugin{ConfigByName: make(map[string]PluginConfig)}, 165 }, 166 }, 167 GRPCServer: plugin.DefaultGRPCServer, 168 Logger: baseLogger, 169 }) 170 }