Bug 1426767 - Disable login context menu items on documents with a null principal. r=Gijs
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Tue, 02 Oct 2018 01:01:53 -0700
changeset 487748 0edeaf35b6e65757caeadee9ed6eb52feeaed0d7
parent 487747 d4a99f4598435e66d76dedd72558a494c73687fc
child 487749 8900229a39b1b2a783d310cd6795a878d62c621a
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
reviewersGijs
bugs1426767
milestone64.0a1
Bug 1426767 - Disable login context menu items on documents with a null principal. r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D7386
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
toolkit/components/passwordmgr/test/browser/form_basic_iframe.html
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -1343,16 +1343,17 @@ var LoginManagerContent = {
    * @returns {Object} an object with information about the
    *                   FormLike username and password field
    *                   or null if the passed field is invalid.
    */
   getFieldContext(aField) {
     // If the element is not a proper form field, return null.
     if (ChromeUtils.getClassName(aField) !== "HTMLInputElement" ||
         (aField.type != "password" && !LoginHelper.isUsernameFieldType(aField)) ||
+        aField.nodePrincipal.isNullPrincipal ||
         !aField.ownerDocument) {
       return null;
     }
     let form = LoginFormFactory.createFromField(aField);
 
     let doc = aField.ownerDocument;
     let formOrigin = LoginUtils._getPasswordOrigin(doc.documentURI);
     let recipes = LoginRecipesContent.getRecipes(formOrigin, doc.defaultView);
--- a/toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_context_menu_iframe.js
@@ -10,45 +10,41 @@ const TEST_HOSTNAME = "https://example.c
 const IFRAME_PAGE_PATH = "/browser/toolkit/components/passwordmgr/test/browser/form_basic_iframe.html";
 
 /**
  * Initialize logins needed for the tests and disable autofill
  * for login forms for easier testing of manual fill.
  */
 add_task(async function test_initialize() {
   Services.prefs.setBoolPref("signon.autofillForms", false);
+  Services.prefs.setBoolPref("signon.schemeUpgrades", true);
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("signon.autofillForms");
     Services.prefs.clearUserPref("signon.schemeUpgrades");
   });
   for (let login of loginList()) {
     Services.logins.addLogin(login);
   }
 });
 
 /**
  * Check if the password field is correctly filled when it's in an iframe.
  */
 add_task(async function test_context_menu_iframe_fill() {
-  Services.prefs.setBoolPref("signon.schemeUpgrades", true);
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: TEST_HOSTNAME + IFRAME_PAGE_PATH,
   }, async function(browser) {
-    function getPasswordInput() {
-      let frame = content.document.getElementById("test-iframe");
-      return frame.contentDocument.getElementById("form-basic-password");
-    }
-
     let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
     let eventDetails = {type: "contextmenu", button: 2};
 
     // To click at the right point we have to take into account the iframe offset.
     // Synthesize a right mouse click over the password input element.
-    BrowserTestUtils.synthesizeMouseAtCenter(getPasswordInput, eventDetails, browser);
+    BrowserTestUtils.synthesizeMouseAtCenter(["#test-iframe", "#form-basic-password"],
+                                             eventDetails, browser);
     await contextMenuShownPromise;
 
     // Synthesize a mouse click over the fill login menu header.
     let popupHeader = document.getElementById("fill-login");
     let popupShownPromise = BrowserTestUtils.waitForEvent(popupHeader, "popupshown");
     EventUtils.synthesizeMouseAtCenter(popupHeader, {});
     await popupShownPromise;
 
@@ -87,16 +83,62 @@ add_task(async function test_context_men
        "Username value was not changed.");
 
     let contextMenu = document.getElementById("contentAreaContextMenu");
     contextMenu.hidePopup();
   });
 });
 
 /**
+ * Check that the login context menu items don't appear on an opaque origin.
+ */
+add_task(async function test_context_menu_iframe_sandbox() {
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: TEST_HOSTNAME + IFRAME_PAGE_PATH,
+  }, async function(browser) {
+    let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
+    let eventDetails = {type: "contextmenu", button: 2};
+
+    BrowserTestUtils.synthesizeMouseAtCenter(["#test-iframe-sandbox", "#form-basic-password"],
+                                             eventDetails, browser);
+    await contextMenuShownPromise;
+
+    let popupHeader = document.getElementById("fill-login");
+    ok(popupHeader.disabled, "Check that the Fill Login menu item is disabled");
+
+    let contextMenu = document.getElementById("contentAreaContextMenu");
+    contextMenu.hidePopup();
+  });
+});
+
+/**
+ * Check that the login context menu item appears for sandbox="allow-same-origin"
+ */
+add_task(async function test_context_menu_iframe_sandbox_same_origin() {
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: TEST_HOSTNAME + IFRAME_PAGE_PATH,
+  }, async function(browser) {
+    let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
+    let eventDetails = {type: "contextmenu", button: 2};
+
+    BrowserTestUtils.synthesizeMouseAtCenter(["#test-iframe-sandbox-same-origin", "#form-basic-password"],
+                                             eventDetails, browser);
+    await contextMenuShownPromise;
+
+    let popupHeader = document.getElementById("fill-login");
+    ok(!popupHeader.disabled, "Check that the Fill Login menu item is enabled");
+
+    let contextMenu = document.getElementById("contentAreaContextMenu");
+    contextMenu.hidePopup();
+  });
+});
+
+/**
  * Search for a login by it's username.
  *
  * Only unique login/hostname combinations should be used at this test.
  */
 function getLoginFromUsername(username) {
   return loginList().find(login => login.username == username);
 }
 
--- a/toolkit/components/passwordmgr/test/browser/form_basic_iframe.html
+++ b/toolkit/components/passwordmgr/test/browser/form_basic_iframe.html
@@ -3,11 +3,21 @@
 
 <head>
     <meta charset="utf-8">
 </head>
 
 <body>
     <!-- Form in an iframe -->
     <iframe src="https://example.org/browser/toolkit/components/passwordmgr/test/browser/form_basic.html" id="test-iframe"></iframe>
+
+    <!-- Form in a fully sandboxed iframe -->
+    <iframe src="https://example.org/browser/toolkit/components/passwordmgr/test/browser/form_basic.html"
+            sandbox=""
+            id="test-iframe-sandbox"></iframe>
+
+    <!-- Form in an "allow-same-origin" sandboxed iframe -->
+    <iframe src="https://example.org/browser/toolkit/components/passwordmgr/test/browser/form_basic.html"
+            sandbox="allow-same-origin"
+            id="test-iframe-sandbox-same-origin"></iframe>
 </body>
 
 </html>