diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index b584039fc..b7ee0b847 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3445,6 +3445,13 @@ getInviteText = Text; getDeepLinkInfo link:string = DeepLinkInfo; +//@description Returns application config, provided by the server. Can be called before authorization +getApplicationConfig = JsonValue; + +//@description Saves application log event on the server. Can be called before authorization @type Event type @chat_id Optional chat identifier, associated with the event @data The log event data +saveApplicationLogEvent type:string chat_id:int53 data:JsonValue = Ok; + + //@description Adds a proxy server for network requests. Can be called before authorization @server Proxy server IP address @port Proxy server port @enable True, if the proxy should be enabled @type Proxy type addProxy server:string port:int32 enable:Bool type:ProxyType = Proxy; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 33eaa4fe9..fe81076e7 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/JsonValue.cpp b/td/telegram/JsonValue.cpp index 226ffc829..ad26b4830 100644 --- a/td/telegram/JsonValue.cpp +++ b/td/telegram/JsonValue.cpp @@ -6,8 +6,11 @@ // #include "td/telegram/JsonValue.h" +#include "td/telegram/misc.h" + #include "td/utils/JsonBuilder.h" #include "td/utils/misc.h" +#include "td/utils/utf8.h" namespace td { @@ -45,6 +48,82 @@ Result> get_json_value(MutableSlice json) return get_json_value_object(json_value); } +static td_api::object_ptr convert_json_value_member_object( + const telegram_api::object_ptr &json_object_value) { + CHECK(json_object_value != nullptr); + return td_api::make_object(json_object_value->key_, + convert_json_value_object(json_object_value->value_)); +} + +td_api::object_ptr convert_json_value_object( + const tl_object_ptr &json_value) { + CHECK(json_value != nullptr); + switch (json_value->get_id()) { + case telegram_api::jsonNull::ID: + return td_api::make_object(); + case telegram_api::jsonBool::ID: + return td_api::make_object( + static_cast(json_value.get())->value_); + case telegram_api::jsonNumber::ID: + return td_api::make_object( + static_cast(json_value.get())->value_); + case telegram_api::jsonString::ID: + return td_api::make_object( + static_cast(json_value.get())->value_); + case telegram_api::jsonArray::ID: + return td_api::make_object( + transform(static_cast(json_value.get())->value_, convert_json_value_object)); + case telegram_api::jsonObject::ID: + return td_api::make_object(transform( + static_cast(json_value.get())->value_, convert_json_value_member_object)); + default: + UNREACHABLE(); + return nullptr; + } +} + +static telegram_api::object_ptr convert_json_value_member( + td_api::object_ptr &&json_object_member) { + CHECK(json_object_member != nullptr); + if (!clean_input_string(json_object_member->key_)) { + json_object_member->key_.clear(); + } + return telegram_api::make_object( + json_object_member->key_, convert_json_value(std::move(json_object_member->value_))); +} + +tl_object_ptr convert_json_value(td_api::object_ptr &&json_value) { + if (json_value == nullptr) { + return td_api::make_object(); + } + switch (json_value->get_id()) { + case td_api::jsonValueNull::ID: + return telegram_api::make_object(); + case td_api::jsonValueBoolean::ID: + return telegram_api::make_object( + static_cast(json_value.get())->value_); + case td_api::jsonValueNumber::ID: + return telegram_api::make_object( + static_cast(json_value.get())->value_); + case td_api::jsonValueString::ID: { + auto &str = static_cast(json_value.get())->value_; + if (!clean_input_string(str)) { + str.clear(); + } + return telegram_api::make_object(str); + } + case td_api::jsonValueArray::ID: + return telegram_api::make_object( + transform(std::move(static_cast(json_value.get())->values_), convert_json_value)); + case td_api::jsonValueObject::ID: + return telegram_api::make_object(transform( + std::move(static_cast(json_value.get())->members_), convert_json_value_member)); + default: + UNREACHABLE(); + return nullptr; + } +} + namespace { class JsonableJsonValue : public Jsonable { @@ -66,9 +145,16 @@ class JsonableJsonValue : public Jsonable { case td_api::jsonValueNumber::ID: *scope << static_cast(json_value_)->value_; break; - case td_api::jsonValueString::ID: - *scope << static_cast(json_value_)->value_; + case td_api::jsonValueString::ID: { + auto &str = static_cast(json_value_)->value_; + if (!check_utf8(str)) { + LOG(ERROR) << "Have incorrect UTF-8 string " << str; + *scope << ""; + } else { + *scope << str; + } break; + } case td_api::jsonValueArray::ID: { auto array = scope->enter_array(); for (auto &value : static_cast(json_value_)->values_) { @@ -80,7 +166,11 @@ class JsonableJsonValue : public Jsonable { auto object = scope->enter_object(); for (auto &member : static_cast(json_value_)->members_) { if (member != nullptr) { - object << ctie(member->key_, JsonableJsonValue(member->value_.get())); + if (!check_utf8(member->key_)) { + LOG(ERROR) << "Have incorrect UTF-8 object key " << member->key_; + } else { + object << ctie(member->key_, JsonableJsonValue(member->value_.get())); + } } } break; diff --git a/td/telegram/JsonValue.h b/td/telegram/JsonValue.h index 36099efc8..575bfb211 100644 --- a/td/telegram/JsonValue.h +++ b/td/telegram/JsonValue.h @@ -7,6 +7,7 @@ #pragma once #include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" #include "td/utils/common.h" #include "td/utils/Slice.h" @@ -16,6 +17,11 @@ namespace td { Result> get_json_value(MutableSlice json); +td_api::object_ptr convert_json_value_object( + const tl_object_ptr &json_value); + +tl_object_ptr convert_json_value(td_api::object_ptr &&json_value); + string get_json_string(const td_api::JsonValue *json_value); } // namespace td diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index b389c2459..8aef48854 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -497,6 +497,64 @@ class GetDeepLinkInfoQuery : public Td::ResultHandler { } }; +class GetAppConfigQuery : public Td::ResultHandler { + Promise> promise_; + + public: + explicit GetAppConfigQuery(Promise> &&promise) : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(create_storer(telegram_api::help_getAppConfig()))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto result = result_ptr.move_as_ok(); + promise_.set_value(convert_json_value_object(result)); + } + + void on_error(uint64 id, Status status) override { + promise_.set_error(std::move(status)); + } +}; + +class SaveAppLogQuery : public Td::ResultHandler { + Promise promise_; + + public: + explicit SaveAppLogQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(const string &type, int64 peer_id, tl_object_ptr &&data) { + CHECK(data != nullptr); + vector> input_app_events; + input_app_events.push_back( + make_tl_object(G()->server_time_cached(), type, peer_id, std::move(data))); + send_query( + G()->net_query_creator().create(create_storer(telegram_api::help_saveAppLog(std::move(input_app_events))))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + bool result = result_ptr.move_as_ok(); + LOG_IF(ERROR, !result) << "Receive false from help.saveAppLog"; + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + promise_.set_error(std::move(status)); + } +}; + /*** Td ***/ /** Td queries **/ class TestQuery : public Td::ResultHandler { @@ -3174,6 +3232,8 @@ bool Td::is_preauthentication_request(int32 id) { case td_api::getStorageStatisticsFast::ID: case td_api::getCountryCode::ID: case td_api::getDeepLinkInfo::ID: + case td_api::getApplicationConfig::ID: + case td_api::saveApplicationLogEvent::ID: case td_api::addProxy::ID: case td_api::editProxy::ID: case td_api::enableProxy::ID: @@ -6710,6 +6770,18 @@ void Td::on_request(uint64 id, td_api::getDeepLinkInfo &request) { create_handler(std::move(promise))->send(request.link_); } +void Td::on_request(uint64 id, const td_api::getApplicationConfig &request) { + CREATE_REQUEST_PROMISE(); + create_handler(std::move(promise))->send(); +} + +void Td::on_request(uint64 id, td_api::saveApplicationLogEvent &request) { + CLEAN_INPUT_STRING(request.type_); + auto result = convert_json_value(std::move(request.data_)); + CREATE_OK_REQUEST_PROMISE(); + create_handler(std::move(promise))->send(request.type_, request.chat_id_, std::move(result)); +} + void Td::on_request(uint64 id, td_api::addProxy &request) { CLEAN_INPUT_STRING(request.server_); CREATE_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 4d0aa0eee..d909cabe8 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -892,6 +892,10 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::getDeepLinkInfo &request); + void on_request(uint64 id, const td_api::getApplicationConfig &request); + + void on_request(uint64 id, td_api::saveApplicationLogEvent &request); + void on_request(uint64 id, td_api::addProxy &request); void on_request(uint64 id, td_api::editProxy &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index fadbee26f..cbc7e5af3 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2389,15 +2389,21 @@ class CliClient final : public Actor { execute(make_tl_object(args)); } else if (op == "gjv") { execute(td_api::make_object(args)); + } else if (op == "gjvtest") { + execute(td_api::make_object("\"aba\200caba\"")); + execute(td_api::make_object("\"\\u0080\"")); + execute(td_api::make_object("\"\\uD800\"")); } else if (op == "gjs") { - execute(td_api::make_object()); - execute(td_api::make_object(td_api::make_object())); - execute(td_api::make_object(td_api::make_object(true))); - execute(td_api::make_object(td_api::make_object(123456789123.0))); - execute( - td_api::make_object(td_api::make_object(string("aba\x00" - "caba", - 8)))); + auto test_get_json_string = [&](auto &&json_value) { + execute(td_api::make_object(std::move(json_value))); + }; + + test_get_json_string(nullptr); + test_get_json_string(td_api::make_object()); + test_get_json_string(td_api::make_object(true)); + test_get_json_string(td_api::make_object(123456789123.0)); + test_get_json_string(td_api::make_object(string("aba\0caba", 8))); + test_get_json_string(td_api::make_object("aba\200caba")); auto inner_array = td_api::make_object(); inner_array->values_.push_back(td_api::make_object(false)); @@ -2406,16 +2412,33 @@ class CliClient final : public Actor { array->values_.push_back(std::move(inner_array)); array->values_.push_back(td_api::make_object()); array->values_.push_back(td_api::make_object(-1)); - execute(td_api::make_object(std::move(array))); + test_get_json_string(std::move(array)); auto object = td_api::make_object(); object->members_.push_back( td_api::make_object("", td_api::make_object("test"))); object->members_.push_back(td_api::make_object("a", nullptr)); + object->members_.push_back(td_api::make_object("\x80", nullptr)); object->members_.push_back(nullptr); object->members_.push_back( td_api::make_object("a", td_api::make_object())); - execute(td_api::make_object(std::move(object))); + test_get_json_string(std::move(object)); + } else if (op == "gac") { + send_request(td_api::make_object()); + } else if (op == "sale") { + string type; + string chat_id; + string json; + std::tie(type, args) = split(args); + std::tie(chat_id, json) = split(args); + + auto result = execute(td_api::make_object(json)); + if (result->get_id() == td_api::error::ID) { + LOG(ERROR) << to_string(result); + } else { + send_request(td_api::make_object( + type, as_chat_id(chat_id), move_tl_object_as(result))); + } } else { op_not_found_count++; }