Bug 1254194: [webext] Test that content security policies are applied to WebExtension documents. r=aswan
authorKris Maglione <maglione.k@gmail.com>
Thu, 14 Apr 2016 16:51:23 -0700
changeset 318479 bd06fa4221949ade2f42498c48554e498bf2d15a
parent 318478 701c0a43f593039d47d385ee103f060a8cd3e570
child 318480 0debbed8046d4778751a75625a9a5ccb3ee748e4
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1254194
milestone48.0a1
Bug 1254194: [webext] Test that content security policies are applied to WebExtension documents. r=aswan MozReview-Commit-ID: J9EPSdyrlsk
toolkit/components/extensions/test/mochitest/mochitest.ini
toolkit/components/extensions/test/mochitest/test_ext_content_security_policy.html
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -33,16 +33,17 @@ support-files =
   file_permission_xhr.html
   file_download.txt
 
 [test_ext_extension.html]
 [test_ext_simple.html]
 [test_ext_schema.html]
 skip-if = e10s # Uses a console montitor. Actual code does not depend on e10s.
 [test_ext_geturl.html]
+[test_ext_content_security_policy.html]
 [test_ext_contentscript.html]
 skip-if = buildapp == 'b2g' # runat != document_idle is not supported.
 [test_ext_contentscript_api_injection.html]
 [test_ext_contentscript_create_iframe.html]
 [test_ext_contentscript_devtools_metadata.html]
 [test_ext_downloads.html]
 [test_ext_exclude_include_globs.html]
 [test_ext_i18n_css.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_content_security_policy.html
@@ -0,0 +1,160 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>WebExtension CSP test</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="text/javascript">
+"use strict";
+
+/**
+ * Tests that content security policies for an add-on are actually applied to *
+ * documents that belong to it. This tests both the base policies and add-on
+ * specific policies, and ensures that the parsed policies applied to the
+ * document's principal match what was specified in the policy string.
+ */
+function* testPolicy(customCSP = null) {
+  let baseURL;
+
+  let baseCSP = {
+    "object-src": ["blob:", "filesystem:", "https://*", "moz-extension:", "'self'"],
+    "script-src": ["'unsafe-eval'", "'unsafe-inline'", "blob:", "filesystem:", "https://*", "moz-extension:", "'self'"],
+  };
+
+  let addonCSP = {
+    "object-src": ["'self'"],
+    "script-src": ["'self'"],
+  };
+
+  let content_security_policy = null;
+
+  if (customCSP) {
+    for (let key of Object.keys(customCSP)) {
+      addonCSP[key] = customCSP[key].split(/\s+/);
+    }
+
+    content_security_policy = Object.keys(customCSP)
+      .map(key => `${key} ${customCSP[key]}`)
+      .join("; ");
+  }
+
+
+  function filterSelf(sources) {
+    return sources.map(src => src == "'self'" ? baseURL : src);
+  }
+
+  function checkSource(name, policy, expected) {
+    is(JSON.stringify(policy[name].sort()),
+       JSON.stringify(filterSelf(expected[name]).sort()),
+       `Expected value for ${name}`);
+  }
+
+  function checkCSP(csp, location) {
+    let policies = csp["csp-policies"];
+
+    info(`Base policy for ${location}`);
+
+    is(policies[0]["report-only"], false, "Policy is not report-only");
+    checkSource("object-src", policies[0], baseCSP);
+    checkSource("script-src", policies[0], baseCSP);
+
+    info(`Add-on policy for ${location}`);
+
+    is(policies[1]["report-only"], false, "Policy is not report-only");
+    checkSource("object-src", policies[1], addonCSP);
+    checkSource("script-src", policies[1], addonCSP);
+  }
+
+
+  function getCSP(window) {
+    let {cspJSON} = SpecialPowers.Cu.getObjectPrincipal(window);
+    return JSON.parse(cspJSON);
+  }
+
+  function background(getCSP) {
+    browser.test.sendMessage("base-url", browser.extension.getURL("").replace(/\/$/, ""));
+
+    browser.test.sendMessage("background-csp", getCSP(window));
+  }
+
+  function tabScript(getCSP) {
+    browser.test.sendMessage("tab-csp", getCSP(window));
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background: `(${background})(${getCSP})`,
+
+    files: {
+      "tab.html": `<html><head><meta charset="utf-8">
+                   <script src="tab.js"></${"script"}></head></html>`,
+
+      "tab.js": `(${tabScript})(${getCSP})`,
+
+      "content.html": `<html><head><meta charset="utf-8"></head></html>`,
+    },
+
+    manifest: {
+      content_security_policy,
+
+      web_accessible_resources: ["content.html", "tab.html"],
+    },
+  });
+
+
+  info(`Testing CSP for policy: ${content_security_policy}`);
+
+  yield extension.startup();
+
+  baseURL = yield extension.awaitMessage("base-url");
+
+
+  let win1 = window.open(`${baseURL}/tab.html`);
+
+  let frame = document.createElement("iframe");
+  frame.src = `${baseURL}/content.html`;
+  document.body.appendChild(frame);
+
+  yield new Promise(resolve => {
+    frame.onload = resolve;
+  });
+
+
+  let backgroundCSP = yield extension.awaitMessage("background-csp");
+  checkCSP(backgroundCSP, "background page");
+
+  let tabCSP = yield extension.awaitMessage("tab-csp");
+  checkCSP(tabCSP, "tab page");
+
+  let contentCSP = getCSP(frame.contentWindow);
+  checkCSP(contentCSP, "content frame");
+
+
+  win1.close();
+  frame.remove();
+
+  yield extension.unload();
+}
+
+add_task(function* testCSP() {
+  yield testPolicy(null);
+
+  let hash = "'sha256-NjZhMDQ1YjQ1MjEwMmM1OWQ4NDBlYzA5N2Q1OWQ5NDY3ZTEzYTNmMzRmNjQ5NGU1MzlmZmQzMmMxYmIzNWYxOCAgLQo='";
+
+  yield testPolicy({
+    "object-src": "'self' https://*.example.com",
+    "script-src": `'self' https://*.example.com 'unsafe-eval' ${hash}`,
+  });
+
+  yield testPolicy({
+    "object-src": "'none'",
+    "script-src": `'self'`,
+  });
+});
+</script>
+</body>