Bug 1258347 - [webext] ExtensionContext sub-frames should have the same privileges of the parent window. r=kmag draft
authorLuca Greco <lgreco@mozilla.com>
Mon, 02 May 2016 14:13:17 +0200
changeset 364275 d6f1866e7470cc096b8d263462a144ec3fe2ba6f
parent 364236 e65c3c2186710e9ee1dfb3f254bd45019ea34c80
child 520227 f3a499fe794af96c071fcb22e1b2508b12f0eb77
push id17403
push userluca.greco@alcacoop.it
push dateFri, 06 May 2016 10:47:15 +0000
reviewerskmag
bugs1258347
milestone49.0a1
Bug 1258347 - [webext] ExtensionContext sub-frames should have the same privileges of the parent window. r=kmag MozReview-Commit-ID: OfOwD68PEK
toolkit/components/extensions/ExtensionManagement.jsm
toolkit/components/extensions/test/mochitest/mochitest.ini
toolkit/components/extensions/test/mochitest/test_ext_subframes_privileges.html
--- a/toolkit/components/extensions/ExtensionManagement.jsm
+++ b/toolkit/components/extensions/ExtensionManagement.jsm
@@ -256,16 +256,24 @@ function getAPILevelForWindow(window, ad
     // full API level privileges. (see Bug 1256282 for rationale)
     let parentDocument = parentWindow.document;
     let parentIsSystemPrincipal = Services.scriptSecurityManager
                                           .isSystemPrincipal(parentDocument.nodePrincipal);
     if (parentDocument.location.href == "about:addons" && parentIsSystemPrincipal) {
       return FULL_PRIVILEGES;
     }
 
+    // The addon iframes embedded in a addon page from with the same addonId
+    // should have the same privileges of the sameTypeParent.
+    // (see Bug 1258347 for rationale)
+    let parentSameAddonPrivileges = getAPILevelForWindow(parentWindow, addonId);
+    if (parentSameAddonPrivileges > NO_PRIVILEGES) {
+      return parentSameAddonPrivileges;
+    }
+
     // In all the other cases, WebExtension URLs loaded into sub-frame UI
     // will have "content script API level privileges".
     // (see Bug 1214658 for rationale)
     return CONTENTSCRIPT_PRIVILEGES;
   }
 
   // WebExtension URLs loaded into top frames UI could have full API level privileges.
   return FULL_PRIVILEGES;
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -89,8 +89,10 @@ skip-if = e10s || buildapp == 'b2g' # Us
 [test_ext_i18n.html]
 skip-if = (os == 'android') # Bug 1258975 on android.
 [test_ext_web_accessible_resources.html]
 skip-if = (os == 'android') # Bug 1258975 on android.
 [test_ext_webrequest.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # webrequest api uninplemented (bug 1199504). Bug 1258975 on android.
 [test_ext_webnavigation.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # needs TabManager which is not yet implemented. Bug 1258975 on android.
+[test_ext_subframes_privileges.html]
+skip-if = (os == 'android' || buildapp == 'b2g') # neews TabManager which is not yet implemented. Bug 1258975 on android.
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_subframes_privileges.html
@@ -0,0 +1,201 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>WebExtension test</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="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="text/javascript">
+"use strict";
+
+add_task(function* test_webext_tab_subframe_privileges() {
+  function backgroundScript() {
+    browser.runtime.onMessage.addListener(({msg, success, tabId, error}) => {
+      if (msg == "webext-tab-subframe-privileges") {
+        if (success) {
+          browser.tabs.remove(tabId)
+            .then(() => browser.test.notifyPass(msg));
+        } else {
+          browser.test.log(`Got an unexpected error: ${error}`);
+          browser.tabs.query({active: true})
+            .then(tabs => browser.tabs.remove(tabs[0].id))
+            .then(() => browser.test.notifyFail(msg));
+        }
+      }
+    });
+    browser.tabs.create({url: browser.runtime.getURL("/tab.html")});
+  }
+
+  function tabSubframeScript() {
+    browser.test.assertTrue(browser.tabs != undefined,
+                            "Subframe of a privileged page has access to privileged APIs");
+    if (browser.tabs) {
+      browser.tabs.getCurrent()
+        .then(tab => {
+          browser.runtime.sendMessage({
+            msg: "webext-tab-subframe-privileges",
+            success: true,
+            tabId: tab.id,
+          }, () => {
+            // NOTE: this empty callback prevents the promise returned from runtime.sendmessage
+            // to be reported as resolved after context unloaded.
+          });
+        })
+        .catch(e => browser.runtime.sendMessage({msg: "webext-tab-subframe-privileges", success: false, error: `${e}`}));
+    } else {
+      browser.runtime.sendMessage({
+        msg: "webext-tab-subframe-privileges",
+        success: false,
+        error: `Privileged APIs missing in WebExtension tab sub-frame`,
+      });
+    }
+  }
+
+  let extensionData = {
+    background: "new " + backgroundScript,
+    files: {
+      "tab.html": `<!DOCTYPE>
+          <head>
+            <meta charset="utf-8">
+          </head>
+          <body>
+            <iframe src="tab-subframe.html"></iframe>
+          </body>
+        </html>`,
+      "tab-subframe.html": `<!DOCTYPE>
+          <head>
+            <meta charset="utf-8">
+            <script src="tab-subframe.js"></${"script"}>
+          </head>
+        </html>`,
+      "tab-subframe.js": `(${tabSubframeScript})()`,
+    },
+  };
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+
+  yield extension.startup();
+
+  yield extension.awaitFinish("webext-tab-subframe-privileges");
+  yield extension.unload();
+});
+
+add_task(function* test_webext_background_subframe_privileges() {
+  function backgroundSubframeScript() {
+    browser.test.assertTrue(browser.tabs != undefined,
+                            "Subframe of a background page has access to privileged APIs");
+    browser.test.notifyPass("webext-background-subframe-privileges");
+  }
+
+  let extensionData = {
+    manifest: {
+      background: {
+        page: "background.html",
+      },
+    },
+    files: {
+      "background.html": `<!DOCTYPE>
+         <head>
+           <meta charset="utf-8">
+         </head>
+         <body>
+           <iframe src="background-subframe.html"></iframe>
+         </body>
+       </html>`,
+      "background-subframe.html": `<!DOCTYPE>
+         <head>
+           <meta charset="utf-8">
+           <script src="background-subframe.js"></${"script"}>
+         </head>
+       </html>`,
+      "background-subframe.js": `(${backgroundSubframeScript})()`,
+    },
+  };
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+
+  yield extension.startup();
+
+  yield extension.awaitFinish("webext-background-subframe-privileges");
+  yield extension.unload();
+});
+
+add_task(function* test_webext_contentscript_iframe_subframe_privileges() {
+  function backgroundScript() {
+    browser.runtime.onMessage.addListener(({name, hasTabsAPI, hasStorageAPI}) => {
+      if (name == "contentscript-iframe-loaded") {
+        browser.test.assertFalse(hasTabsAPI,
+                                 "Subframe of a content script privileged iframes has no access to privileged APIs");
+        browser.test.assertTrue(hasStorageAPI,
+                                 "Subframe of a content script privileged iframes has access to content script APIs");
+
+        browser.test.notifyPass("webext-contentscript-subframe-privileges");
+      }
+    });
+  }
+
+  function subframeScript() {
+    browser.runtime.sendMessage({
+      name: "contentscript-iframe-loaded",
+      hasTabsAPI: browser.tabs != undefined,
+      hasStorageAPI: browser.storage != undefined,
+    });
+  }
+
+  function contentScript() {
+    let iframe = document.createElement("iframe");
+    iframe.setAttribute("src", browser.runtime.getURL("/contentscript-iframe.html"));
+    document.body.appendChild(iframe);
+  }
+
+  let extensionData = {
+    background: "new " + backgroundScript,
+    manifest: {
+      "permissions": ["storage"],
+      "content_scripts": [{
+        "matches": ["http://example.com/*"],
+        "js": ["contentscript.js"],
+      }],
+      web_accessible_resources: [
+        "contentscript-iframe.html",
+      ],
+    },
+    files: {
+      "contentscript.js": `(${contentScript})()`,
+      "contentscript-iframe.html": `<!DOCTYPE>
+         <head>
+           <meta charset="utf-8">
+         </head>
+         <body>
+           <iframe src="contentscript-iframe-subframe.html"></iframe>
+         </body>
+       </html>`,
+      "contentscript-iframe-subframe.html": `<!DOCTYPE>
+         <head>
+           <meta charset="utf-8">
+           <script src="contentscript-iframe-subframe.js"></${"script"}>
+         </head>
+       </html>`,
+      "contentscript-iframe-subframe.js": `(${subframeScript})()`,
+    },
+  };
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+
+  yield extension.startup();
+
+  let win = window.open("http://example.com");
+
+  yield extension.awaitFinish("webext-contentscript-subframe-privileges");
+
+  win.close();
+
+  yield extension.unload();
+});
+
+</script>
+
+</body>
+</html>