tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_mixed_content_download.js (4911B)


      1 ChromeUtils.defineESModuleGetters(this, {
      2  Downloads: "resource://gre/modules/Downloads.sys.mjs",
      3  DownloadsCommon:
      4    "moz-src:///browser/components/downloads/DownloadsCommon.sys.mjs",
      5 });
      6 
      7 const HandlerService = Cc[
      8  "@mozilla.org/uriloader/handler-service;1"
      9 ].getService(Ci.nsIHandlerService);
     10 
     11 const MIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
     12 
     13 let SECURE_BASE_URL =
     14  getRootDirectory(gTestPath).replace(
     15    "chrome://mochitests/content/",
     16    "https://example.com/"
     17  ) + "download_page.html";
     18 
     19 /**
     20 * Waits until a download is triggered.
     21 * It waits until a prompt is shown,
     22 * saves and then accepts the dialog.
     23 *
     24 * @returns {Promise} Resolved once done.
     25 */
     26 
     27 function shouldTriggerDownload() {
     28  return new Promise((resolve, reject) => {
     29    Services.wm.addListener({
     30      onOpenWindow(xulWin) {
     31        Services.wm.removeListener(this);
     32        let win = xulWin.docShell.domWindow;
     33        waitForFocus(() => {
     34          if (
     35            win.location ==
     36            "chrome://mozapps/content/downloads/unknownContentType.xhtml"
     37          ) {
     38            let dialog = win.document.getElementById("unknownContentType");
     39            let button = dialog.getButton("accept");
     40            let actionRadio = win.document.getElementById("save");
     41            actionRadio.click();
     42            button.disabled = false;
     43            dialog.acceptDialog();
     44            resolve();
     45          } else {
     46            reject();
     47          }
     48        }, win);
     49      },
     50    });
     51  });
     52 }
     53 
     54 const CONSOLE_UPGRADE_MESSAGE = "Upgrading insecure request";
     55 const CONSOLE_DOWNGRADE_MESSAGE = "Downgrading to “http” again.";
     56 const DOWNLOAD_URL =
     57  "example.com/browser/dom/security/test/https-first/download_server.sjs";
     58 // Verifies that https-first tries to upgrade download,
     59 // falls back since download is not available via https
     60 let msgCounter = 0;
     61 function shouldConsoleError() {
     62  return new Promise(resolve => {
     63    function listener(msgObj) {
     64      let text = msgObj.message;
     65      if (text.includes(CONSOLE_UPGRADE_MESSAGE) && msgCounter == 0) {
     66        ok(
     67          text.includes("http://" + DOWNLOAD_URL),
     68          "Https-first tries to upgrade download to https"
     69        );
     70        msgCounter++;
     71      }
     72      if (text.includes(CONSOLE_DOWNGRADE_MESSAGE) && msgCounter == 1) {
     73        ok(
     74          text.includes("https://" + DOWNLOAD_URL),
     75          "Https-first downgrades download to http."
     76        );
     77        resolve();
     78        Services.console.unregisterListener(listener);
     79      }
     80    }
     81    Services.console.registerListener(listener);
     82  });
     83 }
     84 
     85 async function resetDownloads() {
     86  // Removes all downloads from the download List
     87  const types = new Set();
     88  let publicList = await Downloads.getList(Downloads.PUBLIC);
     89  let downloads = await publicList.getAll();
     90  for (let download of downloads) {
     91    if (download.contentType) {
     92      types.add(download.contentType);
     93    }
     94    publicList.remove(download);
     95    await download.finalize(true);
     96  }
     97 
     98  if (types.size) {
     99    // reset handlers for the contentTypes of any files previously downloaded
    100    for (let type of types) {
    101      const mimeInfo = MIMEService.getFromTypeAndExtension(type, "");
    102      info("resetting handler for type: " + type);
    103      HandlerService.remove(mimeInfo);
    104    }
    105  }
    106 }
    107 
    108 async function runTest(url, link, checkFunction, description) {
    109  await SpecialPowers.pushPrefEnv({
    110    set: [
    111      ["dom.security.https_first", true],
    112      ["browser.download.always_ask_before_handling_new_types", true],
    113    ],
    114  });
    115  requestLongerTimeout(2);
    116  await resetDownloads();
    117 
    118  let tab = BrowserTestUtils.addTab(gBrowser, url);
    119  gBrowser.selectedTab = tab;
    120 
    121  let browser = gBrowser.getBrowserForTab(tab);
    122  await BrowserTestUtils.browserLoaded(browser);
    123  is(
    124    gBrowser.currentURI.schemeIs("https"),
    125    true,
    126    "Scheme of opened tab should be https"
    127  );
    128  info("Checking: " + description);
    129 
    130  let checkPromise = checkFunction();
    131  // Click the Link to trigger the download
    132  SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => {
    133    content.document.getElementById(contentLink).click();
    134  });
    135  await checkPromise;
    136  ok(true, description);
    137  BrowserTestUtils.removeTab(tab);
    138 }
    139 
    140 //Test description:
    141 // 1. Open "https://example.com"
    142 // 2. From "https://example.com" download something, but that download is only available via http.
    143 // 3. Https-first tries to upgrade the download.
    144 // 4. Upgrading fails - so http-first downgrade download to http.
    145 
    146 add_task(async function test_mixed_download() {
    147  await runTest(
    148    SECURE_BASE_URL,
    149    "insecure",
    150    () => Promise.all([shouldTriggerDownload(), shouldConsoleError()]),
    151    "Secure -> Insecure should Error"
    152  );
    153  // remove downloaded file
    154  let downloadsPromise = Downloads.getList(Downloads.PUBLIC);
    155  let downloadList = await downloadsPromise;
    156  let [download] = downloadList._downloads;
    157  await downloadList.remove(download);
    158 });