diff --git a/toolkit/components/passwordmgr/LoginManagerContent.jsm b/toolkit/components/passwordmgr/LoginManagerContent.jsm index cc976137b51e..37ab8a2c6308 100644 --- a/toolkit/components/passwordmgr/LoginManagerContent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm @@ -1530,12 +1530,13 @@ this.LoginManagerContent = { _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) { diff --git a/toolkit/components/passwordmgr/test/mochitest/test_LoginManagerContent_generatedPasswordFilledOrEdited.html b/toolkit/components/passwordmgr/test/mochitest/test_LoginManagerContent_generatedPasswordFilledOrEdited.html index 4edd23594b44..3d6fd511a3e9 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_LoginManagerContent_generatedPasswordFilledOrEdited.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_LoginManagerContent_generatedPasswordFilledOrEdited.html @@ -94,6 +94,61 @@ add_task(async function test_fieldsMaskedAfterSavedLoginFill() { 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();