diff --git a/src/.vs/slnx.sqlite b/src/.vs/slnx.sqlite new file mode 100644 index 000000000000..d420f57eea30 Binary files /dev/null and b/src/.vs/slnx.sqlite differ diff --git a/src/base/http/httperror.cpp b/src/base/http/httperror.cpp index 7f66fb627f0a..6806bc24e2bd 100644 --- a/src/base/http/httperror.cpp +++ b/src/base/http/httperror.cpp @@ -84,3 +84,7 @@ InternalServerErrorHTTPError::InternalServerErrorHTTPError(const QString &messag : HTTPError(500, QLatin1String("Internal Server Error"), message) { } +SeeOtherHTTPError::SeeOtherHTTPError(const QString &message) + : HTTPError(303, QLatin1String("See Other"), message) +{ +} diff --git a/src/base/http/httperror.h b/src/base/http/httperror.h index 853d6a7a981b..532bbf18306a 100644 --- a/src/base/http/httperror.h +++ b/src/base/http/httperror.h @@ -90,3 +90,9 @@ class InternalServerErrorHTTPError : public HTTPError public: explicit InternalServerErrorHTTPError(const QString &message = {}); }; + +class SeeOtherHTTPError : public HTTPError +{ +public: + explicit SeeOtherHTTPError(const QString &message = {}); +}; diff --git a/src/base/http/types.h b/src/base/http/types.h index 03318bd871db..cb739431a2eb 100644 --- a/src/base/http/types.h +++ b/src/base/http/types.h @@ -55,6 +55,7 @@ namespace Http const char HEADER_X_FORWARDED_HOST[] = "x-forwarded-host"; const char HEADER_X_FRAME_OPTIONS[] = "x-frame-options"; const char HEADER_X_XSS_PROTECTION[] = "x-xss-protection"; + const char HEADER_LOCATION[] = "location"; const char HEADER_REQUEST_METHOD_GET[] = "GET"; const char HEADER_REQUEST_METHOD_HEAD[] = "HEAD"; diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index c545d358046f..f0df9d44c29e 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -777,7 +777,7 @@ QString Preferences::getWebUIBasePath() const return value("Preferences/WebUI/BasePath").toString(); } -void Preferences::setWebUIBasePath(const Qstring &path) +void Preferences::setWebUIBasePath(const QString &path) { setValue("Preferences/WebUI/BasePath", path); } diff --git a/src/gui/optionsdialog.cpp b/src/gui/optionsdialog.cpp index 4de02aa9f9c1..3c989fd5c7ee 100644 --- a/src/gui/optionsdialog.cpp +++ b/src/gui/optionsdialog.cpp @@ -489,6 +489,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(m_ui->textWebUIHttpsKey, &FileSystemPathLineEdit::selectedPathChanged, this, [this](const QString &s) { webUIHttpsKeyChanged(s, ShowError::Show); }); connect(m_ui->textWebUiUsername, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); connect(m_ui->textWebUiPassword, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); + connect(m_ui->textWebUIBasePath, &QLineEdit::textChanged, this, &ThisType::enableApplyButton); connect(m_ui->checkBypassLocalAuth, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, this, &ThisType::enableApplyButton); connect(m_ui->checkBypassAuthSubnetWhitelist, &QAbstractButton::toggled, m_ui->IPSubnetWhitelistButton, &QPushButton::setEnabled); @@ -848,6 +849,7 @@ void OptionsDialog::saveOptions() pref->setWebUIMaxAuthFailCount(m_ui->spinBanCounter->value()); pref->setWebUIBanDuration(std::chrono::seconds {m_ui->spinBanDuration->value()}); pref->setWebUISessionTimeout(m_ui->spinSessionTimeout->value()); + pref->setWebUIBasePath(m_ui->textWebUIBasePath->text()); // Authentication pref->setWebUiUsername(webUiUsername()); if (!webUiPassword().isEmpty()) @@ -1255,6 +1257,7 @@ void OptionsDialog::loadOptions() m_ui->spinBanCounter->setValue(pref->getWebUIMaxAuthFailCount()); m_ui->spinBanDuration->setValue(pref->getWebUIBanDuration().count()); m_ui->spinSessionTimeout->setValue(pref->getWebUISessionTimeout()); + m_ui->textWebUIBasePath->setText(pref->getWebUIBasePath()); // Security m_ui->checkClickjacking->setChecked(pref->isWebUiClickjackingProtectionEnabled()); diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index f27359d1582c..4fe251bbb4aa 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -2945,6 +2945,22 @@ Specify an IPv4 or IPv6 address. You can specify "0.0.0.0" for any IPv + + + + Base Path: + + + + + + + + URL path root for the WebUI. Requires a WebUI restart to take effect. + + + + diff --git a/src/webui/api/appcontroller.cpp b/src/webui/api/appcontroller.cpp index 3a3c01b04738..6d77efc9fd39 100644 --- a/src/webui/api/appcontroller.cpp +++ b/src/webui/api/appcontroller.cpp @@ -228,6 +228,7 @@ void AppController::preferencesAction() data["use_https"] = pref->isWebUiHttpsEnabled(); data["web_ui_https_cert_path"] = pref->getWebUIHttpsCertificatePath(); data["web_ui_https_key_path"] = pref->getWebUIHttpsKeyPath(); + data["web_ui_base_path"] = pref->getWebUIBasePath(); // Authentication data["web_ui_username"] = pref->getWebUiUsername(); data["bypass_local_auth"] = !pref->isWebUiLocalAuthEnabled(); @@ -640,6 +641,8 @@ void AppController::setPreferencesAction() pref->setWebUIBanDuration(std::chrono::seconds {it.value().toInt()}); if (hasKey("web_ui_session_timeout")) pref->setWebUISessionTimeout(it.value().toInt()); + if (hasKey("web_ui_base_path")) + pref->setWebUIBasePath(it.value().toString()); // Use alternative Web UI if (hasKey("alternative_webui_enabled")) pref->setAltWebUiEnabled(it.value().toBool()); diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index 1b22190ca8a1..e6bc3855c7f9 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -130,6 +130,7 @@ WebApplication::WebApplication(QObject *parent) declarePublicAPI(QLatin1String("auth/login")); + fireOnceConfigure(); configure(); connect(Preferences::instance(), &Preferences::changed, this, &WebApplication::configure); } @@ -238,6 +239,7 @@ void WebApplication::translateDocument(QString &data) const data.replace(QLatin1String("${LANG}"), m_currentLocale.left(2)); data.replace(QLatin1String("${CACHEID}"), m_cacheID); + data.replace(QLatin1String("${BASEPATH}"), m_basePath); } } @@ -256,6 +258,24 @@ const Http::Environment &WebApplication::env() const return m_env; } +void WebApplication::doProcessPath() +{ + if(!m_basePath.isEmpty()) + { + if(m_request.path.indexOf(m_basePath) == 0) + { + m_request.path.remove(0, m_basePath.length()); + } + else + { + //Set location header for redirect + setHeader({Http::HEADER_LOCATION, m_basePath + m_request.path}); + + throw SeeOtherHTTPError(m_basePath + m_request.path); + } + } +} + void WebApplication::doProcessRequest() { const QRegularExpressionMatch match = m_apiPathPattern.match(request().path); @@ -314,6 +334,13 @@ void WebApplication::doProcessRequest() } } +//For configurations that require a restart to take effect +void WebApplication::fireOnceConfigure() +{ + const auto *pref = Preferences::instance(); + m_basePath = pref->getWebUIBasePath(); +} + void WebApplication::configure() { const auto *pref = Preferences::instance(); @@ -362,7 +389,6 @@ void WebApplication::configure() m_isSecureCookieEnabled = pref->isWebUiSecureCookieEnabled(); m_isHostHeaderValidationEnabled = pref->isWebUIHostHeaderValidationEnabled(); m_isHttpsEnabled = pref->isWebUiHttpsEnabled(); - m_basePath = pref->getWebUIBasePath(); m_prebuiltHeaders.clear(); m_prebuiltHeaders.push_back({QLatin1String(Http::HEADER_X_XSS_PROTECTION), QLatin1String("1; mode=block")}); @@ -496,11 +522,7 @@ Http::Response WebApplication::processRequest(const Http::Request &request, cons } sessionInitialize(); - - //Replace base path prefix with a '/' - if(!m_basePath.isEmpty() && m_request.path.indexOf(m_basePath == 0)) - m_request.path.replace(0, m_basePath.length, QChar('/')); - + doProcessPath(); doProcessRequest(); } catch (const HTTPError &error) diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index a87ae43bcd4e..a5b4db21e171 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -97,7 +97,9 @@ class WebApplication final private: void doProcessRequest(); + void doProcessPath(); void configure(); + void fireOnceConfigure(); void registerAPIController(const QString &scope, APIController *controller); void declarePublicAPI(const QString &apiPath); diff --git a/src/webui/www/package.json b/src/webui/www/package.json index e94124882519..ce7dccc5b16d 100644 --- a/src/webui/www/package.json +++ b/src/webui/www/package.json @@ -5,7 +5,7 @@ "type": "git", "url": "https://github.com/qbittorrent/qBittorrent.git" }, - "scripts": { + "${BASEPATH}/scripts": { "format": "js-beautify private/*.html private/scripts/*.js private/views/*.html public/*.html public/scripts/*.js", "lint": "eslint private/*.html private/scripts/*.js private/views/*.html public/*.html public/scripts/*.js" }, diff --git a/src/webui/www/private/addpeers.html b/src/webui/www/private/addpeers.html index c2075f7635e3..f4f026ad3677 100644 --- a/src/webui/www/private/addpeers.html +++ b/src/webui/www/private/addpeers.html @@ -1,12 +1,12 @@ - + QBT_TR(Add Peers)QBT_TR[CONTEXT=PeersAdditionDialog] - - - + + + - + + + - + + + - + + + - + + + - + + + - - - + + + + + + -
+

