diff --git a/.gitignore b/.gitignore index fc3274f5b..7e9db75e5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,9 @@ docs/ .idea/ vcpkg/ *.tlo + +td.binlog + +tg_cli.log + +tg_cli.log.old diff --git a/td/telegram/Global.h b/td/telegram/Global.h index d55f272c6..7aa7c7c49 100644 --- a/td/telegram/Global.h +++ b/td/telegram/Global.h @@ -87,6 +87,56 @@ class Global final : public ActorContext { Status init(const TdParameters ¶meters, ActorId td, unique_ptr td_db_ptr) TD_WARN_UNUSED_RESULT; + static bool get_use_custom_database(const std::string &database_directory) { + auto s = get_database_directory_opts(database_directory); + size_t qmarkpos; + std::string token; + size_t find_start_index = 0; + while ((qmarkpos = s.find_first_of('&'), find_start_index) != std::string::npos) { + token = s.substr(find_start_index, qmarkpos - find_start_index); + find_start_index = qmarkpos; + if ((qmarkpos = token.find_first_of('=')) != std::string::npos) { + std::string propkey = token.substr(0, qmarkpos), propval = token.substr(qmarkpos + 1); + if (propkey == "use_custom_database_format" && propval == "true") { + return true; + } + } + } + return false; + } + + static std::string get_database_directory_path(const std::string &database_directory) { + if (database_directory.empty()) { + return database_directory; + } + size_t qmarkpos; + if ((qmarkpos = database_directory.find_first_of('?')) != std::string::npos) { + std::string path = database_directory.substr(0, qmarkpos), + opts = database_directory.substr(qmarkpos + 1); + return path; + } else { + return database_directory; + } + } + + static std::string get_database_directory_opts(const std::string &database_directory) { + if (database_directory.empty()) { + return database_directory; + } + size_t qmarkpos; + if ((qmarkpos = database_directory.find_first_of('?')) != std::string::npos) { + std::string path = database_directory.substr(0, qmarkpos), + opts = database_directory.substr(qmarkpos + 1); + return opts; + } else { + return ""; + } + } + + bool get_use_custom_database() const { + return parameters_.use_custom_db_format; + }; + Slice get_dir() const { return parameters_.database_directory; } diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 6505f3e19..a03220c9a 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -3007,12 +3007,15 @@ td_api::object_ptr Td::get_fake_authorization_state_ } } -DbKey Td::as_db_key(string key) { +DbKey Td::as_db_key(string key, bool custom_db) { // Database will still be effectively not encrypted, but // 1. SQLite database will be protected from corruption, because that's how sqlcipher works // 2. security through obscurity // 3. no need for reencryption of SQLite database if (key.empty()) { + if (custom_db) { + return DbKey::empty(); + } return DbKey::raw_key("cucumber"); } return DbKey::raw_key(std::move(key)); @@ -3080,11 +3083,11 @@ void Td::request(uint64 id, tl_object_ptr function) { switch (function_id) { case td_api::checkDatabaseEncryptionKey::ID: { auto check_key = move_tl_object_as(function); - return answer_ok_query(id, init(as_db_key(std::move(check_key->encryption_key_)))); + return answer_ok_query(id, init(as_db_key(std::move(check_key->encryption_key_), parameters_.use_custom_db_format))); } case td_api::setDatabaseEncryptionKey::ID: { auto set_key = move_tl_object_as(function); - return answer_ok_query(id, init(as_db_key(std::move(set_key->new_encryption_key_)))); + return answer_ok_query(id, init(as_db_key(std::move(set_key->new_encryption_key_), parameters_.use_custom_db_format))); } case td_api::destroy::ID: // need to send response synchronously before actual destroying @@ -4245,7 +4248,8 @@ Status Td::set_parameters(td_api::object_ptr parameters } parameters_.use_test_dc = parameters->use_test_dc_; - parameters_.database_directory = parameters->database_directory_; + parameters_.database_directory = Global::get_database_directory_path(parameters->database_directory_); + parameters_.use_custom_db_format = Global::get_use_custom_database(parameters->database_directory_); parameters_.files_directory = parameters->files_directory_; parameters_.api_id = parameters->api_id_; parameters_.api_hash = parameters->api_hash_; @@ -4310,7 +4314,7 @@ void Td::on_request(uint64 id, const td_api::checkDatabaseEncryptionKey &request void Td::on_request(uint64 id, td_api::setDatabaseEncryptionKey &request) { CREATE_OK_REQUEST_PROMISE(); - G()->td_db()->get_binlog()->change_key(as_db_key(std::move(request.new_encryption_key_)), std::move(promise)); + G()->td_db()->get_binlog()->change_key(as_db_key(std::move(request.new_encryption_key_), parameters_.use_custom_db_format), std::move(promise)); } void Td::on_request(uint64 id, const td_api::getAuthorizationState &request) { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index b8505a5ea..56627f595 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -1344,7 +1344,7 @@ class Td final : public Actor { static td_api::object_ptr do_static_request(const td_api::addLogMessage &request); static td_api::object_ptr do_static_request(td_api::testReturnError &request); - static DbKey as_db_key(string key); + static DbKey as_db_key(string key, bool custom_db); Status init(DbKey key) TD_WARN_UNUSED_RESULT; void init_options_and_network(); void init_connection_creator(); diff --git a/td/telegram/TdDb.cpp b/td/telegram/TdDb.cpp index 54605c1b4..bcc6535b8 100644 --- a/td/telegram/TdDb.cpp +++ b/td/telegram/TdDb.cpp @@ -303,8 +303,16 @@ Status TdDb::init_sqlite(int32 scheduler_id, const TdParameters ¶meters, con sql_connection_ = std::make_shared(sql_database_path, key, db_instance.get_cipher_version()); sql_connection_->set(std::move(db_instance)); auto &db = sql_connection_->get(); - TRY_STATUS(db.exec("PRAGMA journal_mode=WAL")); - TRY_STATUS(db.exec("PRAGMA secure_delete=1")); + if (parameters.use_custom_db_format) { + TRY_STATUS(db.exec("PRAGMA journal_mode=OFF")); + TRY_STATUS(db.exec("PRAGMA synchronous=OFF")) + TRY_STATUS(db.exec("PRAGMA temp_store=MEMORY")); + TRY_STATUS(db.exec("PRAGMA secure_delete=0")); + TRY_STATUS(db.exec("PRAGMA mmap_size=30000000000")); + } else { + TRY_STATUS(db.exec("PRAGMA journal_mode=WAL")); + TRY_STATUS(db.exec("PRAGMA secure_delete=1")); + } // Init databases // Do initialization once and before everything else to avoid "database is locked" error. diff --git a/td/telegram/TdParameters.h b/td/telegram/TdParameters.h index da6ee70f9..dd9359d0a 100644 --- a/td/telegram/TdParameters.h +++ b/td/telegram/TdParameters.h @@ -23,6 +23,7 @@ struct TdParameters { bool use_secret_chats = false; bool use_chat_info_db = false; bool use_message_db = false; + bool use_custom_db_format = false; }; } // namespace td