Skip to content

Commit 35d3b74

Browse files
authored
Merge pull request #66 from moonD4rk/feat/telegram
feat: Add support for Telegram push notifications
2 parents 91e231b + 9466bcb commit 35d3b74

File tree

5 files changed

+129
-1
lines changed

5 files changed

+129
-1
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ Docker 方式推荐使用环境变量来配置服务参数
5252
| `SERVERCHAN_KEY ` | Server酱的 `SCKEY` | |
5353
| `WEBHOOK_URL` | 自定义 webhook 服务的完整 url | |
5454
| `BARK_URL` | Bark 服务的完整 url, 路径需要包含 DeviceKey | |
55+
| `TELEGRAM_BOT_TOKEN` | Telegram Bot Token | |
56+
| `TELEGRAM_CHAT_IDS` | Telegram Bot 需要发送给的 chat 列表,使用 `,` 分割 | |
5557
| `SOURCES` | 启用哪些漏洞信息源,逗号分隔, 可选 `avd`, `ti`, `oscs`, `seebug`,`threatbook`,`struts2` | `avd,ti,oscs,threatbook,seebug,struts2` |
5658
| `INTERVAL` | 检查周期,支持秒 `60s`, 分钟 `10m`, 小时 `1h`, 最低 `1m` | `30m` |
5759
| `ENABLE_CVE_FILTER` | 启用 CVE 过滤,开启后多个数据源的统一 CVE 将只推送一次 | `true` |
@@ -172,6 +174,8 @@ GLOBAL OPTIONS:
172174
--lark-access-token value, --lt value webhook access token of lark
173175
--lark-sign-secret value, --ls value sign secret of lark
174176
--serverchan-key value, --sk value send key for server chan
177+
--telegram-bot-token value, --tgtk value telegram bot token, ex: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
178+
--telegram-chat-ids value, --tgids value chat ids want to send on telegram, ex: 123456,4312341,123123
175179
--webhook-url value, --webhook value your webhook server url, ex: http://127.0.0.1:1111/webhook
176180
--wechatwork-key value, --wk value webhook key of wechat work
177181

