Bug 1238160 - Test mozbrowser APIs to ensure no content exposure. r=bz
authorJ. Ryan Stinnett <jryans@gmail.com>
Wed, 13 Jan 2016 13:08:20 -0600
changeset 324708 d40b29bc4527d67a5a8256461e66af95d34e1743
parent 324707 46f3fe11218c96d4b1770289f172091c1bd925a0
child 324709 9b296adf9b33947907df19cb99094d906bab5419
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1238160
milestone47.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 1238160 - Test mozbrowser APIs to ensure no content exposure. r=bz Check the various mozbrowser APIs to ensure they are allowed when you have browser permission and blocked when you don't (like regular web content). MozReview-Commit-ID: FPDA1lEUwRq
dom/base/test/mochitest.ini
dom/base/test/mozbrowser_api_utils.js
dom/base/test/test_mozbrowser_apis_allowed.html
dom/base/test/test_mozbrowser_apis_blocked.html
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -254,16 +254,17 @@ support-files =
   test_performance_observer.js
   performance_observer.html
   test_anonymousContent_style_csp.html^headers^
   file_explicit_user_agent.sjs
   referrer_change_server.sjs
   file_change_policy_redirect.html
   file_bug1198095.js
   file_bug1250148.sjs
+  mozbrowser_api_utils.js
 
 [test_anonymousContent_api.html]
 [test_anonymousContent_append_after_reflow.html]
 [test_anonymousContent_canvas.html]
 skip-if = buildapp == 'b2g' # Requires webgl support
 [test_anonymousContent_insert.html]
 [test_anonymousContent_manipulate_content.html]
 [test_anonymousContent_style_csp.html]
@@ -867,9 +868,11 @@ skip-if = e10s || os != 'linux' || build
 [test_explicit_user_agent.html]
 [test_change_policy.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_document.all_iteration.html]
 [test_bug1198095.html]
 [test_bug1187157.html]
 [test_bug769117.html]
 [test_bug1250148.html]
-[test_bug1240471.html]
\ No newline at end of file
+[test_bug1240471.html]
+[test_mozbrowser_apis_allowed.html]
+[test_mozbrowser_apis_blocked.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/mozbrowser_api_utils.js
@@ -0,0 +1,72 @@
+const FRAME_URL = "http://example.org/";
+
+const METHODS = {
+  setVisible: {},
+  getVisible: {},
+  setActive: {},
+  getActive: {},
+  addNextPaintListener: {},
+  removeNextPaintListener: {},
+  sendMouseEvent: {},
+  sendTouchEvent: {},
+  goBack: {},
+  goForward: {},
+  reload: {},
+  stop: {},
+  download: {},
+  purgeHistory: {},
+  getScreenshot: {},
+  zoom: {},
+  getCanGoBack: {},
+  getCanGoForward: {},
+  getContentDimensions: {},
+  setInputMethodActive: { alwaysFails: true }, // needs input-manage
+  setNFCFocus: { alwaysFails: true }, // needs nfc-manager
+  findAll: {},
+  findNext: {},
+  clearMatch: {},
+  executeScript: { alwaysFails: true }, // needs browser:universalxss
+  getStructuredData: {},
+  getWebManifest: {},
+  mute: {},
+  unmute: {},
+  getMuted: {},
+  setVolume: {},
+  getVolume: {},
+};
+
+const ATTRIBUTES = [
+  "allowedAudioChannels",
+];
+
+function once(target, eventName, useCapture = false) {
+  info("Waiting for event: '" + eventName + "' on " + target + ".");
+
+  return new Promise(resolve => {
+    for (let [add, remove] of [
+      ["addEventListener", "removeEventListener"],
+      ["addMessageListener", "removeMessageListener"],
+    ]) {
+      if ((add in target) && (remove in target)) {
+        target[add](eventName, function onEvent(...aArgs) {
+          info("Got event: '" + eventName + "' on " + target + ".");
+          target[remove](eventName, onEvent, useCapture);
+          resolve(aArgs);
+        }, useCapture);
+        break;
+      }
+    }
+  });
+}
+
+function* loadFrame(attributes = {}) {
+  let iframe = document.createElement("iframe");
+  iframe.setAttribute("src", FRAME_URL);
+  for (let key in attributes) {
+    iframe.setAttribute(key, attributes[key]);
+  }
+  let loaded = once(iframe, "load");
+  document.body.appendChild(iframe);
+  yield loaded;
+  return iframe;
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_mozbrowser_apis_allowed.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Verify mozbrowser APIs are allowed with browser permission</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="mozbrowser_api_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script type="application/javascript;version=1.8">
+  add_task(function*() {
+    yield new Promise(resolve => {
+      SpecialPowers.pushPrefEnv(
+        { "set": [["dom.mozBrowserFramesEnabled", true]] },
+        resolve);
+    });
+  });
+
+  add_task(function*() {
+    yield new Promise(resolve => {
+      SpecialPowers.pushPermissions([
+        { "type": "browser", "allow": 1, "context": document }
+      ], resolve);
+    });
+  });
+
+  add_task(function*() {
+    // Create <iframe mozbrowser>
+    let frame = yield loadFrame({
+      mozbrowser: "true"
+    });
+
+    // Verify that mozbrowser APIs are accessible
+    for (let method in METHODS) {
+      let { alwaysFails } = METHODS[method];
+      if (alwaysFails) {
+        ok(!(method in frame), `frame does not have method ${method}, ` +
+                               `needs more permissions`);
+      } else {
+        ok(method in frame, `frame has method ${method}`);
+      }
+    }
+    for (let attribute of ATTRIBUTES) {
+      ok(attribute in frame, `frame has attribute ${attribute}`);
+    }
+  });
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_mozbrowser_apis_blocked.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Verify mozbrowser APIs are blocked without browser permission</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="mozbrowser_api_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script type="application/javascript;version=1.8">
+  add_task(function*() {
+    yield new Promise(resolve => {
+      SpecialPowers.pushPrefEnv(
+        { "set": [["dom.mozBrowserFramesEnabled", true]] },
+        resolve);
+    });
+  });
+
+  add_task(function*() {
+    // Create <iframe mozbrowser>
+    let frame = yield loadFrame({
+      mozbrowser: "true"
+    });
+
+    // Verify that mozbrowser APIs are not accessible
+    for (let method in METHODS) {
+      ok(!(method in frame), `frame does not have method ${method}`);
+    }
+    for (let attribute of ATTRIBUTES) {
+      ok(!(attribute in frame), `frame does not have attribute ${attribute}`);
+    }
+  });
+</script>
+</body>
+</html>