From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- .../auto_upgrading_identity.html | 11 + .../auto_upgrading_identity.png | Bin 0 -> 70 bytes dom/security/test/mixedcontentblocker/browser.ini | 28 ++ .../browser_auto_upgrading_identity.js | 55 ++++ ...xedcontent_and_mixed_content_display_upgrade.js | 78 +++++ .../browser_mixed_content_auth_download.js | 165 ++++++++++ ...r_mixed_content_auto_upgrade_display_console.js | 51 ++++ .../browser_test_mixed_content_download.js | 333 ++++++++++++++++++++ .../test/mixedcontentblocker/download_page.html | 41 +++ .../test/mixedcontentblocker/download_server.sjs | 20 ++ .../file_auth_download_page.html | 22 ++ .../file_auth_download_server.sjs | 62 ++++ .../test/mixedcontentblocker/file_bug1551886.html | 25 ++ .../file_bug803225_test_mailto.html | 13 + ...dcontent_and_mixed_content_display_upgrade.html | 14 + .../mixedcontentblocker/file_frameNavigation.html | 74 +++++ .../file_frameNavigation_blankTarget.html | 33 ++ .../file_frameNavigation_grandchild.html | 57 ++++ .../file_frameNavigation_innermost.html | 74 +++++ .../file_frameNavigation_secure.html | 73 +++++ .../file_frameNavigation_secure_grandchild.html | 58 ++++ .../test/mixedcontentblocker/file_main.html | 338 +++++++++++++++++++++ .../mixedcontentblocker/file_main_bug803225.html | 175 +++++++++++ .../file_main_bug803225_websocket_wsh.py | 6 + ...mixed_content_auto_upgrade_display_console.html | 10 + .../test/mixedcontentblocker/file_redirect.html | 31 ++ .../mixedcontentblocker/file_redirect_handler.sjs | 35 +++ .../test/mixedcontentblocker/file_server.sjs | 131 ++++++++ .../test/mixedcontentblocker/mochitest.ini | 40 +++ dom/security/test/mixedcontentblocker/pass.png | Bin 0 -> 1689 bytes dom/security/test/mixedcontentblocker/test.ogv | Bin 0 -> 2344665 bytes dom/security/test/mixedcontentblocker/test.wav | Bin 0 -> 353022 bytes .../test/mixedcontentblocker/test_bug1551886.html | 33 ++ .../test/mixedcontentblocker/test_bug803225.html | 157 ++++++++++ .../mixedcontentblocker/test_frameNavigation.html | 127 ++++++++ .../test/mixedcontentblocker/test_main.html | 231 ++++++++++++++ .../test/mixedcontentblocker/test_redirect.html | 45 +++ 37 files changed, 2646 insertions(+) create mode 100644 dom/security/test/mixedcontentblocker/auto_upgrading_identity.html create mode 100644 dom/security/test/mixedcontentblocker/auto_upgrading_identity.png create mode 100644 dom/security/test/mixedcontentblocker/browser.ini create mode 100644 dom/security/test/mixedcontentblocker/browser_auto_upgrading_identity.js create mode 100644 dom/security/test/mixedcontentblocker/browser_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.js create mode 100644 dom/security/test/mixedcontentblocker/browser_mixed_content_auth_download.js create mode 100644 dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js create mode 100644 dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js create mode 100644 dom/security/test/mixedcontentblocker/download_page.html create mode 100644 dom/security/test/mixedcontentblocker/download_server.sjs create mode 100644 dom/security/test/mixedcontentblocker/file_auth_download_page.html create mode 100644 dom/security/test/mixedcontentblocker/file_auth_download_server.sjs create mode 100644 dom/security/test/mixedcontentblocker/file_bug1551886.html create mode 100644 dom/security/test/mixedcontentblocker/file_bug803225_test_mailto.html create mode 100644 dom/security/test/mixedcontentblocker/file_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_blankTarget.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_grandchild.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_innermost.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_secure.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_secure_grandchild.html create mode 100644 dom/security/test/mixedcontentblocker/file_main.html create mode 100644 dom/security/test/mixedcontentblocker/file_main_bug803225.html create mode 100644 dom/security/test/mixedcontentblocker/file_main_bug803225_websocket_wsh.py create mode 100644 dom/security/test/mixedcontentblocker/file_mixed_content_auto_upgrade_display_console.html create mode 100644 dom/security/test/mixedcontentblocker/file_redirect.html create mode 100644 dom/security/test/mixedcontentblocker/file_redirect_handler.sjs create mode 100644 dom/security/test/mixedcontentblocker/file_server.sjs create mode 100644 dom/security/test/mixedcontentblocker/mochitest.ini create mode 100644 dom/security/test/mixedcontentblocker/pass.png create mode 100644 dom/security/test/mixedcontentblocker/test.ogv create mode 100644 dom/security/test/mixedcontentblocker/test.wav create mode 100644 dom/security/test/mixedcontentblocker/test_bug1551886.html create mode 100644 dom/security/test/mixedcontentblocker/test_bug803225.html create mode 100644 dom/security/test/mixedcontentblocker/test_frameNavigation.html create mode 100644 dom/security/test/mixedcontentblocker/test_main.html create mode 100644 dom/security/test/mixedcontentblocker/test_redirect.html (limited to 'dom/security/test/mixedcontentblocker') diff --git a/dom/security/test/mixedcontentblocker/auto_upgrading_identity.html b/dom/security/test/mixedcontentblocker/auto_upgrading_identity.html new file mode 100644 index 0000000000..d843b7fae1 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/auto_upgrading_identity.html @@ -0,0 +1,11 @@ + + + + + Bug 1674341: Test SiteIdentity when auto-upgrading mixed content + + + + + + diff --git a/dom/security/test/mixedcontentblocker/auto_upgrading_identity.png b/dom/security/test/mixedcontentblocker/auto_upgrading_identity.png new file mode 100644 index 0000000000..52c591798e Binary files /dev/null and b/dom/security/test/mixedcontentblocker/auto_upgrading_identity.png differ diff --git a/dom/security/test/mixedcontentblocker/browser.ini b/dom/security/test/mixedcontentblocker/browser.ini new file mode 100644 index 0000000000..eae1091128 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/browser.ini @@ -0,0 +1,28 @@ +[DEFAULT] +prefs = + dom.security.https_first=false +support-files = + download_page.html + download_server.sjs + +[browser_auto_upgrading_identity.js] +support-files = + auto_upgrading_identity.html + auto_upgrading_identity.png +[browser_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.js] +support-files = + file_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.html + pass.png + test.ogv + test.wav +[browser_mixed_content_auth_download.js] +support-files = + file_auth_download_page.html + file_auth_download_server.sjs +[browser_mixed_content_auto_upgrade_display_console.js] +support-files = file_mixed_content_auto_upgrade_display_console.html +[browser_test_mixed_content_download.js] +skip-if = + win10_2004 && debug # Bug 1723573 + win11_2009 # Bug 1784764 + os == "linux" && !debug # Bug 1784764 diff --git a/dom/security/test/mixedcontentblocker/browser_auto_upgrading_identity.js b/dom/security/test/mixedcontentblocker/browser_auto_upgrading_identity.js new file mode 100644 index 0000000000..7860c06fc2 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/browser_auto_upgrading_identity.js @@ -0,0 +1,55 @@ +"use strict"; + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); +const TEST_TOPLEVEL_URI = TEST_PATH + "auto_upgrading_identity.html"; + +// auto upgrading mixed content should not indicate passive mixed content loaded +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [["security.mixed_content.upgrade_display_content", true]], + }); + await BrowserTestUtils.withNewTab( + TEST_TOPLEVEL_URI, + async function (browser) { + await ContentTask.spawn(browser, {}, async function () { + let testImg = content.document.getElementById("testimage"); + ok( + testImg.src.includes("auto_upgrading_identity.png"), + "sanity: correct image is loaded" + ); + }); + // Ensure the identiy handler does not show mixed content! + ok( + !gIdentityHandler._isMixedPassiveContentLoaded, + "Auto-Upgrading Mixed Content: Identity should note indicate mixed content" + ); + } + ); +}); + +// regular mixed content test should indicate passive mixed content loaded +add_task(async () => { + await SpecialPowers.pushPrefEnv({ + set: [["security.mixed_content.upgrade_display_content", false]], + }); + await BrowserTestUtils.withNewTab( + TEST_TOPLEVEL_URI, + async function (browser) { + await ContentTask.spawn(browser, {}, async function () { + let testImg = content.document.getElementById("testimage"); + ok( + testImg.src.includes("auto_upgrading_identity.png"), + "sanity: correct image is loaded" + ); + }); + // Ensure the identiy handler does show mixed content! + ok( + gIdentityHandler._isMixedPassiveContentLoaded, + "Regular Mixed Content: Identity should indicate mixed content" + ); + } + ); +}); diff --git a/dom/security/test/mixedcontentblocker/browser_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.js b/dom/security/test/mixedcontentblocker/browser_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.js new file mode 100644 index 0000000000..1f738b951d --- /dev/null +++ b/dom/security/test/mixedcontentblocker/browser_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.js @@ -0,0 +1,78 @@ +/* + * Description of the Test: + * We load an https page which uses a CSP including block-all-mixed-content. + * The page embedded an audio, img and video. ML2 should upgrade them and + * CSP should not be triggered. + */ + +const PRE_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); +var gTestBrowser = null; +let expectedMessages = 3; +function on_new_message(msgObj) { + const message = msgObj.message; + + // Check if csp warns about block-all-mixed content being obsolete + if (message.includes("Content-Security-Policy")) { + ok( + message.includes("block-all-mixed-content obsolete"), + "CSP warns about block-all-mixed content being obsolete" + ); + } + if (message.includes("Mixed Content:")) { + ok( + message.includes("Upgrading insecure display request"), + "msg included a mixed content upgrade" + ); + expectedMessages--; + } +} + +add_task(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["security.mixed_content.upgrade_display_content", true]], + }); + Services.console.registerListener(on_new_message); + // Starting the test + var url = + PRE_PATH + + "file_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.html"; + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + waitForLoad: true, + }, + async function (browser) { + let loadedElements = await ContentTask.spawn( + browser, + [], + async function () { + // Check image loaded + let image = content.document.getElementById("some-img"); + let imageLoaded = + image && image.complete && image.naturalHeight !== 0; + // Check audio loaded + let audio = content.document.getElementById("some-audio"); + let audioLoaded = audio && audio.readyState >= 2; + // Check video loaded + let video = content.document.getElementById("some-video"); + //let videoPlayable = await once(video, "loadeddata").then(_ => true); + let videoLoaded = video && video.readyState === 4; + return { audio: audioLoaded, img: imageLoaded, video: videoLoaded }; + } + ); + is(true, loadedElements.img, "Image loaded and was upgraded " + url); + is(true, loadedElements.video, "Video loaded and was upgraded " + url); + is(true, loadedElements.audio, "Audio loaded and was upgraded " + url); + } + ); + + await BrowserTestUtils.waitForCondition(() => expectedMessages === 0); + + // Clean up + Services.console.unregisterListener(on_new_message); +}); diff --git a/dom/security/test/mixedcontentblocker/browser_mixed_content_auth_download.js b/dom/security/test/mixedcontentblocker/browser_mixed_content_auth_download.js new file mode 100644 index 0000000000..e6b01a0cc0 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/browser_mixed_content_auth_download.js @@ -0,0 +1,165 @@ +/* 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(); + ok(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" + ); +}); diff --git a/dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js b/dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js new file mode 100644 index 0000000000..4f41d8b51c --- /dev/null +++ b/dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js @@ -0,0 +1,51 @@ +// Bug 1673574 - Improve Console logging for mixed content auto upgrading +"use strict"; + +const testPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +let seenAutoUpgradeMessage = false; + +const kTestURI = + testPath + "file_mixed_content_auto_upgrade_display_console.html"; + +add_task(async function () { + // A longer timeout is necessary for this test than the plain mochitests + // due to opening a new tab with the web console. + requestLongerTimeout(4); + + // Enable HTTPS-Only Mode and register console-listener + await SpecialPowers.pushPrefEnv({ + set: [["security.mixed_content.upgrade_display_content", true]], + }); + Services.console.registerListener(on_auto_upgrade_message); + + BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, kTestURI); + + await BrowserTestUtils.waitForCondition(() => seenAutoUpgradeMessage); + + Services.console.unregisterListener(on_auto_upgrade_message); +}); + +function on_auto_upgrade_message(msgObj) { + const message = msgObj.message; + + // The console message is: + // "Mixed Content: Upgrading insecure display request + // ‘http://example.com/file_mixed_content_auto_upgrade_display_console.jpg’ to use ‘https’" + + if (!message.includes("Mixed Content:")) { + return; + } + ok( + message.includes("Upgrading insecure display request"), + "msg includes info" + ); + ok( + message.includes("file_mixed_content_auto_upgrade_display_console.jpg"), + "msg includes file" + ); + seenAutoUpgradeMessage = true; +} diff --git a/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js b/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js new file mode 100644 index 0000000000..41b4d3d524 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js @@ -0,0 +1,333 @@ +ChromeUtils.defineESModuleGetters(this, { + Downloads: "resource://gre/modules/Downloads.sys.mjs", + DownloadsCommon: "resource:///modules/DownloadsCommon.sys.mjs", +}); + +const HandlerService = Cc[ + "@mozilla.org/uriloader/handler-service;1" +].getService(Ci.nsIHandlerService); + +const MIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); + +let INSECURE_BASE_URL = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "http://example.com/" + ) + "download_page.html"; +let SECURE_BASE_URL = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "https://example.com/" + ) + "download_page.html"; + +function promiseFocus() { + return new Promise(resolve => { + waitForFocus(resolve); + }); +} + +function promisePanelOpened() { + if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") { + return Promise.resolve(); + } + return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown"); +} + +async function task_openPanel() { + await promiseFocus(); + + let promise = promisePanelOpened(); + DownloadsPanel.showPanel(); + await promise; +} + +const downloadMonitoringView = { + _listeners: [], + onDownloadAdded(download) { + for (let listener of this._listeners) { + listener(download); + } + this._listeners = []; + }, + waitForDownload(listener) { + this._listeners.push(listener); + }, +}; + +/** + * Waits until a download is triggered. + * Unless the always_ask_before_handling_new_types pref is true, the download + * will simply be saved, so resolve when the view is notified of the new + * download. Otherwise, it waits until a prompt is shown, selects the choosen + * , then accepts the dialog + * @param [action] Which action to select, either: + * "handleInternally", "save" or "open". + * @returns {Promise} Resolved once done. + */ + +function shouldTriggerDownload(action = "save") { + if ( + Services.prefs.getBoolPref( + "browser.download.always_ask_before_handling_new_types" + ) + ) { + return new Promise((resolve, reject) => { + Services.wm.addListener({ + onOpenWindow(xulWin) { + Services.wm.removeListener(this); + let win = xulWin.docShell.domWindow; + waitForFocus(() => { + if ( + win.location == + "chrome://mozapps/content/downloads/unknownContentType.xhtml" + ) { + let dialog = win.document.getElementById("unknownContentType"); + let button = dialog.getButton("accept"); + let actionRadio = win.document.getElementById(action); + actionRadio.click(); + button.disabled = false; + dialog.acceptDialog(); + resolve(); + } else { + reject(); + } + }, win); + }, + }); + }); + } + return new Promise(res => { + downloadMonitoringView.waitForDownload(res); + }); +} + +const CONSOLE_ERROR_MESSAGE = "Blocked downloading insecure content"; + +function shouldConsoleError() { + // Waits until CONSOLE_ERROR_MESSAGE was logged + return new Promise((resolve, reject) => { + function listener(msgObj) { + let text = msgObj.message; + if (text.includes(CONSOLE_ERROR_MESSAGE)) { + Services.console.unregisterListener(listener); + resolve(); + } + } + Services.console.registerListener(listener); + }); +} + +async function resetDownloads() { + // Removes all downloads from the download List + const types = new Set(); + let publicList = await Downloads.getList(Downloads.PUBLIC); + let downloads = await publicList.getAll(); + for (let download of downloads) { + if (download.contentType) { + types.add(download.contentType); + } + publicList.remove(download); + await download.finalize(true); + } + + if (types.size) { + // reset handlers for the contentTypes of any files previously downloaded + for (let type of types) { + const mimeInfo = MIMEService.getFromTypeAndExtension(type, ""); + info("resetting handler for type: " + type); + HandlerService.remove(mimeInfo); + } + } +} + +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 presnt + 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 runTest(url, link, checkFunction, description) { + await SpecialPowers.pushPrefEnv({ + set: [["dom.block_download_insecure", true]], + }); + await resetDownloads(); + + let tab = BrowserTestUtils.addTab(gBrowser, url); + gBrowser.selectedTab = tab; + + let browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + info("Checking: " + description); + + let checkPromise = checkFunction(); + // Click the Link to trigger the download + SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => { + content.document.getElementById(contentLink).click(); + }); + + await checkPromise; + + ok(true, description); + BrowserTestUtils.removeTab(tab); + + await SpecialPowers.popPrefEnv(); +} + +add_setup(async () => { + let list = await Downloads.getList(Downloads.ALL); + list.addView(downloadMonitoringView); + registerCleanupFunction(() => list.removeView(downloadMonitoringView)); +}); + +// Test Blocking +add_task(async function test_blocking() { + for (let prefVal of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.always_ask_before_handling_new_types", prefVal]], + }); + await runTest( + INSECURE_BASE_URL, + "insecure", + shouldTriggerDownload, + "Insecure -> Insecure should download" + ); + await runTest( + INSECURE_BASE_URL, + "secure", + shouldTriggerDownload, + "Insecure -> Secure should download" + ); + await runTest( + SECURE_BASE_URL, + "insecure", + () => + Promise.all([ + shouldTriggerDownload(), + shouldNotifyDownloadUI(), + shouldConsoleError(), + ]), + "Secure -> Insecure should Error" + ); + await runTest( + SECURE_BASE_URL, + "secure", + shouldTriggerDownload, + "Secure -> Secure should Download" + ); + await SpecialPowers.popPrefEnv(); + } +}); + +// Test Manual Unblocking +add_task(async function test_manual_unblocking() { + for (let prefVal of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.always_ask_before_handling_new_types", prefVal]], + }); + await runTest( + SECURE_BASE_URL, + "insecure", + async () => { + let [, download] = await Promise.all([ + shouldTriggerDownload(), + shouldNotifyDownloadUI(), + ]); + await download.unblock(); + ok(download.error == null, "There should be no error after unblocking"); + }, + "A Blocked Download Should succeeded to Download after a Manual unblock" + ); + await SpecialPowers.popPrefEnv(); + } +}); + +// Test Unblock Download Visible +add_task(async function test_unblock_download_visible() { + for (let prefVal of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.always_ask_before_handling_new_types", prefVal]], + }); + // Focus, open and close the panel once + // to make sure the panel is loaded and ready + await promiseFocus(); + await runTest( + SECURE_BASE_URL, + "insecure", + async () => { + let panelHasOpened = promisePanelOpened(); + info("awaiting that the download is triggered and added to the list"); + await Promise.all([shouldTriggerDownload(), shouldNotifyDownloadUI()]); + info("awaiting that the Download list shows itself"); + await panelHasOpened; + DownloadsPanel.hidePanel(); + ok(true, "The Download Panel should have opened on blocked download"); + }, + "A Blocked Download Should open the Download Panel" + ); + await SpecialPowers.popPrefEnv(); + } +}); + +// Test Download an insecure svg and choose "Open with Firefox" +add_task(async function download_open_insecure_SVG() { + const mimeInfo = MIMEService.getFromTypeAndExtension("image/svg+xml", "svg"); + mimeInfo.alwaysAskBeforeHandling = false; + mimeInfo.preferredAction = mimeInfo.handleInternally; + HandlerService.store(mimeInfo); + + await SpecialPowers.pushPrefEnv({ + set: [["browser.download.always_ask_before_handling_new_types", false]], + }); + await promiseFocus(); + await runTest( + SECURE_BASE_URL, + "insecureSVG", + async () => { + info("awaiting that the download is triggered and added to the list"); + let [_, download] = await Promise.all([ + shouldTriggerDownload("handleInternally"), + shouldNotifyDownloadUI(), + ]); + + let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser); + await download.unblock(); + ok(download.error == null, "There should be no error after unblocking"); + + let tab = await newTabPromise; + + ok( + tab.linkedBrowser._documentURI.filePath.includes(".svg"), + "The download target was opened" + ); + BrowserTestUtils.removeTab(tab); + ok(true, "The Content was opened in a new tab"); + await SpecialPowers.popPrefEnv(); + }, + "A Blocked SVG can be opened internally" + ); + + HandlerService.remove(mimeInfo); +}); diff --git a/dom/security/test/mixedcontentblocker/download_page.html b/dom/security/test/mixedcontentblocker/download_page.html new file mode 100644 index 0000000000..86f605c478 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/download_page.html @@ -0,0 +1,41 @@ + + + + + + Test for the download attribute + + + + hi + + + + diff --git a/dom/security/test/mixedcontentblocker/download_server.sjs b/dom/security/test/mixedcontentblocker/download_server.sjs new file mode 100644 index 0000000000..e659df2f40 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/download_server.sjs @@ -0,0 +1,20 @@ +// force the Browser to Show a Download Prompt + +function handleRequest(request, response) { + let type = "image/png"; + let filename = "hello.png"; + request.queryString.split("&").forEach(val => { + var [key, value] = val.split("="); + if (key == "type") { + type = value; + } + if (key == "name") { + filename = value; + } + }); + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Disposition", `attachment; filename=${filename}`); + response.setHeader("Content-Type", type); + response.write("🙈🙊🐵🙊"); +} diff --git a/dom/security/test/mixedcontentblocker/file_auth_download_page.html b/dom/security/test/mixedcontentblocker/file_auth_download_page.html new file mode 100644 index 0000000000..931d9d00ad --- /dev/null +++ b/dom/security/test/mixedcontentblocker/file_auth_download_page.html @@ -0,0 +1,22 @@ + + + + Test mixed content download with auth header by https-first + + + hi + + + + diff --git a/dom/security/test/mixedcontentblocker/file_auth_download_server.sjs b/dom/security/test/mixedcontentblocker/file_auth_download_server.sjs new file mode 100644 index 0000000000..d28625abb6 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/file_auth_download_server.sjs @@ -0,0 +1,62 @@ +"use strict"; + +function handleRequest(request, response) { + let match; + + // Allow the caller to drive how authentication is processed via the query. + // Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar + // The extra ? allows the user/pass/realm checks to succeed if the name is + // at the beginning of the query string. + Components.utils.importGlobalProperties(["URLSearchParams"]); + let query = new URLSearchParams(request.queryString); + + let expected_user = query.get("user"); + let expected_pass = query.get("pass"); + let realm = query.get("realm"); + + // Look for an authentication header, if any, in the request. + // + // EG: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== + // + // This test only supports Basic auth. The value sent by the client is + // "username:password", obscured with base64 encoding. + + let actual_user = "", + actual_pass = "", + authHeader; + if (request.hasHeader("Authorization")) { + authHeader = request.getHeader("Authorization"); + match = /Basic (.+)/.exec(authHeader); + if (match.length != 2) { + throw new Error("Couldn't parse auth header: " + authHeader); + } + // Decode base64 to string + let userpass = atob(match[1]); + match = /(.*):(.*)/.exec(userpass); + if (match.length != 3) { + throw new Error("Couldn't decode auth header: " + userpass); + } + actual_user = match[1]; + actual_pass = match[2]; + } + + // Don't request authentication if the credentials we got were what we + // expected. + let requestAuth = + expected_user != actual_user || expected_pass != actual_pass; + + if (requestAuth) { + response.setStatusLine("1.0", 401, "Authentication required"); + response.setHeader("WWW-Authenticate", 'basic realm="' + realm + '"', true); + response.write("Authentication required"); + } else { + response.setStatusLine("1.0", 200, "OK"); + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader( + "Content-Disposition", + "attachment; filename=dummy-file.html" + ); + response.setHeader("Content-Type", "text/html"); + response.write("

SUCCESS

"); + } +} diff --git a/dom/security/test/mixedcontentblocker/file_bug1551886.html b/dom/security/test/mixedcontentblocker/file_bug1551886.html new file mode 100644 index 0000000000..41c46b5273 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/file_bug1551886.html @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/dom/security/test/mixedcontentblocker/file_bug803225_test_mailto.html b/dom/security/test/mixedcontentblocker/file_bug803225_test_mailto.html new file mode 100644 index 0000000000..f1459d3667 --- /dev/null +++ b/dom/security/test/mixedcontentblocker/file_bug803225_test_mailto.html @@ -0,0 +1,13 @@ + + + + + + +Hello + + + diff --git a/dom/security/test/mixedcontentblocker/file_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.html b/dom/security/test/mixedcontentblocker/file_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.html new file mode 100644 index 0000000000..80e97443ed --- /dev/null +++ b/dom/security/test/mixedcontentblocker/file_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.html @@ -0,0 +1,14 @@ + + + + + Bug 1806080 - ML2 with CSP block-all-mixed-content + + + + + +