diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index 5125c09acf0..d9fff7aa804 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -466,7 +466,7 @@ void WebApplication::configure() const QString contentSecurityPolicy = (m_isAltUIUsed ? QString() - : u"default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; object-src 'none'; form-action 'self';"_s) + : u"default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; object-src 'none'; form-action 'self'; frame-src 'self' blob:;"_s) + (isClickjackingProtectionEnabled ? u" frame-ancestors 'self';"_s : QString()) + (m_isHttpsEnabled ? u" upgrade-insecure-requests;"_s : QString()); if (!contentSecurityPolicy.isEmpty()) diff --git a/src/webui/www/private/scripts/misc.js b/src/webui/www/private/scripts/misc.js index 3010c8f42b7..c155487dba0 100644 --- a/src/webui/www/private/scripts/misc.js +++ b/src/webui/www/private/scripts/misc.js @@ -47,6 +47,7 @@ window.qBittorrent.Misc ??= (() => { toFixedPointString: toFixedPointString, containsAllTerms: containsAllTerms, sleep: sleep, + downloadFile: downloadFile, // variables FILTER_INPUT_DELAY: 400, MAX_ETA: 8640000 @@ -275,6 +276,37 @@ window.qBittorrent.Misc ??= (() => { }); }; + const downloadFile = async (url, defaultFileName, errorMessage = undefined) => { + errorMessage ??= "QBT_TR(Unable to download file)QBT_TR[CONTEXT=HttpServer]"; + try { + const response = await fetch(url); + if ((response.status >= 200) && (response.status < 300)) { + const blob = await response.blob(); + const fileNamePrefix = "filename="; + let fileName = defaultFileName; + for (const part of (response.headers.get("content-disposition") ?? "").split(";").map(s => s.trim())) { + if (part.startsWith(fileNamePrefix)) { + fileName = part.substring(fileNamePrefix.length); + if (fileName.startsWith("\"") && fileName.endsWith("\"")) + fileName = fileName.slice(1, -1); + break; + } + } + + const link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + link.download = fileName; + link.click(); + } + else { + alert(errorMessage); + } + } + catch (error) { + alert(errorMessage); + } + }; + return exports(); })(); Object.freeze(window.qBittorrent.Misc); diff --git a/src/webui/www/private/scripts/mocha-init.js b/src/webui/www/private/scripts/mocha-init.js index 75ae8edd828..dc4b28546db 100644 --- a/src/webui/www/private/scripts/mocha-init.js +++ b/src/webui/www/private/scripts/mocha-init.js @@ -1115,16 +1115,10 @@ const initializeWindows = () => { continue; const name = row.full_data.name; - const url = new URI("api/v2/torrents/export"); - url.setData("hash", hash); + const url = new URI("api/v2/torrents/export").setData("hash", hash).toString(); // download response to file - const element = document.createElement("a"); - element.href = url; - element.download = (name + ".torrent"); - document.body.appendChild(element); - element.click(); - document.body.removeChild(element); + await window.qBittorrent.Misc.downloadFile(url, `${name}.torrent`, "QBT_TR(Unable to export torrent file)QBT_TR[CONTEXT=MainWindow]"); // https://stackoverflow.com/questions/53560991/automatic-file-downloads-limited-to-10-files-on-chrome-browser await window.qBittorrent.Misc.sleep(200);