Initial commit

This commit is contained in:
Ethanell 2022-02-11 14:09:02 +01:00
commit 9f78f7a655
5 changed files with 1231 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
notification-telegram
.idea/

34
Makefile Normal file
View file

@ -0,0 +1,34 @@
# Go parameters
GOCMD=go
GOBUILD=$(GOCMD) build
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOGET=$(GOCMD) get
LD_OPTS_STATIC=-ldflags "-s -w -extldflags '-static'"
BINARY_NAME=notification-telegram
clean:
@$(RM) "$(BINARY_NAME)"
build: clean
$(GOBUILD) $(LD_OPTS_STATIC) -o $(BINARY_NAME) -a -tags netgo
deploy: build
cp $(BINARY_NAME) /usr/local/lib/crowdsec/plugins/
chown root:root /usr/local/lib/crowdsec/plugins/$(BINARY_NAME)
systemctl restart crowdsec
docker-deploy: build
docker cp $(BINARY_NAME) crowdsec:/usr/local/lib/crowdsec/plugins/
docker exec crowdsec chown root:root /usr/local/lib/crowdsec/plugins/$(BINARY_NAME)
docker restart crowdsec
test: deploy
while ! cscli decisions delete --ip 1.2.3.4 --debug; do continue; done
cscli decisions add --ip 1.2.3.4 --debug
cscli decisions delete --ip 1.2.3.4 --debug
docker-test: docker-deploy
while ! docker exec crowdsec cscli decisions delete --ip 1.2.3.4 --debug; do continue; done
docker exec crowdsec cscli decisions add --ip 1.2.3.4 --debug
docker exec crowdsec cscli decisions delete --ip 1.2.3.4 --debug

32
go.mod Normal file
View file

@ -0,0 +1,32 @@
module crowdsec-notification-telegram
go 1.17
require (
github.com/crowdsecurity/crowdsec v1.3.0
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
github.com/hashicorp/go-hclog v1.1.0
github.com/hashicorp/go-plugin v1.4.3
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/enescakir/emoji v1.0.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f // indirect
google.golang.org/grpc v1.35.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)

1018
go.sum Normal file

File diff suppressed because it is too large Load diff

144
main.go Normal file
View file

@ -0,0 +1,144 @@
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,
})
}