Bug 1238160 - Test mozbrowser APIs to ensure no content exposure. r=bz draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Wed, 13 Jan 2016 13:08:20 -0600
changeset 331745 d296d9459e11545c102f203a56a9e2d5897b00b6
parent 328489 a57ce02b70bf9660cbd65cb52405d2498c4281ec
child 331746 4bca2ef04eeb58efba462721ba34a4438b68706d
push id11069
push userbmo:jryans@gmail.com
push dateThu, 18 Feb 2016 06:17:44 +0000
reviewersbz
bugs1238160
milestone47.0a1
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
@@ -253,16 +253,17 @@ support-files =
   iframe_postMessages.html
   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
+  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]
@@ -865,8 +866,10 @@ support-files = worker_postMessages.js
 skip-if = e10s || os != 'linux' || buildapp != 'browser'
 [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_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>