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 294670 bd06fa4221949ade2f42498c48554e498bf2d15a
parent 294669 701c0a43f593039d47d385ee103f060a8cd3e570
child 294671 0debbed8046d4778751a75625a9a5ccb3ee748e4
push id75639
push usermaglione.k@gmail.com
push dateSun, 24 Apr 2016 04:34:45 +0000
treeherdermozilla-inbound@bd06fa422194 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1254194
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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>