From 8a0f1dd730aa41ab7b792b9ff03d92b1c5022c9f Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 4 May 2022 20:12:23 +0300 Subject: [PATCH 01/11] Update TDLib and version to 6.0.2. --- CMakeLists.txt | 2 +- td | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b73a401..665263d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 6.0.1 LANGUAGES CXX) +project(TelegramBotApi VERSION 6.0.2 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/td b/td index 782670c..ab3a828 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 782670c7dbf278e0ba07fc7e168f39ac154c7238 +Subproject commit ab3a8282d4ee307d341071267ef1090b1a941478 diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index b1283e9..9e197da 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) { auto start_time = td::Time::now(); auto shared_data = std::make_shared(); auto parameters = std::make_unique(); - parameters->version_ = "6.0.1"; + parameters->version_ = "6.0.2"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From 2001518ec568b53af764c3bada22f329c4693062 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 9 May 2022 19:25:56 +0300 Subject: [PATCH 02/11] Update TDLib to 1.8.4. --- td | 2 +- telegram-bot-api/Client.cpp | 36 ++++++++++-------------------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/td b/td index ab3a828..b393215 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit ab3a8282d4ee307d341071267ef1090b1a941478 +Subproject commit b393215d6671863b6baf2a589d343cff9474f6ba diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 5c0a153..957f6d3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1195,7 +1195,7 @@ class Client::JsonInvoice final : public Jsonable { void store(JsonValueScope *scope) const { auto object = scope->enter_object(); object("title", invoice_->title_); - object("description", invoice_->description_); + object("description", invoice_->description_->text_); object("start_parameter", invoice_->start_parameter_); object("currency", invoice_->currency_); object("total_amount", invoice_->total_amount_); @@ -1860,10 +1860,7 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { } case td_api::messageChatChangePhoto::ID: { auto content = static_cast(message_->content.get()); - if (content->photo_ == nullptr) { - LOG(ERROR) << "Got empty messageChatChangePhoto"; - break; - } + CHECK(content->photo_ != nullptr); object("new_chat_photo", JsonChatPhoto(content->photo_.get(), client_)); break; } @@ -4603,7 +4600,9 @@ void Client::on_update(object_ptr result) { auto user_id = update->user_id_; auto full_info = update->user_full_info_.get(); set_user_photo(user_id, std::move(full_info->photo_)); - set_user_bio(user_id, std::move(full_info->bio_)); + if (full_info->bio_ != nullptr) { + set_user_bio(user_id, std::move(full_info->bio_->text_)); + } set_user_has_private_forwards(user_id, full_info->has_private_forwards_); break; } @@ -5478,8 +5477,9 @@ td::Result> Client::get_input_me return make_object( make_object(currency, std::move(prices), max_tip_amount, std::move(suggested_tip_amounts), - false, need_name, need_phone_number, need_email_address, need_shipping_address, - send_phone_number_to_provider, send_email_address_to_provider, is_flexible), + td::string(), false, need_name, need_phone_number, need_email_address, + need_shipping_address, send_phone_number_to_provider, + send_email_address_to_provider, is_flexible), title, description, photo_url, photo_size, photo_width, photo_height, payload, provider_token, provider_data, td::string()); } @@ -7111,7 +7111,7 @@ td::Status Client::process_send_invoice_query(PromisedQueryPtr &query) { do_send_message(make_object( make_object( currency.str(), std::move(prices), max_tip_amount, std::move(suggested_tip_amounts), false, - need_name, need_phone_number, need_email_address, need_shipping_address, + td::string(), need_name, need_phone_number, need_email_address, need_shipping_address, send_phone_number_to_provider, send_email_address_to_provider, is_flexible), title.str(), description.str(), photo_url.str(), photo_size, photo_width, photo_height, payload.str(), provider_token.str(), provider_data.str(), start_parameter.str()), @@ -9576,14 +9576,6 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrcontent_->get_id()) { - case td_api::messagePhoto::ID: { - auto content = static_cast(message->content_.get()); - if (content->photo_ == nullptr) { - LOG(ERROR) << "Got empty messagePhoto"; - return true; - } - break; - } case td_api::messageChatAddMembers::ID: { auto content = static_cast(message->content_.get()); if (content->member_user_ids_.empty()) { @@ -9592,14 +9584,6 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr(message->content_.get()); - if (content->photo_ == nullptr) { - LOG(ERROR) << "Got empty messageChatChangePhoto"; - return true; - } - break; - } case td_api::messageSupergroupChatCreate::ID: { if (chat->type != ChatInfo::Type::Supergroup) { LOG(ERROR) << "Receive messageSupergroupChatCreate in the non-supergroup chat " << chat_id; @@ -9615,7 +9599,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Mon, 9 May 2022 21:49:26 +0300 Subject: [PATCH 03/11] Add createInvoiceLink. --- telegram-bot-api/Client.cpp | 157 +++++++++++++++++++++--------------- telegram-bot-api/Client.h | 4 + 2 files changed, 98 insertions(+), 63 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 957f6d3..2616f1a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -225,6 +225,7 @@ bool Client::init_methods() { methods_.emplace("editmessagecaption", &Client::process_edit_message_caption_query); methods_.emplace("editmessagereplymarkup", &Client::process_edit_message_reply_markup_query); methods_.emplace("deletemessage", &Client::process_delete_message_query); + methods_.emplace("createinvoicelink", &Client::process_create_invoice_link_query); methods_.emplace("setgamescore", &Client::process_set_game_score_query); methods_.emplace("getgamehighscores", &Client::process_get_game_high_scores_query); methods_.emplace("answerwebappquery", &Client::process_answer_web_app_query_query); @@ -3493,6 +3494,25 @@ class Client::TdOnGetSupergroupMembersCountCallback final : public TdQueryCallba PromisedQueryPtr query_; }; +class Client::TdOnCreateInvoiceLinkCallback final : public TdQueryCallback { + public: + explicit TdOnCreateInvoiceLinkCallback(PromisedQueryPtr query) : query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::httpUrl::ID); + auto http_url = move_object_as(result); + return answer_query(td::VirtuallyJsonableString(http_url->url_), std::move(query_)); + } + + private: + PromisedQueryPtr query_; +}; + class Client::TdOnReplacePrimaryChatInviteLinkCallback final : public TdQueryCallback { public: explicit TdOnReplacePrimaryChatInviteLinkCallback(PromisedQueryPtr query) : query_(std::move(query)) { @@ -6609,6 +6629,71 @@ td::Result>> Client:: return std::move(contents); } +td::Result> Client::get_input_message_invoice(const Query *query) { + TRY_RESULT(title, get_required_string_arg(query, "title")); + TRY_RESULT(description, get_required_string_arg(query, "description")); + TRY_RESULT(payload, get_required_string_arg(query, "payload")); + if (!td::check_utf8(payload.str())) { + return Status::Error(400, "The payload must be encoded in UTF-8"); + } + TRY_RESULT(provider_token, get_required_string_arg(query, "provider_token")); + auto provider_data = query->arg("provider_data"); + auto start_parameter = query->arg("start_parameter"); + TRY_RESULT(currency, get_required_string_arg(query, "currency")); + + TRY_RESULT(labeled_price_parts, get_required_string_arg(query, "prices")); + auto r_labeled_price_parts_value = json_decode(labeled_price_parts); + if (r_labeled_price_parts_value.is_error()) { + return Status::Error(400, "Can't parse prices JSON object"); + } + + TRY_RESULT(prices, get_labeled_price_parts(r_labeled_price_parts_value.ok_ref())); + + int64 max_tip_amount = 0; + td::vector suggested_tip_amounts; + { + auto max_tip_amount_str = query->arg("max_tip_amount"); + if (!max_tip_amount_str.empty()) { + auto r_max_tip_amount = td::to_integer_safe(max_tip_amount_str); + if (r_max_tip_amount.is_error()) { + return Status::Error(400, "Can't parse \"max_tip_amount\" as Number"); + } + max_tip_amount = r_max_tip_amount.ok(); + } + + auto suggested_tip_amounts_str = query->arg("suggested_tip_amounts"); + if (!suggested_tip_amounts_str.empty()) { + auto r_suggested_tip_amounts_value = json_decode(suggested_tip_amounts_str); + if (r_suggested_tip_amounts_value.is_error()) { + return Status::Error(400, "Can't parse suggested_tip_amounts JSON object"); + } + + TRY_RESULT_ASSIGN(suggested_tip_amounts, get_suggested_tip_amounts(r_suggested_tip_amounts_value.ok_ref())); + } + } + + auto photo_url = query->arg("photo_url"); + int32 photo_size = get_integer_arg(query, "photo_size", 0, 0, 1000000000); + int32 photo_width = get_integer_arg(query, "photo_width", 0, 0, MAX_LENGTH); + int32 photo_height = get_integer_arg(query, "photo_height", 0, 0, MAX_LENGTH); + + auto need_name = to_bool(query->arg("need_name")); + auto need_phone_number = to_bool(query->arg("need_phone_number")); + auto need_email_address = to_bool(query->arg("need_email")); + auto need_shipping_address = to_bool(query->arg("need_shipping_address")); + auto send_phone_number_to_provider = to_bool(query->arg("send_phone_number_to_provider")); + auto send_email_address_to_provider = to_bool(query->arg("send_email_to_provider")); + auto is_flexible = to_bool(query->arg("is_flexible")); + + return make_object( + make_object(currency.str(), std::move(prices), max_tip_amount, std::move(suggested_tip_amounts), + td::string(), false, need_name, need_phone_number, need_email_address, + need_shipping_address, send_phone_number_to_provider, send_email_address_to_provider, + is_flexible), + title.str(), description.str(), photo_url.str(), photo_size, photo_width, photo_height, payload.str(), + provider_token.str(), provider_data.str(), start_parameter.str()); +} + td::Result> Client::get_poll_options(const Query *query) { auto input_options = query->arg("options"); LOG(INFO) << "Parsing JSON object: " << input_options; @@ -7053,69 +7138,8 @@ td::Status Client::process_send_game_query(PromisedQueryPtr &query) { } td::Status Client::process_send_invoice_query(PromisedQueryPtr &query) { - TRY_RESULT(title, get_required_string_arg(query.get(), "title")); - TRY_RESULT(description, get_required_string_arg(query.get(), "description")); - TRY_RESULT(payload, get_required_string_arg(query.get(), "payload")); - if (!td::check_utf8(payload.str())) { - return Status::Error(400, "The payload must be encoded in UTF-8"); - } - TRY_RESULT(provider_token, get_required_string_arg(query.get(), "provider_token")); - auto provider_data = query->arg("provider_data"); - auto start_parameter = query->arg("start_parameter"); - TRY_RESULT(currency, get_required_string_arg(query.get(), "currency")); - - TRY_RESULT(labeled_price_parts, get_required_string_arg(query.get(), "prices")); - auto r_labeled_price_parts_value = json_decode(labeled_price_parts); - if (r_labeled_price_parts_value.is_error()) { - return Status::Error(400, "Can't parse prices JSON object"); - } - - TRY_RESULT(prices, get_labeled_price_parts(r_labeled_price_parts_value.ok_ref())); - - int64 max_tip_amount = 0; - td::vector suggested_tip_amounts; - { - auto max_tip_amount_str = query->arg("max_tip_amount"); - if (!max_tip_amount_str.empty()) { - auto r_max_tip_amount = td::to_integer_safe(max_tip_amount_str); - if (r_max_tip_amount.is_error()) { - return Status::Error(400, "Can't parse \"max_tip_amount\" as Number"); - } - max_tip_amount = r_max_tip_amount.ok(); - } - - auto suggested_tip_amounts_str = query->arg("suggested_tip_amounts"); - if (!suggested_tip_amounts_str.empty()) { - auto r_suggested_tip_amounts_value = json_decode(suggested_tip_amounts_str); - if (r_suggested_tip_amounts_value.is_error()) { - return Status::Error(400, "Can't parse suggested_tip_amounts JSON object"); - } - - TRY_RESULT_ASSIGN(suggested_tip_amounts, get_suggested_tip_amounts(r_suggested_tip_amounts_value.ok_ref())); - } - } - - auto photo_url = query->arg("photo_url"); - int32 photo_size = get_integer_arg(query.get(), "photo_size", 0, 0, 1000000000); - int32 photo_width = get_integer_arg(query.get(), "photo_width", 0, 0, MAX_LENGTH); - int32 photo_height = get_integer_arg(query.get(), "photo_height", 0, 0, MAX_LENGTH); - - auto need_name = to_bool(query->arg("need_name")); - auto need_phone_number = to_bool(query->arg("need_phone_number")); - auto need_email_address = to_bool(query->arg("need_email")); - auto need_shipping_address = to_bool(query->arg("need_shipping_address")); - auto send_phone_number_to_provider = to_bool(query->arg("send_phone_number_to_provider")); - auto send_email_address_to_provider = to_bool(query->arg("send_email_to_provider")); - auto is_flexible = to_bool(query->arg("is_flexible")); - - do_send_message(make_object( - make_object( - currency.str(), std::move(prices), max_tip_amount, std::move(suggested_tip_amounts), false, - td::string(), need_name, need_phone_number, need_email_address, need_shipping_address, - send_phone_number_to_provider, send_email_address_to_provider, is_flexible), - title.str(), description.str(), photo_url.str(), photo_size, photo_width, photo_height, - payload.str(), provider_token.str(), provider_data.str(), start_parameter.str()), - std::move(query)); + TRY_RESULT(input_message_invoice, get_input_message_invoice(query.get())); + do_send_message(std::move(input_message_invoice), std::move(query)); return Status::OK(); } @@ -7499,6 +7523,13 @@ td::Status Client::process_delete_message_query(PromisedQueryPtr &query) { return Status::OK(); } +td::Status Client::process_create_invoice_link_query(PromisedQueryPtr &query) { + TRY_RESULT(input_message_invoice, get_input_message_invoice(query.get())); + send_request(make_object(std::move(input_message_invoice)), + td::make_unique(std::move(query))); + return Status::OK(); +} + td::Status Client::process_set_game_score_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); auto message_id = get_message_id(query.get()); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 5891eb6..2d6edc4 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -186,6 +186,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetGroupMembersCallback; class TdOnGetSupergroupMembersCallback; class TdOnGetSupergroupMembersCountCallback; + class TdOnCreateInvoiceLinkCallback; class TdOnReplacePrimaryChatInviteLinkCallback; class TdOnGetChatInviteLinkCallback; class TdOnGetGameHighScoresCallback; @@ -431,6 +432,8 @@ class Client final : public WebhookActor::Callback { td::Result>> get_input_message_contents( const Query *query, td::JsonValue &&value) const; + static td::Result> get_input_message_invoice(const Query *query); + static object_ptr get_message_send_options(bool disable_notification, bool protect_content); @@ -493,6 +496,7 @@ class Client final : public WebhookActor::Callback { Status process_edit_message_caption_query(PromisedQueryPtr &query); Status process_edit_message_reply_markup_query(PromisedQueryPtr &query); Status process_delete_message_query(PromisedQueryPtr &query); + Status process_create_invoice_link_query(PromisedQueryPtr &query); Status process_set_game_score_query(PromisedQueryPtr &query); Status process_get_game_high_scores_query(PromisedQueryPtr &query); Status process_answer_web_app_query_query(PromisedQueryPtr &query); From fd7489f6da3e42740563fb4fcb0dbb355b254088 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 11 May 2022 19:46:07 +0300 Subject: [PATCH 04/11] Add the field User.added_to_attachment_menu. --- telegram-bot-api/Client.cpp | 4 ++++ telegram-bot-api/Client.h | 1 + 2 files changed, 5 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 2616f1a..ea8e2f1 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -348,6 +348,9 @@ class Client::JsonUser final : public Jsonable { if (user_info != nullptr && !user_info->language_code.empty()) { object("language_code", user_info->language_code); } + if (user_info != nullptr && user_info->added_to_attachment_menu) { + object("added_to_attachment_menu", td::JsonTrue()); + } if (is_bot && full_bot_info_) { object("can_join_groups", td::JsonBool(user_info->can_join_groups)); object("can_read_all_group_messages", td::JsonBool(user_info->can_read_all_group_messages)); @@ -8883,6 +8886,7 @@ void Client::add_user(UserInfo *user_info, object_ptr &&user) { user_info->language_code = std::move(user->language_code_); user_info->have_access = user->have_access_; + user_info->added_to_attachment_menu = user->added_to_attachment_menu_; switch (user->type_->get_id()) { case td_api::userTypeRegular::ID: diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 2d6edc4..1168835 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -615,6 +615,7 @@ class Client final : public WebhookActor::Callback { bool can_read_all_group_messages = false; bool is_inline_bot = false; bool has_private_forwards = false; + bool added_to_attachment_menu = false; }; static void add_user(UserInfo *user_info, object_ptr &&user); void set_user_photo(int64 user_id, object_ptr &&photo); From 06d40edb0a1cd1c56213b738b223ca383e96a9dd Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 13 May 2022 16:39:32 +0300 Subject: [PATCH 05/11] Allow to specify a secret_token in setWebhook to ensure that webhook was set by the domain owner. --- telegram-bot-api/Client.cpp | 17 +++++++++++++++-- telegram-bot-api/Client.h | 1 + telegram-bot-api/ClientManager.cpp | 5 +++++ telegram-bot-api/WebhookActor.cpp | 8 ++++++-- telegram-bot-api/WebhookActor.h | 3 ++- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ea8e2f1..44cc67c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -8382,13 +8382,14 @@ td::Status Client::process_set_webhook_query(PromisedQueryPtr &query) { int32 new_max_connections = new_url.empty() ? 0 : get_webhook_max_connections(query.get()); Slice new_ip_address = new_url.empty() ? Slice() : query->arg("ip_address"); bool new_fix_ip_address = new_url.empty() ? false : get_webhook_fix_ip_address(query.get()); + Slice new_secret_token = new_url.empty() ? Slice() : query->arg("secret_token"); bool drop_pending_updates = to_bool(query->arg("drop_pending_updates")); if (webhook_set_query_) { // already updating webhook. Cancel previous request fail_query_conflict("Conflict: terminated by other setWebhook", std::move(webhook_set_query_)); } else if (webhook_url_ == new_url && !has_webhook_certificate_ && query->file("certificate") == nullptr && query->arg("certificate").empty() && new_max_connections == webhook_max_connections_ && - new_fix_ip_address == webhook_fix_ip_address_ && + new_fix_ip_address == webhook_fix_ip_address_ && new_secret_token == webhook_secret_token_ && (!new_fix_ip_address || new_ip_address == webhook_ip_address_) && !drop_pending_updates) { if (update_allowed_update_types(query.get())) { save_webhook(); @@ -8512,6 +8513,9 @@ void Client::save_webhook() const { if (webhook_fix_ip_address_) { value += "#fix_ip/"; } + if (!webhook_secret_token_.empty()) { + value += PSTRING() << "#secret" << webhook_secret_token_ << '/'; + } if (allowed_update_types_ != DEFAULT_ALLOWED_UPDATE_TYPES) { value += PSTRING() << "#allow" << allowed_update_types_ << '/'; } @@ -8555,6 +8559,7 @@ void Client::webhook_closed(Status status) { webhook_max_connections_ = 0; webhook_ip_address_ = td::string(); webhook_fix_ip_address_ = false; + webhook_secret_token_ = td::string(); webhook_set_time_ = td::Time::now(); last_webhook_error_date_ = 0; last_webhook_error_ = Status::OK(); @@ -8604,6 +8609,13 @@ void Client::do_set_webhook(PromisedQueryPtr query, bool was_deleted) { if (url.is_error()) { return fail_query(400, "Bad Request: invalid webhook URL specified", std::move(query)); } + auto secret_token = query->arg("secret_token"); + if (secret_token.size() > 256) { + return fail_query(400, "Bad Request: secret token is too long", std::move(query)); + } + if (!td::is_base64url_characters(secret_token)) { + return fail_query(400, "Bad Request: secret token contains unallowed characters", std::move(query)); + } auto *cert_file_ptr = query->file("certificate"); has_webhook_certificate_ = false; if (cert_file_ptr != nullptr) { @@ -8627,6 +8639,7 @@ void Client::do_set_webhook(PromisedQueryPtr query, bool was_deleted) { webhook_url_ = new_url.str(); webhook_set_time_ = td::Time::now(); webhook_max_connections_ = get_webhook_max_connections(query.get()); + webhook_secret_token_ = secret_token.str(); webhook_ip_address_ = query->arg("ip_address").str(); webhook_fix_ip_address_ = get_webhook_fix_ip_address(query.get()); last_webhook_error_date_ = 0; @@ -8639,7 +8652,7 @@ void Client::do_set_webhook(PromisedQueryPtr query, bool was_deleted) { webhook_id_ = td::create_actor( webhook_actor_name, actor_shared(this, webhook_generation_), tqueue_id_, url.move_as_ok(), has_webhook_certificate_ ? get_webhook_certificate_path() : "", webhook_max_connections_, query->is_internal(), - webhook_ip_address_, webhook_fix_ip_address_, parameters_); + webhook_ip_address_, webhook_fix_ip_address_, webhook_secret_token_, parameters_); // wait for webhook verified or webhook callback webhook_query_type_ = WebhookQueryType::Verify; webhook_set_query_ = std::move(query); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 1168835..ac46db3 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1007,6 +1007,7 @@ class Client final : public WebhookActor::Callback { int32 webhook_max_connections_ = 0; td::string webhook_ip_address_; bool webhook_fix_ip_address_ = false; + td::string webhook_secret_token_; int32 last_webhook_error_date_ = 0; Status last_webhook_error_; double next_allowed_set_webhook_time_ = 0; diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index 740f92d..13bf98a 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -378,6 +378,11 @@ PromisedQueryPtr ClientManager::get_webhook_restore_query(td::Slice token, td::S parser.skip('/'); } + if (parser.try_skip("#secret")) { + args.emplace_back(add_string("secret_token"), add_string(parser.read_till('/'))); + parser.skip('/'); + } + if (parser.try_skip("#allow")) { args.emplace_back(add_string("allowed_updates"), add_string(parser.read_till('/'))); parser.skip('/'); diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 1a42b81..68b9ac9 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -42,7 +42,7 @@ std::atomic WebhookActor::total_connections_count_{0}; WebhookActor::WebhookActor(td::ActorShared callback, td::int64 tqueue_id, td::HttpUrl url, td::string cert_path, td::int32 max_connections, bool from_db_flag, - td::string cached_ip_address, bool fix_ip_address, + td::string cached_ip_address, bool fix_ip_address, td::string secret_token, std::shared_ptr parameters) : callback_(std::move(callback)) , tqueue_id_(tqueue_id) @@ -51,7 +51,8 @@ WebhookActor::WebhookActor(td::ActorShared callback, td::int64 tqueue_ , parameters_(std::move(parameters)) , fix_ip_address_(fix_ip_address) , from_db_flag_(from_db_flag) - , max_connections_(max_connections) { + , max_connections_(max_connections) + , secret_token_(std::move(secret_token)) { CHECK(max_connections_ > 0); if (!cached_ip_address.empty()) { @@ -539,6 +540,9 @@ td::Status WebhookActor::send_update() { if (!url_.userinfo_.empty()) { hc.add_header("Authorization", PSLICE() << "Basic " << td::base64_encode(url_.userinfo_)); } + if (!secret_token_.empty()) { + hc.add_header("X-Telegram-Bot-Api-Secret-Token", secret_token_); + } hc.set_content_type("application/json"); hc.set_content_size(body.size()); hc.set_keep_alive(); diff --git a/telegram-bot-api/WebhookActor.h b/telegram-bot-api/WebhookActor.h index 71d702e..d5e2499 100644 --- a/telegram-bot-api/WebhookActor.h +++ b/telegram-bot-api/WebhookActor.h @@ -54,7 +54,7 @@ class WebhookActor final : public td::HttpOutboundConnection::Callback { WebhookActor(td::ActorShared callback, td::int64 tqueue_id, td::HttpUrl url, td::string cert_path, td::int32 max_connections, bool from_db_flag, td::string cached_ip_address, bool fix_ip_address, - std::shared_ptr parameters); + td::string secret_token, std::shared_ptr parameters); void update(); @@ -163,6 +163,7 @@ class WebhookActor final : public td::HttpOutboundConnection::Callback { td::vector> ready_sockets_; td::int32 max_connections_ = 0; + td::string secret_token_; td::Container connections_; td::ListNode ready_connections_; td::FloodControlFast active_new_connection_flood_; From 0ac93c8674a4e8cece4615b32f4d8697bf26ff91 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 13 May 2022 16:41:12 +0300 Subject: [PATCH 06/11] Add join_to_send_messages and join_by_request flags to Chat. --- telegram-bot-api/Client.cpp | 8 ++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 44cc67c..a73766f 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -712,6 +712,12 @@ class Client::JsonChat final : public Jsonable { if (supergroup_info->is_supergroup) { object("permissions", JsonChatPermissions(chat_info->permissions.get())); } + if (supergroup_info->is_supergroup && supergroup_info->join_to_send_messages) { + object("join_to_send_messages", td::JsonTrue()); + } + if (supergroup_info->is_supergroup && supergroup_info->join_by_request) { + object("join_by_request", td::JsonTrue()); + } if (supergroup_info->slow_mode_delay != 0) { object("slow_mode_delay", supergroup_info->slow_mode_delay); } @@ -8998,6 +9004,8 @@ void Client::add_supergroup(SupergroupInfo *supergroup_info, object_ptrstatus = std::move(supergroup->status_); supergroup_info->is_supergroup = !supergroup->is_channel_; supergroup_info->has_location = supergroup->has_location_; + supergroup_info->join_to_send_messages = supergroup->join_to_send_messages_; + supergroup_info->join_by_request = supergroup->join_by_request_; } void Client::set_supergroup_photo(int64 supergroup_id, object_ptr &&photo) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index ac46db3..1110c59 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -655,6 +655,8 @@ class Client final : public WebhookActor::Callback { bool is_supergroup = false; bool can_set_sticker_set = false; bool has_location = false; + bool join_to_send_messages = false; + bool join_by_request = false; }; static void add_supergroup(SupergroupInfo *supergroup_info, object_ptr &&supergroup); void set_supergroup_photo(int64 supergroup_id, object_ptr &&photo); From 7b20bdacdf9575e6fb30edc5b535dca0b294a719 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 13 May 2022 18:24:18 +0300 Subject: [PATCH 07/11] Allow to use attach protocol to upload webhook certificate. --- telegram-bot-api/Client.cpp | 29 ++++++++++++++++++++++------- telegram-bot-api/Client.h | 3 +++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a73766f..2179820 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -8385,6 +8385,9 @@ td::Status Client::process_set_webhook_query(PromisedQueryPtr &query) { // do not send warning just after webhook was deleted or set next_bot_updates_warning_time_ = td::max(next_bot_updates_warning_time_, now + BOT_UPDATES_WARNING_DELAY); + bool new_has_certificate = new_url.empty() ? false + : (get_webhook_certificate(query.get()) != nullptr || + (query->is_internal() && query->arg("certificate") == "previous")); int32 new_max_connections = new_url.empty() ? 0 : get_webhook_max_connections(query.get()); Slice new_ip_address = new_url.empty() ? Slice() : query->arg("ip_address"); bool new_fix_ip_address = new_url.empty() ? false : get_webhook_fix_ip_address(query.get()); @@ -8393,9 +8396,9 @@ td::Status Client::process_set_webhook_query(PromisedQueryPtr &query) { if (webhook_set_query_) { // already updating webhook. Cancel previous request fail_query_conflict("Conflict: terminated by other setWebhook", std::move(webhook_set_query_)); - } else if (webhook_url_ == new_url && !has_webhook_certificate_ && query->file("certificate") == nullptr && - query->arg("certificate").empty() && new_max_connections == webhook_max_connections_ && - new_fix_ip_address == webhook_fix_ip_address_ && new_secret_token == webhook_secret_token_ && + } else if (webhook_url_ == new_url && !has_webhook_certificate_ && !new_has_certificate && + new_max_connections == webhook_max_connections_ && new_fix_ip_address == webhook_fix_ip_address_ && + new_secret_token == webhook_secret_token_ && (!new_fix_ip_address || new_ip_address == webhook_ip_address_) && !drop_pending_updates) { if (update_allowed_update_types(query.get())) { save_webhook(); @@ -8588,6 +8591,18 @@ td::string Client::get_webhook_certificate_path() const { return dir_ + "cert.pem"; } +const td::HttpFile *Client::get_webhook_certificate(const Query *query) const { + auto file = query->file("certificate"); + if (file == nullptr) { + auto attach_name = query->arg("certificate"); + Slice attach_protocol{"attach://"}; + if (td::begins_with(attach_name, attach_protocol)) { + file = query->file(attach_name.substr(attach_protocol.size())); + } + } + return file; +} + td::int32 Client::get_webhook_max_connections(const Query *query) const { auto default_value = parameters_->default_max_webhook_connections_; auto max_value = parameters_->local_mode_ ? 100000 : 100; @@ -8622,8 +8637,9 @@ void Client::do_set_webhook(PromisedQueryPtr query, bool was_deleted) { if (!td::is_base64url_characters(secret_token)) { return fail_query(400, "Bad Request: secret token contains unallowed characters", std::move(query)); } - auto *cert_file_ptr = query->file("certificate"); + has_webhook_certificate_ = false; + auto *cert_file_ptr = get_webhook_certificate(query.get()); if (cert_file_ptr != nullptr) { auto size = cert_file_ptr->size; if (size > MAX_CERTIFICATE_FILE_SIZE) { @@ -8637,11 +8653,10 @@ void Client::do_set_webhook(PromisedQueryPtr query, bool was_deleted) { return fail_query(500, "Internal Server Error: failed to save certificate", std::move(query)); } has_webhook_certificate_ = true; - } - - if (query->is_internal() && query->arg("certificate") == "previous") { + } else if (query->is_internal() && query->arg("certificate") == "previous") { has_webhook_certificate_ = true; } + webhook_url_ = new_url.str(); webhook_set_time_ = td::Time::now(); webhook_max_connections_ = get_webhook_max_connections(query.get()); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 1110c59..da41953 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -13,6 +13,8 @@ #include "td/telegram/ClientActor.h" #include "td/telegram/td_api.h" +#include "td/net/HttpFile.h" + #include "td/actor/actor.h" #include "td/actor/PromiseFuture.h" #include "td/actor/SignalSlot.h" @@ -552,6 +554,7 @@ class Client final : public WebhookActor::Callback { void webhook_error(Status status) final; void webhook_closed(Status status) final; void hangup_shared() final; + const td::HttpFile *get_webhook_certificate(const Query *query) const; int32 get_webhook_max_connections(const Query *query) const; static bool get_webhook_fix_ip_address(const Query *query); void do_set_webhook(PromisedQueryPtr query, bool was_deleted); From 897ddb64ce125ec1030d2c469f02d49bec397467 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 24 May 2022 16:56:53 +0300 Subject: [PATCH 08/11] Add User.is_premium. --- telegram-bot-api/Client.cpp | 4 ++++ telegram-bot-api/Client.h | 1 + 2 files changed, 5 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 2179820..c30f54a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -348,6 +348,9 @@ class Client::JsonUser final : public Jsonable { if (user_info != nullptr && !user_info->language_code.empty()) { object("language_code", user_info->language_code); } + if (user_info != nullptr && user_info->is_premium) { + object("is_premium", td::JsonTrue()); + } if (user_info != nullptr && user_info->added_to_attachment_menu) { object("added_to_attachment_menu", td::JsonTrue()); } @@ -8920,6 +8923,7 @@ void Client::add_user(UserInfo *user_info, object_ptr &&user) { user_info->language_code = std::move(user->language_code_); user_info->have_access = user->have_access_; + user_info->is_premium = user->is_premium_; user_info->added_to_attachment_menu = user->added_to_attachment_menu_; switch (user->type_->get_id()) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index da41953..8bcc5c8 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -618,6 +618,7 @@ class Client final : public WebhookActor::Callback { bool can_read_all_group_messages = false; bool is_inline_bot = false; bool has_private_forwards = false; + bool is_premium = false; bool added_to_attachment_menu = false; }; static void add_user(UserInfo *user_info, object_ptr &&user); From b10216322068553fa2f5841762c4106c429fe520 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 30 May 2022 21:32:01 +0300 Subject: [PATCH 09/11] Improve sendMediaGroup error message. --- telegram-bot-api/Client.cpp | 16 +++++++++++++--- telegram-bot-api/Client.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c30f54a..b7a87c7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6851,8 +6851,15 @@ void Client::on_message_send_failed(int64 chat_id, int64 old_message_id, int64 n auto query_id = extract_yet_unsent_message_query_id(chat_id, old_message_id, nullptr); auto &query = *pending_send_message_queries_[query_id]; if (query.is_multisend) { - if (query.error == nullptr) { - query.error = std::move(error); + if (query.error == nullptr || query.error->message_ == "Group send failed") { + if (error->code_ == 429 || error->message_ == "Group send failed") { + query.error = std::move(error); + } else { + auto pos = (query.total_message_count - query.awaited_message_count + 1); + query.error = make_object(error->code_, PSTRING() << "Failed to send message #" << pos + << " with the error message \"" + << error->message_ << '"'); + } } query.awaited_message_count--; @@ -8750,7 +8757,10 @@ void Client::on_sent_message(object_ptr &&message, int64 query_ auto emplace_result = yet_unsent_messages_.emplace(yet_unsent_message_id, yet_unsent_message); CHECK(emplace_result.second); yet_unsent_message_count_[chat_id]++; - pending_send_message_queries_[query_id]->awaited_message_count++; + + auto &query = *pending_send_message_queries_[query_id]; + query.awaited_message_count++; + query.total_message_count++; } void Client::abort_long_poll(bool from_set_webhook) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 8bcc5c8..852c309 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -936,6 +936,7 @@ class Client final : public WebhookActor::Callback { struct PendingSendMessageQuery { PromisedQueryPtr query; bool is_multisend = false; + int32 total_message_count = 0; int32 awaited_message_count = 0; td::vector messages; object_ptr error; From ba6f4c2e8d476482cdf2956672f1505434be1085 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 6 Jun 2022 16:33:42 +0300 Subject: [PATCH 10/11] Add Sticker.premium_animation. --- telegram-bot-api/Client.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index b7a87c7..ca5db6a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -283,16 +283,18 @@ bool Client::init_methods() { class Client::JsonFile final : public Jsonable { public: - JsonFile(const td_api::file *file, const Client *client) : file_(file), client_(client) { + JsonFile(const td_api::file *file, const Client *client, bool with_path) + : file_(file), client_(client), with_path_(with_path) { } void store(JsonValueScope *scope) const { auto object = scope->enter_object(); - client_->json_store_file(object, file_, true); + client_->json_store_file(object, file_, with_path_); } private: const td_api::file *file_; const Client *client_; + bool with_path_; }; class Client::JsonDatedFile final : public Jsonable { @@ -1021,6 +1023,9 @@ class Client::JsonSticker final : public Jsonable { object("mask_position", JsonMaskPosition(mask_position.get())); } } + if (sticker_->premium_animation_ != nullptr) { + object("premium_animation", JsonFile(sticker_->premium_animation_.get(), client_, false)); + } client_->json_store_thumbnail(object, sticker_->thumbnail_.get()); client_->json_store_file(object, sticker_->sticker_.get()); } @@ -3625,7 +3630,7 @@ class Client::TdOnReturnFileCallback final : public TdQueryCallback { CHECK(result->get_id() == td_api::file::ID); auto file = move_object_as(result); - answer_query(JsonFile(file.get(), client_), std::move(query_)); + answer_query(JsonFile(file.get(), client_, false), std::move(query_)); } private: @@ -8500,7 +8505,7 @@ void Client::on_file_download(int32 file_id, td::Result const auto &error = r_file.error(); fail_query_with_error(std::move(query), error.code(), error.public_message()); } else { - answer_query(JsonFile(r_file.ok().get(), this), std::move(query)); + answer_query(JsonFile(r_file.ok().get(), this, true), std::move(query)); } } } From 24ee05d15fca6f771c8229c38d96d6008b81c64a Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 19 Jun 2022 20:25:15 +0300 Subject: [PATCH 11/11] Update version to 6.1. --- CMakeLists.txt | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 665263d..76ef36a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 6.0.2 LANGUAGES CXX) +project(TelegramBotApi VERSION 6.1 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 9e197da..bdce424 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) { auto start_time = td::Time::now(); auto shared_data = std::make_shared(); auto parameters = std::make_unique(); - parameters->version_ = "6.0.2"; + parameters->version_ = "6.1"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();