summaryrefslogtreecommitdiffstats
path: root/dom/security/test/mixedcontentblocker/browser_mixed_content_auth_download.js
blob: 25fee8de3c459335b843052c5f6bd24df8a88207 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* Any copyright is dedicated to the Public Domain.
 * https://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

ChromeUtils.defineESModuleGetters(this, {
  Downloads: "resource://gre/modules/Downloads.sys.mjs",
  DownloadsCommon: "resource:///modules/DownloadsCommon.sys.mjs",
});

const { PromptTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/PromptTestUtils.sys.mjs"
);

let authPromptModalType = Services.prefs.getIntPref(
  "prompts.modalType.httpAuth"
);

const downloadMonitoringView = {
  _listeners: [],
  onDownloadAdded(download) {
    for (let listener of this._listeners) {
      listener(download);
    }
    this._listeners = [];
  },
  waitForDownload(listener) {
    this._listeners.push(listener);
  },
};

let SECURE_BASE_URL =
  getRootDirectory(gTestPath).replace(
    "chrome://mochitests/content/",
    "https://example.com/"
  ) + "file_auth_download_page.html";

/**
 * Waits until a download is triggered.
 * It waits until a prompt is shown,
 * saves and then accepts the dialog.
 * @returns {Promise} Resolved once done.
 */

function shouldTriggerDownload() {
  return new Promise(res => {
    downloadMonitoringView.waitForDownload(res);
  });
}
function shouldNotifyDownloadUI() {
  return new Promise(res => {
    downloadMonitoringView.waitForDownload(async aDownload => {
      let { error } = aDownload;
      if (
        error.becauseBlockedByReputationCheck &&
        error.reputationCheckVerdict == Downloads.Error.BLOCK_VERDICT_INSECURE
      ) {
        // It's an insecure Download, now Check that it has been cleaned up properly
        if ((await IOUtils.stat(aDownload.target.path)).size != 0) {
          throw new Error(`Download target is not empty!`);
        }
        if ((await IOUtils.stat(aDownload.target.path)).size != 0) {
          throw new Error(`Download partFile was not cleaned up properly`);
        }
        // Assert that the Referrer is present
        if (!aDownload.source.referrerInfo) {
          throw new Error("The Blocked download is missing the ReferrerInfo");
        }

        res(aDownload);
      } else {
        ok(false, "No error for download that was expected to error!");
      }
    });
  });
}

async function resetDownloads() {
  // Removes all downloads from the download List
  const types = new Set();
  let publicList = await Downloads.getList(Downloads.ALL);
  let downloads = await publicList.getAll();
  for (let download of downloads) {
    if (download.contentType) {
      types.add(download.contentType);
    }
    publicList.remove(download);
    await download.finalize(true);
  }
}

async function runTest(url, link, checkFunction, description) {
  await resetDownloads();
  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
  is(
    gBrowser.currentURI.schemeIs("https"),
    true,
    "Scheme of opened tab should be https"
  );
  info("Checking: " + description);

  let checkPromise = checkFunction();
  // Click the Link to trigger the download
  SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => {
    content.document.getElementById(contentLink).click();
  });
  // Wait for the auth prompt, enter the login details and close the prompt
  await PromptTestUtils.handleNextPrompt(
    gBrowser.selectedBrowser,
    { modalType: authPromptModalType, promptType: "promptUserAndPass" },
    { buttonNumClick: 0, loginInput: "user", passwordInput: "pass" }
  );
  await checkPromise;
  ok(true, description);
  // Close download panel
  DownloadsPanel.hidePanel();
  is(DownloadsPanel.panel.state, "closed", "Panel should be closed");
  await BrowserTestUtils.removeTab(tab);
}

add_setup(async function () {
  let list = await Downloads.getList(Downloads.ALL);
  list.addView(downloadMonitoringView);
  registerCleanupFunction(() => list.removeView(downloadMonitoringView));
  // Ensure to delete all cached credentials before running test
  await new Promise(resolve => {
    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, resolve);
  });
  await SpecialPowers.pushPrefEnv({
    set: [["dom.block_download_insecure", true]],
  });
});
//Test description:
// 1. Open "https://example.com".
// 2. From "https://example.com" download something, but that download is only available via http
//    and with authentication.
// 3. Login and start download.
// 4. Mixed-content blocker blocks download.
// 5. Unblock download and verify the downloaded file.
add_task(async function test_auth_download() {
  await runTest(
    SECURE_BASE_URL,
    "insecure",
    async () => {
      let [, download] = await Promise.all([
        shouldTriggerDownload(),
        shouldNotifyDownloadUI(),
      ]);
      await download.unblock();
      Assert.equal(
        download.error,
        null,
        "There should be no error after unblocking"
      );
      info(
        "Start download to be able to validate the size and the success of the download"
      );
      await download.start();
      is(
        download.contentType,
        "text/html",
        "File contentType should be correct."
      );
      ok(download.succeeded, "Download succeeded!");
      is(download.target.size, 27, "Download has correct size");
    },
    "A locked Download from an auth server should succeeded to Download after a Manual unblock"
  );
});