From cdff7c4edaf588150ade11a6da971b5871342252 Mon Sep 17 00:00:00 2001 From: Ashok <114943948+AshokShau@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:40:42 +0530 Subject: [PATCH] fix: add Sanitize HTML in inline query responses (#1) * fix * Update README.md --- .github/README.md | 7 ++++--- Telegram/modules/inline.go | 38 ++++++++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/README.md b/.github/README.md index bcc7eef..25040aa 100644 --- a/.github/README.md +++ b/.github/README.md @@ -103,6 +103,7 @@ This project is licensed under the MIT License—see the [LICENSE](/LICENSE) fil [![Telegram](https://img.shields.io/badge/Telegram-Chat-blue.svg)](https://t.me/AshokShau) -## Thanks -- [Ashok Shau](https://github.com/AshokShau) for the project. -- [PaulSonOfLars](https://github.com/PaulSonOfLars) for the [GoTgBot](https://github.com/PaulSonOfLars/gotgbot) library and [Api](https://github.com/PaulSonOfLars/telegram-bot-api-spec/raw/main/api.json). +## Acknowledgments +- **[Ashok Shau](https://github.com/AshokShau)**: For creating and maintaining this [project](https://github.com/AshokShau/BotApiDocs), which provides a solid foundation for building Telegram bots. + +- **[PaulSonOfLars](https://github.com/PaulSonOfLars)**: For the invaluable [GoTgBot](https://github.com/PaulSonOfLars/gotgbot) library, which simplifies Telegram bot development in Go, and for the [API specification](https://github.com/PaulSonOfLars/telegram-bot-api-spec/raw/main/api.json) that serves as a reference for bot methods and types. diff --git a/Telegram/modules/inline.go b/Telegram/modules/inline.go index 1ffe746..b2ad59a 100644 --- a/Telegram/modules/inline.go +++ b/Telegram/modules/inline.go @@ -6,6 +6,7 @@ import ( "log" "math/rand" "net/http" + "regexp" "strconv" "strings" "sync" @@ -15,6 +16,8 @@ import ( "github.com/PaulSonOfLars/gotgbot/v2/ext" ) +const maxMessageLength = 4096 // Telegram's maximum message length + // apiCache is a global cache for storing API methods and types. var apiCache struct { sync.RWMutex @@ -56,10 +59,6 @@ func fetchAPI() error { } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("unexpected status code: %d", resp.StatusCode) - } - var apiDocs struct { Methods map[string]Method `json:"methods"` Types map[string]Type `json:"types"` @@ -128,7 +127,7 @@ func sendEmptyQueryResponse(bot *gotgbot.Bot, ctx *ext.Context) error { IsPersonal: true, CacheTime: 5, Button: &gotgbot.InlineQueryResultsButton{ - Text: "Type '' to search!", + Text: "Type 'your_query' to search!", StartParameter: "start", }, }) @@ -169,35 +168,43 @@ func sendNoResultsResponse(bot *gotgbot.Bot, ctx *ext.Context, query string) err func buildMethodMessage(method Method) string { var msgBuilder strings.Builder msgBuilder.WriteString(fmt.Sprintf("%s\n", method.Name)) - msgBuilder.WriteString(fmt.Sprintf("Description: %s\n\n", strings.Join(method.Description, ", "))) + msgBuilder.WriteString(fmt.Sprintf("Description: %s\n\n", sanitizeHTML(strings.Join(method.Description, ", ")))) msgBuilder.WriteString("Returns: " + strings.Join(method.Returns, ", ") + "\n") if len(method.Fields) > 0 { msgBuilder.WriteString("Fields:\n") for _, field := range method.Fields { msgBuilder.WriteString(fmt.Sprintf("%s (%s) - Required: %t\n", field.Name, strings.Join(field.Types, ", "), field.Required)) - msgBuilder.WriteString(field.Description + "\n\n") + msgBuilder.WriteString(sanitizeHTML(field.Description) + "\n\n") } } - return msgBuilder.String() + message := msgBuilder.String() + if len(message) > maxMessageLength { + return fmt.Sprintf("See full documentation: %s", method.Href) + } + return message } // buildTypeMessage builds a message string for a given API type. func buildTypeMessage(typ Type) string { var msgBuilder strings.Builder msgBuilder.WriteString(fmt.Sprintf("%s\n", typ.Name)) - msgBuilder.WriteString(fmt.Sprintf("Description: %s\n\n", strings.Join(typ.Description, ", "))) + msgBuilder.WriteString(fmt.Sprintf("Description: %s\n\n", sanitizeHTML(strings.Join(typ.Description, ", ")))) if len(typ.Fields) > 0 { msgBuilder.WriteString("Fields:\n") for _, field := range typ.Fields { msgBuilder.WriteString(fmt.Sprintf("%s (%s) - Required: %t\n", field.Name, strings.Join(field.Types, ", "), field.Required)) - msgBuilder.WriteString(field.Description + "\n\n") + msgBuilder.WriteString(sanitizeHTML(field.Description) + "\n\n") } } - return msgBuilder.String() + message := msgBuilder.String() + if len(message) > maxMessageLength { + return fmt.Sprintf("See full documentation: %s", typ.Href) + } + return message } // createInlineResult creates an inline query result for a given API method or type. @@ -225,7 +232,7 @@ func createInlineResult(title, url, message, methodUrl string) gotgbot.InlineQue func noResultsArticle(query string) gotgbot.InlineQueryResult { ok := "botapi" return gotgbot.InlineQueryResultArticle{ - Id: "no_results", + Id: strconv.Itoa(rand.Intn(100000)), Title: "No Results Found!", InputMessageContent: gotgbot.InputTextMessageContent{ MessageText: fmt.Sprintf("đŸ‘‹ Sorry, I couldn't find any results for '%s'. Try searching with a different keyword!", query), @@ -239,3 +246,10 @@ func noResultsArticle(query string) gotgbot.InlineQueryResult { }, } } + +// sanitizeHTML removes unsupported HTML tags from the message +func sanitizeHTML(input string) string { + // This regex matches any HTML tags that are not supported + re := regexp.MustCompile(`<[^>]*>`) + return re.ReplaceAllString(input, "") +}