From 5a660fc8a979aa6b97c9059df4216da8b9a80a57 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Tue, 4 Jul 2023 01:30:54 +0800 Subject: [PATCH] Expose 'bdecode limits' settings This includes: * Bdecode depth limit * Bdecode token limit --- .../bittorrent/bencoderesumedatastorage.cpp | 8 +++--- src/base/bittorrent/common.h | 3 --- src/base/bittorrent/dbresumedatastorage.cpp | 9 ++++--- src/base/bittorrent/sessionimpl.cpp | 4 +++ src/base/bittorrent/torrentinfo.cpp | 5 ++-- src/base/preferences.cpp | 26 +++++++++++++++++++ src/base/preferences.h | 4 +++ src/gui/advancedsettings.cpp | 18 +++++++++++++ src/gui/advancedsettings.h | 2 +- src/webui/api/appcontroller.cpp | 10 +++++++ src/webui/webapplication.h | 2 +- src/webui/www/private/views/preferences.html | 20 ++++++++++++++ 12 files changed, 98 insertions(+), 13 deletions(-) diff --git a/src/base/bittorrent/bencoderesumedatastorage.cpp b/src/base/bittorrent/bencoderesumedatastorage.cpp index 922e1f678..eeb1a8cc0 100644 --- a/src/base/bittorrent/bencoderesumedatastorage.cpp +++ b/src/base/bittorrent/bencoderesumedatastorage.cpp @@ -50,7 +50,6 @@ #include "base/utils/fs.h" #include "base/utils/io.h" #include "base/utils/string.h" -#include "common.h" #include "infohash.h" #include "loadtorrentparams.h" @@ -203,9 +202,11 @@ void BitTorrent::BencodeResumeDataStorage::loadQueue(const Path &queueFilename) BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorrentResumeData(const QByteArray &data, const QByteArray &metadata) const { + const auto *pref = Preferences::instance(); + lt::error_code ec; const lt::bdecode_node resumeDataRoot = lt::bdecode(data, ec - , nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); + , nullptr, pref->getBdecodeDepthLimit(), pref->getBdecodeTokenLimit()); if (ec) return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message()))); @@ -272,8 +273,9 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre if (!metadata.isEmpty()) { + const auto *pref = Preferences::instance(); const lt::bdecode_node torentInfoRoot = lt::bdecode(metadata, ec - , nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); + , nullptr, pref->getBdecodeDepthLimit(), pref->getBdecodeTokenLimit()); if (ec) return nonstd::make_unexpected(tr("Cannot parse torrent info: %1").arg(QString::fromStdString(ec.message()))); diff --git a/src/base/bittorrent/common.h b/src/base/bittorrent/common.h index fa46c0d8d..fd1e98872 100644 --- a/src/base/bittorrent/common.h +++ b/src/base/bittorrent/common.h @@ -33,6 +33,3 @@ #include "base/global.h" inline const QString QB_EXT = u".!qB"_s; - -inline const int BENCODE_DEPTH_LIMIT = 100; -inline const int BENCODE_TOKEN_LIMIT = 10'000'000; diff --git a/src/base/bittorrent/dbresumedatastorage.cpp b/src/base/bittorrent/dbresumedatastorage.cpp index 86ffac9fd..619ce97b3 100644 --- a/src/base/bittorrent/dbresumedatastorage.cpp +++ b/src/base/bittorrent/dbresumedatastorage.cpp @@ -55,10 +55,10 @@ #include "base/global.h" #include "base/logger.h" #include "base/path.h" +#include "base/preferences.h" #include "base/profile.h" #include "base/utils/fs.h" #include "base/utils/string.h" -#include "common.h" #include "infohash.h" #include "loadtorrentparams.h" @@ -246,10 +246,13 @@ namespace } const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray(); + const auto *pref = Preferences::instance(); + const int bdecodeDepthLimit = pref->getBdecodeDepthLimit(); + const int bdecodeTokenLimit = pref->getBdecodeTokenLimit(); lt::error_code ec; const lt::bdecode_node resumeDataRoot = lt::bdecode(bencodedResumeData, ec - , nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); + , nullptr, bdecodeDepthLimit, bdecodeTokenLimit); lt::add_torrent_params &p = resumeData.ltAddTorrentParams; @@ -259,7 +262,7 @@ namespace ; !bencodedMetadata.isEmpty()) { const lt::bdecode_node torentInfoRoot = lt::bdecode(bencodedMetadata, ec - , nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); + , nullptr, bdecodeDepthLimit, bdecodeTokenLimit); p.ti = std::make_shared(torentInfoRoot, ec); } diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 45f26e18b..5d1c2efd2 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -1740,6 +1740,10 @@ lt::settings_pack SessionImpl::loadLTSettings() const settingsPack.set_int(lt::settings_pack::max_out_request_queue, requestQueueSize()); +#ifdef QBT_USES_LIBTORRENT2 + settingsPack.set_int(lt::settings_pack::metadata_token_limit, Preferences::instance()->getBdecodeTokenLimit()); +#endif + settingsPack.set_int(lt::settings_pack::aio_threads, asyncIOThreads()); #ifdef QBT_USES_LIBTORRENT2 settingsPack.set_int(lt::settings_pack::hashing_threads, hashingThreads()); diff --git a/src/base/bittorrent/torrentinfo.cpp b/src/base/bittorrent/torrentinfo.cpp index 7d3e440b2..71b82138e 100644 --- a/src/base/bittorrent/torrentinfo.cpp +++ b/src/base/bittorrent/torrentinfo.cpp @@ -46,7 +46,6 @@ #include "base/utils/fs.h" #include "base/utils/io.h" #include "base/utils/misc.h" -#include "common.h" #include "infohash.h" #include "trackerentry.h" @@ -87,9 +86,11 @@ nonstd::expected TorrentInfo::load(const QByteArray &data) { // 2-step construction to overcome default limits of `depth_limit` & `token_limit` which are // used in `torrent_info()` constructor + const auto *pref = Preferences::instance(); + lt::error_code ec; const lt::bdecode_node node = lt::bdecode(data, ec - , nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); + , nullptr, pref->getBdecodeDepthLimit(), pref->getBdecodeTokenLimit()); if (ec) return nonstd::make_unexpected(QString::fromStdString(ec.message())); diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index be4ef0832..10cf3234a 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -317,6 +317,32 @@ void Preferences::setTorrentFileSizeLimit(const qint64 value) setValue(u"BitTorrent/TorrentFileSizeLimit"_s, value); } +int Preferences::getBdecodeDepthLimit() const +{ + return value(u"BitTorrent/BdecodeDepthLimit"_s, 100); +} + +void Preferences::setBdecodeDepthLimit(const int value) +{ + if (value == getBdecodeDepthLimit()) + return; + + setValue(u"BitTorrent/BdecodeDepthLimit"_s, value); +} + +int Preferences::getBdecodeTokenLimit() const +{ + return value(u"BitTorrent/BdecodeTokenLimit"_s, 10'000'000); +} + +void Preferences::setBdecodeTokenLimit(const int value) +{ + if (value == getBdecodeTokenLimit()) + return; + + setValue(u"BitTorrent/BdecodeTokenLimit"_s, value); +} + bool Preferences::isToolbarDisplayed() const { return value(u"Preferences/General/ToolbarDisplayed"_s, true); diff --git a/src/base/preferences.h b/src/base/preferences.h index 7d6c3c1de..c65590e4d 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -335,6 +335,10 @@ public: #endif // Q_OS_MACOS qint64 getTorrentFileSizeLimit() const; void setTorrentFileSizeLimit(qint64 value); + int getBdecodeDepthLimit() const; + void setBdecodeDepthLimit(int value); + int getBdecodeTokenLimit() const; + void setBdecodeTokenLimit(int value); // Stuff that don't appear in the Options GUI but are saved // in the same file. diff --git a/src/gui/advancedsettings.cpp b/src/gui/advancedsettings.cpp index 882a6abd6..0d0ce6642 100644 --- a/src/gui/advancedsettings.cpp +++ b/src/gui/advancedsettings.cpp @@ -101,6 +101,8 @@ namespace TRACKER_PORT_FORWARDING, // libtorrent section LIBTORRENT_HEADER, + BDECODE_DEPTH_LIMIT, + BDECODE_TOKEN_LIMIT, ASYNC_IO_THREADS, #ifdef QBT_USES_LIBTORRENT2 HASHING_THREADS, @@ -199,6 +201,10 @@ void AdvancedSettings::saveAdvancedSettings() const #if defined(Q_OS_WIN) app()->setProcessMemoryPriority(m_comboBoxOSMemoryPriority.currentData().value()); #endif + // Bdecode depth limit + pref->setBdecodeDepthLimit(m_spinBoxBdecodeDepthLimit.value()); + // Bdecode token limit + pref->setBdecodeTokenLimit(m_spinBoxBdecodeTokenLimit.value()); // Async IO threads session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value()); #ifdef QBT_USES_LIBTORRENT2 @@ -464,6 +470,18 @@ void AdvancedSettings::loadAdvancedSettings() + u' ' + makeLink(u"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-memory_priority_information", u"(?)")) , &m_comboBoxOSMemoryPriority); #endif + // Bdecode depth limit + m_spinBoxBdecodeDepthLimit.setMinimum(0); + m_spinBoxBdecodeDepthLimit.setMaximum(std::numeric_limits::max()); + m_spinBoxBdecodeDepthLimit.setValue(pref->getBdecodeDepthLimit()); + addRow(BDECODE_DEPTH_LIMIT, (tr("Bdecode depth limit") + u' ' + makeLink(u"https://www.libtorrent.org/reference-Bdecoding.html#bdecode()", u"(?)")) + , &m_spinBoxBdecodeDepthLimit); + // Bdecode token limit + m_spinBoxBdecodeTokenLimit.setMinimum(0); + m_spinBoxBdecodeTokenLimit.setMaximum(std::numeric_limits::max()); + m_spinBoxBdecodeTokenLimit.setValue(pref->getBdecodeTokenLimit()); + addRow(BDECODE_TOKEN_LIMIT, (tr("Bdecode token limit") + u' ' + makeLink(u"https://www.libtorrent.org/reference-Bdecoding.html#bdecode()", u"(?)")) + , &m_spinBoxBdecodeTokenLimit); // Async IO threads m_spinBoxAsyncIOThreads.setMinimum(1); m_spinBoxAsyncIOThreads.setMaximum(1024); diff --git a/src/gui/advancedsettings.h b/src/gui/advancedsettings.h index fc1a46907..1cb869e9e 100644 --- a/src/gui/advancedsettings.h +++ b/src/gui/advancedsettings.h @@ -67,7 +67,7 @@ private: void loadAdvancedSettings(); template void addRow(int row, const QString &text, T *widget); - QSpinBox m_spinBoxSaveResumeDataInterval, m_spinBoxTorrentFileSizeLimit, + QSpinBox m_spinBoxSaveResumeDataInterval, m_spinBoxTorrentFileSizeLimit, m_spinBoxBdecodeDepthLimit, m_spinBoxBdecodeTokenLimit, m_spinBoxAsyncIOThreads, m_spinBoxFilePoolSize, m_spinBoxCheckingMemUsage, m_spinBoxDiskQueueSize, m_spinBoxOutgoingPortsMin, m_spinBoxOutgoingPortsMax, m_spinBoxUPnPLeaseDuration, m_spinBoxPeerToS, m_spinBoxListRefresh, m_spinBoxTrackerPort, m_spinBoxSendBufferWatermark, m_spinBoxSendBufferLowWatermark, diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index c718e5232..870d696d4 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -335,6 +335,10 @@ void AppController::preferencesAction() data[u"reannounce_when_address_changed"_s] = session->isReannounceWhenAddressChangedEnabled(); // libtorrent preferences + // Bdecode depth limit + data[u"bdecode_depth_limit"_s] = pref->getBdecodeDepthLimit(); + // Bdecode token limit + data[u"bdecode_token_limit"_s] = pref->getBdecodeTokenLimit(); // Async IO threads data[u"async_io_threads"_s] = session->asyncIOThreads(); // Hashing threads @@ -872,6 +876,12 @@ void AppController::setPreferencesAction() session->setReannounceWhenAddressChangedEnabled(it.value().toBool()); // libtorrent preferences + // Bdecode depth limit + if (hasKey(u"bdecode_depth_limit"_s)) + pref->setBdecodeDepthLimit(it.value().toInt()); + // Bdecode token limit + if (hasKey(u"bdecode_token_limit"_s)) + pref->setBdecodeTokenLimit(it.value().toInt()); // Async IO threads if (hasKey(u"async_io_threads"_s)) session->setAsyncIOThreads(it.value().toInt()); diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index 8f68a08a3..364d5ee41 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -52,7 +52,7 @@ #include "base/utils/version.h" #include "api/isessionmanager.h" -inline const Utils::Version<3, 2> API_VERSION {2, 9, 1}; +inline const Utils::Version<3, 2> API_VERSION {2, 9, 2}; class APIController; class AuthController; diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 253cfcfcf..00aa4a59d 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -1046,6 +1046,22 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
QBT_TR(libtorrent Section)QBT_TR[CONTEXT=OptionsDialog] (QBT_TR(Open documentation)QBT_TR[CONTEXT=HttpServer]) + + + + + + + +
+ + + +
+ + + +
@@ -2161,6 +2177,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD $('resolvePeerCountries').setProperty('checked', pref.resolve_peer_countries); $('reannounceWhenAddressChanged').setProperty('checked', pref.reannounce_when_address_changed); // libtorrent section + $('bdecodeDepthLimit').setProperty('value', pref.bdecode_depth_limit); + $('bdecodeTokenLimit').setProperty('value', pref.bdecode_token_limit); $('asyncIOThreads').setProperty('value', pref.async_io_threads); $('hashingThreads').setProperty('value', pref.hashing_threads); $('filePoolSize').setProperty('value', pref.file_pool_size); @@ -2579,6 +2597,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings.set('reannounce_when_address_changed', $('reannounceWhenAddressChanged').getProperty('checked')); // libtorrent section + settings.set('bdecode_depth_limit', $('bdecodeDepthLimit').getProperty('value')); + settings.set('bdecode_token_limit', $('bdecodeTokenLimit').getProperty('value')); settings.set('async_io_threads', $('asyncIOThreads').getProperty('value')); settings.set('hashing_threads', $('hashingThreads').getProperty('value')); settings.set('file_pool_size', $('filePoolSize').getProperty('value'));