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 275262 89e666316ea0c2cc12976b2bd7f6dc54c566e94f
parent 275261 72b3671ac8ef311a3469cb6ea74fe3bdd8ff21f1
child 275263 10a9cf7c54fadd9073807e863725ee1b32449ba6
push id29751
push usercbook@mozilla.com
push dateThu, 03 Dec 2015 10:59:01 +0000
treeherdermozilla-central@31fc97d173b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1190688
milestone45.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 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);
 }