From d80b613b55a5f8b1b82813dfb4e0d773d5a8e96e Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 8 Jun 2021 18:31:29 +0300 Subject: [PATCH] Remove support for secret chat layers before 73. --- td/generate/scheme/td_api.tl | 2 +- td/telegram/AnimationsManager.cpp | 13 +--- td/telegram/AnimationsManager.h | 2 +- td/telegram/MessageContent.cpp | 12 +--- td/telegram/MessageContent.h | 2 +- td/telegram/MessagesManager.cpp | 10 ++- td/telegram/SecretChatActor.cpp | 107 +++++------------------------- td/telegram/SecretChatActor.h | 10 +-- td/telegram/VideoNotesManager.cpp | 4 +- td/telegram/VideoNotesManager.h | 2 +- 10 files changed, 38 insertions(+), 126 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 53773f53f..eac43bee2 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -668,7 +668,7 @@ secretChatStateClosed = SecretChatState; //@is_outbound True, if the chat was created by the current user; otherwise false //@key_hash Hash of the currently used key for comparison with the hash of the chat partner's key. This is a string of 36 little-endian bytes, which must be split into groups of 2 bits, each denoting a pixel of one of 4 colors FFFFFF, D5E6F3, 2D5775, and 2F99C9. //-The pixels must be used to make a 12x12 square image filled from left to right, top to bottom. Alternatively, the first 32 bytes of the hash can be converted to the hexadecimal format and printed as 32 2-digit hex numbers -//@layer Secret chat layer; determines features supported by the chat partner's application. Video notes are supported if the layer >= 66; nested text entities and underline and strikethrough entities are supported if the layer >= 101 +//@layer Secret chat layer; determines features supported by the chat partner's application. Nested text entities and underline and strikethrough entities are supported if the layer >= 101 secretChat id:int32 user_id:int32 state:SecretChatState is_outbound:Bool key_hash:bytes layer:int32 = SecretChat; diff --git a/td/telegram/AnimationsManager.cpp b/td/telegram/AnimationsManager.cpp index 51d8bab77..fa6274a1c 100644 --- a/td/telegram/AnimationsManager.cpp +++ b/td/telegram/AnimationsManager.cpp @@ -18,7 +18,6 @@ #include "td/telegram/logevent/LogEvent.h" #include "td/telegram/misc.h" #include "td/telegram/secret_api.h" -#include "td/telegram/SecretChatActor.h" #include "td/telegram/Td.h" #include "td/telegram/td_api.h" #include "td/telegram/TdDb.h" @@ -402,8 +401,7 @@ tl_object_ptr AnimationsManager::get_input_media( SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file_id, tl_object_ptr input_file, - const string &caption, BufferSlice thumbnail, - int32 layer) const { + const string &caption, BufferSlice thumbnail) const { auto *animation = get_animation(animation_file_id); CHECK(animation != nullptr); auto file_view = td_->file_manager_->get_file_view(animation_file_id); @@ -425,13 +423,8 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file attributes.push_back(make_tl_object(animation->file_name)); } if (animation->duration != 0 && animation->mime_type == "video/mp4") { - if (layer >= SecretChatActor::VIDEO_NOTES_LAYER) { - attributes.push_back(make_tl_object( - 0, false, animation->duration, animation->dimensions.width, animation->dimensions.height)); - } else { - attributes.push_back(make_tl_object( - animation->duration, animation->dimensions.width, animation->dimensions.height)); - } + attributes.push_back(make_tl_object( + 0, false, animation->duration, animation->dimensions.width, animation->dimensions.height)); } if (animation->dimensions.width != 0 && animation->dimensions.height != 0) { attributes.push_back(make_tl_object(animation->dimensions.width, diff --git a/td/telegram/AnimationsManager.h b/td/telegram/AnimationsManager.h index 796bb63cb..29daa79fa 100644 --- a/td/telegram/AnimationsManager.h +++ b/td/telegram/AnimationsManager.h @@ -45,7 +45,7 @@ class AnimationsManager : public Actor { SecretInputMedia get_secret_input_media(FileId animation_file_id, tl_object_ptr input_file, - const string &caption, BufferSlice thumbnail, int32 layer) const; + const string &caption, BufferSlice thumbnail) const; FileId get_animation_thumbnail_file_id(FileId file_id) const; diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index bf770e8ac..65834e98a 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -50,7 +50,6 @@ #include "td/telegram/PollId.hpp" #include "td/telegram/PollManager.h" #include "td/telegram/secret_api.hpp" -#include "td/telegram/SecretChatActor.h" #include "td/telegram/SecureValue.h" #include "td/telegram/SecureValue.hpp" #include "td/telegram/StickersManager.h" @@ -2061,12 +2060,12 @@ bool can_have_input_media(const Td *td, const MessageContent *content) { SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td, tl_object_ptr input_file, - BufferSlice thumbnail, int32 layer) { + BufferSlice thumbnail) { switch (content->get_type()) { case MessageContentType::Animation: { auto m = static_cast(content); return td->animations_manager_->get_secret_input_media(m->file_id, std::move(input_file), m->caption.text, - std::move(thumbnail), layer); + std::move(thumbnail)); } case MessageContentType::Audio: { auto m = static_cast(content); @@ -2112,8 +2111,7 @@ SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td, } case MessageContentType::VideoNote: { auto m = static_cast(content); - return td->video_notes_manager_->get_secret_input_media(m->file_id, std::move(input_file), std::move(thumbnail), - layer); + return td->video_notes_manager_->get_secret_input_media(m->file_id, std::move(input_file), std::move(thumbnail)); } case MessageContentType::VoiceNote: { auto m = static_cast(content); @@ -2567,10 +2565,6 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten if (!permissions.can_send_media()) { return Status::Error(400, "Not enough rights to send video notes to the chat"); } - if (secret_chat_layer < SecretChatActor::VIDEO_NOTES_LAYER) { - return Status::Error(400, PSLICE() - << "Video notes can't be sent to secret chat with layer " << secret_chat_layer); - } break; case MessageContentType::VoiceNote: if (!permissions.can_send_media()) { diff --git a/td/telegram/MessageContent.h b/td/telegram/MessageContent.h index fbd5fe8ba..891ebfeef 100644 --- a/td/telegram/MessageContent.h +++ b/td/telegram/MessageContent.h @@ -107,7 +107,7 @@ bool can_have_input_media(const Td *td, const MessageContent *content); SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td, tl_object_ptr input_file, - BufferSlice thumbnail, int32 layer); + BufferSlice thumbnail); tl_object_ptr get_input_media(const MessageContent *content, Td *td, tl_object_ptr input_file, diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 26b420b86..cac14f04a 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -8647,11 +8647,10 @@ void MessagesManager::do_send_secret_media(DialogId dialog_id, Message *m, FileI LOG(INFO) << "Do send secret media file " << file_id << " with thumbnail " << thumbnail_file_id << ", have_input_file = " << have_input_file; - auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); on_secret_message_media_uploaded( dialog_id, m, - get_secret_input_media(m->content.get(), td_, std::move(input_encrypted_file), std::move(thumbnail), layer), - file_id, thumbnail_file_id); + get_secret_input_media(m->content.get(), td_, std::move(input_encrypted_file), std::move(thumbnail)), file_id, + thumbnail_file_id); } void MessagesManager::on_upload_media_error(FileId file_id, Status status) { @@ -23422,8 +23421,7 @@ void MessagesManager::do_send_message(DialogId dialog_id, const Message *m, vect LOG(DEBUG) << "Need to send file " << file_id << " with thumbnail " << thumbnail_file_id; if (is_secret) { CHECK(!is_edit); - auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); - auto secret_input_media = get_secret_input_media(content, td_, nullptr, BufferSlice(), layer); + auto secret_input_media = get_secret_input_media(content, td_, nullptr, BufferSlice()); if (secret_input_media.empty()) { LOG(INFO) << "Ask to upload encrypted file " << file_id; CHECK(file_view.is_encrypted_secret()); @@ -23862,7 +23860,7 @@ void MessagesManager::on_text_message_ready_to_send(DialogId dialog_id, MessageI auto layer = td_->contacts_manager_->get_secret_chat_layer(dialog_id.get_secret_chat_id()); send_closure(td_->create_net_actor(), &SendSecretMessageActor::send, dialog_id, m->reply_to_random_id, m->ttl, message_text->text, - get_secret_input_media(content, td_, nullptr, BufferSlice(), layer), + get_secret_input_media(content, td_, nullptr, BufferSlice()), get_input_secret_message_entities(message_text->entities, layer), m->via_bot_user_id, m->media_album_id, m->disable_notification, random_id); } else { diff --git a/td/telegram/SecretChatActor.cpp b/td/telegram/SecretChatActor.cpp index d3f7ca3fb..571de4d48 100644 --- a/td/telegram/SecretChatActor.cpp +++ b/td/telegram/SecretChatActor.cpp @@ -180,7 +180,7 @@ void SecretChatActor::replay_inbound_message(unique_ptrdecrypted_message_layer); // from binlog if (message->is_pending) { // wait for gaps? - // check_status(do_inbound_message_decrypted_unchecked(std::move(message))); + // check_status(do_inbound_message_decrypted_unchecked(std::move(message)), -1); do_inbound_message_decrypted_pending(std::move(message)); } else { // just replay LOG_CHECK(message->message_id > last_binlog_message_id_) @@ -208,31 +208,23 @@ void SecretChatActor::replay_outbound_message(unique_ptr SecretChatActor::create_encrypted_message(int32 layer, int32 my_in_seq_no, int32 my_out_seq_no, +Result SecretChatActor::create_encrypted_message(int32 my_in_seq_no, int32 my_out_seq_no, tl_object_ptr &message) { - if (message->get_id() == secret_api::decryptedMessage::ID && layer < MTPROTO_2_LAYER) { - auto old = secret_api::move_object_as(message); - old->flags_ &= ~secret_api::decryptedMessage::GROUPED_ID_MASK; - message = secret_api::make_object( - old->flags_, old->random_id_, old->ttl_, std::move(old->message_), std::move(old->media_), - std::move(old->entities_), std::move(old->via_bot_name_), old->reply_to_random_id_); - } - mtproto::AuthKey *auth_key = &pfs_state_.auth_key; auto in_seq_no = my_in_seq_no * 2 + auth_state_.x; auto out_seq_no = my_out_seq_no * 2 - 1 - auth_state_.x; + auto layer = current_layer(); BufferSlice random_bytes(32); Random::secure_bytes(random_bytes.as_slice().ubegin(), random_bytes.size()); auto message_with_layer = secret_api::make_object( std::move(random_bytes), layer, in_seq_no, out_seq_no, std::move(message)); - LOG(INFO) << to_string(message_with_layer); + LOG(INFO) << "Create message " << to_string(message_with_layer); auto storer = create_storer(*message_with_layer); auto new_storer = mtproto::PacketStorer(storer); mtproto::PacketInfo info; info.type = mtproto::PacketInfo::EndToEnd; - // Send with mtproto 2.0 if current layer is at least MTPROTO_2_LAYER - info.version = layer >= MTPROTO_2_LAYER ? 2 : 1; + info.version = 2; info.is_creator = auth_state_.x == 0; auto packet_writer = BufferWriter{mtproto::Transport::write(new_storer, *auth_key, &info), 0, 0}; mtproto::Transport::write(new_storer, *auth_key, &info, packet_writer.as_slice()); @@ -249,63 +241,6 @@ void SecretChatActor::send_message(tl_object_ptr m send_message_impl(std::move(message), std::move(file), SendFlag::External | SendFlag::Push, std::move(promise)); } -static int32 get_min_layer(const secret_api::decryptedMessageActionTyping &message) { - switch (message.action_->get_id()) { - case secret_api::sendMessageRecordRoundAction::ID: - case secret_api::sendMessageUploadRoundAction::ID: - return SecretChatActor::VIDEO_NOTES_LAYER; - } - return 0; -} -static int32 get_min_layer(const secret_api::decryptedMessageService &message) { - switch (message.action_->get_id()) { - case secret_api::decryptedMessageActionTyping::ID: - return get_min_layer(static_cast(*message.action_)); - default: - return 0; - } -} -static int32 get_min_layer(const secret_api::DocumentAttribute &attribute) { - switch (attribute.get_id()) { - case secret_api::documentAttributeVideo66::ID: - return SecretChatActor::VIDEO_NOTES_LAYER; - default: - return 0; - } -} -static int32 get_min_layer(const secret_api::decryptedMessageMediaDocument &message) { - int32 res = 0; - for (auto &attribute : message.attributes_) { - auto attrirbute_layer = get_min_layer(*attribute); - if (attrirbute_layer > res) { - res = attrirbute_layer; - } - return res; - } - return res; -} -static int32 get_min_layer(const secret_api::decryptedMessage &message) { - if (!message.media_) { - return 0; - } - switch (message.media_->get_id()) { - case secret_api::decryptedMessageMediaDocument::ID: - return get_min_layer(static_cast(*message.media_)); - default: - return 0; - } -} -static int32 get_min_layer(const secret_api::DecryptedMessage &message) { - switch (message.get_id()) { - case secret_api::decryptedMessageService::ID: - return get_min_layer(static_cast(message)); - case secret_api::decryptedMessage::ID: - return get_min_layer(static_cast(message)); - default: - return 0; - } -} - void SecretChatActor::send_message_impl(tl_object_ptr message, tl_object_ptr file, int32 flags, Promise<> promise) { @@ -317,16 +252,11 @@ void SecretChatActor::send_message_impl(tl_object_ptr config_state_.his_layer) { - return promise.set_error(Status::Error(400, "Message is not supported by the other side")); - } LOG_CHECK(binlog_replay_finish_flag_) << "Trying to send message before binlog replay is finished: " << to_string(*message) << to_string(file); int64 random_id = 0; downcast_call(*message, [&](auto &x) { random_id = x.random_id_; }); - LOG(INFO) << "Send message: " << to_string(message) << to_string(file); - auto it = random_id_to_outbound_message_state_token_.find(random_id); if (it != random_id_to_outbound_message_state_token_.end()) { return on_outbound_outer_send_message_promise(it->second, std::move(promise)); @@ -341,8 +271,7 @@ void SecretChatActor::send_message_impl(tl_object_ptrmy_out_seq_no = seq_no_state_.my_out_seq_no + 1; binlog_event->his_in_seq_no = seq_no_state_.his_in_seq_no; binlog_event->encrypted_message = - create_encrypted_message(current_layer(), binlog_event->my_in_seq_no, binlog_event->my_out_seq_no, message) - .move_as_ok(); + create_encrypted_message(binlog_event->my_in_seq_no, binlog_event->my_out_seq_no, message).move_as_ok(); binlog_event->need_notify_user = (flags & SendFlag::Push) == 0; binlog_event->is_external = (flags & SendFlag::External) != 0; binlog_event->is_silent = (message->get_id() == secret_api::decryptedMessage::ID && @@ -617,7 +546,7 @@ void SecretChatActor::run_fill_gaps() { LOG(INFO) << "Replay pending event: " << tag("seq_no", next_seq_no); auto message = std::move(begin->second); pending_inbound_messages_.erase(begin); - check_status(do_inbound_message_decrypted_unchecked(std::move(message))); + check_status(do_inbound_message_decrypted_unchecked(std::move(message), -1)); CHECK(pending_inbound_messages_.find(next_seq_no) == pending_inbound_messages_.end()); } else { break; @@ -861,7 +790,6 @@ Result> SecretChatActor::decrypt(BufferSl int32 mtproto_version = -1; Result r_read_result; for (size_t i = 0; i < versions.size(); i++) { - bool is_last = i + 1 == versions.size(); encrypted_message_copy = encrypted_message.copy(); data = encrypted_message_copy.as_slice(); CHECK(is_aligned_pointer<4>(data.data())); @@ -872,7 +800,7 @@ Result> SecretChatActor::decrypt(BufferSl info.version = mtproto_version; info.is_creator = auth_state_.x == 0; r_read_result = mtproto::Transport::read(data, *auth_key, &info); - if (!is_last && r_read_result.is_error()) { + if (i + 1 == versions.size() && r_read_result.is_error()) { LOG(WARNING) << tag("mtproto", mtproto_version) << " decryption failed " << r_read_result.error(); continue; } @@ -883,7 +811,7 @@ Result> SecretChatActor::decrypt(BufferSl case mtproto::Transport::ReadResult::Quickack: return Status::Error("Got quickack instead of a message"); case mtproto::Transport::ReadResult::Error: - return Status::Error(PSLICE() << "Got mtproto error code instead of a message: " << read_result.error()); + return Status::Error(PSLICE() << "Got MTProto error code instead of a message: " << read_result.error()); case mtproto::Transport::ReadResult::Nop: return Status::Error("Got nop instead of a message"); case mtproto::Transport::ReadResult::Packet: @@ -938,7 +866,7 @@ Status SecretChatActor::do_inbound_message_encrypted(unique_ptrdecrypted_message_layer = std::move(message_with_layer); - return do_inbound_message_decrypted_unchecked(std::move(message)); + return do_inbound_message_decrypted_unchecked(std::move(message), mtproto_version); } else { status = Status::Error(PSLICE() << parser.get_error() << format::as_hex_dump<4>(data_buffer.as_slice())); } @@ -958,7 +886,7 @@ Status SecretChatActor::do_inbound_message_encrypted(unique_ptrdecrypted_message_layer = secret_api::make_object( BufferSlice(), config_state_.his_layer, -1, -1, std::move(message_without_layer)); - return do_inbound_message_decrypted_unchecked(std::move(message)); + return do_inbound_message_decrypted_unchecked(std::move(message), mtproto_version); } LOG(ERROR) << "Failed to fetch update (DecryptedMessage): " << new_parser.get_error() << format::as_hex_dump<4>(data_buffer.as_slice()); @@ -995,7 +923,8 @@ Status SecretChatActor::check_seq_no(int in_seq_no, int out_seq_no, int32 his_la return Status::OK(); } -Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptr message) { +Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptr message, + int32 mtproto_version) { SCOPE_EXIT { CHECK(message == nullptr || !message->promise); }; @@ -1056,7 +985,8 @@ Status SecretChatActor::do_inbound_message_decrypted_unchecked(unique_ptrdecrypted_message_layer); + LOG(INFO) << "Receive message encrypted with MTProto " << mtproto_version << ": " + << to_string(message->decrypted_message_layer); if (status.is_error()) { CHECK(status.code() == 2); // gap found @@ -1592,8 +1522,8 @@ Status SecretChatActor::outbound_rewrite_with_empty(uint64 state_id) { state->message->random_id, secret_api::make_object( std::vector{static_cast(state->message->random_id)})); - TRY_RESULT(encrypted_message, create_encrypted_message(current_layer(), state->message->my_in_seq_no, - state->message->my_out_seq_no, message)); + TRY_RESULT(encrypted_message, + create_encrypted_message(state->message->my_in_seq_no, state->message->my_out_seq_no, message)); state->message->encrypted_message = std::move(encrypted_message); LOG(INFO) << tag("crc", crc64(state->message->encrypted_message.as_slice())); state->message->is_rewritable = false; @@ -1820,7 +1750,7 @@ void SecretChatActor::on_outbound_outer_send_message_promise(uint64 state_id, Pr } auto *state = outbound_message_states_.get(state_id); CHECK(state); - LOG(INFO) << "Outbound secret message [TODO] " << tag("log_event_id", state->message->log_event_id()); + LOG(INFO) << "Outbound secret message " << tag("log_event_id", state->message->log_event_id()); promise.set_value(Unit()); // Seems like this message is at least stored to binlog already if (state->send_result_) { state->send_result_({}); @@ -1918,7 +1848,6 @@ Status SecretChatActor::on_update_chat(telegram_api::encryptedChat &update) { // NB: order is important context_->secret_chat_db()->set_value(pfs_state_); context_->secret_chat_db()->set_value(auth_state_); - LOG(INFO) << "OK! Ready!"; send_update_secret_chat(); send_action(secret_api::make_object(MY_LAYER), SendFlag::None, Promise<>()); diff --git a/td/telegram/SecretChatActor.h b/td/telegram/SecretChatActor.h index 957605708..ac951b77a 100644 --- a/td/telegram/SecretChatActor.h +++ b/td/telegram/SecretChatActor.h @@ -48,10 +48,8 @@ class NetQueryCreator; class SecretChatActor : public NetQueryCallback { public: - // do not change DEFAULT_LAYER, unless all it's usages are fixed enum : int32 { - DEFAULT_LAYER = 46, - VIDEO_NOTES_LAYER = 66, + DEFAULT_LAYER = 73, MTPROTO_2_LAYER = 73, NEW_ENTITIES_LAYER = 101, DELETE_MESSAGES_ON_CLOSE_LAYER = 123, @@ -571,7 +569,8 @@ class SecretChatActor : public NetQueryCallback { Result> decrypt(BufferSlice &encrypted_message); Status do_inbound_message_encrypted(unique_ptr message); - Status do_inbound_message_decrypted_unchecked(unique_ptr message); + Status do_inbound_message_decrypted_unchecked(unique_ptr message, + int32 mtproto_version); Status do_inbound_message_decrypted(unique_ptr message); void do_inbound_message_decrypted_pending(unique_ptr message); @@ -620,7 +619,8 @@ class SecretChatActor : public NetQueryCallback { tl_object_ptr file, int32 flags, Promise<> promise); void do_outbound_message_impl(unique_ptr, Promise<> promise); - Result create_encrypted_message(int32 layer, int32 my_in_seq_no, int32 my_out_seq_no, + + Result create_encrypted_message(int32 my_in_seq_no, int32 my_out_seq_no, tl_object_ptr &message); NetQueryPtr create_net_query(const log_event::OutboundSecretMessage &message); diff --git a/td/telegram/VideoNotesManager.cpp b/td/telegram/VideoNotesManager.cpp index 97f3289ee..cf967a041 100644 --- a/td/telegram/VideoNotesManager.cpp +++ b/td/telegram/VideoNotesManager.cpp @@ -9,7 +9,6 @@ #include "td/telegram/AuthManager.h" #include "td/telegram/files/FileManager.h" #include "td/telegram/secret_api.h" -#include "td/telegram/SecretChatActor.h" #include "td/telegram/Td.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" @@ -167,7 +166,7 @@ void VideoNotesManager::create_video_note(FileId file_id, string minithumbnail, SecretInputMedia VideoNotesManager::get_secret_input_media(FileId video_note_file_id, tl_object_ptr input_file, - BufferSlice thumbnail, int32 layer) const { + BufferSlice thumbnail) const { const VideoNote *video_note = get_video_note(video_note_file_id); CHECK(video_note != nullptr); auto file_view = td_->file_manager_->get_file_view(video_note_file_id); @@ -184,7 +183,6 @@ SecretInputMedia VideoNotesManager::get_secret_input_media(FileId video_note_fil if (video_note->thumbnail.file_id.is_valid() && thumbnail.empty()) { return SecretInputMedia{}; } - CHECK(layer >= SecretChatActor::VIDEO_NOTES_LAYER); vector> attributes; attributes.push_back(make_tl_object( secret_api::documentAttributeVideo66::ROUND_MESSAGE_MASK, true, video_note->duration, diff --git a/td/telegram/VideoNotesManager.h b/td/telegram/VideoNotesManager.h index be1e74d5e..b49611e33 100644 --- a/td/telegram/VideoNotesManager.h +++ b/td/telegram/VideoNotesManager.h @@ -39,7 +39,7 @@ class VideoNotesManager { SecretInputMedia get_secret_input_media(FileId video_note_file_id, tl_object_ptr input_file, - BufferSlice thumbnail, int32 layer) const; + BufferSlice thumbnail) const; FileId get_video_note_thumbnail_file_id(FileId file_id) const;