44 "context"
55 "encoding/json"
66 "fmt"
7+ "html"
78 "io"
89 "net/http"
910 "os"
@@ -21,6 +22,33 @@ import (
2122 "github.com/Matrix86/driplane/data"
2223)
2324
25+ // telegramTemplateFuncs returns sprig's funcs plus telegram-specific helpers.
26+ //
27+ // Extra funcs:
28+ // - htmlEscape: escapes <, >, &, " for Telegram HTML parse_mode.
29+ // - mdv2Escape: escapes the MarkdownV2 reserved set (_*[]()~`>#+-=|{}.!).
30+ func telegramTemplateFuncs () template.FuncMap {
31+ fm := sprig .FuncMap ()
32+ fm ["htmlEscape" ] = html .EscapeString
33+ fm ["mdv2Escape" ] = escapeMarkdownV2
34+ return fm
35+ }
36+
37+ // escapeMarkdownV2 escapes every reserved character defined by Telegram's
38+ // MarkdownV2 parse_mode. See https://core.telegram.org/bots/api#markdownv2-style
39+ func escapeMarkdownV2 (s string ) string {
40+ const reserved = "_*[]()~`>#+-=|{}.!"
41+ var b strings.Builder
42+ b .Grow (len (s ))
43+ for _ , r := range s {
44+ if strings .ContainsRune (reserved , r ) {
45+ b .WriteByte ('\\' )
46+ }
47+ b .WriteRune (r )
48+ }
49+ return b .String ()
50+ }
51+
2452// TelegramBot is a Filter to perform Bot API actions on top of the telegrambot feeder.
2553type TelegramBot struct {
2654 Base
@@ -109,7 +137,7 @@ func (f *TelegramBot) compileTemplates() error {
109137 if ! ok || v == "" {
110138 continue
111139 }
112- tpl , err := template .New ("telegrambot:" + e .key ).Funcs (sprig . FuncMap ()).Parse (v )
140+ tpl , err := template .New ("telegrambot:" + e .key ).Funcs (telegramTemplateFuncs ()).Parse (v )
113141 if err != nil {
114142 return fmt .Errorf ("telegrambot: invalid template for %q: %w" , e .key , err )
115143 }
@@ -407,26 +435,28 @@ func (f *TelegramBot) doEditMessage(ctx context.Context, b *bot.Bot, msg *data.M
407435}
408436
409437func (f * TelegramBot ) doDeleteMessage (ctx context.Context , b * bot.Bot , msg * data.Message ) bool {
410- chatID , ok := f .resolveChatID (msg )
411- if ! ok { return false }
412-
413- msgIDStr , err := msg .ApplyPlaceholder (f .messageID )
414- if err != nil {
415- log .Error ("[%s::%s] telegrambot: render message_id: %s" , f .Rule (), f .Name (), err )
416- return false
417- }
418- msgID , err := strconv .Atoi (strings .TrimSpace (msgIDStr ))
419- if err != nil {
420- log .Error ("[%s::%s] telegrambot: parse message_id: %s" , f .Rule (), f .Name (), err )
421- return false
422- }
423-
424- if _ , err := b .DeleteMessage (ctx , & bot.DeleteMessageParams {ChatID : chatID , MessageID : msgID }); err != nil {
425- log .Error ("[%s::%s] telegrambot: deleteMessage failed: %s" , f .Rule (), f .Name (), err )
426- return false
427- }
428- msg .SetTarget ("delete_success" , "true" )
429- return true
438+ chatID , ok := f .resolveChatID (msg )
439+ if ! ok {
440+ return false
441+ }
442+
443+ msgIDStr , err := msg .ApplyPlaceholder (f .messageID )
444+ if err != nil {
445+ log .Error ("[%s::%s] telegrambot: render message_id: %s" , f .Rule (), f .Name (), err )
446+ return false
447+ }
448+ msgID , err := strconv .Atoi (strings .TrimSpace (msgIDStr ))
449+ if err != nil {
450+ log .Error ("[%s::%s] telegrambot: parse message_id: %s" , f .Rule (), f .Name (), err )
451+ return false
452+ }
453+
454+ if _ , err := b .DeleteMessage (ctx , & bot.DeleteMessageParams {ChatID : chatID , MessageID : msgID }); err != nil {
455+ log .Error ("[%s::%s] telegrambot: deleteMessage failed: %s" , f .Rule (), f .Name (), err )
456+ return false
457+ }
458+ msg .SetTarget ("delete_success" , "true" )
459+ return true
430460}
431461
432462func (f * TelegramBot ) doAnswerCallback (ctx context.Context , b * bot.Bot , msg * data.Message ) bool {
0 commit comments