package tgbotapi import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "errors" "fmt" "net/url" "sort" "strings" ) // NewMessage creates a new Message. // // chatID is where to send it, text is the message text. func NewMessage(chatID int64, text string) MessageConfig { return MessageConfig{ BaseChat: BaseChat{ ChatID: chatID, ReplyToMessageID: 0, }, Text: text, DisableWebPagePreview: false, } } // NewDeleteMessage creates a request to delete a message. func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { return DeleteMessageConfig{ ChatID: chatID, MessageID: messageID, } } // NewMessageToChannel creates a new Message that is sent to a channel // by username. // // username is the username of the channel, text is the message text, // and the username should be in the form of `@username`. func NewMessageToChannel(username string, text string) MessageConfig { return MessageConfig{ BaseChat: BaseChat{ ChannelUsername: username, }, Text: text, } } // NewForward creates a new forward. // // chatID is where to send it, fromChatID is the source chat, // and messageID is the ID of the original message. func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig { return ForwardConfig{ BaseChat: BaseChat{ChatID: chatID}, FromChatID: fromChatID, MessageID: messageID, } } // NewCopyMessage creates a new copy message. // // chatID is where to send it, fromChatID is the source chat, // and messageID is the ID of the original message. func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig { return CopyMessageConfig{ BaseChat: BaseChat{ChatID: chatID}, FromChatID: fromChatID, MessageID: messageID, } } // NewPhoto creates a new sendPhoto request. // // chatID is where to send it, file is a string path to the file, // FileReader, or FileBytes. // // Note that you must send animated GIFs as a document. func NewPhoto(chatID int64, file RequestFileData) PhotoConfig { return PhotoConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ChatID: chatID}, File: file, }, } } // NewPhotoToChannel creates a new photo uploader to send a photo to a channel. // // Note that you must send animated GIFs as a document. func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig { return PhotoConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ ChannelUsername: username, }, File: file, }, } } // NewAudio creates a new sendAudio request. func NewAudio(chatID int64, file RequestFileData) AudioConfig { return AudioConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ChatID: chatID}, File: file, }, } } // NewDocument creates a new sendDocument request. func NewDocument(chatID int64, file RequestFileData) DocumentConfig { return DocumentConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ChatID: chatID}, File: file, }, } } // NewSticker creates a new sendSticker request. func NewSticker(chatID int64, file RequestFileData) StickerConfig { return StickerConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ChatID: chatID}, File: file, }, } } // NewCustomEmojiStickerSetThumbnal creates a new setCustomEmojiStickerSetThumbnal request func NewCustomEmojiStickerSetThumbnal(name, customEmojiID string) SetCustomEmojiStickerSetThumbnailConfig { return SetCustomEmojiStickerSetThumbnailConfig{ Name: name, CustomEmojiID: customEmojiID, } } // NewStickerSetTitle creates a new setStickerSetTitle request func NewStickerSetTitle(name, title string) SetStickerSetTitleConfig { return SetStickerSetTitleConfig{ Name: name, Title: title, } } // NewDeleteStickerSet creates a new deleteStickerSet request func NewDeleteStickerSet(name, title string) DeleteStickerSetConfig { return DeleteStickerSetConfig{ Name: name, } } // NewVideo creates a new sendVideo request. func NewVideo(chatID int64, file RequestFileData) VideoConfig { return VideoConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ChatID: chatID}, File: file, }, } } // NewAnimation creates a new sendAnimation request. func NewAnimation(chatID int64, file RequestFileData) AnimationConfig { return AnimationConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ChatID: chatID}, File: file, }, } } // NewVideoNote creates a new sendVideoNote request. // // chatID is where to send it, file is a string path to the file, // FileReader, or FileBytes. func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig { return VideoNoteConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ChatID: chatID}, File: file, }, Length: length, } } // NewVoice creates a new sendVoice request. func NewVoice(chatID int64, file RequestFileData) VoiceConfig { return VoiceConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ChatID: chatID}, File: file, }, } } // NewMediaGroup creates a new media group. Files should be an array of // two to ten InputMediaPhoto or InputMediaVideo. func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig { return MediaGroupConfig{ BaseChat: BaseChat{ ChatID: chatID, }, Media: files, } } // NewInputMediaPhoto creates a new InputMediaPhoto. func NewInputMediaPhoto(media RequestFileData) InputMediaPhoto { return InputMediaPhoto{ BaseInputMedia{ Type: "photo", Media: media, }, } } // NewInputMediaVideo creates a new InputMediaVideo. func NewInputMediaVideo(media RequestFileData) InputMediaVideo { return InputMediaVideo{ BaseInputMedia: BaseInputMedia{ Type: "video", Media: media, }, } } // NewInputMediaAnimation creates a new InputMediaAnimation. func NewInputMediaAnimation(media RequestFileData) InputMediaAnimation { return InputMediaAnimation{ BaseInputMedia: BaseInputMedia{ Type: "animation", Media: media, }, } } // NewInputMediaAudio creates a new InputMediaAudio. func NewInputMediaAudio(media RequestFileData) InputMediaAudio { return InputMediaAudio{ BaseInputMedia: BaseInputMedia{ Type: "audio", Media: media, }, } } // NewInputMediaDocument creates a new InputMediaDocument. func NewInputMediaDocument(media RequestFileData) InputMediaDocument { return InputMediaDocument{ BaseInputMedia: BaseInputMedia{ Type: "document", Media: media, }, } } // NewContact allows you to send a shared contact. func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig { return ContactConfig{ BaseChat: BaseChat{ ChatID: chatID, }, PhoneNumber: phoneNumber, FirstName: firstName, } } // NewLocation shares your location. // // chatID is where to send it, latitude and longitude are coordinates. func NewLocation(chatID int64, latitude float64, longitude float64) LocationConfig { return LocationConfig{ BaseChat: BaseChat{ ChatID: chatID, }, Latitude: latitude, Longitude: longitude, } } // NewVenue allows you to send a venue and its location. func NewVenue(chatID int64, title, address string, latitude, longitude float64) VenueConfig { return VenueConfig{ BaseChat: BaseChat{ ChatID: chatID, }, Title: title, Address: address, Latitude: latitude, Longitude: longitude, } } // NewChatAction sets a chat action. // Actions last for 5 seconds, or until your next action. // // chatID is where to send it, action should be set via Chat constants. func NewChatAction(chatID int64, action string) ChatActionConfig { return ChatActionConfig{ BaseChat: BaseChat{ChatID: chatID}, Action: action, } } // NewUserProfilePhotos gets user profile photos. // // userID is the ID of the user you wish to get profile photos from. func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig { return UserProfilePhotosConfig{ UserID: userID, Offset: 0, Limit: 0, } } // NewUpdate gets updates since the last Offset. // // offset is the last Update ID to include. // You likely want to set this to the last Update ID plus 1. func NewUpdate(offset int) UpdateConfig { return UpdateConfig{ Offset: offset, Limit: 0, Timeout: 0, } } // NewWebhook creates a new webhook. // // link is the url parsable link you wish to get the updates. func NewWebhook(link string) (WebhookConfig, error) { u, err := url.Parse(link) if err != nil { return WebhookConfig{}, err } return WebhookConfig{ URL: u, }, nil } // NewWebhookWithCert creates a new webhook with a certificate. // // link is the url you wish to get webhooks, // file contains a string to a file, FileReader, or FileBytes. func NewWebhookWithCert(link string, file RequestFileData) (WebhookConfig, error) { u, err := url.Parse(link) if err != nil { return WebhookConfig{}, err } return WebhookConfig{ URL: u, Certificate: file, }, nil } // NewInlineQueryResultArticle creates a new inline query article. func NewInlineQueryResultArticle(id, title, messageText string) InlineQueryResultArticle { return InlineQueryResultArticle{ Type: "article", ID: id, Title: title, InputMessageContent: InputTextMessageContent{ Text: messageText, }, } } // NewInlineQueryResultArticleMarkdown creates a new inline query article with Markdown parsing. func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQueryResultArticle { return InlineQueryResultArticle{ Type: "article", ID: id, Title: title, InputMessageContent: InputTextMessageContent{ Text: messageText, ParseMode: "Markdown", }, } } // NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing. func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle { return InlineQueryResultArticle{ Type: "article", ID: id, Title: title, InputMessageContent: InputTextMessageContent{ Text: messageText, ParseMode: "MarkdownV2", }, } } // NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing. func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle { return InlineQueryResultArticle{ Type: "article", ID: id, Title: title, InputMessageContent: InputTextMessageContent{ Text: messageText, ParseMode: "HTML", }, } } // NewInlineQueryResultGIF creates a new inline query GIF. func NewInlineQueryResultGIF(id, url string) InlineQueryResultGIF { return InlineQueryResultGIF{ Type: "gif", ID: id, URL: url, } } // NewInlineQueryResultCachedGIF create a new inline query with cached photo. func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF { return InlineQueryResultCachedGIF{ Type: "gif", ID: id, GIFID: gifID, } } // NewInlineQueryResultMPEG4GIF creates a new inline query MPEG4 GIF. func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF { return InlineQueryResultMPEG4GIF{ Type: "mpeg4_gif", ID: id, URL: url, } } // NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF. func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF { return InlineQueryResultCachedMPEG4GIF{ Type: "mpeg4_gif", ID: id, MPEG4FileID: MPEG4GIFID, } } // NewInlineQueryResultPhoto creates a new inline query photo. func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto { return InlineQueryResultPhoto{ Type: "photo", ID: id, URL: url, } } // NewInlineQueryResultPhotoWithThumb creates a new inline query photo. func NewInlineQueryResultPhotoWithThumb(id, url, thumb string) InlineQueryResultPhoto { return InlineQueryResultPhoto{ Type: "photo", ID: id, URL: url, ThumbURL: thumb, } } // NewInlineQueryResultCachedPhoto create a new inline query with cached photo. func NewInlineQueryResultCachedPhoto(id, photoID string) InlineQueryResultCachedPhoto { return InlineQueryResultCachedPhoto{ Type: "photo", ID: id, PhotoID: photoID, } } // NewInlineQueryResultVideo creates a new inline query video. func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo { return InlineQueryResultVideo{ Type: "video", ID: id, URL: url, } } // NewInlineQueryResultCachedVideo create a new inline query with cached video. func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResultCachedVideo { return InlineQueryResultCachedVideo{ Type: "video", ID: id, VideoID: videoID, Title: title, } } // NewInlineQueryResultCachedSticker create a new inline query with cached sticker. func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker { return InlineQueryResultCachedSticker{ Type: "sticker", ID: id, StickerID: stickerID, Title: title, } } // NewInlineQueryResultAudio creates a new inline query audio. func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio { return InlineQueryResultAudio{ Type: "audio", ID: id, URL: url, Title: title, } } // NewInlineQueryResultCachedAudio create a new inline query with cached photo. func NewInlineQueryResultCachedAudio(id, audioID string) InlineQueryResultCachedAudio { return InlineQueryResultCachedAudio{ Type: "audio", ID: id, AudioID: audioID, } } // NewInlineQueryResultVoice creates a new inline query voice. func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice { return InlineQueryResultVoice{ Type: "voice", ID: id, URL: url, Title: title, } } // NewInlineQueryResultCachedVoice create a new inline query with cached photo. func NewInlineQueryResultCachedVoice(id, voiceID, title string) InlineQueryResultCachedVoice { return InlineQueryResultCachedVoice{ Type: "voice", ID: id, VoiceID: voiceID, Title: title, } } // NewInlineQueryResultDocument creates a new inline query document. func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument { return InlineQueryResultDocument{ Type: "document", ID: id, URL: url, Title: title, MimeType: mimeType, } } // NewInlineQueryResultCachedDocument create a new inline query with cached photo. func NewInlineQueryResultCachedDocument(id, documentID, title string) InlineQueryResultCachedDocument { return InlineQueryResultCachedDocument{ Type: "document", ID: id, DocumentID: documentID, Title: title, } } // NewInlineQueryResultLocation creates a new inline query location. func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation { return InlineQueryResultLocation{ Type: "location", ID: id, Title: title, Latitude: latitude, Longitude: longitude, } } // NewInlineQueryResultVenue creates a new inline query venue. func NewInlineQueryResultVenue(id, title, address string, latitude, longitude float64) InlineQueryResultVenue { return InlineQueryResultVenue{ Type: "venue", ID: id, Title: title, Address: address, Latitude: latitude, Longitude: longitude, } } // NewEditMessageText allows you to edit the text of a message. func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig { return EditMessageTextConfig{ BaseEdit: BaseEdit{ ChatID: chatID, MessageID: messageID, }, Text: text, } } // NewEditMessageTextAndMarkup allows you to edit the text and reply markup of a message. func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig { return EditMessageTextConfig{ BaseEdit: BaseEdit{ ChatID: chatID, MessageID: messageID, ReplyMarkup: &replyMarkup, }, Text: text, } } // NewEditMessageCaption allows you to edit the caption of a message. func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig { return EditMessageCaptionConfig{ BaseEdit: BaseEdit{ ChatID: chatID, MessageID: messageID, }, Caption: caption, } } // NewEditMessageReplyMarkup allows you to edit the inline // keyboard markup. func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKeyboardMarkup) EditMessageReplyMarkupConfig { return EditMessageReplyMarkupConfig{ BaseEdit: BaseEdit{ ChatID: chatID, MessageID: messageID, ReplyMarkup: &replyMarkup, }, } } // NewRemoveKeyboard hides the keyboard, with the option for being selective // or hiding for everyone. func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove { return ReplyKeyboardRemove{ RemoveKeyboard: true, Selective: selective, } } // NewKeyboardButton creates a regular keyboard button. func NewKeyboardButton(text string) KeyboardButton { return KeyboardButton{ Text: text, } } // NewKeyboardButtonWebApp creates a keyboard button with text // which goes to a WebApp. func NewKeyboardButtonWebApp(text string, webapp WebAppInfo) KeyboardButton { return KeyboardButton{ Text: text, WebApp: &webapp, } } // NewKeyboardButtonContact creates a keyboard button that requests // user contact information upon click. func NewKeyboardButtonContact(text string) KeyboardButton { return KeyboardButton{ Text: text, RequestContact: true, } } // NewKeyboardButtonLocation creates a keyboard button that requests // user location information upon click. func NewKeyboardButtonLocation(text string) KeyboardButton { return KeyboardButton{ Text: text, RequestLocation: true, } } // NewKeyboardButtonRow creates a row of keyboard buttons. func NewKeyboardButtonRow(buttons ...KeyboardButton) []KeyboardButton { var row []KeyboardButton row = append(row, buttons...) return row } // NewReplyKeyboard creates a new regular keyboard with sane defaults. func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { var keyboard [][]KeyboardButton keyboard = append(keyboard, rows...) return ReplyKeyboardMarkup{ ResizeKeyboard: true, Keyboard: keyboard, } } // NewOneTimeReplyKeyboard creates a new one time keyboard. func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { markup := NewReplyKeyboard(rows...) markup.OneTimeKeyboard = true return markup } // NewInlineKeyboardButtonData creates an inline keyboard button with text // and data for a callback. func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, CallbackData: &data, } } // NewInlineKeyboardButtonWebApp creates an inline keyboard button with text // which goes to a WebApp. func NewInlineKeyboardButtonWebApp(text string, webapp WebAppInfo) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, WebApp: &webapp, } } // NewInlineKeyboardButtonSwitchInlineQueryChoosenChat creates an inline keyboard button with text // which goes to a SwitchInlineQueryChosenChat. func NewInlineKeyboardButtonSwitchInlineQueryChoosenChat(text string, switchInlineQueryChosenChat SwitchInlineQueryChosenChat) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, SwitchInlineQueryChosenChat: &switchInlineQueryChosenChat, } } // NewInlineKeyboardButtonLoginURL creates an inline keyboard button with text // which goes to a LoginURL. func NewInlineKeyboardButtonLoginURL(text string, loginURL LoginURL) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, LoginURL: &loginURL, } } // NewInlineKeyboardButtonURL creates an inline keyboard button with text // which goes to a URL. func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, URL: &url, } } // NewInlineKeyboardButtonSwitch creates an inline keyboard button with // text which allows the user to switch to a chat or return to a chat. func NewInlineKeyboardButtonSwitch(text, sw string) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, SwitchInlineQuery: &sw, } } // NewInlineKeyboardRow creates an inline keyboard row with buttons. func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton { var row []InlineKeyboardButton row = append(row, buttons...) return row } // NewInlineKeyboardMarkup creates a new inline keyboard. func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) InlineKeyboardMarkup { var keyboard [][]InlineKeyboardButton keyboard = append(keyboard, rows...) return InlineKeyboardMarkup{ InlineKeyboard: keyboard, } } // NewCallback creates a new callback message. func NewCallback(id, text string) CallbackConfig { return CallbackConfig{ CallbackQueryID: id, Text: text, ShowAlert: false, } } // NewCallbackWithAlert creates a new callback message that alerts // the user. func NewCallbackWithAlert(id, text string) CallbackConfig { return CallbackConfig{ CallbackQueryID: id, Text: text, ShowAlert: true, } } // NewInvoice creates a new Invoice request to the user. func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice) InvoiceConfig { return InvoiceConfig{ BaseChat: BaseChat{ChatID: chatID}, Title: title, Description: description, Payload: payload, ProviderToken: providerToken, StartParameter: startParameter, Currency: currency, Prices: prices} } // NewChatTitle allows you to update the title of a chat. func NewChatTitle(chatID int64, title string) SetChatTitleConfig { return SetChatTitleConfig{ ChatID: chatID, Title: title, } } // NewChatDescription allows you to update the description of a chat. func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig { return SetChatDescriptionConfig{ ChatID: chatID, Description: description, } } // NewChatPhoto allows you to update the photo for a chat. func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig { return SetChatPhotoConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ ChatID: chatID, }, File: photo, }, } } // NewDeleteChatPhoto allows you to delete the photo for a chat. func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig { return DeleteChatPhotoConfig{ ChatID: chatID, } } // NewPoll allows you to create a new poll. func NewPoll(chatID int64, question string, options ...string) SendPollConfig { return SendPollConfig{ BaseChat: BaseChat{ ChatID: chatID, }, Question: question, Options: options, IsAnonymous: true, // This is Telegram's default. } } // NewStopPoll allows you to stop a poll. func NewStopPoll(chatID int64, messageID int) StopPollConfig { return StopPollConfig{ BaseEdit{ ChatID: chatID, MessageID: messageID, }, } } // NewDice allows you to send a random dice roll. func NewDice(chatID int64) DiceConfig { return DiceConfig{ BaseChat: BaseChat{ ChatID: chatID, }, } } // NewDiceWithEmoji allows you to send a random roll of one of many types. // // Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5). func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig { return DiceConfig{ BaseChat: BaseChat{ ChatID: chatID, }, Emoji: emoji, } } // NewBotCommandScopeDefault represents the default scope of bot commands. func NewBotCommandScopeDefault() BotCommandScope { return BotCommandScope{Type: "default"} } // NewBotCommandScopeAllPrivateChats represents the scope of bot commands, // covering all private chats. func NewBotCommandScopeAllPrivateChats() BotCommandScope { return BotCommandScope{Type: "all_private_chats"} } // NewBotCommandScopeAllGroupChats represents the scope of bot commands, // covering all group and supergroup chats. func NewBotCommandScopeAllGroupChats() BotCommandScope { return BotCommandScope{Type: "all_group_chats"} } // NewBotCommandScopeAllChatAdministrators represents the scope of bot commands, // covering all group and supergroup chat administrators. func NewBotCommandScopeAllChatAdministrators() BotCommandScope { return BotCommandScope{Type: "all_chat_administrators"} } // NewBotCommandScopeChat represents the scope of bot commands, covering a // specific chat. func NewBotCommandScopeChat(chatID int64) BotCommandScope { return BotCommandScope{ Type: "chat", ChatID: chatID, } } // NewBotCommandScopeChatAdministrators represents the scope of bot commands, // covering all administrators of a specific group or supergroup chat. func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope { return BotCommandScope{ Type: "chat_administrators", ChatID: chatID, } } // NewBotCommandScopeChatMember represents the scope of bot commands, covering a // specific member of a group or supergroup chat. func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope { return BotCommandScope{ Type: "chat_member", ChatID: chatID, UserID: userID, } } // NewSetMyDescription allows you to change the bot's description, which is shown in the chat with the bot if the chat is empty. func NewSetMyDescription(description, languageCode string) SetMyDescriptionConfig { return SetMyDescriptionConfig{ Description: description, LanguageCode: languageCode, } } // NewGetMyDescription returns the current bot description for the given user language func NewGetMyDescription(languageCode string) GetMyDescriptionConfig { return GetMyDescriptionConfig{ LanguageCode: languageCode, } } // NewSetMyShortDescription allows you change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot. func NewSetMyShortDescription(shortDescription, languageCode string) SetMyShortDescriptionConfig { return SetMyShortDescriptionConfig{ ShortDescription: shortDescription, LanguageCode: languageCode, } } // NewGetMyShortDescription returns the current bot short description for the given user language. func NewGetMyShortDescription(languageCode string) GetMyShortDescriptionConfig { return GetMyShortDescriptionConfig{ LanguageCode: languageCode, } } // NewGetMyName get the current bot name for the given user language func NewGetMyName(languageCode string) GetMyNameConfig { return GetMyNameConfig{ LanguageCode: languageCode, } } // NewSetMyName change the bot's name func NewSetMyName(languageCode, name string) SetMyNameConfig { return SetMyNameConfig{ Name: name, LanguageCode: languageCode, } } // NewGetMyCommandsWithScope allows you to set the registered commands for a // given scope. func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig { return GetMyCommandsConfig{Scope: &scope} } // NewGetMyCommandsWithScopeAndLanguage allows you to set the registered // commands for a given scope and language code. func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig { return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} } // NewSetMyCommands allows you to set the registered commands. func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig { return SetMyCommandsConfig{Commands: commands} } // NewSetMyCommandsWithScope allows you to set the registered commands for a given scope. func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig { return SetMyCommandsConfig{Commands: commands, Scope: &scope} } // NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope // and language code. func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig { return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode} } // NewDeleteMyCommands allows you to delete the registered commands. func NewDeleteMyCommands() DeleteMyCommandsConfig { return DeleteMyCommandsConfig{} } // NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given // scope. func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig { return DeleteMyCommandsConfig{Scope: &scope} } // NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given // scope and language code. func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig { return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} } // ValidateWebAppData validate data received via the Web App // https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app func ValidateWebAppData(token, telegramInitData string) (bool, error) { initData, err := url.ParseQuery(telegramInitData) if err != nil { return false, fmt.Errorf("error parsing data %w", err) } dataCheckString := make([]string, 0, len(initData)) for k, v := range initData { if k == "hash" { continue } if len(v) > 0 { dataCheckString = append(dataCheckString, fmt.Sprintf("%s=%s", k, v[0])) } } sort.Strings(dataCheckString) secret := hmac.New(sha256.New, []byte("WebAppData")) secret.Write([]byte(token)) hHash := hmac.New(sha256.New, secret.Sum(nil)) hHash.Write([]byte(strings.Join(dataCheckString, "\n"))) hash := hex.EncodeToString(hHash.Sum(nil)) if initData.Get("hash") != hash { return false, errors.New("hash not equal") } return true, nil }