package main import ( "context" "encoding/json" "errors" "fmt" "github.com/enescakir/emoji" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "net/http" "os" "strings" "github.com/crowdsecurity/crowdsec/pkg/protobufs" "github.com/hashicorp/go-hclog" plugin "github.com/hashicorp/go-plugin" "gopkg.in/yaml.v2" ) var logger hclog.Logger = hclog.New(&hclog.LoggerOptions{ Name: "telegram-plugin", Level: hclog.LevelFromString("DEBUG"), Output: os.Stderr, JSONFormat: true, }) type PluginConfig struct { Name string `yaml:"name"` LogLevel *string `yaml:"log_level"` BotToken string `yaml:"bot_token"` ChannelID int64 `yaml:"channel_id"` } type TelegramPlugin struct { ConfigByName map[string]PluginConfig } type Datas struct { Message string `json:"message"` Image string `json:"image,omitempty"` Country string `json:"country,omitempty"` } func (n *TelegramPlugin) Configure(ctx context.Context, config *protobufs.Config) (*protobufs.Empty, error) { d := PluginConfig{} if err := yaml.Unmarshal(config.Config, &d); err != nil { return nil, err } n.ConfigByName[d.Name] = d return &protobufs.Empty{}, nil } func (n *TelegramPlugin) Notify(ctx context.Context, notification *protobufs.Notification) (*protobufs.Empty, error) { if _, ok := n.ConfigByName[notification.Name]; !ok { return nil, fmt.Errorf("invalid plugin config name %s", notification.Name) } cfg := n.ConfigByName[notification.Name] if cfg.LogLevel != nil && *cfg.LogLevel != "" { logger.SetLevel(hclog.LevelFromString(*cfg.LogLevel)) } else { logger.SetLevel(hclog.Info) } var datas []Datas err := json.Unmarshal([]byte(notification.Text), &datas) if err != nil { logger.Error(err.Error()) return nil, err } bot, err := tgbotapi.NewBotAPI(cfg.BotToken) if err != nil { logger.Error(err.Error()) return nil, err } //bot.Debug = true // ToDo alling with logger level logger.Info(fmt.Sprintf("Authorized on account %s", bot.Self.UserName)) for _, data := range datas { var flag emoji.Emoji if len(data.Country) != 0 { flag, err = emoji.CountryFlag(data.Country) } if len(data.Country) == 0 || err != nil { flag = emoji.PirateFlag } data.Message = strings.Replace(data.Message, ":flag:", string(flag), -1) data.Message = strings.Replace(data.Message, ".", "\\.", -1) data.Message = strings.Replace(data.Message, "-", "\\-", -1) var msg tgbotapi.Chattable if len(data.Image) != 0 { response, err := http.Get(data.Image) if err != nil { return nil, err } defer response.Body.Close() if response.StatusCode != 200 { return nil, errors.New("received non 200 response code for image") } tmpMsg := tgbotapi.NewPhoto(cfg.ChannelID, tgbotapi.FileReader{Name: "map.png", Reader: response.Body}) tmpMsg.Caption = data.Message tmpMsg.ParseMode = tgbotapi.ModeMarkdownV2 msg = tmpMsg } else { tmpMsg := tgbotapi.NewMessage(cfg.ChannelID, data.Message) tmpMsg.ParseMode = tgbotapi.ModeMarkdownV2 tmpMsg.DisableWebPagePreview = true msg = tmpMsg } _, err = bot.Send(msg) if err != nil { return nil, err } } return &protobufs.Empty{}, nil } func main() { var handshake = plugin.HandshakeConfig{ ProtocolVersion: 1, MagicCookieKey: "CROWDSEC_PLUGIN_KEY", MagicCookieValue: os.Getenv("CROWDSEC_PLUGIN_KEY"), } plugin.Serve(&plugin.ServeConfig{ HandshakeConfig: handshake, Plugins: map[string]plugin.Plugin{ "telegram": &protobufs.NotifierPlugin{ Impl: &TelegramPlugin{ConfigByName: make(map[string]PluginConfig)}, }, }, GRPCServer: plugin.DefaultGRPCServer, Logger: logger, }) }