Bug 1571465 - Stop treating fields with replaced values as generated password ones r=sfoster
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Wed, 14 Aug 2019 19:35:09 +0000
changeset 488108 a6f4fcb2f96000cf3d93d1316652670600852afc
parent 488107 21fccebed05de6fcbb24d34d817b3dbba0c10ac8
child 488109 0b74cfbb22fd9cdea4eca0dd78be110c5cb35767
push id113900
push usercbrindusan@mozilla.com
push dateThu, 15 Aug 2019 09:53:50 +0000
treeherdermozilla-inbound@0db07ff50ab5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfoster
bugs1571465
milestone70.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 1571465 - Stop treating fields with replaced values as generated password ones r=sfoster Depends on D41147 Differential Revision: https://phabricator.services.mozilla.com/D41148
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/test/mochitest/test_LoginManagerContent_generatedPasswordFilledOrEdited.html
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -1525,22 +1525,23 @@ this.LoginManagerContent = {
       oldPasswordField: mockOldPassword,
       openerTopWindowID,
       dismissedPrompt,
     });
   },
 
   _maybeStopTreatingAsGeneratedPasswordField(event) {
     let passwordField = event.target;
+    let { value } = passwordField;
 
-    // If the field isn't empty then keep treating it as a generated password field.
-    if (passwordField.value) {
-      return;
+    // If the field is now empty or the inserted text replaced the whole value
+    // then stop treating it as a generated password field.
+    if (!value || (event.data && event.data == value)) {
+      this._stopTreatingAsGeneratedPasswordField(passwordField);
     }
-    this._stopTreatingAsGeneratedPasswordField(passwordField);
   },
 
   _stopTreatingAsGeneratedPasswordField(passwordField) {
     log("_stopTreatingAsGeneratedPasswordField");
 
     // Remove all the event listeners added in _generatedPasswordFilledOrEdited
     for (let eventType of ["blur", "change", "focus", "input"]) {
       passwordField.removeEventListener(eventType, observer, {
--- a/toolkit/components/passwordmgr/test/mochitest/test_LoginManagerContent_generatedPasswordFilledOrEdited.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_LoginManagerContent_generatedPasswordFilledOrEdited.html
@@ -89,16 +89,71 @@ add_task(async function test_fieldsMaske
   is(pword.value, "pass1", "Saved password was filled")
   LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "After filling a saved login");
 
   // Cleanup
   recreateTree(document.getElementById("form1"));
   await promiseFormsProcessed();
 });
 
+add_task(async function test_fieldsMaskedAfterReplacingWholeValue() {
+  let pword = $_(1, "pword");
+  pword.focus();
+
+  SpecialPowers.wrap(pword).setUserInput("generatedpass");
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "Before first fill");
+  LoginManagerContent._generatedPasswordFilledOrEdited(pword);
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, false, "After first fill");
+  synthesizeKey("KEY_Tab", { shiftKey: true }); // blur pw, focus un
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "After blur");
+
+  synthesizeKey("KEY_Tab"); // focus again and replace the whole password value
+  info("Replacing password field value with arbitrary string");
+  sendString("some_other_password");
+  is(pword.value, "some_other_password", "Whole password replaced")
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "Replaced password value");
+
+  synthesizeKey("KEY_Tab"); // blur pw
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "After blur");
+  synthesizeKey("KEY_Tab", { shiftKey: true }); // focus pw again
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "After focus again");
+
+  // Cleanup
+  recreateTree(document.getElementById("form1"));
+  await promiseFormsProcessed();
+});
+
+add_task(async function test_fieldsUnmaskedAfterAddingCharacter() {
+  let pword = $_(1, "pword");
+  pword.focus();
+
+  SpecialPowers.wrap(pword).setUserInput("generatedpass");
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "Before first fill");
+  LoginManagerContent._generatedPasswordFilledOrEdited(pword);
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, false, "After first fill");
+  synthesizeKey("KEY_Tab", { shiftKey: true }); // blur pw, focus un
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "After blur");
+
+  synthesizeKey("KEY_Tab"); // focus again
+  synthesizeKey("KEY_ArrowRight"); // Remove the selection
+  info("Adding a character to the end of the password");
+  sendString("@");
+  is(pword.value, "generatedpass@", "Character was added to the value")
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, false, "Added @");
+
+  synthesizeKey("KEY_Tab"); // blur pw
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "After blur after @");
+  synthesizeKey("KEY_Tab", { shiftKey: true }); // focus pw again
+  LOGIN_FIELD_UTILS.checkPasswordMasked(pword, false, "After focus after @");
+
+  // Cleanup
+  recreateTree(document.getElementById("form1"));
+  await promiseFormsProcessed();
+});
+
 add_task(async function test_typeNotPassword() {
   let pword = $_(1, "pword");
   pword.focus();
 
   LOGIN_FIELD_UTILS.checkPasswordMasked(pword, true, "Before first fill");
   SpecialPowers.wrap(pword).setUserInput("generatedpass");
   LoginManagerContent._generatedPasswordFilledOrEdited(pword);
   LOGIN_FIELD_UTILS.checkPasswordMasked(pword, false, "After first fill");