Bug 1190688: Part 2 - [webext] Add tests for executeScript permission checks. r=billm
☠☠ backed out by 689eebc89b6d ☠ ☠
authorKris Maglione <maglione.k@gmail.com>
Tue, 01 Dec 2015 20:47:08 -0800
changeset 275203 1d5e9f3d094d075cfda767dd2108b07c7f8557de
parent 275202 4a10c564dfca3189ab521c3ccfa92330163189b1
child 275204 4f704aecb2496b6aa9082ad1f61d9dcbddb5d638
push id16511
push usermaglione.k@gmail.com
push dateWed, 02 Dec 2015 16:52:18 +0000
treeherderfx-team@1d5e9f3d094d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1190688
milestone45.0a1
Bug 1190688: Part 2 - [webext] Add tests for executeScript permission checks. r=billm
browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
browser/components/extensions/test/browser/head.js
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
@@ -1,32 +1,259 @@
-add_task(function* () {
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
+"use strict";
+
+function* testHasPermission(params) {
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/", true);
+
+  let contentSetup = params.contentSetup || (() => Promise.resolve());
 
   let extension = ExtensionTestUtils.loadExtension({
-    manifest: {
-      "permissions": ["tabs"]
-    },
+    manifest: params.manifest,
 
-    background: function() {
+    background: `(${function(contentSetup) {
       browser.runtime.onMessage.addListener((msg, sender) => {
         browser.test.assertEq(msg, "script ran", "script ran");
         browser.test.notifyPass("executeScript");
       });
 
-      browser.tabs.executeScript({
-        file: "script.js"
+      browser.test.onMessage.addListener(msg => {
+        browser.test.assertEq(msg, "execute-script");
+
+        browser.tabs.executeScript({
+          file: "script.js"
+        });
       });
-    },
+
+      contentSetup().then(() => {
+        browser.test.sendMessage("ready");
+      });
+    }})(${contentSetup})`,
 
     files: {
       "script.js": function() {
         browser.runtime.sendMessage("script ran");
       }
     }
   });
 
   yield extension.startup();
+  yield extension.awaitMessage("ready");
+
+  if (params.setup) {
+    yield params.setup(extension);
+  }
+
+  extension.sendMessage("execute-script");
+
   yield extension.awaitFinish("executeScript");
   yield extension.unload();
 
   yield BrowserTestUtils.removeTab(tab);
+}
+
+// This is a pretty terrible hack, but it's the best we can do until we
+// support |executeScript| callbacks and |lastError|.
+function* testHasNoPermission(params) {
+  let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
+  let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
+
+  let contentSetup = params.contentSetup || (() => Promise.resolve());
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: params.manifest,
+
+    background: `(${function(contentSetup) {
+      browser.runtime.onMessage.addListener((msg, sender) => {
+        browser.test.assertEq(msg, "second script ran", "second script ran");
+        browser.test.notifyPass("executeScript");
+      });
+
+      browser.test.onMessage.addListener(msg => {
+        browser.test.assertEq(msg, "execute-script");
+
+        browser.tabs.query({ activeWindow: true }, tabs => {
+          browser.tabs.executeScript({
+            file: "script.js"
+          });
+
+          // Execute a script we know we have permissions for in the
+          // second tab, in the hopes that it will execute after the
+          // first one. This has intermittent failure written all over
+          // it, but it's just about the best we can do until we
+          // support callbacks for executeScript.
+          browser.tabs.executeScript(tabs[1].id, {
+            file: "second-script.js"
+          });
+        });
+      });
+
+      contentSetup().then(() => {
+        browser.test.sendMessage("ready");
+      });
+    }})(${contentSetup})`,
+
+    files: {
+      "script.js": function() {
+        browser.runtime.sendMessage("first script ran");
+      },
+
+      "second-script.js": function() {
+        browser.runtime.sendMessage("second script ran");
+      }
+    }
+  });
+
+  yield extension.startup();
+  yield extension.awaitMessage("ready");
+
+  if (params.setup) {
+    yield params.setup(extension);
+  }
+
+  extension.sendMessage("execute-script");
+
+  yield extension.awaitFinish("executeScript");
+  yield extension.unload();
+
+  yield BrowserTestUtils.removeTab(tab2);
+  yield BrowserTestUtils.removeTab(tab1);
+}
+
+add_task(function* testGoodPermissions() {
+  info("Test explicit host permission");
+  yield testHasPermission({
+    manifest: { "permissions": ["http://mochi.test/"] }
+  });
+
+  info("Test explicit host subdomain permission");
+  yield testHasPermission({
+    manifest: { "permissions": ["http://*.mochi.test/"] }
+  });
+
+  info("Test explicit <all_urls> permission");
+  yield testHasPermission({
+    manifest: { "permissions": ["<all_urls>"] }
+  });
+
+  info("Test activeTab permission with a browser action click");
+  yield testHasPermission({
+    manifest: {
+      "permissions": ["activeTab"],
+      "browser_action": {},
+    },
+    setup: clickBrowserAction,
+  });
+
+  info("Test activeTab permission with a page action click");
+  yield testHasPermission({
+    manifest: {
+      "permissions": ["activeTab"],
+      "page_action": {},
+    },
+    contentSetup() {
+      return new Promise(resolve => {
+        browser.tabs.query({ active: true, currentWindow: true }, tabs => {
+          browser.pageAction.show(tabs[0].id);
+          resolve();
+        });
+      });
+    },
+    setup: clickPageAction,
+  });
+
+  info("Test activeTab permission with a browser action w/popup click");
+  yield testHasPermission({
+    manifest: {
+      "permissions": ["activeTab"],
+      "browser_action": { "default_popup": "_blank.html" },
+    },
+    setup: clickBrowserAction,
+  });
+
+  info("Test activeTab permission with a page action w/popup click");
+  yield testHasPermission({
+    manifest: {
+      "permissions": ["activeTab"],
+      "page_action": { "default_popup": "_blank.html" },
+    },
+    contentSetup() {
+      return new Promise(resolve => {
+        browser.tabs.query({ active: true, currentWindow: true }, tabs => {
+          browser.pageAction.show(tabs[0].id);
+          resolve();
+        });
+      });
+    },
+    setup: clickPageAction,
+  });
+
+  info("Test activeTab permission with a context menu click");
+  yield testHasPermission({
+    manifest: {
+      "permissions": ["activeTab", "contextMenus"],
+    },
+    contentSetup() {
+      browser.contextMenus.create({ title: "activeTab", contexts: ["all"] });
+      return Promise.resolve();
+    },
+    setup: function* (extension) {
+      info("setup");
+      let contextMenu = document.getElementById("contentAreaContextMenu");
+      let awaitPopupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
+      let awaitPopupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
+
+      yield BrowserTestUtils.synthesizeMouseAtCenter("a[href]", { type: "contextmenu", button: 2 },
+                                                     gBrowser.selectedBrowser);
+      info("clicked");
+      yield awaitPopupShown;
+      info("shown");
+
+      let item = contextMenu.querySelector("[label=activeTab]");
+
+      yield EventUtils.synthesizeMouseAtCenter(item, {}, window);
+      info("re-clicked");
+
+      yield awaitPopupHidden;
+      info("hidden");
+    },
+  });
 });
+
+add_task(function* testBadPermissions() {
+  info("Test no special permissions");
+  yield testHasNoPermission({
+    manifest: { "permissions": ["http://example.com/"] }
+  });
+
+  info("Test tabs permissions");
+  yield testHasNoPermission({
+    manifest: { "permissions": ["http://example.com/", "tabs"] }
+  });
+
+  info("Test active tab, browser action, no click");
+  yield testHasNoPermission({
+    manifest: {
+      "permissions": ["http://example.com/", "activeTab"],
+      "browser_action": {},
+    },
+  });
+
+  info("Test active tab, page action, no click");
+  yield testHasNoPermission({
+    manifest: {
+      "permissions": ["http://example.com/", "activeTab"],
+      "page_action": {},
+    },
+    contentSetup() {
+      return new Promise(resolve => {
+        browser.tabs.query({ active: true, currentWindow: true }, tabs => {
+          browser.pageAction.show(tabs[0].id);
+          resolve();
+        });
+      });
+    }
+  });
+});
+
+// TODO: Test that |executeScript| fails if the tab has navigated to a
+// new page, and no longer matches our expected state. This involves
+// intentionally trying to trigger a race condition, and is probably not
+// even worth attempting until we have proper |executeScript| callbacks.
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -39,11 +39,11 @@ function clickPageAction(extension, win 
   //
   // Unfortunately, that doesn't happen automatically in browser chrome
   // tests.
   SetPageProxyState("valid");
 
   let pageActionId = makeWidgetId(extension.id) + "-page-action";
   let elem = win.document.getElementById(pageActionId);
 
-  EventUtils.synthesizeMouse(elem, 8, 8, {}, win);
+  EventUtils.synthesizeMouseAtCenter(elem, {}, win);
   return new Promise(SimpleTest.executeSoon);
 }