Bug 1531135 - Honor autocomplete=off on password when signon.autofillForms.autocompleteOff is false. r=MattN

Differential Revision: https://phabricator.services.mozilla.com/D22025

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Sam Foster 2019-03-07 01:12:11 +00:00
Родитель 07a1cbed27
Коммит 3528b01310
5 изменённых файлов: 176 добавлений и 12 удалений

Просмотреть файл

@ -4675,6 +4675,7 @@ pref("font.name-list.monospace.x-unicode", "dt-interface user-ucs2.cjk_japan-0")
pref("signon.rememberSignons", true);
pref("signon.rememberSignons.visibilityToggle", true);
pref("signon.autofillForms", true);
pref("signon.autofillForms.autocompleteOff", true);
pref("signon.autofillForms.http", false);
pref("signon.autologin.proxy", false);
pref("signon.formlessCapture.enabled", true);

Просмотреть файл

@ -40,6 +40,7 @@ var LoginHelper = {
updateSignonPrefs() {
this.autofillForms = Services.prefs.getBoolPref("signon.autofillForms");
this.autofillAutocompleteOff = Services.prefs.getBoolPref("signon.autofillForms.autocompleteOff");
this.debug = Services.prefs.getBoolPref("signon.debug");
this.enabled = Services.prefs.getBoolPref("signon.rememberSignons");
this.formlessCaptureEnabled = Services.prefs.getBoolPref("signon.formlessCapture.enabled");

Просмотреть файл

@ -1122,7 +1122,6 @@ var LoginManagerContent = {
}
log("_fillForm", form.elements);
let ignoreAutocomplete = true;
// Will be set to one of AUTOFILL_RESULT in the `try` block.
let autofillResult = -1;
const AUTOFILL_RESULT = {
@ -1214,13 +1213,6 @@ var LoginManagerContent = {
return;
}
var isAutocompleteOff = false;
if (this._isAutocompleteDisabled(form) ||
this._isAutocompleteDisabled(usernameField) ||
this._isAutocompleteDisabled(passwordField)) {
isAutocompleteOff = true;
}
// Discard logins which have username/password values that don't
// fit into the fields (as specified by the maxlength attribute).
// The user couldn't enter these values anyway, and it helps
@ -1252,9 +1244,11 @@ var LoginManagerContent = {
return;
}
const passwordACFieldName = passwordField.getAutocompleteInfo().fieldName;
// If the password field has the autocomplete value of "new-password"
// and we're autofilling without user interaction, there's nothing to do.
if (!userTriggered && passwordField.getAutocompleteInfo().fieldName == "new-password") {
if (!userTriggered && passwordACFieldName == "new-password") {
log("not filling form, password field has the autocomplete new-password value");
autofillResult = AUTOFILL_RESULT.PASSWORD_AUTOCOMPLETE_NEW_PASSWORD;
return;
@ -1325,8 +1319,8 @@ var LoginManagerContent = {
return;
}
if (isAutocompleteOff && !ignoreAutocomplete) {
log("Not filling the login because we're respecting autocomplete=off");
if (!userTriggered && passwordACFieldName == "off" && !LoginHelper.autofillAutocompleteOff) {
log("Not autofilling the login because we're respecting autocomplete=off");
autofillResult = AUTOFILL_RESULT.AUTOCOMPLETE_OFF;
return;
}

Просмотреть файл

@ -51,6 +51,9 @@ skip-if = toolkit == 'android' # autocomplete
[test_basic_form_3pw_1.html]
[test_basic_form_autocomplete.html]
skip-if = toolkit == 'android' # android:autocomplete.
[test_basic_form_honor_autocomplete_off.html]
scheme = https
skip-if = toolkit == 'android' # android:autocomplete.
[test_insecure_form_field_autocomplete.html]
skip-if = toolkit == 'android' || os == 'linux' # android:autocomplete., linux: bug 1325778
[test_password_field_autocomplete.html]

Просмотреть файл

@ -0,0 +1,165 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test login autofill autocomplete when signon.autofillForms.autocompleteOff is false</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/AddTask.js"></script>
<script type="text/javascript" src="../../../satchel/test/satchel_common.js"></script>
<script type="text/javascript" src="pwmgr_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
Login Manager test: autofilling when autocomplete=off
<script>
let readyPromise = registerRunTests();
runInParent(function setup() {
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
// Create some logins just for this form, since we'll be deleting them.
const nsLoginInfo = Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
Ci.nsILoginInfo, "init");
assert.ok(nsLoginInfo != null, "nsLoginInfo constructor");
const login = new nsLoginInfo("https://example.com", "https://autocomplete2", null,
"singleuser", "singlepass", "uname", "pword");
Services.logins.addLogin(login);
});
</script>
<p id="display"></p>
<!-- we presumably can't hide the content for this test. -->
<div id="content">
<!-- test single logins, with autocomplete=off set -->
<form id="form1" action="https://autocomplete2" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="off">
<button type="submit">Submit</button>
</form>
<form id="form2" action="https://autocomplete2" onsubmit="return false;">
<input type="text" name="uname" autocomplete="off">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<form id="form3" action="https://autocomplete2" onsubmit="return false;" autocomplete="off">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<form id="form4" action="https://autocomplete2" onsubmit="return false;">
<input type="text" name="uname" autocomplete="off">
<input type="password" name="pword" autocomplete="off">
<button type="submit">Submit</button>
</form>
<!-- control -->
<form id="form5" action="https://autocomplete2" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: multiple login autocomplete. **/
let {ContentTaskUtils} = SpecialPowers.Cu.import("resource://testing-common/ContentTaskUtils.jsm", {});
// Set the pref before the document loads.
SpecialPowers.setBoolPref("signon.autofillForms.autocompleteOff", false);
SimpleTest.registerCleanupFunction(() => {
SpecialPowers.clearUserPref("signon.autofillForms.autocompleteOff");
});
// Check for expected username/password in form.
function checkFormValues(form, expectedUsername, expectedPassword) {
let uname = form.querySelector("[name='uname']");
let pword = form.querySelector("[name='pword']");
is(uname.value, expectedUsername, `Checking ${form.id} username is: ${expectedUsername}`);
is(pword.value, expectedPassword, `Checking ${form.id} password is: ${expectedPassword}`);
}
async function autoCompleteFieldsFromFirstMatch(form) {
// trigger autocomplete from the username field
await SimpleTest.promiseFocus(form.ownerGlobal);
let uname = form.querySelector("[name='uname']");
let shownPromise = promiseACShown();
uname.focus();
await shownPromise;
let formFilled = promiseFormsProcessed();
await synthesizeKey("KEY_ArrowDown"); // open
await synthesizeKey("KEY_Enter");
await formFilled;
await Promise.resolve();
}
add_task(async function setup() {
ok(readyPromise, "check promise is available");
await readyPromise;
listenForUnexpectedPopupShown();
});
/* Tests for autofill of single-user forms for when we honor autocomplete=off on password fields */
add_task(async function test_form1_honor_password_autocomplete_off() {
await SimpleTest.promiseFocus(window);
// With the pref toggled off, and with autocomplete=off on the password field,
// we expect not to have autofilled this form
let form = document.getElementById("form1");
ok(form, "found form under test");
checkFormValues(form, "", "");
// ..but it should autocomplete just fine
await autoCompleteFieldsFromFirstMatch(form);
checkFormValues(form, "singleuser", "singlepass");
});
add_task(async function test_form2_honor_password_autocomplete_off() {
await SimpleTest.promiseFocus(window);
// With the pref toggled off, and with autocomplete=off on the username field,
// we expect to have autofilled this form
let form = document.getElementById("form2");
ok(form, "found form under test");
checkFormValues(form, "singleuser", "singlepass");
});
add_task(async function test_form3_honor_password_autocomplete_off() {
await SimpleTest.promiseFocus(window);
// With the pref toggled off, and with autocomplete=off on the form,
// we expect to have autofilled this form
let form = document.getElementById("form3");
ok(form, "found form under test");
checkFormValues(form, "singleuser", "singlepass");
});
add_task(async function test_form4_honor_password_autocomplete_off() {
await SimpleTest.promiseFocus(window);
// With the pref toggled off, and autocomplete=off on the username and password field,
// we expect not to have autofilled this form
let form = document.getElementById("form4");
ok(form, "found form under test");
checkFormValues(form, "", "");
// ..but it should autocomplete just fine
await autoCompleteFieldsFromFirstMatch(form);
checkFormValues(form, "singleuser", "singlepass");
});
add_task(async function test_form5() {
await SimpleTest.promiseFocus(window);
// (this is a control, w/o autocomplete=off, to ensure the login
// that was being suppressed would have been filled in otherwise)
let form = document.getElementById("form5");
ok(form, "found form under test");
checkFormValues(form, "singleuser", "singlepass");
});
</script>
</pre>
</body>
</html>