Bug 1190688: Part 2 - [webext] Add tests for executeScript permission checks. r=billm
authorKris Maglione <maglione.k@gmail.com>
Wed, 02 Dec 2015 15:07:02 -0800
changeset 275238 89e666316ea0c2cc12976b2bd7f6dc54c566e94f
parent 275237 72b3671ac8ef311a3469cb6ea74fe3bdd8ff21f1
child 275239 10a9cf7c54fadd9073807e863725ee1b32449ba6
push id16526
push usermaglione.k@gmail.com
push dateThu, 03 Dec 2015 01:43:30 +0000
treeherderfx-team@89e666316ea0 [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.ini
browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
browser/components/extensions/test/browser/browser_ext_tabs_executeScript_good.js
browser/components/extensions/test/browser/head.js
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -15,17 +15,18 @@ support-files =
 [browser_ext_browserAction_context.js]
 [browser_ext_browserAction_disabled.js]
 [browser_ext_pageAction_context.js]
 [browser_ext_pageAction_popup.js]
 [browser_ext_browserAction_popup.js]
 [browser_ext_popup_api_injection.js]
 [browser_ext_contextMenus.js]
 [browser_ext_getViews.js]
-[browser_ext_tabs_executeScript.js]
+[browser_ext_tabs_executeScript_good.js]
+[browser_ext_tabs_executeScript_bad.js]
 [browser_ext_tabs_query.js]
 [browser_ext_tabs_getCurrent.js]
 [browser_ext_tabs_update.js]
 [browser_ext_tabs_onUpdated.js]
 [browser_ext_tabs_sendMessage.js]
 [browser_ext_windows_update.js]
 [browser_ext_contentscript_connect.js]
 [browser_ext_tab_runtimeConnect.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
@@ -0,0 +1,110 @@
+"use strict";
+
+// 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 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();
+}
+
+add_task(function* testBadPermissions() {
+  let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/");
+  let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
+
+  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();
+        });
+      });
+    }
+  });
+
+  yield BrowserTestUtils.removeTab(tab2);
+  yield BrowserTestUtils.removeTab(tab1);
+});
+
+// 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.
rename from browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
rename to browser/components/extensions/test/browser/browser_ext_tabs_executeScript_good.js
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_good.js
@@ -1,32 +1,151 @@
-add_task(function* () {
-  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
+"use strict";
+
+function* testHasPermission(params) {
+  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();
+}
+
+add_task(function* testGoodPermissions() {
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/", true);
+
+  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": {},
+    },
+    contentSetup() {
+      browser.browserAction.onClicked.addListener(() => {
+        browser.test.log("Clicked.");
+      });
+      return Promise.resolve();
+    },
+    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) {
+      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);
+      yield awaitPopupShown;
+
+      let item = contextMenu.querySelector("[label=activeTab]");
+
+      yield EventUtils.synthesizeMouseAtCenter(item, {}, window);
+
+      yield awaitPopupHidden;
+    },
+  });
 
   yield BrowserTestUtils.removeTab(tab);
 });
--- 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);
 }