Bug 1388674 - Use document state to track generated password fields, not just the event handlers. r=MattN
☠☠ backed out by dbb0fff9e65c ☠ ☠
authorSam Foster <sfoster@mozilla.com>
Mon, 18 Nov 2019 23:55:12 +0000
changeset 502515 ee452cb16fac66c1f5011cef8435f7e2b3e83502
parent 502514 11f48aaae9552c1f8da22578aedc41d5fa07ebbc
child 502516 5caf9e9337388ac29a786e9600a6af240bb00275
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMattN
bugs1388674
milestone72.0a1
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,