QBT_TR(Download Torrents from their URLs or Magnet links)QBT_TR[CONTEXT=HttpServer]

diff --git a/src/webui/www/private/downloadlimit.html b/src/webui/www/private/downloadlimit.html index 57f3f8e97811..71e3181eada3 100644 --- a/src/webui/www/private/downloadlimit.html +++ b/src/webui/www/private/downloadlimit.html @@ -1,14 +1,14 @@ - + QBT_TR(Torrent Download Speed Limiting)QBT_TR[CONTEXT=TransferListWidget] - - - - - + + + + + @@ -29,7 +29,7 @@ const limit = $("dllimitUpdatevalue").value.toInt() * 1024; if (hashes[0] == "global") { new Request({ - url: 'api/v2/transfer/setDownloadLimit', + url: '${BASEPATH}/api/v2/transfer/setDownloadLimit', method: 'post', data: { 'limit': limit @@ -42,7 +42,7 @@ } else { new Request({ - url: 'api/v2/torrents/setDownloadLimit', + url: '${BASEPATH}/api/v2/torrents/setDownloadLimit', method: 'post', data: { 'hashes': hashes.join('|'), diff --git a/src/webui/www/private/edittracker.html b/src/webui/www/private/edittracker.html index 56420fd16e26..a141a1aee405 100644 --- a/src/webui/www/private/edittracker.html +++ b/src/webui/www/private/edittracker.html @@ -4,9 +4,9 @@ QBT_TR(Tracker editing)QBT_TR[CONTEXT=TrackerListWidget] - - - + + + - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/src/webui/www/private/newcategory.html b/src/webui/www/private/newcategory.html index 5b7cc642fb03..1f698f23d4fb 100644 --- a/src/webui/www/private/newcategory.html +++ b/src/webui/www/private/newcategory.html @@ -4,10 +4,10 @@ QBT_TR(New Category)QBT_TR[CONTEXT=TransferListWidget] - - - - + + + + - - + + + + - - + + + + - - + + + + - - + + + + - - + + + + - - + + + + - - - + + + + + - - + + + + - - + + + + - - + + + + - + + + + - +
diff --git a/src/webui/www/private/uploadlimit.html b/src/webui/www/private/uploadlimit.html index b33ebaeea498..d3c16b7e156c 100644 --- a/src/webui/www/private/uploadlimit.html +++ b/src/webui/www/private/uploadlimit.html @@ -4,11 +4,11 @@ QBT_TR(Torrent Upload Speed Limiting)QBT_TR[CONTEXT=TransferListWidget] - - - - - + + + + + @@ -29,7 +29,7 @@ const limit = $("uplimitUpdatevalue").value.toInt() * 1024; if (hashes[0] == "global") { new Request({ - url: 'api/v2/transfer/setUploadLimit', + url: '${BASEPATH}/api/v2/transfer/setUploadLimit', method: 'post', data: { 'limit': limit @@ -42,7 +42,7 @@ } else { new Request({ - url: 'api/v2/torrents/setUploadLimit', + url: '${BASEPATH}/api/v2/torrents/setUploadLimit', method: 'post', data: { 'hashes': hashes.join('|'), diff --git a/src/webui/www/private/views/about.html b/src/webui/www/private/views/about.html index 92042cb229f8..fec230a9b4d4 100644 --- a/src/webui/www/private/views/about.html +++ b/src/webui/www/private/views/about.html @@ -691,7 +691,7 @@

How to Apply These Terms to + " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]"); new Request.JSON({ - url: 'api/v2/app/buildInfo', + url: '${BASEPATH}/api/v2/app/buildInfo', method: 'get', noCache: true, onSuccess: function(info) { diff --git a/src/webui/www/private/views/installsearchplugin.html b/src/webui/www/private/views/installsearchplugin.html index e9526dcd49c4..369c56419cdc 100644 --- a/src/webui/www/private/views/installsearchplugin.html +++ b/src/webui/www/private/views/installsearchplugin.html @@ -64,7 +64,7 @@

QBT_TR(Plugin path:)QBT_TR[CONTEXT=PluginSourceDlg]

const path = $("newPluginPath").get("value").trim(); if (path) new Request({ - url: 'api/v2/search/installPlugin', + url: '${BASEPATH}/api/v2/search/installPlugin', noCache: true, method: 'post', data: { diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index d8e845baa7eb..2aaab1a2232e 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -705,6 +705,14 @@ + + + + + + + +
@@ -1525,7 +1533,7 @@ // Advanced Tab const updateNetworkInterfaces = function(default_iface) { - const url = 'api/v2/app/networkInterfaceList'; + const url = '${BASEPATH}/api/v2/app/networkInterfaceList'; $('networkInterface').empty(); new Request.JSON({ url: url, @@ -1547,7 +1555,7 @@ }; const updateInterfaceAddresses = function(iface, default_addr) { - const url = 'api/v2/app/networkInterfaceAddressList'; + const url = '${BASEPATH}/api/v2/app/networkInterfaceAddressList'; $('optionalIPAddressToBind').empty(); new Request.JSON({ url: url, @@ -1574,7 +1582,7 @@ }; const loadPreferences = function() { - const url = 'api/v2/app/preferences'; + const url = '${BASEPATH}/api/v2/app/preferences'; new Request.JSON({ url: url, method: 'get', @@ -1835,6 +1843,7 @@ $('webui_address_value').setProperty('value', pref.web_ui_address); $('webui_port_value').setProperty('value', pref.web_ui_port); $('webui_upnp_checkbox').setProperty('checked', pref.web_ui_upnp); + $('webui_basepath_text').setProperty('value', pref.web_ui_base_path); $('use_https_checkbox').setProperty('checked', pref.use_https); $('ssl_cert_text').setProperty('value', pref.web_ui_https_cert_path); $('ssl_key_text').setProperty('value', pref.web_ui_https_key_path); @@ -2213,6 +2222,7 @@ settings.set('use_https', $('use_https_checkbox').getProperty('checked')); settings.set('web_ui_https_cert_path', $('ssl_cert_text').getProperty('value')); settings.set('web_ui_https_key_path', $('ssl_key_text').getProperty('value')); + settings.set('web_ui_base_path', $('webui_basepath_text').getProperty('value')); // Authentication const web_ui_username = $('webui_username_text').getProperty('value'); @@ -2312,7 +2322,7 @@ const json_str = JSON.encode(settings); new Request({ - url: 'api/v2/app/setPreferences', + url: '${BASEPATH}/api/v2/app/setPreferences', method: 'post', data: { 'json': json_str, diff --git a/src/webui/www/private/views/rss.html b/src/webui/www/private/views/rss.html index dadd3ea5704c..37fa438bab12 100644 --- a/src/webui/www/private/views/rss.html +++ b/src/webui/www/private/views/rss.html @@ -190,7 +190,7 @@ const init = () => { new Request.JSON({ - url: 'api/v2/app/preferences', + url: '${BASEPATH}/api/v2/app/preferences', method: 'get', noCache: true, onFailure: () => { @@ -434,7 +434,7 @@ // Place in iframe with sandbox attribute to prevent js execution let torrentDescription = document.createRange().createContextualFragment(''); $('rssDetailsView').append(torrentDescription); - document.getElementById('rssDescription').srcdoc = '' + article.description + ""; + document.getElementById('rssDescription').srcdoc = '' + article.description + ""; //calculate height to fill screen document.getElementById('rssDescription').style.height = @@ -445,7 +445,7 @@ const updateRssFeedList = () => { new Request.JSON({ - url: 'api/v2/rss/items', + url: '${BASEPATH}/api/v2/rss/items', noCache: true, method: 'post', data: { @@ -667,7 +667,7 @@ rssFeedTable.updateIcons(); new Request({ - url: 'api/v2/rss/refreshItem', + url: '${BASEPATH}/api/v2/rss/refreshItem', noCache: true, method: 'post', data: { @@ -745,7 +745,7 @@ // send request new Request({ - url: 'api/v2/rss/markAsRead', + url: '${BASEPATH}/api/v2/rss/markAsRead', noCache: true, method: 'post', data: { @@ -786,7 +786,7 @@ rssFeedTable.updateTable(true); new Request({ - url: 'api/v2/rss/markAsRead', + url: '${BASEPATH}/api/v2/rss/markAsRead', noCache: true, method: 'post', data: { @@ -817,7 +817,7 @@ id: id, title: 'QBT_TR(Rss Downloader)QBT_TR[CONTEXT=AutomatedRssDownloader]', loadMethod: 'xhr', - contentURL: 'views/rssDownloader.html', + contentURL: '${BASEPATH}/views/rssDownloader.html', maximizable: false, width: loadWindowWidth(id, 800), height: loadWindowHeight(id, 650), diff --git a/src/webui/www/private/views/rssDownloader.html b/src/webui/www/private/views/rssDownloader.html index c21622274e5c..25de77712fec 100644 --- a/src/webui/www/private/views/rssDownloader.html +++ b/src/webui/www/private/views/rssDownloader.html @@ -350,7 +350,7 @@ const initRssDownloader = () => { new Request.JSON({ - url: 'api/v2/app/preferences', + url: '${BASEPATH}/api/v2/app/preferences', method: 'get', noCache: true, onFailure: () => { @@ -426,7 +426,7 @@ }); // get all categories and add to combobox new Request.JSON({ - url: 'api/v2/torrents/categories', + url: '${BASEPATH}/api/v2/torrents/categories', noCache: true, method: 'get', onSuccess: (response) => { @@ -440,7 +440,7 @@ }).send(); // get all rss feed new Request.JSON({ - url: 'api/v2/rss/items', + url: '${BASEPATH}/api/v2/rss/items', noCache: true, method: 'post', data: { @@ -468,7 +468,7 @@ const updateRulesList = () => { // get all rules new Request.JSON({ - url: 'api/v2/rss/rules', + url: '${BASEPATH}/api/v2/rss/rules', noCache: true, method: 'get', onSuccess: (response) => { @@ -490,7 +490,7 @@ const modifyRuleState = (rule, setting, newState, callback = () => {}) => { rulesList[rule][setting] = newState; new Request({ - url: 'api/v2/rss/setRule', + url: '${BASEPATH}/api/v2/rss/setRule', noCache: true, method: 'post', data: { @@ -613,7 +613,7 @@ .getValues(); new Request({ - url: 'api/v2/rss/setRule', + url: '${BASEPATH}/api/v2/rss/setRule', noCache: true, method: 'post', data: { @@ -628,7 +628,7 @@ const updateMatchingArticles = (ruleName) => { new Request.JSON({ - url: 'api/v2/rss/matchingArticles', + url: '${BASEPATH}/api/v2/rss/matchingArticles', noCache: true, method: 'post', data: { diff --git a/src/webui/www/private/views/search.html b/src/webui/www/private/views/search.html index 0ce38239aa4d..4566a14db8ad 100644 --- a/src/webui/www/private/views/search.html +++ b/src/webui/www/private/views/search.html @@ -301,7 +301,7 @@ searchResultsRowId = 0; requestCount = 0; - const url = new URI('api/v2/search/start'); + const url = new URI('${BASEPATH}/api/v2/search/start'); new Request.JSON({ url: url, noCache: true, @@ -321,7 +321,7 @@ }; const stopSearch = function() { - const url = new URI('api/v2/search/stop'); + const url = new URI('${BASEPATH}/api/v2/search/stop'); new Request({ url: url, noCache: true, @@ -402,7 +402,7 @@ id: id, title: "QBT_TR(Search plugins)QBT_TR[CONTEXT=PluginSelectDlg]", loadMethod: 'xhr', - contentURL: 'views/searchplugins.html', + contentURL: '${BASEPATH}/views/searchplugins.html', scrollbars: false, maximizable: false, paddingVertical: 0, @@ -512,7 +512,7 @@ const getPlugins = function() { new Request.JSON({ - url: new URI('api/v2/search/plugins'), + url: new URI('${BASEPATH}/api/v2/search/plugins'), noCache: true, method: 'get', onSuccess: function(response) { @@ -638,7 +638,7 @@ const loadSearchResultsData = function() { const maxResults = 500; - const url = new URI('api/v2/search/results'); + const url = new URI('${BASEPATH}/api/v2/search/results'); new Request.JSON({ url: url, noCache: true, diff --git a/src/webui/www/private/views/searchplugins.html b/src/webui/www/private/views/searchplugins.html index f49ae2415037..8011f3052681 100644 --- a/src/webui/www/private/views/searchplugins.html +++ b/src/webui/www/private/views/searchplugins.html @@ -122,7 +122,7 @@

QBT_TR(Installed search plugins:)QBT_TR[CONTEXT=PluginSelectDlg]

id: 'installSearchPlugin', title: "QBT_TR(Install plugin)QBT_TR[CONTEXT=PluginSourceDlg]", loadMethod: 'xhr', - contentURL: 'views/installsearchplugin.html', + contentURL: '${BASEPATH}/views/installsearchplugin.html', scrollbars: false, resizable: false, maximizable: false, @@ -135,7 +135,7 @@

QBT_TR(Installed search plugins:)QBT_TR[CONTEXT=PluginSelectDlg]

const uninstallPlugin = function() { const plugins = searchPluginsTable.selectedRowsIds().join('|'); - const url = new URI('api/v2/search/uninstallPlugin'); + const url = new URI('${BASEPATH}/api/v2/search/uninstallPlugin'); new Request({ url: url, noCache: true, @@ -152,7 +152,7 @@

QBT_TR(Installed search plugins:)QBT_TR[CONTEXT=PluginSelectDlg]

if (plugins && plugins.length) enable = !window.qBittorrent.Search.getPlugin(plugins[0]).enabled; - const url = new URI('api/v2/search/enablePlugin'); + const url = new URI('${BASEPATH}/api/v2/search/enablePlugin'); new Request({ url: url, noCache: true, @@ -165,7 +165,7 @@

QBT_TR(Installed search plugins:)QBT_TR[CONTEXT=PluginSelectDlg]

}; const checkForUpdates = function() { - const url = new URI('api/v2/search/updatePlugins'); + const url = new URI('${BASEPATH}/api/v2/search/updatePlugins'); new Request({ url: url, noCache: true, diff --git a/src/webui/www/public/index.html b/src/webui/www/public/index.html index e08289abcd5c..675eaecf3e2c 100644 --- a/src/webui/www/public/index.html +++ b/src/webui/www/public/index.html @@ -1,16 +1,16 @@ - + qBittorrent QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog] - - - + + + - + @@ -20,7 +20,7 @@

QBT_TR(JavaScript Required! You must enable JavaScript for the Web UI to wor

qBittorrent QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]

diff --git a/src/webui/www/public/scripts/login.js b/src/webui/www/public/scripts/login.js index 175e0012c80f..b06a2d9dbac1 100644 --- a/src/webui/www/public/scripts/login.js +++ b/src/webui/www/public/scripts/login.js @@ -41,7 +41,7 @@ function submitLoginForm() { const errorMsgElement = document.getElementById('error_msg'); const xhr = new XMLHttpRequest(); - xhr.open('POST', 'api/v2/auth/login', true); + xhr.open('POST', '${BASEPATH}/api/v2/auth/login', true); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=UTF-8'); xhr.addEventListener('readystatechange', function() { if (xhr.readyState === 4) { // DONE state