From 13be53f22a7a29d98ac1d9c3cddd7579908de30b Mon Sep 17 00:00:00 2001 From: Thomas Piccirello Date: Sat, 14 Sep 2024 16:35:07 -0700 Subject: [PATCH 1/3] Add WebAPI for managing cookies Signed-off-by: Thomas Piccirello --- src/webui/api/appcontroller.cpp | 66 +++++++++++++++++++++++++++++++++ src/webui/api/appcontroller.h | 2 + src/webui/webapplication.h | 1 + 3 files changed, 69 insertions(+) diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index fd6cd442c712..1cd877a15f53 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ #include "base/bittorrent/session.h" #include "base/global.h" #include "base/interfaces/iapplication.h" +#include "base/net/downloadmanager.h" #include "base/net/portforwarder.h" #include "base/net/proxyconfigurationmanager.h" #include "base/path.h" @@ -58,6 +60,7 @@ #include "base/rss/rss_session.h" #include "base/torrentfileguard.h" #include "base/torrentfileswatcher.h" +#include "base/utils/datetime.h" #include "base/utils/fs.h" #include "base/utils/misc.h" #include "base/utils/net.h" @@ -69,6 +72,12 @@ using namespace std::chrono_literals; +const QString KEY_COOKIE_NAME = u"name"_s; +const QString KEY_COOKIE_DOMAIN = u"domain"_s; +const QString KEY_COOKIE_PATH = u"path"_s; +const QString KEY_COOKIE_VALUE = u"value"_s; +const QString KEY_COOKIE_EXPIRATION_DATE = u"expirationDate"_s; + void AppController::webapiVersionAction() { setResult(API_VERSION.toString()); @@ -1187,6 +1196,63 @@ void AppController::getDirectoryContentAction() setResult(ret); } +void AppController::cookiesAction() +{ + const QList cookies = Net::DownloadManager::instance()->allCookies(); + QJsonArray ret; + for (const QNetworkCookie &cookie : cookies) + { + ret << QJsonObject { + {KEY_COOKIE_NAME, QString::fromLatin1(cookie.name())}, + {KEY_COOKIE_DOMAIN, cookie.domain()}, + {KEY_COOKIE_PATH, cookie.path()}, + {KEY_COOKIE_VALUE, QString::fromLatin1(cookie.value())}, + {KEY_COOKIE_EXPIRATION_DATE, Utils::DateTime::toSecsSinceEpoch(cookie.expirationDate())}, + }; + } + + setResult(ret); +} + +void AppController::setCookiesAction() +{ + requireParams({u"cookies"_s}); + const QString cookiesParam {params()[u"cookies"_s].trimmed()}; + + QJsonParseError jsonError; + const auto cookiesJsonDocument = QJsonDocument::fromJson(cookiesParam.toUtf8(), &jsonError); + if (jsonError.error != QJsonParseError::NoError) + throw APIError(APIErrorType::BadParams, jsonError.errorString()); + if (!cookiesJsonDocument.isArray()) + throw APIError(APIErrorType::BadParams, tr("cookies must be array")); + + const QJsonArray cookiesJsonArr = cookiesJsonDocument.array(); + QList cookies; + cookies.reserve(cookiesJsonArr.size()); + for (const QJsonValue &jsonVal : cookiesJsonArr) + { + if (!jsonVal.isObject()) + throw APIError(APIErrorType::BadParams); + + QNetworkCookie cookie; + const QJsonObject jsonObj = jsonVal.toObject(); + if (jsonObj.contains(KEY_COOKIE_NAME)) + cookie.setName(jsonObj.value(KEY_COOKIE_NAME).toString().toLatin1()); + if (jsonObj.contains(KEY_COOKIE_DOMAIN)) + cookie.setDomain(jsonObj.value(KEY_COOKIE_DOMAIN).toString()); + if (jsonObj.contains(KEY_COOKIE_PATH)) + cookie.setPath(jsonObj.value(KEY_COOKIE_PATH).toString()); + if (jsonObj.contains(KEY_COOKIE_VALUE)) + cookie.setValue(jsonObj.value(KEY_COOKIE_VALUE).toString().toUtf8()); + if (jsonObj.contains(KEY_COOKIE_EXPIRATION_DATE)) + cookie.setExpirationDate(QDateTime::fromSecsSinceEpoch(jsonObj.value(KEY_COOKIE_EXPIRATION_DATE).toInteger())); + + cookies << cookie; + } + + Net::DownloadManager::instance()->setAllCookies(cookies); +} + void AppController::networkInterfaceListAction() { QJsonArray ifaceList; diff --git a/src/webui/api/appcontroller.h b/src/webui/api/appcontroller.h index 432c9f1f5b4b..dea33eadaec4 100644 --- a/src/webui/api/appcontroller.h +++ b/src/webui/api/appcontroller.h @@ -50,6 +50,8 @@ private slots: void defaultSavePathAction(); void sendTestEmailAction(); void getDirectoryContentAction(); + void cookiesAction(); + void setCookiesAction(); void networkInterfaceListAction(); void networkInterfaceAddressListAction(); diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index 80530b15dd3e..514ed3f14d96 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -152,6 +152,7 @@ class WebApplication final : public ApplicationComponent { // <, HTTP method> {{u"app"_s, u"sendTestEmail"_s}, Http::METHOD_POST}, + {{u"app"_s, u"setCookies"_s}, Http::METHOD_POST}, {{u"app"_s, u"setPreferences"_s}, Http::METHOD_POST}, {{u"app"_s, u"shutdown"_s}, Http::METHOD_POST}, {{u"auth"_s, u"login"_s}, Http::METHOD_POST}, From 08ba8f2812c9a9095c56a36833ef6775711ebe02 Mon Sep 17 00:00:00 2001 From: Thomas Piccirello Date: Sat, 14 Sep 2024 16:36:46 -0700 Subject: [PATCH 2/3] Add WebUI for managing cookies Signed-off-by: Thomas Piccirello --- .../www/private/images/browser-cookies.svg | 1 + src/webui/www/private/index.html | 1 + src/webui/www/private/scripts/mocha-init.js | 21 ++ src/webui/www/private/views/cookies.html | 191 ++++++++++++++++++ src/webui/www/webui.qrc | 2 + 5 files changed, 216 insertions(+) create mode 100644 src/webui/www/private/images/browser-cookies.svg create mode 100644 src/webui/www/private/views/cookies.html diff --git a/src/webui/www/private/images/browser-cookies.svg b/src/webui/www/private/images/browser-cookies.svg new file mode 100644 index 000000000000..0873b0db0beb --- /dev/null +++ b/src/webui/www/private/images/browser-cookies.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/webui/www/private/index.html b/src/webui/www/private/index.html index f8508db753b3..440a0c66b8bb 100644 --- a/src/webui/www/private/index.html +++ b/src/webui/www/private/index.html @@ -94,6 +94,7 @@

