commit 8725e1596b6b83e1421de5e79bac538b16f40659
parent b0dc617b7c64b3146378a50637c7572d27f34475
Author: hackademix <giorgio@maone.net>
Date: Wed, 5 Jul 2023 17:05:40 +0200
BB 41854: Allow overriding download spam protection.
Diffstat:
4 files changed, 66 insertions(+), 15 deletions(-)
diff --git a/browser/components/downloads/DownloadSpamProtection.sys.mjs b/browser/components/downloads/DownloadSpamProtection.sys.mjs
@@ -96,8 +96,9 @@ class WindowSpamProtection {
* existing blocked download, then notify listeners about this.
*
* @param {string} url
+ * @param {DownloadSpamEnabler} enabler
*/
- addDownloadSpam(url) {
+ addDownloadSpam(url, enabler) {
this._blocking = true;
// Start listening on registered downloads views, if any exist.
this._maybeAddViews();
@@ -111,7 +112,7 @@ class WindowSpamProtection {
}
// Otherwise, create a new DownloadSpam object for the URL, add it to the
// spamList, and open the downloads panel.
- let downloadSpam = new DownloadSpam(url);
+ let downloadSpam = new DownloadSpam(url, enabler);
this.spamList.add(downloadSpam);
this._downloadSpamForUrl.set(url, downloadSpam);
this._notifyDownloadSpamAdded(downloadSpam);
@@ -199,6 +200,41 @@ class WindowSpamProtection {
}
/**
+ * Helper to grant a certain principal permission for automatic downloads
+ * and to clear its download spam messages from the UI
+ */
+class DownloadSpamEnabler {
+ /**
+ * Constructs a DownloadSpamEnabler object
+ *
+ * @param {nsIPrincipal} principal
+ * @param {DownloadSpamProtection} downloadSpamProtection
+ */
+ constructor(principal, downloadSpamProtection) {
+ this.principal = principal;
+ this.downloadSpamProtection = downloadSpamProtection;
+ }
+ /**
+ * Allows a DownloadSpam item
+ *
+ * @param {DownloadSpam} downloadSpam
+ */
+ allow(downloadSpam) {
+ const pm = Services.perms;
+ pm.addFromPrincipal(
+ this.principal,
+ "automatic-download",
+ pm.ALLOW_ACTION,
+ pm.EXPIRE_SESSION
+ );
+ downloadSpam.hasBlockedData = downloadSpam.hasPartialData = false;
+ const { url } = downloadSpam.source;
+ for (let window of lazy.BrowserWindowTracker.orderedWindows) {
+ this.downloadSpamProtection.removeDownloadSpamForWindow(url, window);
+ }
+ }
+}
+/**
* Responsible for detecting events related to downloads spam and notifying the
* relevant window's WindowSpamProtection object. This is a singleton object,
* constructed by DownloadIntegration.sys.mjs when the first download is blocked.
@@ -217,9 +253,11 @@ export class DownloadSpamProtection {
* nsExternalAppHandler::IsDownloadSpam
*
* @param {string} url
- * @param {Window} window
+ * @param {nsILoadInfo} loadInfo
*/
- update(url, window) {
+ update(url, loadInfo) {
+ loadInfo = loadInfo.QueryInterface(Ci.nsILoadInfo);
+ const window = loadInfo.browsingContext.topChromeWindow;
if (window == null) {
lazy.DownloadsCommon.log(
"Download spam blocked in a non-chrome window. URL: ",
@@ -233,7 +271,10 @@ export class DownloadSpamProtection {
let wsp =
this._forWindowMap.get(window) ?? new WindowSpamProtection(window);
this._forWindowMap.set(window, wsp);
- wsp.addDownloadSpam(url);
+ wsp.addDownloadSpam(
+ url,
+ new DownloadSpamEnabler(loadInfo.triggeringPrincipal, this)
+ );
}
/**
@@ -297,8 +338,9 @@ export class DownloadSpamProtection {
* @augments Download
*/
class DownloadSpam extends Download {
- constructor(url) {
+ constructor(url, downloadSpamEnabler) {
super();
+ this._downloadSpamEnabler = downloadSpamEnabler;
this.hasBlockedData = true;
this.stopped = true;
this.error = new DownloadError({
@@ -309,4 +351,13 @@ class DownloadSpam extends Download {
this.source = { url };
this.blockedDownloadsCount = 1;
}
+
+ /**
+ * Allows the principal which triggered this download to perform automatic downloads
+ * and clears the UI from messages reporting this download spam
+ */
+ allow() {
+ this._downloadSpamEnabler.allow(this);
+ this._notifyChange();
+ }
}
diff --git a/toolkit/components/downloads/DownloadCore.sys.mjs b/toolkit/components/downloads/DownloadCore.sys.mjs
@@ -773,6 +773,10 @@ Download.prototype = {
}
this._promiseUnblock = (async () => {
+ if (this.allow) {
+ this.allow();
+ return;
+ }
try {
if (this.target.partFilePath) {
await IOUtils.move(this.target.partFilePath, this.target.path);
@@ -783,7 +787,6 @@ Download.prototype = {
this._promiseUnblock = null;
throw ex;
}
-
this.succeeded = true;
this.hasBlockedData = false;
this._notifyChange();
@@ -1058,7 +1061,9 @@ Download.prototype = {
await this._promiseCanceled;
}
// Ask the saver object to remove any partial data.
- await this.saver.removeData();
+ if (this.saver) {
+ await this.saver.removeData();
+ }
// For completeness, clear the number of bytes transferred.
if (this.currentBytes != 0 || this.hasPartialData) {
this.currentBytes = 0;
diff --git a/toolkit/components/downloads/DownloadIntegration.sys.mjs b/toolkit/components/downloads/DownloadIntegration.sys.mjs
@@ -1467,10 +1467,7 @@ var DownloadObserver = {
case "blocked-automatic-download":
if (AppConstants.MOZ_BUILD_APP == "browser") {
DownloadIntegration._initializeDownloadSpamProtection();
- DownloadIntegration.downloadSpamProtection.update(
- aData,
- aSubject.topChromeWindow
- );
+ DownloadIntegration.downloadSpamProtection.update(aData, aSubject);
}
break;
}
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -1954,13 +1954,11 @@ bool nsExternalAppHandler::IsDownloadSpam(nsIChannel* aChannel) {
if (capability == nsIPermissionManager::PROMPT_ACTION) {
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
- RefPtr<BrowsingContext> browsingContext;
- loadInfo->GetBrowsingContext(getter_AddRefs(browsingContext));
nsAutoCString cStringURI;
loadInfo->TriggeringPrincipal()->GetPrePath(cStringURI);
observerService->NotifyObservers(
- browsingContext, "blocked-automatic-download",
+ loadInfo, "blocked-automatic-download",
NS_ConvertASCIItoUTF16(cStringURI.get()).get());
// FIXME: In order to escape memory leaks, currently we cancel blocked
// downloads. This is temporary solution, because download data should be