summaryrefslogtreecommitdiffstats
path: root/comm/mail/test/browser/content-policy
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/test/browser/content-policy')
-rw-r--r--comm/mail/test/browser/content-policy/browser.ini19
-rw-r--r--comm/mail/test/browser/content-policy/browser_composeMailto.js119
-rw-r--r--comm/mail/test/browser/content-policy/browser_dnsPrefetch.js233
-rw-r--r--comm/mail/test/browser/content-policy/browser_exposedInContentTabs.js175
-rw-r--r--comm/mail/test/browser/content-policy/browser_generalContentPolicy.js908
-rw-r--r--comm/mail/test/browser/content-policy/browser_jsContentPolicy.js285
-rw-r--r--comm/mail/test/browser/content-policy/browser_pluginsPolicy.js245
-rw-r--r--comm/mail/test/browser/content-policy/html/401.sjs10
-rw-r--r--comm/mail/test/browser/content-policy/html/mailtolink.html8
-rw-r--r--comm/mail/test/browser/content-policy/html/pass.pngbin0 -> 732 bytes
-rw-r--r--comm/mail/test/browser/content-policy/html/plugin.html10
-rw-r--r--comm/mail/test/browser/content-policy/html/remote-noscript.html19
-rw-r--r--comm/mail/test/browser/content-policy/html/remoteimage.html9
-rw-r--r--comm/mail/test/browser/content-policy/html/remoteimagedata.html9
-rw-r--r--comm/mail/test/browser/content-policy/html/remotevideo.html9
-rw-r--r--comm/mail/test/browser/content-policy/html/video.ogvbin0 -> 40604 bytes
16 files changed, 2058 insertions, 0 deletions
diff --git a/comm/mail/test/browser/content-policy/browser.ini b/comm/mail/test/browser/content-policy/browser.ini
new file mode 100644
index 0000000000..24490fe53b
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/browser.ini
@@ -0,0 +1,19 @@
+[DEFAULT]
+prefs =
+ mail.provider.suppress_dialog_on_startup=true
+ mail.spotlight.firstRunDone=true
+ mail.winsearch.firstRunDone=true
+ mailnews.start_page.override_url=about:blank
+ mailnews.start_page.url=about:blank
+ datareporting.policy.dataSubmissionPolicyBypassNotification=true
+skip-if = debug
+subsuite = thunderbird
+support-files = html/**
+
+[browser_composeMailto.js]
+[browser_dnsPrefetch.js]
+[browser_exposedInContentTabs.js]
+[browser_generalContentPolicy.js]
+skip-if = headless # clipboard doesn't work with headless
+[browser_jsContentPolicy.js]
+[browser_pluginsPolicy.js]
diff --git a/comm/mail/test/browser/content-policy/browser_composeMailto.js b/comm/mail/test/browser/content-policy/browser_composeMailto.js
new file mode 100644
index 0000000000..ceac2b2b8e
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/browser_composeMailto.js
@@ -0,0 +1,119 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var utils = ChromeUtils.import("resource://testing-common/mozmill/utils.jsm");
+var { close_compose_window, wait_for_compose_window } = ChromeUtils.import(
+ "resource://testing-common/mozmill/ComposeHelpers.jsm"
+);
+var { open_content_tab_with_url } = ChromeUtils.import(
+ "resource://testing-common/mozmill/ContentTabHelpers.jsm"
+);
+var { mc } = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { input_value } = ChromeUtils.import(
+ "resource://testing-common/mozmill/KeyboardHelpers.jsm"
+);
+var {
+ click_menus_in_sequence,
+ plan_for_modal_dialog,
+ plan_for_new_window,
+ wait_for_modal_dialog,
+ wait_for_window_close,
+} = ChromeUtils.import("resource://testing-common/mozmill/WindowHelpers.jsm");
+
+var folder = null;
+var gMsgNo = 0;
+var gCwc;
+var gNewTab;
+var gPreCount;
+
+var url =
+ "http://mochi.test:8888/browser/comm/mail/test/browser/content-policy/html/";
+
+add_task(async function test_openComposeFromMailToLink() {
+ let tabmail = mc.window.document.getElementById("tabmail");
+ // Open a content tab with the mailto link in it.
+ // To open a tab we're going to have to cheat and use tabmail so we can load
+ // in the data of what we want.
+ gPreCount = tabmail.tabContainer.allTabs.length;
+ gNewTab = open_content_tab_with_url(url + "mailtolink.html");
+
+ plan_for_new_window("msgcompose");
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ "#mailtolink",
+ {},
+ gNewTab.browser
+ );
+ gCwc = wait_for_compose_window();
+});
+
+add_task(async function test_checkInsertImage() {
+ // First focus on the editor element
+ gCwc.window.document.getElementById("messageEditor").focus();
+
+ // Now open the image window
+ plan_for_modal_dialog("Mail:image", async function insert_image(mwc) {
+ // Insert the url of the image.
+ let srcloc = mwc.window.document.getElementById("srcInput");
+ srcloc.focus();
+
+ input_value(mwc, url + "pass.png");
+ await new Promise(resolve => setTimeout(resolve));
+
+ let noAlt = mwc.window.document.getElementById("noAltTextRadio");
+ // Don't add alternate text
+ EventUtils.synthesizeMouseAtCenter(noAlt, {}, noAlt.ownerGlobal);
+
+ // Accept the dialog
+ mwc.window.document.querySelector("dialog").acceptDialog();
+ });
+
+ let insertMenu = gCwc.window.document.getElementById("InsertPopupButton");
+ let insertMenuPopup = gCwc.window.document.getElementById("InsertPopup");
+ EventUtils.synthesizeMouseAtCenter(insertMenu, {}, insertMenu.ownerGlobal);
+ await click_menus_in_sequence(insertMenuPopup, [{ id: "InsertImageItem" }]);
+
+ wait_for_modal_dialog();
+ wait_for_window_close();
+
+ // Test that the image load has not been denied
+ let childImages = gCwc.window.document
+ .getElementById("messageEditor")
+ .contentDocument.getElementsByTagName("img");
+
+ Assert.equal(childImages.length, 1, "Should be one image in the document");
+
+ utils.waitFor(() => childImages[0].complete);
+
+ // Should be the only image, so just check the first.
+ Assert.ok(
+ !childImages[0].matches(":-moz-broken"),
+ "Loading of image in a mailto compose window should not be blocked"
+ );
+ Assert.ok(
+ childImages[0].naturalWidth > 0,
+ "Non blocked image should have naturalWidth"
+ );
+});
+
+add_task(function test_closeComposeWindowAndTab() {
+ close_compose_window(gCwc);
+ let tabmail = mc.window.document.getElementById("tabmail");
+
+ tabmail.closeTab(gNewTab);
+
+ if (tabmail.tabContainer.allTabs.length != gPreCount) {
+ throw new Error("The content tab didn't close");
+ }
+
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+});
diff --git a/comm/mail/test/browser/content-policy/browser_dnsPrefetch.js b/comm/mail/test/browser/content-policy/browser_dnsPrefetch.js
new file mode 100644
index 0000000000..2f29d0fa35
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/browser_dnsPrefetch.js
@@ -0,0 +1,233 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * The purpose of this test is to ensure that dns prefetch is turned off in
+ * the message pane and compose windows. It also checks that dns prefetch is
+ * currently turned off in content tabs, although when bug 545407 is fixed, it
+ * should be turned back on again.
+ */
+
+"use strict";
+
+var composeHelper = ChromeUtils.import(
+ "resource://testing-common/mozmill/ComposeHelpers.jsm"
+);
+var { open_content_tab_with_url } = ChromeUtils.import(
+ "resource://testing-common/mozmill/ContentTabHelpers.jsm"
+);
+var {
+ assert_nothing_selected,
+ assert_selected_and_displayed,
+ be_in_folder,
+ close_message_window,
+ create_folder,
+ get_about_3pane,
+ get_about_message,
+ mc,
+ open_selected_message_in_new_window,
+ select_click_row,
+ select_shift_click_row,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var folder = null;
+var gMsgNo = 0;
+var gMsgHdr = null;
+
+// These two constants are used to build the message body.
+var msgBody =
+ '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n' +
+ "<html>\n" +
+ "<head>\n" +
+ "\n" +
+ '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">\n' +
+ "</head>\n" +
+ '<body bgcolor="#ffffff" text="#000000">\n' +
+ "dns prefetch test message\n" +
+ "</body>\n</html>\n";
+
+add_setup(async function () {
+ folder = await create_folder("dnsPrefetch");
+});
+
+function addToFolder(aSubject, aBody, aFolder) {
+ let msgId = Services.uuid.generateUUID() + "@mozillamessaging.invalid";
+
+ let source =
+ "From - Sat Nov 1 12:39:54 2008\n" +
+ "X-Mozilla-Status: 0001\n" +
+ "X-Mozilla-Status2: 00000000\n" +
+ "Message-ID: <" +
+ msgId +
+ ">\n" +
+ "Date: Wed, 11 Jun 2008 20:32:02 -0400\n" +
+ "From: Tester <tests@mozillamessaging.invalid>\n" +
+ "User-Agent: Thunderbird 3.0a2pre (Macintosh/2008052122)\n" +
+ "MIME-Version: 1.0\n" +
+ "To: recipient@mozillamessaging.invalid\n" +
+ "Subject: " +
+ aSubject +
+ "\n" +
+ "Content-Type: text/html; charset=ISO-8859-1\n" +
+ "Content-Transfer-Encoding: 7bit\n" +
+ "\n" +
+ aBody +
+ "\n";
+
+ aFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ aFolder.gettingNewMessages = true;
+
+ aFolder.addMessage(source);
+ aFolder.gettingNewMessages = false;
+
+ return aFolder.msgDatabase.getMsgHdrForMessageID(msgId);
+}
+
+function addMsgToFolder(folder) {
+ let msgDbHdr = addToFolder("exposed test message " + gMsgNo, msgBody, folder);
+
+ // select the newly created message
+ gMsgHdr = select_click_row(gMsgNo);
+
+ Assert.equal(
+ msgDbHdr,
+ gMsgHdr,
+ "Should have selected the same message header as the generated header"
+ );
+
+ assert_selected_and_displayed(gMsgNo);
+
+ return gMsgNo++;
+}
+
+/**
+ * Check remote content in a compose window.
+ *
+ * @param test The test from TESTS that is being performed.
+ * @param replyType The type of the compose window, 0 = normal compose,
+ * 1 = reply, 2 = forward.
+ * @param loadAllowed Whether or not the load is expected to be allowed.
+ */
+function checkComposeWindow(replyType) {
+ let errMsg = "";
+ let replyWindow = null;
+ switch (replyType) {
+ case 0:
+ replyWindow = composeHelper.open_compose_new_mail();
+ errMsg = "new mail";
+ break;
+ case 1:
+ replyWindow = composeHelper.open_compose_with_reply();
+ errMsg = "reply";
+ break;
+ case 2:
+ replyWindow = composeHelper.open_compose_with_forward();
+ errMsg = "forward";
+ break;
+ }
+
+ // Check the prefetch in the compose window.
+ Assert.ok(
+ !replyWindow.window.document.getElementById("messageEditor").docShell
+ .allowDNSPrefetch,
+ `Should have disabled DNS prefetch in the compose window (${errMsg})`
+ );
+
+ composeHelper.close_compose_window(replyWindow);
+}
+
+add_task(async function test_dnsPrefetch_message() {
+ // Now we have started up, simply check that DNS prefetch is disabled
+ let aboutMessage = get_about_message();
+ Assert.ok(
+ !aboutMessage.document.getElementById("messagepane").docShell
+ .allowDNSPrefetch,
+ "messagepane should have disabled DNS prefetch at startup"
+ );
+ let about3Pane = get_about_3pane();
+ Assert.ok(
+ !about3Pane.document.getElementById("multiMessageBrowser").docShell
+ .allowDNSPrefetch.allowDNSPrefetch,
+ "multimessagepane should have disabled DNS prefetch at startup"
+ );
+
+ await be_in_folder(folder);
+
+ assert_nothing_selected();
+
+ let firstMsg = addMsgToFolder(folder);
+
+ // Now we've got a message selected, check again.
+ Assert.ok(
+ !aboutMessage.document.getElementById("messagepane").docShell
+ .allowDNSPrefetch,
+ "Should keep DNS Prefetch disabled on messagepane after selecting message"
+ );
+
+ let secondMsg = addMsgToFolder(folder);
+ select_shift_click_row(firstMsg);
+ assert_selected_and_displayed(firstMsg, secondMsg);
+
+ Assert.ok(
+ !about3Pane.document.getElementById("multiMessageBrowser").docShell
+ .allowDNSPrefetch,
+ "Should keep DNS Prefetch disabled on multimessage after selecting message"
+ );
+
+ select_shift_click_row(secondMsg);
+});
+
+add_task(async function test_dnsPrefetch_standaloneMessage() {
+ let msgc = await open_selected_message_in_new_window();
+ assert_selected_and_displayed(msgc, gMsgHdr);
+
+ // Check the docshell.
+ let aboutMessage = get_about_message(msgc.window);
+ Assert.ok(
+ !aboutMessage.document.getElementById("messagepane").docShell
+ .allowDNSPrefetch,
+ "Should disable DNS Prefetch on messagepane in standalone message window."
+ );
+
+ close_message_window(msgc);
+});
+
+add_task(function test_dnsPrefetch_compose() {
+ checkComposeWindow(0);
+ checkComposeWindow(1);
+ checkComposeWindow(2);
+});
+
+add_task(async function test_dnsPrefetch_contentTab() {
+ // To open a tab we're going to have to cheat and use tabmail so we can load
+ // in the data of what we want.
+ let tabmail = mc.window.document.getElementById("tabmail");
+ let preCount = tabmail.tabContainer.allTabs.length;
+
+ let dataurl =
+ "data:text/html,<html><head><title>test dns prefetch</title>" +
+ "</head><body>test dns prefetch</body></html>";
+
+ let newTab = open_content_tab_with_url(dataurl);
+
+ await SpecialPowers.spawn(tabmail.getBrowserForSelectedTab(), [], () => {
+ Assert.ok(docShell, "docShell should be available");
+ Assert.ok(docShell.allowDNSPrefetch, "allowDNSPrefetch should be enabled");
+ });
+
+ tabmail.closeTab(newTab);
+
+ if (tabmail.tabContainer.allTabs.length != preCount) {
+ throw new Error("The content tab didn't close");
+ }
+
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+});
diff --git a/comm/mail/test/browser/content-policy/browser_exposedInContentTabs.js b/comm/mail/test/browser/content-policy/browser_exposedInContentTabs.js
new file mode 100644
index 0000000000..faf6ce975c
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/browser_exposedInContentTabs.js
@@ -0,0 +1,175 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * The purpose of this test is to ensure that remote content can't gain access
+ * to messages by loading their URIs.
+ */
+
+"use strict";
+
+var composeHelper = ChromeUtils.import(
+ "resource://testing-common/mozmill/ComposeHelpers.jsm"
+);
+var { open_content_tab_with_url } = ChromeUtils.import(
+ "resource://testing-common/mozmill/ContentTabHelpers.jsm"
+);
+var {
+ assert_nothing_selected,
+ assert_selected_and_displayed,
+ be_in_folder,
+ create_folder,
+ mc,
+ select_click_row,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+var folder = null;
+var gMsgNo = 0;
+
+var url =
+ "http://mochi.test:8888/browser/comm/mail/test/browser/content-policy/html/";
+
+// These two constants are used to build the message body.
+var msgBody =
+ '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n' +
+ "<html>\n" +
+ "<head>\n" +
+ "\n" +
+ '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">\n' +
+ "</head>\n" +
+ '<body bgcolor="#ffffff" text="#000000">\n' +
+ '<img id="testelement" src="' +
+ url +
+ 'pass.png"/>\n' +
+ "</body>\n</html>\n";
+
+add_setup(async function () {
+ folder = await create_folder("exposedInContent");
+});
+
+function addToFolder(aSubject, aBody, aFolder) {
+ let msgId = Services.uuid.generateUUID() + "@mozillamessaging.invalid";
+
+ let source =
+ "From - Sat Nov 1 12:39:54 2008\n" +
+ "X-Mozilla-Status: 0001\n" +
+ "X-Mozilla-Status2: 00000000\n" +
+ "Message-ID: <" +
+ msgId +
+ ">\n" +
+ "Date: Wed, 11 Jun 2008 20:32:02 -0400\n" +
+ "From: Tester <tests@mozillamessaging.invalid>\n" +
+ "User-Agent: Thunderbird 3.0a2pre (Macintosh/2008052122)\n" +
+ "MIME-Version: 1.0\n" +
+ "To: recipient@mozillamessaging.invalid\n" +
+ "Subject: " +
+ aSubject +
+ "\n" +
+ "Content-Type: text/html; charset=ISO-8859-1\n" +
+ "Content-Transfer-Encoding: 7bit\n" +
+ "\n" +
+ aBody +
+ "\n";
+
+ aFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ aFolder.gettingNewMessages = true;
+
+ aFolder.addMessage(source);
+ aFolder.gettingNewMessages = false;
+
+ return aFolder.msgDatabase.getMsgHdrForMessageID(msgId);
+}
+
+function addMsgToFolder(folder) {
+ let msgDbHdr = addToFolder("exposed test message " + gMsgNo, msgBody, folder);
+
+ // select the newly created message
+ let msgHdr = select_click_row(gMsgNo);
+
+ if (msgDbHdr != msgHdr) {
+ throw new Error(
+ "Selected Message Header is not the same as generated header"
+ );
+ }
+
+ assert_selected_and_displayed(gMsgNo);
+
+ ++gMsgNo;
+
+ // We also want to return the url of the message, so save that here.
+ let msgSimpleURL = msgHdr.folder.getUriForMsg(msgHdr);
+
+ let msgService = MailServices.messageServiceFromURI(msgSimpleURL);
+
+ let neckoURL = msgService.getUrlForUri(msgSimpleURL);
+
+ // This is the full url to the message that we want (i.e. passing this to
+ // a browser element or iframe will display it).
+ return neckoURL.spec;
+}
+
+async function checkContentTab(msgURL) {
+ // To open a tab we're going to have to cheat and use tabmail so we can load
+ // in the data of what we want.
+ let preCount =
+ mc.window.document.getElementById("tabmail").tabContainer.allTabs.length;
+
+ let dataurl =
+ "data:text/html,<html><head><title>test exposed</title>" +
+ '</head><body><iframe id="msgIframe" src="' +
+ encodeURI(msgURL) +
+ '"/></body></html>';
+
+ let newTab = open_content_tab_with_url(dataurl);
+
+ Assert.notEqual(newTab.browser.currentURI.spec, "about:blank");
+ Assert.equal(newTab.browser.webProgress.isLoadingDocument, false);
+ Assert.equal(
+ newTab.browser.browsingContext.children[0].currentWindowGlobal,
+ null,
+ "Message display/access has been blocked from remote content!"
+ );
+
+ await SpecialPowers.spawn(newTab.browser, [], () => {
+ Assert.equal(
+ content.frames[0].location.href,
+ "about:blank",
+ "Message display/access has been blocked from remote content!"
+ );
+ });
+
+ mc.window.document.getElementById("tabmail").closeTab(newTab);
+
+ if (
+ mc.window.document.getElementById("tabmail").tabContainer.allTabs.length !=
+ preCount
+ ) {
+ throw new Error("The content tab didn't close");
+ }
+}
+
+add_task(async function test_exposedInContentTabs() {
+ await be_in_folder(folder);
+
+ assert_nothing_selected();
+
+ // Check for denied in mail
+ let msgURL = addMsgToFolder(folder);
+
+ // Check allowed in content tab
+ await checkContentTab(msgURL);
+
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+});
diff --git a/comm/mail/test/browser/content-policy/browser_generalContentPolicy.js b/comm/mail/test/browser/content-policy/browser_generalContentPolicy.js
new file mode 100644
index 0000000000..eacb8fb309
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/browser_generalContentPolicy.js
@@ -0,0 +1,908 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Checks various remote content policy workings, including:
+ *
+ * - Images
+ * - Video
+ *
+ * In:
+ *
+ * - Messages
+ * - Reply email compose window
+ * - Forward email compose window
+ * - Content tab
+ * - Feed message
+ */
+
+"use strict";
+
+var utils = ChromeUtils.import("resource://testing-common/mozmill/utils.jsm");
+var {
+ close_compose_window,
+ open_compose_new_mail,
+ open_compose_with_forward,
+ open_compose_with_reply,
+} = ChromeUtils.import("resource://testing-common/mozmill/ComposeHelpers.jsm");
+var { open_content_tab_with_url } = ChromeUtils.import(
+ "resource://testing-common/mozmill/ContentTabHelpers.jsm"
+);
+var {
+ assert_nothing_selected,
+ assert_selected_and_displayed,
+ be_in_folder,
+ close_message_window,
+ create_folder,
+ get_about_message,
+ mc,
+ open_message_from_file,
+ open_selected_message,
+ plan_for_message_display,
+ select_click_row,
+ set_open_message_behavior,
+ wait_for_message_display_completion,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { input_value } = ChromeUtils.import(
+ "resource://testing-common/mozmill/KeyboardHelpers.jsm"
+);
+var {
+ get_notification_button,
+ wait_for_notification_to_show,
+ wait_for_notification_to_stop,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/NotificationBoxHelpers.jsm"
+);
+var {
+ async_plan_for_new_window,
+ click_menus_in_sequence,
+ plan_for_modal_dialog,
+ wait_for_modal_dialog,
+ wait_for_new_window,
+ wait_for_window_close,
+} = ChromeUtils.import("resource://testing-common/mozmill/WindowHelpers.jsm");
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+var folder = null;
+var gMsgNo = -1; // msg index in folder
+
+var url =
+ "http://mochi.test:8888/browser/comm/mail/test/browser/content-policy/html/";
+
+/**
+ * The TESTS array is constructed from objects containing the following:
+ *
+ * type: The type of the test being run.
+ * body: The html to be inserted into the body of the message under
+ * test. Note: the element under test for content
+ * allowed/disallowed should have id 'testelement'.
+ * webPage: The web page to load during the content tab part of the
+ * test.
+ * checkForAllowed: A function that is passed the element with id 'testelement'
+ * to check for remote content being allowed/disallowed.
+ * This function should return true if remote content was
+ * allowed, false otherwise.
+ */
+var TESTS = [
+ {
+ type: "Iframe-Image",
+ description: "iframe img served over http should be blocked",
+ shouldBeBlocked: true,
+
+ // Blocked from showing by other means. Network request can happen.
+ neverAllowed: true,
+ body: `<iframe id='testelement' src='${url}remoteimage.html' />\n`,
+ checkForAllowed: async element => {
+ await new Promise(window.requestAnimationFrame);
+ return element.contentDocument.readyState != "uninitialized";
+ },
+ },
+ {
+ type: "Iframe-datauri-Image",
+ description: "iframe datauri img served over http should be blocked",
+ shouldBeBlocked: true,
+
+ // Blocked by other means. MsgContentPolicy accepts the iframe load since
+ // data: is not a mailnews url. No blocked content notification will show.
+ neverAllowed: true,
+ body: `<iframe id='testelement' src='data:text/html,<html><p>data uri iframe with pic</p><img src='${url}pass.png' /></html>\n`,
+ checkForAllowed: async element => {
+ await new Promise(window.requestAnimationFrame);
+ return element.contentDocument.readyState != "uninitialized";
+ },
+ },
+ {
+ type: "Image",
+ description: "img served over http should be blocked",
+ shouldBeBlocked: true,
+ checkRemoteImg: true,
+ body: '<img id="testelement" src="' + url + 'pass.png"/>\n',
+ webPage: "remoteimage.html",
+ checkForAllowed: async element => {
+ await new Promise(window.requestAnimationFrame);
+ return !element.matches(":-moz-broken") && element.naturalWidth > 0;
+ },
+ checkForAllowedRemote: () => {
+ let element = content.document.getElementById("testelement");
+ return !element.matches(":-moz-broken") && element.naturalWidth > 0;
+ },
+ },
+ {
+ type: "Video",
+ description: "video served over http should be blocked",
+ shouldBeBlocked: true,
+ body: '<video id="testelement" src="' + url + 'video.ogv"/>\n',
+ webPage: "remotevideo.html",
+ checkForAllowed: async element => {
+ await new Promise(window.requestAnimationFrame);
+ return element.networkState != element.NETWORK_NO_SOURCE;
+ },
+ checkForAllowedRemote: () => {
+ let element = content.document.getElementById("testelement");
+ return element.networkState != element.NETWORK_NO_SOURCE;
+ },
+ },
+ {
+ type: "Image-Data",
+ description: "img from data url should be allowed",
+ shouldBeBlocked: false,
+ body: '<img id="testelement" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAC4UlEQVR42o2UW0gUURzGZ7Wa3fW2667XF/OyPQSmmZaZEYWRFN1QEYxeCi3CCCmxl6CHEMzQyAi1IAktLxSipkJghl0swswShbxFD+Hiquvqus7OzNf5T7uhslsN/OCc//f9vz17zpzhOM+PD2Mjg2doXPCumg/3H4+KzLcu++yvL+WeNZZxUy3lnEzQmGqkuQJVfwvRPrqhutd6Z4Mw+mY75qZzIcvFCjSmGmnkIa+nMFXmHs7YXK4aet0UhiXbGUjLpyHMZWLFnK5AY6qRRh7yUs/6MP5xmW/Hh44oQC6CuHAQw28TMdCzDc7ZNAX3nDTykLe+1LfNtXe/N7aiWHOss1Yji0IhpMUDEK2pOHdSj1MZgcp4/VzxMC/1lF/RHHEfAP/kprp7fCgFsjMP0tIuhey9/jiUqPY6Jy/1sN5O96oC2u/yM7b5PCZmQBZ2KhSfNeJ8jt7rnLzU01bFmymDgvTPazSiJF2CLLFfklIUrHNJsHw3QZiOwvJUGMyDBvz8qMficADsY0bYx0PhXMlGZ7XGQRkUFNz5wE90ChfYJrIgMRFOSwyWx4JhHwn0zqgeov04uu5rBcpQVtRd4z9vs+axE4mHgwU4vun/ifAjCgvmDHRXB1jcKwpoqdC9m/icAMmWiuprfqi6qsVEHzNPGtdANdLIQ96JwXg0V+j63HvEl+TrCnqbjLLI/vPiZDSKctUw+XF/OKrmkMVzKNzEKRp5yEs9JQW6fPep0TsQ/vR2yPuhVyZAyoFkNmGkJwS11wPxIi4OX9PYC8nojo5WNPKQt6XS2E+9qy8yH7dZm9JVGzo10BMDu+0EYN8HeXYr6vy0mI+MVGgIClK0Ty9jQV7qWf1muy+sPyPhYWloR29TmDjxZQesM4fREBEBISubkaWMSSMPeV09Ko+3nxFTkGu42FwZ3t9TF2pp321CY2ycQmvSFgdp5PF2+9d8jxgGhomRzEh3keyqGTx9j34B1t40GMHNFqwAAAAASUVORK5CYII="/>\n',
+ webPage: "remoteimagedata.html",
+ checkForAllowed: async element => {
+ await new Promise(window.requestAnimationFrame);
+ return !element.matches(":-moz-broken") && element.naturalWidth > 0;
+ },
+ checkForAllowedRemote: () => {
+ let element = content.document.getElementById("testelement");
+ return !element.matches(":-moz-broken") && element.naturalWidth > 0;
+ },
+ },
+ {
+ type: "Iframe-srcdoc-Image",
+ description: "iframe srcdoc img served over http should be blocked",
+ shouldBeBlocked: true,
+
+ body: `<html><iframe id='testelement' srcdoc='<html><img src="${url}pass.png" alt="pichere"/>'></html>`,
+ checkForAllowed: async element => {
+ if (element.contentDocument.readyState != "complete") {
+ await new Promise(resolve => element.addEventListener("load", resolve));
+ }
+ let img = element.contentDocument.querySelector("img");
+ return img && !img.matches(":-moz-broken") && img.naturalWidth > 0;
+ },
+ },
+];
+
+// TESTS = [TESTS[0]]; // To test single tests.
+
+// These two constants are used to build the message body.
+var msgBodyStart =
+ '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n' +
+ "<html>\n" +
+ "<head>\n" +
+ "\n" +
+ '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">\n' +
+ "</head>\n" +
+ '<body bgcolor="#ffffff" text="#000000">\n';
+
+var msgBodyEnd = "</body>\n</html>\n";
+
+add_setup(async () => {
+ requestLongerTimeout(3);
+ folder = await create_folder("generalContentPolicy");
+ Assert.ok(folder, "folder should be set up");
+ folder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ registerCleanupFunction(() => {
+ folder.deleteSelf(null);
+ });
+});
+
+// We can't call it test since that it would be run as subtest.
+function checkPermission(aURI) {
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ aURI,
+ {}
+ );
+ return Services.perms.testPermissionFromPrincipal(principal, "image");
+}
+
+function addPermission(aURI, aAllowDeny) {
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ aURI,
+ {}
+ );
+ return Services.perms.addFromPrincipal(principal, "image", aAllowDeny);
+}
+
+function removePermission(aURI) {
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ aURI,
+ {}
+ );
+ return Services.perms.removeFromPrincipal(principal, "image");
+}
+
+function addToFolder(aSubject, aBody, aFolder) {
+ let msgId = Services.uuid.generateUUID() + "@mozillamessaging.invalid";
+
+ gMsgNo++;
+ let source =
+ "From - Sat Nov 1 12:39:54 2008\n" +
+ "X-Mozilla-Status: 0001\n" +
+ "X-Mozilla-Status2: 00000000\n" +
+ "Message-ID: <" +
+ msgId +
+ ">\n" +
+ "Date: Wed, 11 Jun 2008 20:32:02 -0400\n" +
+ "From: Tester <tests@mozillamessaging.invalid>\n" +
+ "User-Agent: Thunderbird 3.0a2pre (Macintosh/2008052122)\n" +
+ "MIME-Version: 1.0\n" +
+ "To: recipient@mozillamessaging.invalid\n" +
+ "Subject: " +
+ aSubject +
+ " #" +
+ gMsgNo +
+ "\n" +
+ "Content-Type: text/html; charset=ISO-8859-1\n" +
+ "Content-Transfer-Encoding: 7bit\n" +
+ "\n" +
+ aBody +
+ "\n";
+
+ aFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ aFolder.gettingNewMessages = true;
+
+ aFolder.addMessage(source);
+ aFolder.gettingNewMessages = false;
+
+ return aFolder.msgDatabase.getMsgHdrForMessageID(msgId);
+}
+
+async function addMsgToFolderAndCheckContent(folder, test) {
+ info(`Checking msg in folder; test=${test.type}`);
+ let msgDbHdr = addToFolder(
+ test.type + " test message ",
+ msgBodyStart + test.body + msgBodyEnd,
+ folder
+ );
+
+ // select the newly created message
+ let msgHdr = select_click_row(gMsgNo);
+
+ if (msgDbHdr != msgHdr) {
+ throw new Error(
+ "Selected Message Header is not the same as generated header"
+ );
+ }
+
+ assert_selected_and_displayed(gMsgNo);
+
+ // Now check that the content hasn't been loaded
+ let messageDocument =
+ get_about_message().getMessagePaneBrowser().contentDocument;
+ let testelement = messageDocument.getElementById("testelement");
+ Assert.ok(testelement, "testelement should be found");
+ if (test.shouldBeBlocked) {
+ if (await test.checkForAllowed(testelement)) {
+ throw new Error(
+ test.type + " has not been blocked in message content as expected."
+ );
+ }
+ } else if (!(await test.checkForAllowed(testelement))) {
+ throw new Error(
+ test.type + " has been unexpectedly blocked in message content."
+ );
+ }
+}
+
+/**
+ * Check remote content in a compose window.
+ *
+ * @param test The test from TESTS that is being performed.
+ * @param replyType The type of the compose window, set to true for "reply",
+ * false for "forward".
+ * @param loadAllowed Whether or not the load is expected to be allowed.
+ */
+async function checkComposeWindow(test, replyType, loadAllowed) {
+ if (loadAllowed && test.neverAllowed) {
+ return;
+ }
+ info(
+ `Checking compose win; replyType=${replyType}, test=${test.type}; shouldLoad=${loadAllowed}`
+ );
+ let replyWindow = replyType
+ ? open_compose_with_reply()
+ : open_compose_with_forward();
+
+ let what =
+ test.description +
+ ": " +
+ test.type +
+ " has not been " +
+ (loadAllowed ? "allowed" : "blocked") +
+ " in reply window as expected.";
+ await TestUtils.waitForCondition(async () => {
+ return (
+ (await test.checkForAllowed(
+ replyWindow.window.document
+ .getElementById("messageEditor")
+ .contentDocument.getElementById("testelement")
+ )) == loadAllowed
+ );
+ }, what);
+
+ close_compose_window(replyWindow);
+}
+
+/**
+ * Check remote content in stand-alone message window, and reload
+ */
+async function checkStandaloneMessageWindow(test, loadAllowed) {
+ if (loadAllowed && test.neverAllowed) {
+ return;
+ }
+ info(
+ `Checking standalong msg win; test=${test.type}; shouldLoad=${loadAllowed}`
+ );
+ let newWindowPromise = async_plan_for_new_window("mail:messageWindow");
+ // Open it
+ set_open_message_behavior("NEW_WINDOW");
+ open_selected_message();
+ let msgc = await newWindowPromise;
+ wait_for_message_display_completion(msgc, true);
+ if (
+ (await test.checkForAllowed(
+ get_about_message(msgc.window)
+ .getMessagePaneBrowser()
+ .contentDocument.getElementById("testelement")
+ )) != loadAllowed
+ ) {
+ let expected = loadAllowed ? "allowed" : "blocked";
+ throw new Error(
+ `${test.type} was not ${expected} in standalone message content`
+ );
+ }
+
+ // Clean up, close the window
+ close_message_window(msgc);
+}
+
+/**
+ * Check remote content in stand-alone message window loaded from .eml file.
+ * Make sure there's a notification bar.
+ */
+async function checkEMLMessageWindow(test, emlFile) {
+ let msgc = await open_message_from_file(emlFile);
+ let aboutMessage = get_about_message(msgc.window);
+ if (!aboutMessage.document.getElementById("mail-notification-top")) {
+ throw new Error(test.type + " has no content notification bar.");
+ }
+ if (aboutMessage.document.getElementById("mail-notification-top").collapsed) {
+ throw new Error(test.type + " content notification bar not shown.");
+ }
+
+ // Clean up, close the window
+ close_message_window(msgc);
+}
+
+/**
+ * Helper method to save one of the test files as an .eml file.
+ *
+ * @returns the file the message was safed to
+ */
+async function saveAsEMLFile(msgNo) {
+ let msgHdr = select_click_row(msgNo);
+ let messenger = Cc["@mozilla.org/messenger;1"].createInstance(
+ Ci.nsIMessenger
+ );
+ let profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ file.initWithFile(profD);
+ file.append("content-policy-test-" + msgNo + ".eml");
+ messenger.saveAs(
+ msgHdr.folder.getUriForMsg(msgHdr),
+ true,
+ null,
+ file.path,
+ true
+ );
+ // no listener for saveAs, though we should add one.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 5000));
+ return file;
+}
+
+async function allowRemoteContentAndCheck(test) {
+ if (test.neverAllowed) {
+ return;
+ }
+ info(`Checking allow remote content; test=${test.type}`);
+ await addMsgToFolderAndCheckContent(folder, test);
+
+ let aboutMessage = get_about_message();
+
+ // Click on the allow remote content button
+ const kBoxId = "mail-notification-top";
+ const kNotificationValue = "remoteContent";
+ wait_for_notification_to_show(aboutMessage, kBoxId, kNotificationValue);
+ let prefButton = get_notification_button(
+ aboutMessage,
+ kBoxId,
+ kNotificationValue,
+ {
+ popup: "remoteContentOptions",
+ }
+ );
+ EventUtils.synthesizeMouseAtCenter(
+ prefButton,
+ { clickCount: 1 },
+ aboutMessage
+ );
+ aboutMessage.document
+ .getElementById("remoteContentOptions")
+ .activateItem(
+ aboutMessage.document.getElementById("remoteContentOptionAllowForMsg")
+ );
+ wait_for_notification_to_stop(aboutMessage, kBoxId, kNotificationValue);
+
+ wait_for_message_display_completion(mc, true);
+
+ if (
+ !(await test.checkForAllowed(
+ aboutMessage
+ .getMessagePaneBrowser()
+ .contentDocument.getElementById("testelement")
+ ))
+ ) {
+ throw new Error(
+ test.type + " has been unexpectedly blocked in message content"
+ );
+ }
+}
+
+async function checkContentTab(test) {
+ if (!test.webPage) {
+ return;
+ }
+ // To open a tab we're going to have to cheat and use tabmail so we can load
+ // in the data of what we want.
+ let preCount =
+ mc.window.document.getElementById("tabmail").tabContainer.allTabs.length;
+
+ let newTab = open_content_tab_with_url(url + test.webPage);
+
+ if (
+ !(await SpecialPowers.spawn(newTab.browser, [], test.checkForAllowedRemote))
+ ) {
+ throw new Error(
+ test.type + " has been unexpectedly blocked in content tab"
+ );
+ }
+
+ mc.window.document.getElementById("tabmail").closeTab(newTab);
+
+ if (
+ mc.window.document.getElementById("tabmail").tabContainer.allTabs.length !=
+ preCount
+ ) {
+ throw new Error("The content tab didn't close");
+ }
+}
+
+/**
+ * Check remote content is not blocked in feed message (flagged with
+ * nsMsgMessageFlags::FeedMsg)
+ */
+async function checkAllowFeedMsg(test) {
+ if (test.neverAllowed) {
+ return;
+ }
+ let msgDbHdr = addToFolder(
+ test.type + " test feed message",
+ msgBodyStart + test.body + msgBodyEnd,
+ folder
+ );
+ msgDbHdr.orFlags(Ci.nsMsgMessageFlags.FeedMsg);
+
+ // select the newly created message
+ let msgHdr = select_click_row(gMsgNo);
+
+ Assert.equal(msgDbHdr, msgHdr);
+ assert_selected_and_displayed(gMsgNo);
+
+ // Now check that the content hasn't been blocked
+ let messageDocument =
+ get_about_message().getMessagePaneBrowser().contentDocument;
+ if (
+ !(await test.checkForAllowed(messageDocument.getElementById("testelement")))
+ ) {
+ throw new Error(
+ test.type + " has been unexpectedly blocked in feed message content."
+ );
+ }
+}
+
+/**
+ * Check remote content is not blocked for a sender with permissions.
+ */
+async function checkAllowForSenderWithPerms(test) {
+ if (test.neverAllowed) {
+ return;
+ }
+ let msgDbHdr = addToFolder(
+ test.type + " priv sender test message ",
+ msgBodyStart + test.body + msgBodyEnd,
+ folder
+ );
+
+ let addresses = MailServices.headerParser.parseEncodedHeader(msgDbHdr.author);
+ let authorEmailAddress = addresses[0].email;
+
+ let uri = Services.io.newURI(
+ "chrome://messenger/content/email=" + authorEmailAddress
+ );
+ addPermission(uri, Services.perms.ALLOW_ACTION);
+ Assert.equal(checkPermission(uri), Services.perms.ALLOW_ACTION);
+
+ // select the newly created message
+ let msgHdr = select_click_row(gMsgNo);
+
+ Assert.equal(msgDbHdr, msgHdr);
+ assert_selected_and_displayed(gMsgNo);
+
+ // Now check that the content hasn't been blocked
+ let messageDocument =
+ get_about_message().getMessagePaneBrowser().contentDocument;
+ if (
+ !(await test.checkForAllowed(messageDocument.getElementById("testelement")))
+ ) {
+ throw new Error(
+ `${test.type} has been unexpectedly blocked for sender=${authorEmailAddress}`
+ );
+ }
+
+ // Clean up after ourselves, and make sure that worked as expected.
+ removePermission(uri);
+ Assert.equal(checkPermission(uri), Services.perms.UNKNOWN_ACTION);
+}
+
+/**
+ * Check remote content is not blocked for a hosts with permissions.
+ */
+async function checkAllowForHostsWithPerms(test) {
+ if (test.neverAllowed) {
+ return;
+ }
+ let msgDbHdr = addToFolder(
+ test.type + " priv host test message ",
+ msgBodyStart + test.body + msgBodyEnd,
+ folder
+ );
+
+ // Select the newly created message.
+ let msgHdr = select_click_row(gMsgNo);
+ Assert.equal(msgDbHdr, msgHdr);
+ assert_selected_and_displayed(gMsgNo);
+
+ let aboutMessage = get_about_message();
+ let messageDocument = aboutMessage.getMessagePaneBrowser().contentDocument;
+ let src = messageDocument.getElementById("testelement").src;
+
+ if (!src.startsWith("http")) {
+ // Just test http in this test.
+ return;
+ }
+
+ let uri = Services.io.newURI(src);
+ addPermission(uri, Services.perms.ALLOW_ACTION);
+ Assert.equal(checkPermission(uri), Services.perms.ALLOW_ACTION);
+
+ // Click back one msg, then the original again, which should now allow loading.
+ select_click_row(gMsgNo - 1);
+ // Select the newly created message.
+ msgHdr = select_click_row(gMsgNo);
+ Assert.equal(msgDbHdr, msgHdr);
+ assert_selected_and_displayed(gMsgNo);
+
+ // Now check that the content hasn't been blocked.
+ messageDocument = aboutMessage.getMessagePaneBrowser().contentDocument;
+ if (
+ !(await test.checkForAllowed(messageDocument.getElementById("testelement")))
+ ) {
+ throw new Error(
+ test.type + " has been unexpectedly blocked for url=" + uri.spec
+ );
+ }
+
+ // Clean up after ourselves, and make sure that worked as expected.
+ removePermission(uri);
+ Assert.equal(checkPermission(uri), Services.perms.UNKNOWN_ACTION);
+}
+
+add_task(async function test_generalContentPolicy() {
+ await be_in_folder(folder);
+
+ assert_nothing_selected();
+
+ for (let i = 0; i < TESTS.length; ++i) {
+ // Check for denied in mail
+ info("Doing test: " + TESTS[i].description + " ...\n");
+ await addMsgToFolderAndCheckContent(folder, TESTS[i]);
+
+ if (TESTS[i].shouldBeBlocked) {
+ // Check denied in reply window
+ await checkComposeWindow(TESTS[i], true, false);
+
+ // Check denied in forward window
+ await checkComposeWindow(TESTS[i], false, false);
+
+ if (TESTS[i].checkRemoteImg) {
+ // Now check that image is visible after site is whitelisted.
+ // Only want to do this for the test case which has the remote image.
+
+ // Add the site to the whitelist.
+ let messageDocument =
+ get_about_message().getMessagePaneBrowser().contentDocument;
+ let src = messageDocument.getElementById("testelement").src;
+
+ let uri = Services.io.newURI(src);
+ addPermission(uri, Services.perms.ALLOW_ACTION);
+ Assert.equal(checkPermission(uri), Services.perms.ALLOW_ACTION);
+
+ // Check allowed in reply window
+ await checkComposeWindow(TESTS[i], true, true);
+
+ // Check allowed in forward window
+ await checkComposeWindow(TESTS[i], false, true);
+
+ // Clean up after ourselves, and make sure that worked as expected.
+ removePermission(uri);
+ Assert.equal(checkPermission(uri), Services.perms.UNKNOWN_ACTION);
+ }
+
+ // Check denied in standalone message window
+ await checkStandaloneMessageWindow(TESTS[i], false);
+
+ // Now allow the remote content and check result
+ await allowRemoteContentAndCheck(TESTS[i]);
+ }
+
+ // Check allowed in reply window
+ await checkComposeWindow(TESTS[i], true, true);
+
+ // Check allowed in forward window
+ await checkComposeWindow(TESTS[i], false, true);
+
+ // Check allowed in standalone message window
+ await checkStandaloneMessageWindow(TESTS[i], true);
+
+ // Check allowed in content tab
+ await checkContentTab(TESTS[i]);
+
+ // Check allowed in a feed message
+ await checkAllowFeedMsg(TESTS[i]);
+
+ // Check per sender privileges.
+ await checkAllowForSenderWithPerms(TESTS[i]);
+
+ // Check per host privileges.
+ await checkAllowForHostsWithPerms(TESTS[i]);
+
+ // Only want to do this for the test case which has the remote image.
+ if (TESTS[i].checkRemoteImg) {
+ let emlFile = await saveAsEMLFile(i);
+ await checkEMLMessageWindow(TESTS[i], emlFile);
+ emlFile.remove(false);
+ }
+ }
+});
+
+/** Test that an image requiring auth won't ask for credentials in compose. */
+add_task(async function test_imgAuth() {
+ addToFolder(
+ `Image auth test - msg`,
+ `${msgBodyStart}<img alt="[401!]" id="401img" src="${url}401.sjs"/>${msgBodyEnd}`,
+ folder
+ );
+
+ // Allow loading remote, to be able to test.
+ Services.prefs.setBoolPref(
+ "mailnews.message_display.disable_remote_image",
+ false
+ );
+
+ // Select the newly created message.
+ await be_in_folder(folder);
+ select_click_row(gMsgNo);
+
+ // Open reply/fwd. If we get a prompt the test will timeout.
+ let rwc = open_compose_with_reply();
+ close_compose_window(rwc);
+
+ let fwc = open_compose_with_forward();
+ close_compose_window(fwc);
+
+ Services.prefs.clearUserPref("mailnews.message_display.disable_remote_image");
+});
+
+/** Make sure remote images work in signatures. */
+add_task(async function test_sigPic() {
+ let identity = MailServices.accounts.allIdentities[0];
+ identity.htmlSigFormat = true;
+ identity.htmlSigText = `Tb remote! <img id='testelement' alt='[sigpic]' src='${url}pass.png' />`;
+
+ let wasAllowed = element => {
+ return !element.matches(":-moz-broken") && element.naturalWidth > 0;
+ };
+
+ be_in_folder(folder);
+ select_click_row(gMsgNo);
+
+ let nwc = open_compose_new_mail();
+ await TestUtils.waitForCondition(async () => {
+ return wasAllowed(
+ nwc.window.document
+ .getElementById("messageEditor")
+ .contentDocument.getElementById("testelement")
+ );
+ }, "Should allow remote sig in new mail");
+ close_compose_window(nwc);
+
+ let rwc = open_compose_with_reply();
+ await TestUtils.waitForCondition(async () => {
+ return wasAllowed(
+ rwc.window.document
+ .getElementById("messageEditor")
+ .contentDocument.getElementById("testelement")
+ );
+ }, "Should allow remote sig in reply");
+
+ close_compose_window(rwc);
+
+ identity.htmlSigFormat = false;
+ identity.htmlSigText = "";
+});
+
+// Copied from test-blocked-content.js.
+async function putHTMLOnClipboard(html) {
+ let trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(
+ Ci.nsITransferable
+ );
+
+ // Register supported data flavors
+ trans.init(null);
+ trans.addDataFlavor("text/html");
+
+ let wapper = Cc["@mozilla.org/supports-string;1"].createInstance(
+ Ci.nsISupportsString
+ );
+ wapper.data = html;
+ trans.setTransferData("text/html", wapper);
+
+ Services.clipboard.setData(trans, null, Ci.nsIClipboard.kGlobalClipboard);
+ // NOTE: this doesn't seem to work in headless mode.
+}
+
+async function subtest_insertImageIntoReplyForward(aReplyType) {
+ Assert.ok(folder, "folder should be set up");
+ let msgDbHdr = addToFolder(
+ "Test insert image into reply or forward",
+ "Stand by for image insertion ;-)",
+ folder
+ );
+
+ // Select the newly created message.
+ await be_in_folder(folder);
+ let msgHdr = select_click_row(gMsgNo);
+
+ if (msgDbHdr != msgHdr) {
+ throw new Error(
+ "Selected Message Header is not the same as generated header"
+ );
+ }
+
+ assert_selected_and_displayed(gMsgNo);
+
+ let replyWindow = aReplyType
+ ? open_compose_with_reply()
+ : open_compose_with_forward();
+
+ // Now insert the image
+ // (copied from test-compose-mailto.js:test_checkInsertImage()).
+
+ // First focus on the editor element
+ replyWindow.window.document.getElementById("messageEditor").focus();
+
+ // Now open the image window
+ plan_for_modal_dialog("Mail:image", async function insert_image(mwc) {
+ // Insert the url of the image.
+ let srcloc = mwc.window.document.getElementById("srcInput");
+ srcloc.focus();
+
+ input_value(mwc, url + "pass.png");
+
+ // Don't add alternate text
+ let noAlt = mwc.window.document.getElementById("noAltTextRadio");
+ EventUtils.synthesizeMouseAtCenter(noAlt, {}, noAlt.ownerGlobal);
+ await new Promise(resolve => setTimeout(resolve));
+
+ // Accept the dialog
+ mwc.window.document.querySelector("dialog").acceptDialog();
+ });
+
+ let insertMenu =
+ replyWindow.window.document.getElementById("InsertPopupButton");
+ let insertMenuPopup =
+ replyWindow.window.document.getElementById("InsertPopup");
+
+ EventUtils.synthesizeMouseAtCenter(insertMenu, {}, insertMenu.ownerGlobal);
+ await click_menus_in_sequence(insertMenuPopup, [{ id: "InsertImageItem" }]);
+
+ wait_for_modal_dialog();
+ wait_for_window_close();
+ await new Promise(resolve => setTimeout(resolve));
+
+ // Paste an image.
+ try {
+ await putHTMLOnClipboard("<img id='tmp-img' src='" + url + "pass.png' />");
+ } catch (e) {
+ Assert.ok(false, "Paste should have worked: " + e);
+ throw e;
+ }
+
+ // Ctrl+V = Paste
+ EventUtils.synthesizeKey(
+ "v",
+ { shiftKey: false, accelKey: true },
+ replyWindow.window
+ );
+
+ // Now wait for the paste.
+ utils.waitFor(function () {
+ let img = replyWindow.window.document
+ .getElementById("messageEditor")
+ .contentDocument.getElementById("tmp-img");
+ return img != null && img.complete;
+ }, "Timeout waiting for pasted tmp image to be loaded ok");
+
+ // Test that the image load has not been denied
+ let childImages = replyWindow.window.document
+ .getElementById("messageEditor")
+ .contentDocument.getElementsByTagName("img");
+
+ Assert.equal(childImages.length, 2, "Should have two images in the doc.");
+
+ // Check both images.
+ Assert.ok(
+ !childImages[0].matches(":-moz-broken"),
+ "Loading of image #0 should not be blocked"
+ );
+ Assert.ok(
+ childImages[0].naturalWidth > 0,
+ "Loading of image #0 should not be blocked (and have width)"
+ );
+ Assert.ok(
+ !childImages[1].matches(":-moz-broken"),
+ "Loading of image #1 should not be blocked"
+ );
+ Assert.ok(
+ childImages[1].naturalWidth > 0,
+ "Loading of image #1 should not be blocked (and have width)"
+ );
+
+ close_compose_window(replyWindow);
+}
+
+add_task(async function test_insertImageIntoReply() {
+ await subtest_insertImageIntoReplyForward(true);
+});
+
+add_task(async function test_insertImageIntoForward() {
+ await subtest_insertImageIntoReplyForward(false);
+});
diff --git a/comm/mail/test/browser/content-policy/browser_jsContentPolicy.js b/comm/mail/test/browser/content-policy/browser_jsContentPolicy.js
new file mode 100644
index 0000000000..d5f749c1f6
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/browser_jsContentPolicy.js
@@ -0,0 +1,285 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Tests whether JavaScript in a local/remote message works. The test
+ * mailnews/extensions/newsblog/test/browser/browser_feedDisplay.js does the
+ * same thing for feeds.
+ *
+ * @note This assumes an existing local account.
+ */
+
+"use strict";
+
+var {
+ assert_nothing_selected,
+ assert_selected_and_displayed,
+ be_in_folder,
+ create_folder,
+ get_about_message,
+ select_click_row,
+ select_none,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+
+var {
+ close_compose_window,
+ open_compose_with_forward,
+ open_compose_with_reply,
+} = ChromeUtils.import("resource://testing-common/mozmill/ComposeHelpers.jsm");
+
+var { MailE10SUtils } = ChromeUtils.import(
+ "resource:///modules/MailE10SUtils.jsm"
+);
+
+let aboutMessage = get_about_message();
+
+var folder;
+registerCleanupFunction(async () => {
+ let promptPromise = BrowserTestUtils.promiseAlertDialog("accept");
+ folder.deleteSelf(window.msgWindow);
+ await promptPromise;
+
+ Services.focus.focusedWindow = window;
+});
+
+var url =
+ "http://mochi.test:8888/browser/comm/mail/test/browser/content-policy/html/";
+
+function addToFolder(aSubject, aBody, aFolder) {
+ let msgId = Services.uuid.generateUUID() + "@mozillamessaging.invalid";
+
+ let source =
+ "From - Sat Nov 1 12:39:54 2008\n" +
+ "X-Mozilla-Status: 0001\n" +
+ "X-Mozilla-Status2: 00000000\n" +
+ "Message-ID: <" +
+ msgId +
+ ">\n" +
+ "Date: Wed, 11 Jun 2008 20:32:02 -0400\n" +
+ "From: Tester <tests@mozillamessaging.invalid>\n" +
+ "User-Agent: Thunderbird 3.0a2pre (Macintosh/2008052122)\n" +
+ "MIME-Version: 1.0\n" +
+ "To: recipient@mozillamessaging.invalid\n" +
+ "Subject: " +
+ aSubject +
+ "\n" +
+ "Content-Type: text/html; charset=ISO-8859-1\n" +
+ "Content-Transfer-Encoding: 7bit\n" +
+ "Content-Base: " +
+ url +
+ "remote-noscript.html\n" +
+ "\n" +
+ aBody +
+ "\n";
+
+ aFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ aFolder.gettingNewMessages = true;
+
+ aFolder.addMessage(source);
+ aFolder.gettingNewMessages = false;
+
+ return aFolder.msgDatabase.getMsgHdrForMessageID(msgId);
+}
+
+/*
+ * Runs in the browser process via SpecialPowers.spawn to check JavaScript
+ * is disabled.
+ */
+function assertJSDisabled() {
+ Assert.ok(content.location.href);
+ Assert.ok(
+ !content.wrappedJSObject.jsIsTurnedOn,
+ "JS should not be turned on in content."
+ );
+
+ let noscript = content.document.querySelector("noscript");
+ let display = content.getComputedStyle(noscript).display;
+ Assert.equal(display, "inline", "noscript display should be 'inline'");
+}
+
+/*
+ * Runs in the browser process via SpecialPowers.spawn to check JavaScript
+ * is enabled.
+ */
+function assertJSEnabled() {
+ Assert.ok(content.location.href);
+ Assert.ok(
+ content.wrappedJSObject.jsIsTurnedOn,
+ "JS should be turned on in content."
+ );
+
+ let noscript = content.document.querySelector("noscript");
+ let display = content.getComputedStyle(noscript).display;
+ Assert.equal(display, "none", "noscript display should be 'none'");
+}
+
+var jsMsgBody =
+ '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n' +
+ "<html>\n" +
+ "<head>\n" +
+ "\n" +
+ '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">\n' +
+ "</head>\n" +
+ '<body bgcolor="#ffffff" text="#000000">\n' +
+ "this is a test<big><big><big> stuff\n" +
+ "<br><br>\n" +
+ "</big></big></big>\n" +
+ "<noscript>\n" +
+ "hello, this content is noscript!\n" +
+ "</noscript>\n" +
+ "<script>\n" +
+ "var jsIsTurnedOn = true;\n" +
+ "</script>\n" +
+ "\n" +
+ "</body>\n" +
+ "</html>\n";
+
+var gMsgNo = 0;
+
+var messagePane = aboutMessage.document.getElementById("messagepane");
+
+add_setup(async function () {
+ folder = await create_folder("jsContentPolicy");
+});
+
+/**
+ * Check JavaScript is disabled when loading messages in the message pane.
+ */
+add_task(async function testJsInMail() {
+ await be_in_folder(folder);
+
+ let msgDbHdr = addToFolder("JS test message " + gMsgNo, jsMsgBody, folder);
+
+ // select the newly created message
+ let msgHdr = select_click_row(gMsgNo);
+
+ Assert.equal(
+ msgDbHdr,
+ msgHdr,
+ "selected message header should be the same as generated header"
+ );
+
+ assert_selected_and_displayed(gMsgNo);
+
+ await SpecialPowers.spawn(messagePane, [], assertJSDisabled);
+
+ ++gMsgNo;
+ select_none();
+});
+
+/**
+ * Check JavaScript is enabled when loading local content in the message pane.
+ */
+add_task(async function testJsInNonMessageContent() {
+ let loadedPromise = BrowserTestUtils.browserLoaded(messagePane);
+ MailE10SUtils.loadURI(
+ messagePane,
+ "data:text/html;charset=utf-8,<script>var jsIsTurnedOn%3Dtrue%3B<%2Fscript>bar" +
+ "<noscript><p id='noscript-p'>hey this is noscript</p><%2Fnoscript>"
+ );
+ await loadedPromise;
+
+ await SpecialPowers.spawn(messagePane, [], assertJSEnabled);
+
+ MailE10SUtils.loadURI(messagePane, "about:blank");
+});
+
+/**
+ * Check JavaScript is enabled when loading remote content in the message pane.
+ */
+add_task(async function testJsInRemoteContent() {
+ // load something non-message-like in the message pane
+ let loadedPromise = BrowserTestUtils.browserLoaded(messagePane);
+ MailE10SUtils.loadURI(messagePane, url + "remote-noscript.html");
+ await loadedPromise;
+
+ await SpecialPowers.spawn(messagePane, [], assertJSEnabled);
+
+ MailE10SUtils.loadURI(messagePane, "about:blank");
+});
+
+/**
+ * Check JavaScript is disabled when loading messages in the message pane,
+ * after remote content has been displayed there.
+ */
+add_task(async function testJsInMailAgain() {
+ await be_in_folder(folder);
+
+ let msgDbHdr = addToFolder("JS test message " + gMsgNo, jsMsgBody, folder);
+
+ // select the newly created message
+ let msgHdr = select_click_row(gMsgNo);
+
+ Assert.equal(
+ msgDbHdr,
+ msgHdr,
+ "selected message header should be the same as generated header"
+ );
+
+ assert_selected_and_displayed(gMsgNo);
+
+ await SpecialPowers.spawn(messagePane, [], assertJSDisabled);
+
+ ++gMsgNo;
+ select_none();
+});
+
+/*
+ * Runs in the browser process via SpecialPowers.spawn to check JavaScript
+ * is disabled.
+ */
+function assertJSDisabledInEditor() {
+ Assert.ok(content.location.href);
+ Assert.ok(
+ !content.wrappedJSObject.jsIsTurnedOn,
+ "JS should not be turned on in editor."
+ );
+
+ // <noscript> is not shown in the editor, independent of whether scripts
+ // are on or off. So we can't check that like in assertJSDisabledIn.
+}
+
+/**
+ * Check JavaScript is disabled in the editor.
+ */
+add_task(async function testJsInMailReply() {
+ await be_in_folder(folder);
+
+ var body = jsMsgBody.replace(
+ "</body>",
+ "<img src=x onerror=alert(1)></body>"
+ );
+
+ let msgDbHdr = addToFolder("js msg reply " + gMsgNo, body, folder);
+
+ // select the newly created message
+ let msgHdr = select_click_row(gMsgNo);
+
+ Assert.equal(
+ msgDbHdr,
+ msgHdr,
+ "selected message header should be the same as generated header"
+ );
+
+ assert_selected_and_displayed(gMsgNo);
+
+ await SpecialPowers.spawn(messagePane, [], assertJSDisabledInEditor);
+
+ let replyWin = open_compose_with_reply();
+ // If JavaScript is on, loading the window will actually show an alert(1)
+ // so execution doesn't go further from here.
+ let editor = replyWin.window.document.getElementById("messageEditor");
+ await SpecialPowers.spawn(editor, [], assertJSDisabledInEditor);
+ close_compose_window(replyWin);
+
+ let fwdWin = open_compose_with_forward();
+ editor = fwdWin.window.document.getElementById("messageEditor");
+ await SpecialPowers.spawn(editor, [], assertJSDisabledInEditor);
+ close_compose_window(fwdWin);
+
+ ++gMsgNo;
+ select_none();
+});
diff --git a/comm/mail/test/browser/content-policy/browser_pluginsPolicy.js b/comm/mail/test/browser/content-policy/browser_pluginsPolicy.js
new file mode 100644
index 0000000000..9fcb1bde0c
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/browser_pluginsPolicy.js
@@ -0,0 +1,245 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Checks if plugins are enabled in messages correctly or not.
+ * As of bug 1508942, plugins are no longer enabled in any context.
+ */
+
+"use strict";
+
+var { open_content_tab_with_url } = ChromeUtils.import(
+ "resource://testing-common/mozmill/ContentTabHelpers.jsm"
+);
+
+var {
+ assert_nothing_selected,
+ assert_selected_and_displayed,
+ be_in_folder,
+ close_message_window,
+ create_folder,
+ get_about_message,
+ mc,
+ open_selected_message,
+ select_click_row,
+ select_none,
+ set_open_message_behavior,
+ wait_for_message_display_completion,
+} = ChromeUtils.import(
+ "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
+);
+var { async_plan_for_new_window } = ChromeUtils.import(
+ "resource://testing-common/mozmill/WindowHelpers.jsm"
+);
+
+var { MailE10SUtils } = ChromeUtils.import(
+ "resource:///modules/MailE10SUtils.jsm"
+);
+
+var folder = null;
+var gMsgNo = 0;
+
+var url =
+ "http://mochi.test:8888/browser/comm/mail/test/browser/content-policy/html/";
+
+// These two constants are used to build the message body.
+var msgBody =
+ '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n' +
+ "<html>\n" +
+ "<head>\n" +
+ "\n" +
+ '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">\n' +
+ "</head>\n" +
+ '<body bgcolor="#ffffff" text="#000000">\n' +
+ '<embed id="testelement" type="application/x-test" width="400" height="400" border="1"></embed>\n' +
+ "</body>\n</html>\n";
+
+add_setup(async function () {
+ folder = await create_folder("pluginPolicy");
+});
+
+function addToFolder(aSubject, aBody, aFolder) {
+ let msgId = Services.uuid.generateUUID() + "@mozillamessaging.invalid";
+
+ let source =
+ "From - Sat Nov 1 12:39:54 2008\n" +
+ "X-Mozilla-Status: 0001\n" +
+ "X-Mozilla-Status2: 00000000\n" +
+ "Message-ID: <" +
+ msgId +
+ ">\n" +
+ "Date: Wed, 11 Jun 2008 20:32:02 -0400\n" +
+ "From: Tester <tests@mozillamessaging.invalid>\n" +
+ "User-Agent: Thunderbird 3.0a2pre (Macintosh/2008052122)\n" +
+ "MIME-Version: 1.0\n" +
+ "To: recipient@mozillamessaging.invalid\n" +
+ "Subject: " +
+ aSubject +
+ "\n" +
+ "Content-Type: text/html; charset=ISO-8859-1\n" +
+ "Content-Transfer-Encoding: 7bit\n" +
+ "\n" +
+ aBody +
+ "\n";
+
+ aFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ aFolder.gettingNewMessages = true;
+
+ aFolder.addMessage(source);
+ aFolder.gettingNewMessages = false;
+
+ return aFolder.msgDatabase.getMsgHdrForMessageID(msgId);
+}
+
+function isPluginLoaded(browser) {
+ return SpecialPowers.spawn(browser, [], () => {
+ let element = content.document.getElementById("testelement");
+
+ try {
+ // if setColor throws, then the plugin isn't running
+ element.setColor("FFFF0000");
+ return true;
+ } catch (ex) {
+ // Any errors and we'll just return false below - they may be expected.
+ }
+ return false;
+ });
+}
+
+async function addMsgToFolderAndCheckContent(loadAllowed) {
+ let msgDbHdr = addToFolder("Plugin test message " + gMsgNo, msgBody, folder);
+
+ // select the newly created message
+ let msgHdr = select_click_row(gMsgNo);
+
+ if (msgDbHdr != msgHdr) {
+ throw new Error(
+ "Selected Message Header is not the same as generated header"
+ );
+ }
+
+ assert_selected_and_displayed(gMsgNo);
+
+ ++gMsgNo;
+
+ // XXX It appears the assert_selected_and_displayed doesn't actually wait
+ // long enough for plugin load. However, I also can't find a way to wait for
+ // long enough in all situations, so this will have to do for now.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 1000));
+
+ // Now check that the content hasn't been loaded
+ if (
+ (await isPluginLoaded(
+ get_about_message().document.getElementById("messagepane")
+ )) != loadAllowed
+ ) {
+ throw new Error(
+ loadAllowed
+ ? "Plugin has been unexpectedly blocked in message content"
+ : "Plugin has not been blocked in message as expected"
+ );
+ }
+}
+
+async function checkStandaloneMessageWindow(loadAllowed) {
+ let newWindowPromise = async_plan_for_new_window("mail:messageWindow");
+ // Open it
+ set_open_message_behavior("NEW_WINDOW");
+
+ open_selected_message();
+ let msgc = await newWindowPromise;
+ wait_for_message_display_completion(msgc, true);
+
+ // XXX It appears the wait_for_message_display_completion doesn't actually
+ // wait long enough for plugin load. However, I also can't find a way to wait
+ // for long enough in all situations, so this will have to do for now.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 1000));
+
+ let aboutMessage = get_about_message(msgc.window);
+ if (
+ (await isPluginLoaded(
+ aboutMessage.document.getElementById("messagepane")
+ )) != loadAllowed
+ ) {
+ throw new Error(
+ loadAllowed
+ ? "Plugin has been unexpectedly blocked in standalone window"
+ : "Plugin has not been blocked in standalone window as expected"
+ );
+ }
+
+ // Clean up, close the window
+ close_message_window(msgc);
+}
+
+add_task(async function test_3paneWindowDenied() {
+ await be_in_folder(folder);
+
+ assert_nothing_selected();
+
+ await addMsgToFolderAndCheckContent(false);
+});
+
+add_task(async function test_checkPluginsInNonMessageContent() {
+ // Deselect everything so we can load our content
+ select_none();
+
+ // load something non-message-like in the message pane
+ let browser = get_about_message().document.getElementById("messagepane");
+ MailE10SUtils.loadURI(browser, url + "plugin.html");
+ await BrowserTestUtils.browserLoaded(browser);
+
+ if (await isPluginLoaded(browser)) {
+ throw new Error(
+ "Plugin is turned on in content in message pane - it should not be."
+ );
+ }
+});
+
+add_task(async function test_3paneWindowDeniedAgain() {
+ select_click_row(0);
+
+ assert_selected_and_displayed(0);
+
+ let browser = get_about_message().document.getElementById("messagepane");
+ // Now check that the content hasn't been loaded
+ if (await isPluginLoaded(browser)) {
+ throw new Error("Plugin has not been blocked in message as expected");
+ }
+});
+
+add_task(async function test_checkStandaloneMessageWindowDenied() {
+ await checkStandaloneMessageWindow(false);
+});
+
+add_task(async function test_checkContentTab() {
+ // To open a tab we're going to have to cheat and use tabmail so we can load
+ // in the data of what we want.
+ let preCount =
+ mc.window.document.getElementById("tabmail").tabContainer.allTabs.length;
+
+ let newTab = open_content_tab_with_url(url + "plugin.html");
+
+ if (await isPluginLoaded(newTab.browser)) {
+ throw new Error("Plugin has been unexpectedly not blocked in content tab");
+ }
+
+ mc.window.document.getElementById("tabmail").closeTab(newTab);
+
+ if (
+ mc.window.document.getElementById("tabmail").tabContainer.allTabs.length !=
+ preCount
+ ) {
+ throw new Error("The content tab didn't close");
+ }
+
+ Assert.report(
+ false,
+ undefined,
+ undefined,
+ "Test ran to completion successfully"
+ );
+});
diff --git a/comm/mail/test/browser/content-policy/html/401.sjs b/comm/mail/test/browser/content-policy/html/401.sjs
new file mode 100644
index 0000000000..93757fe5a5
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/401.sjs
@@ -0,0 +1,10 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function handleRequest(request, response) {
+ if (!request.hasHeader("Authorization")) {
+ response.setStatusLine("1.1", 401, "Unauthorized");
+ response.setHeader("WWW-Authenticate", `Basic realm="401test"`);
+ }
+}
diff --git a/comm/mail/test/browser/content-policy/html/mailtolink.html b/comm/mail/test/browser/content-policy/html/mailtolink.html
new file mode 100644
index 0000000000..4027a5248e
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/mailtolink.html
@@ -0,0 +1,8 @@
+<html>
+ <head>
+ <title>Mailto Link Test</title>
+ </head>
+ <body bgcolor="#FFFFFF">
+ <a href="mailto:nobody@mozilla.invalid" id="mailtolink">mailtolink</a>
+ </body>
+</html>
diff --git a/comm/mail/test/browser/content-policy/html/pass.png b/comm/mail/test/browser/content-policy/html/pass.png
new file mode 100644
index 0000000000..4b0d444cf6
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/pass.png
Binary files differ
diff --git a/comm/mail/test/browser/content-policy/html/plugin.html b/comm/mail/test/browser/content-policy/html/plugin.html
new file mode 100644
index 0000000000..f8a3f4e241
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/plugin.html
@@ -0,0 +1,10 @@
+<html>
+ <head>
+ <title>Plugin Test</title>
+ </head>
+ <body bgcolor="#FFFFFF">
+ <embed id="testelement" type="application/x-test"
+ style="width:400px; height:400px; margin-top:20px;" border="1">
+ </embed>
+ </body>
+</html>
diff --git a/comm/mail/test/browser/content-policy/html/remote-noscript.html b/comm/mail/test/browser/content-policy/html/remote-noscript.html
new file mode 100644
index 0000000000..28445bfe11
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/remote-noscript.html
@@ -0,0 +1,19 @@
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>noscript test</title>
+ </head>
+ <body bgcolor="#FFFFFF">
+ <h1>remote-noscript.html</h1>
+ <p>This content is served over http!</p>
+ <noscript>
+ JavaScript is OFF!
+ </noscript>
+
+ <div id="scripted"></div>
+ <script>
+ var jsIsTurnedOn = true; // variable to check in test
+ document.getElementById("scripted").innerHTML = "JavaScript is ON!";
+ </script>
+ </body>
+</html>
diff --git a/comm/mail/test/browser/content-policy/html/remoteimage.html b/comm/mail/test/browser/content-policy/html/remoteimage.html
new file mode 100644
index 0000000000..f7a005cf57
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/remoteimage.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Remote Image Test</title>
+ </head>
+ <body bgcolor="#FFFFFF">
+ <img id="testelement" src="pass.png"/>
+ </body>
+</html>
diff --git a/comm/mail/test/browser/content-policy/html/remoteimagedata.html b/comm/mail/test/browser/content-policy/html/remoteimagedata.html
new file mode 100644
index 0000000000..aca2427376
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/remoteimagedata.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <title>Remote Image Test</title>
+ </head>
+ <body bgcolor="#FFFFFF">
+ <img id="testelement" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAC4UlEQVR42o2UW0gUURzGZ7Wa3fW2667XF/OyPQSmmZaZEYWRFN1QEYxeCi3CCCmxl6CHEMzQyAi1IAktLxSipkJghl0swswShbxFD+Hiquvqus7OzNf5T7uhslsN/OCc//f9vz17zpzhOM+PD2Mjg2doXPCumg/3H4+KzLcu++yvL+WeNZZxUy3lnEzQmGqkuQJVfwvRPrqhutd6Z4Mw+mY75qZzIcvFCjSmGmnkIa+nMFXmHs7YXK4aet0UhiXbGUjLpyHMZWLFnK5AY6qRRh7yUs/6MP5xmW/Hh44oQC6CuHAQw28TMdCzDc7ZNAX3nDTykLe+1LfNtXe/N7aiWHOss1Yji0IhpMUDEK2pOHdSj1MZgcp4/VzxMC/1lF/RHHEfAP/kprp7fCgFsjMP0tIuhey9/jiUqPY6Jy/1sN5O96oC2u/yM7b5PCZmQBZ2KhSfNeJ8jt7rnLzU01bFmymDgvTPazSiJF2CLLFfklIUrHNJsHw3QZiOwvJUGMyDBvz8qMficADsY0bYx0PhXMlGZ7XGQRkUFNz5wE90ChfYJrIgMRFOSwyWx4JhHwn0zqgeov04uu5rBcpQVtRd4z9vs+axE4mHgwU4vun/ifAjCgvmDHRXB1jcKwpoqdC9m/icAMmWiuprfqi6qsVEHzNPGtdANdLIQ96JwXg0V+j63HvEl+TrCnqbjLLI/vPiZDSKctUw+XF/OKrmkMVzKNzEKRp5yEs9JQW6fPep0TsQ/vR2yPuhVyZAyoFkNmGkJwS11wPxIi4OX9PYC8nojo5WNPKQt6XS2E+9qy8yH7dZm9JVGzo10BMDu+0EYN8HeXYr6vy0mI+MVGgIClK0Ty9jQV7qWf1muy+sPyPhYWloR29TmDjxZQesM4fREBEBISubkaWMSSMPeV09Ko+3nxFTkGu42FwZ3t9TF2pp321CY2ycQmvSFgdp5PF2+9d8jxgGhomRzEh3keyqGTx9j34B1t40GMHNFqwAAAAASUVORK5CYII="/>
+ (that's smiley-tongue-out.png)
+ </body>
+</html>
diff --git a/comm/mail/test/browser/content-policy/html/remotevideo.html b/comm/mail/test/browser/content-policy/html/remotevideo.html
new file mode 100644
index 0000000000..2a4cad15b5
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/remotevideo.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Remote Image Test</title>
+ </head>
+ <body bgcolor="#FFFFFF">
+ <video id="testelement" src="video.ogv"/>
+ </body>
+</html>
diff --git a/comm/mail/test/browser/content-policy/html/video.ogv b/comm/mail/test/browser/content-policy/html/video.ogv
new file mode 100644
index 0000000000..61c179447f
--- /dev/null
+++ b/comm/mail/test/browser/content-policy/html/video.ogv
Binary files differ