Bug 1771148 - Ignore events in formautofill from about page or documents with null or system principal r=sgalich
authorDimi <dlee@mozilla.com>
Thu, 02 Jun 2022 11:43:45 +0000
changeset 619557 91c0d77ad11a265da849201725096dfff8e0cd60
parent 619556 065de83e89d3e907f491e348b42dc9ac0750a798
child 619558 f5a1c9036ed8226fe1b82973a850851f355f8630
push id163889
push userdlee@mozilla.com
push dateThu, 02 Jun 2022 11:46:12 +0000
treeherderautoland@91c0d77ad11a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssgalich
bugs1771148
milestone103.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 1771148 - Ignore events in formautofill from about page or documents with null or system principal r=sgalich This patch follows how we ignore events in LoginManagerChild.shouldIgnoreLoginManagerEvent Differential Revision: https://phabricator.services.mozilla.com/D147725
browser/extensions/formautofill/test/browser/browser_autocomplete_footer.js
browser/extensions/formautofill/test/browser/browser_remoteiframe.js
browser/extensions/formautofill/test/browser/creditCard/browser_editCreditCardDialog.js
browser/extensions/formautofill/test/browser/head.js
toolkit/components/formautofill/FormAutofillChild.jsm
--- a/browser/extensions/formautofill/test/browser/browser_autocomplete_footer.js
+++ b/browser/extensions/formautofill/test/browser/browser_autocomplete_footer.js
@@ -1,12 +1,11 @@
 "use strict";
 
 const URL = BASE_URL + "autocomplete_basic.html";
-const PRIVACY_PREF_URL = "about:preferences#privacy";
 
 add_task(async function setup_storage() {
   await setStorage(
     TEST_ADDRESS_2,
     TEST_ADDRESS_3,
     TEST_ADDRESS_4,
     TEST_ADDRESS_5
   );
--- a/browser/extensions/formautofill/test/browser/browser_remoteiframe.js
+++ b/browser/extensions/formautofill/test/browser/browser_remoteiframe.js
@@ -1,12 +1,11 @@
 "use strict";
 
 const IFRAME_URL_PATH = BASE_URL + "autocomplete_iframe.html";
-const PRIVACY_PREF_URL = "about:preferences#privacy";
 
 // Start by adding a few addresses to storage.
 add_task(async function setup_storage() {
   await SpecialPowers.pushPrefEnv({
     set: [
       [AUTOFILL_ADDRESSES_AVAILABLE_PREF, "on"],
       [ENABLED_AUTOFILL_ADDRESSES_PREF, true],
       [ENABLED_AUTOFILL_ADDRESSES_CAPTURE_PREF, true],
--- a/browser/extensions/formautofill/test/browser/creditCard/browser_editCreditCardDialog.js
+++ b/browser/extensions/formautofill/test/browser/creditCard/browser_editCreditCardDialog.js
@@ -441,8 +441,47 @@ add_task(async function test_editCreditC
   creditCards = await getCreditCards();
 
   is(creditCards.length, 1, "only one credit card is in storage");
   await removeCreditCards([creditCards[0].guid]);
 
   creditCards = await getCreditCards();
   is(creditCards.length, 0, "Credit card storage is empty");
 });
+
+add_task(async function test_noAutocompletePopupOnSystemTab() {
+  await setStorage(TEST_CREDIT_CARD_1);
+
+  await BrowserTestUtils.withNewTab(
+    { gBrowser, url: PRIVACY_PREF_URL },
+    async browser => {
+      // Open credit card manage dialog
+      await SpecialPowers.spawn(browser, [], async () => {
+        let button = content.document.querySelector(
+          "#creditCardAutofill button"
+        );
+        button.click();
+      });
+      let dialog = await waitForSubDialogLoad(
+        content,
+        MANAGE_CREDIT_CARDS_DIALOG_URL
+      );
+
+      // Open edit credit card dialog
+      await SpecialPowers.spawn(dialog, [], async () => {
+        let button = content.document.querySelector("#add");
+        button.click();
+      });
+      dialog = await waitForSubDialogLoad(content, EDIT_CREDIT_CARD_DIALOG_URL);
+
+      // Focus on credit card number field
+      await SpecialPowers.spawn(dialog, [], async () => {
+        let number = content.document.querySelector("#cc-number");
+        number.focus();
+      });
+
+      // autocomplete popup should not appear
+      await ensureNoAutocompletePopup(browser);
+    }
+  );
+
+  await removeAllRecords();
+});
--- a/browser/extensions/formautofill/test/browser/head.js
+++ b/browser/extensions/formautofill/test/browser/head.js
@@ -14,16 +14,17 @@ const { FormAutofillParent } = ChromeUti
 const MANAGE_ADDRESSES_DIALOG_URL =
   "chrome://formautofill/content/manageAddresses.xhtml";
 const MANAGE_CREDIT_CARDS_DIALOG_URL =
   "chrome://formautofill/content/manageCreditCards.xhtml";
 const EDIT_ADDRESS_DIALOG_URL =
   "chrome://formautofill/content/editAddress.xhtml";
 const EDIT_CREDIT_CARD_DIALOG_URL =
   "chrome://formautofill/content/editCreditCard.xhtml";
+const PRIVACY_PREF_URL = "about:preferences#privacy";
 
 const HTTP_TEST_PATH = "/browser/browser/extensions/formautofill/test/browser/";
 const BASE_URL = "http://mochi.test:8888" + HTTP_TEST_PATH;
 const FORM_URL = BASE_URL + "autocomplete_basic.html";
 const CREDITCARD_FORM_URL =
   "https://example.org" +
   HTTP_TEST_PATH +
   "creditCard/autocomplete_creditcard_basic.html";
@@ -175,16 +176,17 @@ const MAIN_BUTTON = "button";
 const SECONDARY_BUTTON = "secondaryButton";
 const MENU_BUTTON = "menubutton";
 
 /**
  * Collection of timeouts that are used to ensure something should not happen.
  */
 const TIMEOUT_ENSURE_PROFILE_NOT_SAVED = 1000;
 const TIMEOUT_ENSURE_CC_EDIT_DIALOG_NOT_CLOSED = 500;
+const TIMEOUT_ENSURE_AUTOCOMPLETE_NOT_SHOWN = 1000;
 
 function getDisplayedPopupItems(
   browser,
   selector = ".autocomplete-richlistitem"
 ) {
   info("getDisplayedPopupItems");
   const {
     autoCompletePopup: { richlistbox: itemsBox },
@@ -195,16 +197,24 @@ function getDisplayedPopupItems(
     item => item.getAttribute("collapsed") != "true"
   );
 }
 
 async function sleep(ms = 500) {
   await new Promise(resolve => setTimeout(resolve, ms));
 }
 
+async function ensureNoAutocompletePopup(browser) {
+  await new Promise(resolve =>
+    setTimeout(resolve, TIMEOUT_ENSURE_AUTOCOMPLETE_NOT_SHOWN)
+  );
+  const items = getDisplayedPopupItems(browser);
+  ok(!items.length, "Should not found autocomplete items");
+}
+
 /**
  * Wait for "formautofill-storage-changed" events
  *
  * @param {Array<string>} eventTypes
  *        eventType must be one of the following:
  *        `add`, `update`, `remove`, `notifyUsed`, `removeAll`, `reconcile`
  *
  * @returns {Promise} resolves when all events are received
@@ -240,16 +250,44 @@ async function waitForAutofill(target, s
     await ContentTaskUtils.waitForCondition(() => {
       let element = content.document.querySelector(selector);
       return element.value == val;
     }, "Autofill never fills");
   });
 }
 
 /**
+ * Waits for the subDialog to be loaded
+ *
+ * @param {Window} win The window of the dialog
+ * @param {string} dialogUrl The url of the dialog that we are waiting for
+ *
+ * @returns {Promise} resolves when the sub dialog is loaded
+ */
+function waitForSubDialogLoad(win, dialogUrl) {
+  return new Promise((resolve, reject) => {
+    win.gSubDialog._dialogStack.addEventListener(
+      "dialogopen",
+      async function dialogopen(evt) {
+        let cwin = evt.detail.dialog._frame.contentWindow;
+        if (cwin.location != dialogUrl) {
+          return;
+        }
+        content.gSubDialog._dialogStack.removeEventListener(
+          "dialogopen",
+          dialogopen
+        );
+
+        resolve(cwin);
+      }
+    );
+  });
+}
+
+/**
  * Use this function when you want to update the value of elements in
  * a form and then submit the form. This function makes sure the form
  * is "identified" (`identifyAutofillFields` is called) before submitting
  * the form.
  * This is guaranteed by first focusing on an element in the form to trigger
  * the 'FormAutofill:FieldsIdentified' message.
  *
  * @param {Object} target
--- a/toolkit/components/formautofill/FormAutofillChild.jsm
+++ b/toolkit/components/formautofill/FormAutofillChild.jsm
@@ -105,21 +105,34 @@ class FormAutofillChild extends JSWindow
       this._nextHandleElement = null;
       // This is for testing purpose only which sends a notification to indicate that the
       // form has been identified, and ready to open popup.
       this.sendAsyncMessage("FormAutofill:FieldsIdentified");
       FormAutofillContent.updateActiveInput();
     });
   }
 
+  shouldIgnoreFormAutofillEvent(event) {
+    let nodePrincipal = event.target.nodePrincipal;
+    return (
+      nodePrincipal.isSystemPrincipal ||
+      nodePrincipal.isNullPrincipal ||
+      nodePrincipal.schemeIs("about")
+    );
+  }
+
   handleEvent(evt) {
     if (!evt.isTrusted) {
       return;
     }
 
+    if (this.shouldIgnoreFormAutofillEvent(evt)) {
+      return;
+    }
+
     switch (evt.type) {
       case "focusin": {
         if (FormAutofill.isAutofillEnabled) {
           this.onFocusIn(evt);
         }
         break;
       }
       case "DOMFormBeforeSubmit": {