go.mod

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ require (
99
github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d
1010
github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c
1111
github.com/go-sql-driver/mysql v1.7.1
12+
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
1213
github.com/google/go-github/v53 v53.2.0
14+
github.com/hashicorp/go-multierror v1.1.1
1315
github.com/imroc/req/v3 v3.42.2
1416
github.com/jackc/pgx/v5 v5.5.1
1517
github.com/kataras/golog v0.1.8
@@ -46,7 +48,6 @@ require (
4648
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e // indirect
4749
github.com/google/uuid v1.5.0 // indirect
4850
github.com/hashicorp/errwrap v1.1.0 // indirect
49-
github.com/hashicorp/go-multierror v1.1.1 // indirect
5051
github.com/hashicorp/hcl/v2 v2.16.2 // indirect
5152
github.com/jackc/pgpassfile v1.0.0 // indirect
5253
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
@@ -68,6 +69,7 @@ require (
6869
github.com/refraction-networking/utls v1.6.0 // indirect
6970
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
7071
github.com/russross/blackfriday/v2 v2.1.0 // indirect
72+
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
7173
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
7274
github.com/zclconf/go-cty v1.13.1 // indirect
7375
go.uber.org/mock v0.3.0 // indirect

go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrt
5454
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
5555
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
5656
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
57+
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
58+
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
5759
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
5860
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
5961
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -158,6 +160,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
158160
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
159161
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
160162
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
163+
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
164+
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
161165
github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
162166
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
163167
github.com/vimsucks/wxwork-bot-go v0.0.0-20221213061339-fcbcd88ede1c h1:gyl9LgDfFBpVSbAY816tU/nhDuSHMa0tXoleQrIJyE8=

main.go

+29
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/kataras/golog"
1414
"github.com/pkg/errors"
1515
"github.com/urfave/cli/v2"
16+
1617
"github.com/zema1/watchvuln/push"
1718
)
1819

@@ -88,6 +89,18 @@ func main() {
8889
Usage: "your bark server url, ex: http://127.0.0.1:1111/DeviceKey",
8990
Category: "[\x00Push Options]",
9091
},
92+
&cli.StringFlag{
93+
Name: "telegram-bot-token",
94+
Aliases: []string{"tgtk"},
95+
Usage: "telegram bot token, ex: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
96+
Category: "[\x00Push Options]",
97+
},
98+
&cli.StringFlag{
99+
Name: "telegram-chat-ids",
100+
Aliases: []string{"tgids"},
101+
Usage: "chat ids want to send on telegram, ex: 123456,4312341,123123",
102+
Category: "[\x00Push Options]",
103+
},
91104
&cli.StringFlag{
92105
Name: "db-conn",
93106
Aliases: []string{"db"},
@@ -256,6 +269,8 @@ func initPusher(c *cli.Context) (push.TextPusher, push.RawPusher, error) {
256269
larkToken := c.String("lark-access-token")
257270
larkSecret := c.String("lark-sign-secret")
258271
serverChanKey := c.String("serverchan-key")
272+
telegramBotTokey := c.String("telegram-bot-token")
273+
telegramChatIDs := c.String("telegram-chat-ids")
259274

260275
if os.Getenv("DINGDING_ACCESS_TOKEN") != "" {
261276
dingToken = os.Getenv("DINGDING_ACCESS_TOKEN")
@@ -281,6 +296,13 @@ func initPusher(c *cli.Context) (push.TextPusher, push.RawPusher, error) {
281296
if os.Getenv("SERVERCHAN_KEY") != "" {
282297
serverChanKey = os.Getenv("SERVERCHAN_KEY")
283298
}
299+
if os.Getenv("TELEGRAM_BOT_TOKEN") != "" {
300+
telegramBotTokey = os.Getenv("TELEGRAM_BOT_TOKEN")
301+
}
302+
if os.Getenv("TELEGRAM_CHAT_IDS") != "" {
303+
telegramChatIDs = os.Getenv("TELEGRAM_CHAT_IDS")
304+
}
305+
284306
var textPusher []push.TextPusher
285307
var rawPusher []push.RawPusher
286308
if dingToken != "" && dingSecret != "" {
@@ -304,6 +326,13 @@ func initPusher(c *cli.Context) (push.TextPusher, push.RawPusher, error) {
304326
if serverChanKey != "" {
305327
textPusher = append(textPusher, push.NewServerChan(serverChanKey))
306328
}
329+
if telegramBotTokey != "" && telegramChatIDs != "" {
330+
tgPusher, err := push.NewTelegram(telegramBotTokey, telegramChatIDs)
331+
if err != nil {
332+
return nil, nil, fmt.Errorf("init telegram error %w", err)
333+
}
334+
textPusher = append(textPusher, tgPusher)
335+
}
307336
if len(textPusher) == 0 && len(rawPusher) == 0 {
308337
msg := `
309338
you must setup a pusher, eg:

push/telegram.go

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package push
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"strings"
7+
8+
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
9+
"github.com/kataras/golog"
10+
)
11+
12+
var _ = TextPusher(&Telegram{})
13+
14+
type Telegram struct {
15+
APIToken string
16+
log *golog.Logger
17+
client *tgbotapi.BotAPI
18+
chatIDs []int64
19+
}
20+
21+
// NewTelegram creates a new Telegram pusher, it requires a token and a list of chatIDs
22+
// separated by comma. eg "123456,4312341,123123"
23+
func NewTelegram(token string, chatIDs string) (*Telegram, error) {
24+
bot, err := tgbotapi.NewBotAPI(token)
25+
if err != nil {
26+
return nil, fmt.Errorf("NewTelegram NewBotAPI failed: %w", err)
27+
}
28+
ids, err := convertChatIDs(chatIDs)
29+
if err != nil {
30+
return nil, fmt.Errorf("NewTelegram convertChatIDs failed: %w", err)
31+
}
32+
return &Telegram{
33+
APIToken: token,
34+
log: golog.Child("[telegram]"),
35+
client: bot,
36+
chatIDs: ids,
37+
}, nil
38+
}
39+
40+
func convertChatIDs(rawIDs string) ([]int64, error) {
41+
ids := strings.Split(rawIDs, ",")
42+
var chatIDs []int64
43+
for _, id := range ids {
44+
chatID := strings.TrimSpace(id)
45+
if chatID == "" {
46+
continue
47+
}
48+
// convert string to int64
49+
id64, err := strconv.ParseInt(chatID, 10, 64)
50+
if err != nil {
51+
return nil, fmt.Errorf("failed to convert chatID %q to int64: %w", id, err)
52+
}
53+
chatIDs = append(chatIDs, id64)
54+
}
55+
if len(chatIDs) == 0 {
56+
return nil, fmt.Errorf("no valid chatIDs found")
57+
}
58+
return chatIDs, nil
59+
}
60+
61+
func (t *Telegram) PushText(content string) error {
62+
msg := tgbotapi.NewMessage(0, content)
63+
msg.ParseMode = tgbotapi.ModeHTML
64+
65+
for _, chatID := range t.chatIDs {
66+
msg.ChatID = chatID
67+
_, err := t.client.Send(msg)
68+
if err != nil {
69+
return fmt.Errorf("failed to send message to Telegram chat %q err %w", chatID, err)
70+
}
71+
}
72+
return nil
73+
}
74+
75+
func (t *Telegram) PushMarkdown(title, content string) error {
76+
fullMessage := title + "\n" + content // Treating subject as message title
77+
78+
msg := tgbotapi.NewMessage(0, fullMessage)
79+
msg.ParseMode = tgbotapi.ModeMarkdown
80+
81+
for _, chatID := range t.chatIDs {
82+
msg.ChatID = chatID
83+
_, err := t.client.Send(msg)
84+
if err != nil {
85+
return fmt.Errorf("failed to send message to Telegram chat %q err %w", chatID, err)
86+
}
87+
}
88+
return nil
89+
}

0 commit comments

Comments
 (0)