qBittorrent Web User Interface QBT_TR(Options...)QBT_TR[CONTEXT=MainWindow]QBT_TR(Options...)QBT_TR[CONTEXT=MainWindow]
  • QBT_TR(Register to handle magnet links...)QBT_TR[CONTEXT=HttpServer]QBT_TR(Register to handle magnet links...)QBT_TR[CONTEXT=HttpServer]
  • +
  • QBT_TR(Manage Cookies...)QBT_TR[CONTEXT=MainWindow]QBT_TR(Manage Cookies...)QBT_TR[CONTEXT=MainWindow]
  • diff --git a/src/webui/www/private/scripts/mocha-init.js b/src/webui/www/private/scripts/mocha-init.js index 337f704c5025..c33c583ffef6 100644 --- a/src/webui/www/private/scripts/mocha-init.js +++ b/src/webui/www/private/scripts/mocha-init.js @@ -239,6 +239,27 @@ const initializeWindows = function() { }); }); + addClickEvent("manageCookies", (e) => { + e.preventDefault(); + e.stopPropagation(); + + const id = "cookiesPage"; + new MochaUI.Window({ + id: id, + title: "QBT_TR(Manage Cookies)QBT_TR[CONTEXT=CookiesDialog]", + loadMethod: "xhr", + contentURL: new URI("views/cookies.html").toString(), + maximizable: false, + paddingVertical: 0, + paddingHorizontal: 0, + width: loadWindowWidth(id, 900), + height: loadWindowHeight(id, 400), + onResize: function() { + saveWindowSize(id); + } + }); + }); + addClickEvent("upload", (e) => { e.preventDefault(); e.stopPropagation(); diff --git a/src/webui/www/private/views/cookies.html b/src/webui/www/private/views/cookies.html new file mode 100644 index 000000000000..535bfae2dfd1 --- /dev/null +++ b/src/webui/www/private/views/cookies.html @@ -0,0 +1,191 @@ + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    QBT_TR(Domain)QBT_TR[CONTEXT=CookiesDialog]QBT_TR(Path)QBT_TR[CONTEXT=CookiesDialog]QBT_TR(Name)QBT_TR[CONTEXT=CookiesDialog]QBT_TR(Value)QBT_TR[CONTEXT=CookiesDialog]QBT_TR(Expiration Date)QBT_TR[CONTEXT=CookiesDialog]
    QBT_TR(Add Cookie)QBT_TR[CONTEXT=CookiesDialog]
    + +
    + +
    +
    + + diff --git a/src/webui/www/webui.qrc b/src/webui/www/webui.qrc index df27f335ed1f..e1197281e96c 100644 --- a/src/webui/www/webui.qrc +++ b/src/webui/www/webui.qrc @@ -23,6 +23,7 @@ private/images/application-rss.svg private/images/application-url.svg private/images/arrow-right.gif + private/images/browser-cookies.svg private/images/checked-completed.svg private/images/collapse.svg private/images/configure.svg @@ -422,6 +423,7 @@ private/views/aboutToolbar.html private/views/confirmdeletion.html private/views/confirmRecheck.html + private/views/cookies.html private/views/filters.html private/views/installsearchplugin.html private/views/log.html From c352f895f3cabcc317aec0d097fd98e84752c933 Mon Sep 17 00:00:00 2001 From: Thomas Piccirello Date: Sat, 14 Sep 2024 16:37:49 -0700 Subject: [PATCH 3/3] Remove cookie field from WebUI torrent download form The cookie manager should now be used. Signed-off-by: Thomas Piccirello --- src/webui/api/torrentscontroller.cpp | 21 --------------------- src/webui/www/private/download.html | 8 -------- 2 files changed, 29 deletions(-) diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index 20b2eff2521b..e4dfe402b936 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -53,7 +52,6 @@ #include "base/interfaces/iapplication.h" #include "base/global.h" #include "base/logger.h" -#include "base/net/downloadmanager.h" #include "base/torrentfilter.h" #include "base/utils/datetime.h" #include "base/utils/fs.h" @@ -787,7 +785,6 @@ void TorrentsController::pieceStatesAction() void TorrentsController::addAction() { const QString urls = params()[u"urls"_s]; - const QString cookie = params()[u"cookie"_s]; const bool skipChecking = parseBool(params()[u"skip_checking"_s]).value_or(false); const bool seqDownload = parseBool(params()[u"sequentialDownload"_s]).value_or(false); @@ -818,23 +815,6 @@ void TorrentsController::addAction() ? Utils::String::toEnum(contentLayoutParam, BitTorrent::TorrentContentLayout::Original) : std::optional {}); - QList cookies; - if (!cookie.isEmpty()) - { - const QStringList cookiesStr = cookie.split(u"; "_s); - for (QString cookieStr : cookiesStr) - { - cookieStr = cookieStr.trimmed(); - int index = cookieStr.indexOf(u'='); - if (index > 1) - { - QByteArray name = cookieStr.left(index).toLatin1(); - QByteArray value = cookieStr.right(cookieStr.length() - index - 1).toLatin1(); - cookies += QNetworkCookie(name, value); - } - } - } - const BitTorrent::AddTorrentParams addTorrentParams { // TODO: Check if destination actually exists @@ -875,7 +855,6 @@ void TorrentsController::addAction() url = url.trimmed(); if (!url.isEmpty()) { - Net::DownloadManager::instance()->setCookiesFromUrl(cookies, QUrl::fromEncoded(url.toUtf8())); partialSuccess |= app()->addTorrentManager()->addTorrent(url, addTorrentParams); } } diff --git a/src/webui/www/private/download.html b/src/webui/www/private/download.html index a9ae77030dc1..d59d0e5abc77 100644 --- a/src/webui/www/private/download.html +++ b/src/webui/www/private/download.html @@ -44,14 +44,6 @@