Initial commit
This commit is contained in:
commit
9f78f7a655
5 changed files with 1231 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
notification-telegram
|
||||
.idea/
|
||||
|
34
Makefile
Normal file
34
Makefile
Normal 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
32
go.mod
Normal 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
|
||||
)
|
144
main.go
Normal file
144
main.go
Normal 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,
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue