Bug 1388674 - Use document state to track generated password fields, not just the event handlers. r=MattN
☠☠ backed out by fcefdbe73a81 ☠ ☠
authorSam Foster <sfoster@mozilla.com>
Thu, 21 Nov 2019 22:47:00 +0000
changeset 503379 05c8232e7dc52152aa89535399d7fd2e2eb9b1e9
parent 503378 b6b7862f1da1f6596865653b74fa53bd57daa971
child 503380 d1e436047e1e90824a5835d62a15e764c986f054
push id36833
push userbtara@mozilla.com
push dateFri, 22 Nov 2019 21:40:53 +0000
treeherdermozilla-central@2c912e46295e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1388674
milestone72.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 1388674 - Use document state to track generated password fields, not just the event handlers. r=MattN Differential Revision: https://phabricator.services.mozilla.com/D53055
toolkit/components/passwordmgr/LoginManagerChild.jsm
--- a/toolkit/components/passwordmgr/LoginManagerChild.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerChild.jsm
@@ -211,59 +211,72 @@ const observer = {
     if (!aEvent.isTrusted) {
       return;
     }
 
     if (!LoginHelper.enabled) {
       return;
     }
 
-    let window = aEvent.target.ownerDocument.defaultView;
+    let ownerDocument = aEvent.target.ownerDocument;
+    let window = ownerDocument.defaultView;
+    let docState = LoginManagerChild.forWindow(window).stateForDocument(
+      ownerDocument
+    );
 
     switch (aEvent.type) {
       // Used to mask fields with filled generated passwords when blurred.
       case "blur": {
-        let unmask = false;
-        LoginManagerChild.forWindow(window)._togglePasswordFieldMasking(
-          aEvent.target,
-          unmask
-        );
+        if (docState.generatedPasswordFields.has(aEvent.target)) {
+          let unmask = false;
+          LoginManagerChild.forWindow(window)._togglePasswordFieldMasking(
+            aEvent.target,
+            unmask
+          );
+        }
         break;
       }
 
       // Used to watch for changes to fields filled with generated passwords.
       case "change": {
-        LoginManagerChild.forWindow(window)._generatedPasswordFilledOrEdited(
-          aEvent.target
-        );
+        if (docState.generatedPasswordFields.has(aEvent.target)) {
+          LoginManagerChild.forWindow(window)._generatedPasswordFilledOrEdited(
+            aEvent.target
+          );
+        }
         break;
       }
 
       // Used to watch for changes to fields filled with generated passwords.
       case "input": {
-        LoginManagerChild.forWindow(
-          window
-        )._maybeStopTreatingAsGeneratedPasswordField(aEvent);
+        if (docState.generatedPasswordFields.has(aEvent.target)) {
+          LoginManagerChild.forWindow(
+            window
+          )._maybeStopTreatingAsGeneratedPasswordField(aEvent);
+        }
         break;
       }
 
       case "keydown": {
         if (
           aEvent.keyCode == aEvent.DOM_VK_TAB ||
           aEvent.keyCode == aEvent.DOM_VK_RETURN
         ) {
           LoginManagerChild.forWindow(window).onUsernameAutocompleted(
             aEvent.target
           );
         }
         break;
       }
 
       case "focus": {
-        if (aEvent.target.type == "password") {
+        if (
+          aEvent.target.type == "password" &&
+          docState.generatedPasswordFields.has(aEvent.target)
+        ) {
           // Used to unmask fields with filled generated passwords when focused.
           let unmask = true;
           LoginManagerChild.forWindow(window)._togglePasswordFieldMasking(
             aEvent.target,
             unmask
           );
           break;
         }
@@ -870,16 +883,20 @@ this.LoginManagerChild = class LoginMana
     let loginFormState = this._loginFormStateByDocument.get(document);
     if (!loginFormState) {
       loginFormState = {
         /**
          * Keeps track of filled fields and values.
          */
         fillsByRootElement: new WeakMap(),
         /**
+         * Keeps track of fields we've filled with generated passwords
+         */
+        generatedPasswordFields: new WeakSet(),
+        /**
          * Keeps track of logins that were last submitted.
          */
         lastSubmittedValuesByRootElement: new WeakMap(),
         loginFormRootElements: new WeakSet(),
       };
       this._loginFormStateByDocument.set(document, loginFormState);
     }
     return loginFormState;
@@ -1570,16 +1587,20 @@ this.LoginManagerChild = class LoginMana
     if (!value || (event.data && event.data == value)) {
       this._stopTreatingAsGeneratedPasswordField(passwordField);
     }
   }
 
   _stopTreatingAsGeneratedPasswordField(passwordField) {
     log("_stopTreatingAsGeneratedPasswordField");
 
+    let fields = this.stateForDocument(passwordField.ownerDocument)
+      .generatedPasswordFields;
+    fields.delete(passwordField);
+
     // Remove all the event listeners added in _generatedPasswordFilledOrEdited
     for (let eventType of ["blur", "change", "focus", "input"]) {
       passwordField.removeEventListener(eventType, observer, {
         capture: true,
         mozSystemGroup: true,
       });
     }
 
@@ -1598,16 +1619,18 @@ this.LoginManagerChild = class LoginMana
     if (!LoginHelper.enabled) {
       throw new Error(
         "A generated password was filled while the password manager was disabled."
       );
     }
 
     let win = passwordField.ownerGlobal;
     let formLikeRoot = FormLikeFactory.findRootForField(passwordField);
+    let docState = this.stateForDocument(passwordField.ownerDocument);
+    docState.generatedPasswordFields.add(passwordField);
 
     this._highlightFilledField(passwordField);
 
     // change: Listen for changes to the field filled with the generated password so we can preserve edits.
     // input: Listen for the field getting blanked (without blurring) or a paste
     for (let eventType of ["blur", "change", "focus", "input"]) {
       passwordField.addEventListener(eventType, observer, {
         capture: true,