Commit a86adcd6 authored by ma1's avatar ma1 Committed by Pier Angelo Vendrame
Browse files

BB 41854: Allow overriding download spam protection.

parent 0aaa1817
Loading
Loading
Loading
Loading
+55 −6
Original line number Diff line number Diff line
@@ -89,8 +89,9 @@ class WindowSpamProtection {
   * Add a blocked download to the spamList or increment the count of an
   * 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();
@@ -104,7 +105,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);
@@ -188,6 +189,39 @@ 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,
@@ -205,9 +239,11 @@ export class DownloadSpamProtection {
   * download was blocked. This is invoked when a download is blocked by
   * 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: ",
@@ -221,7 +257,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)
    );
  }

  /**
@@ -280,8 +319,9 @@ export class DownloadSpamProtection {
 * @extends Download
 */
class DownloadSpam extends Download {
  constructor(url) {
  constructor(url, downloadSpamEnabler) {
    super();
    this._downloadSpamEnabler = downloadSpamEnabler;
    this.hasBlockedData = true;
    this.stopped = true;
    this.error = new DownloadError({
@@ -292,4 +332,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();
  }
}
+7 −2
Original line number Diff line number Diff line
@@ -722,6 +722,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);
@@ -732,7 +736,6 @@ Download.prototype = {
        this._promiseUnblock = null;
        throw ex;
      }

      this.succeeded = true;
      this.hasBlockedData = false;
      this._notifyChange();
@@ -1003,7 +1006,9 @@ Download.prototype = {
            await this._promiseCanceled;
          }
          // Ask the saver object to remove any partial data.
          if (this.saver) {
            await this.saver.removeData();
          }
          // For completeness, clear the number of bytes transferred.
          if (this.currentBytes != 0 || this.hasPartialData) {
            this.currentBytes = 0;
+1 −4
Original line number Diff line number Diff line
@@ -1387,10 +1387,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;
    }
+1 −3
Original line number Diff line number Diff line
@@ -1942,13 +1942,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