Bug 1145754 - Allow per-site recipes to adjust the username/password field detection for capture. r=dolske

This commit is contained in:
Matthew Noorenberghe 2015-05-19 14:01:27 -07:00
parent 56e885c080
commit c2966b7ec6
5 changed files with 120 additions and 14 deletions

View File

@ -654,11 +654,8 @@ var LoginManagerContent = {
return false;
},
/*
* _onFormSubmit
*
* Called by the our observer when notified of a form submission.
/**
* Called by our observer when notified of a form submission.
* [Note that this happens before any DOM onsubmit handlers are invoked.]
* Looks for a password change in the submitted form, so we can update
* our stored password.
@ -692,11 +689,17 @@ var LoginManagerContent = {
return;
}
var formSubmitURL = LoginUtils._getActionOrigin(form)
let formSubmitURL = LoginUtils._getActionOrigin(form);
let messageManager = messageManagerFromWindow(win);
let recipesArray = messageManager.sendSyncMessage("RemoteLogins:findRecipes", {
formOrigin: hostname,
})[0];
let recipes = new Set(recipesArray);
// Get the appropriate fields from the form.
var [usernameField, newPasswordField, oldPasswordField] =
this._getFormFields(form, true);
this._getFormFields(form, true, recipes);
// Need at least 1 valid password field to do anything.
if (newPasswordField == null)
@ -730,7 +733,6 @@ var LoginManagerContent = {
// Make sure to pass the opener's top in case it was in a frame.
let opener = win.opener ? win.opener.top : null;
let messageManager = messageManagerFromWindow(win);
messageManager.sendAsyncMessage("RemoteLogins:onFormSubmit",
{ hostname: hostname,
formSubmitURL: formSubmitURL,

View File

@ -166,10 +166,21 @@ Services.prefs.addObserver("signon.debug", prefChanged, false);
prefChanged();
var LoginManagerParent = {
/**
* Reference to the default LoginRecipesParent (instead of the initialization promise) for
* synchronous access. This is a temporary hack and new consumers should yield on
* recipeParentPromise instead.
*
* @type LoginRecipesParent
* @deprecated
*/
_recipeManager: null,
init: function() {
let mm = Cc["@mozilla.org/globalmessagemanager;1"]
.getService(Ci.nsIMessageListenerManager);
mm.addMessageListener("RemoteLogins:findLogins", this);
mm.addMessageListener("RemoteLogins:findRecipes", this);
mm.addMessageListener("RemoteLogins:onFormSubmit", this);
mm.addMessageListener("RemoteLogins:autoCompleteLogins", this);
mm.addMessageListener("RemoteLogins:updateLoginFormPresence", this);
@ -179,8 +190,8 @@ var LoginManagerParent = {
XPCOMUtils.defineLazyGetter(this, "recipeParentPromise", () => {
const { LoginRecipesParent } = Cu.import("resource://gre/modules/LoginRecipes.jsm", {});
let parent = new LoginRecipesParent();
return parent.initializationPromise;
this._recipeManager = new LoginRecipesParent();
return this._recipeManager.initializationPromise;
});
},
@ -209,6 +220,11 @@ var LoginManagerParent = {
break;
}
case "RemoteLogins:findRecipes": {
let formHost = (new URL(data.formOrigin)).host;
return this._recipeManager.getRecipesForHost(formHost);
}
case "RemoteLogins:onFormSubmit": {
// TODO Verify msg.target's principals against the formOrigin?
this.onFormSubmit(data.hostname,

View File

@ -14,6 +14,7 @@ support-files =
subtst_notifications_11_popup.html
subtst_notifications_2.html
subtst_notifications_2pw_0un.html
subtst_notifications_2pw_1un_1text.html
subtst_notifications_3.html
subtst_notifications_4.html
subtst_notifications_5.html

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Subtest for Login Manager notifications with 2 password fields and 1 username field and one other text field before the first password field</title>
</head>
<body>
<h2>1 username field followed by a text field followed by 2 username fields</h2>
<form id="form" action="formsubmit.sjs">
<input id="user" name="user" value="staticpw">
<input id="city" name="city" value="city">
<input id="pass" name="pass" type="password">
<input id="pin" name="pin" type="password" value="static-pin">
<button type="submit">Submit</button>
</form>
<script>
function submitForm() {
userField.value = "notifyu1";
passField.value = "notifyp1";
form.submit();
}
window.onload = submitForm;
var form = document.getElementById("form");
var userField = document.getElementById("user");
var passField = document.getElementById("pass");
</script>
</body>
</html>

View File

@ -1,8 +1,9 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Login Manager</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="pwmgr_common.js"></script>
<script type="text/javascript" src="notification_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
@ -16,7 +17,7 @@ Login Manager test: notifications
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
<script class="testbody" type="application/javascript;version=1.8">
/** Test for Login Manager: notifications. **/
@ -53,6 +54,8 @@ var subtests = [
"subtst_notifications_2pw_0un.html", // 26
"subtst_notifications_2pw_0un.html", // 27
"subtst_notifications_2pw_0un.html", // 28
"http://example.org" + testpath + "subtst_notifications_2pw_1un_1text.html", // 29
"http://example.org" + testpath + "subtst_notifications_2pw_1un_1text.html", // 30
];
@ -472,6 +475,44 @@ function checkTest() {
pwmgr.removeLogin(login2);
break;
case 29: {
// Check that we capture the proper fields when a field recipe is in use.
is(gotUser, "notifyu1", "Checking submitted username");
is(gotPass, "notifyp1", "Checking submitted password");
popup = getPopup(popupNotifications, "password-save");
ok(popup, "got notification popup");
// Sanity check, no logins should exist yet.
let logins = pwmgr.getAllLogins();
is(logins.length, 0, "Should not have any logins yet");
clickPopupButton(popup, kRememberButton);
break;
}
case 30: {
// Same subtest, make sure we didn't prompt for an existing login.
is(gotUser, "notifyu1", "Checking submitted username");
is(gotPass, "notifyp1", "Checking submitted password");
popup = getPopup(popupNotifications, "password-save");
ok(!popup, "checking for no notification popup");
// Check to make sure we updated the timestamps and use count on the
// existing login that was submitted for this form.
let logins = pwmgr.getAllLogins();
is(logins.length, 1, "Should only have 1 login");
ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI");
is(logins[0].username, "notifyu1", "check .username for existing login submission");
is(logins[0].password, "notifyp1", "check .password for existing login submission");
is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission");
ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped");
ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated");
// remove the added login
pwmgr.removeAllLogins();
break;
}
default:
ok(false, "Unexpected call to checkTest for test #" + testNum);
@ -509,6 +550,9 @@ var login1B = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888"
var login2B = new nsLoginInfo("http://mochi.test:8888", "http://mochi.test:8888", null,
"", "notifyp1B", "", "pass");
var parentScriptURL = SimpleTest.getTestFileURL("pwmgr_common.js");
var mm = SpecialPowers.loadChromeScript(parentScriptURL);
var iframe = document.getElementById("iframe");
iframe.onload = handleLoad;
@ -518,8 +562,20 @@ var popupNotifications = getPopupNotifications(window.top);
ok(popupNotifications, "Got popupNotifications");
var testNum = 1;
ok(true, "Starting test #" + testNum);
iframe.src = subtests[testNum-1];
// Load recipes for this test.
mm.sendAsyncMessage("loadRecipes", {
siteRecipes: [{
hosts: ["example.org"],
usernameSelector: "#user",
passwordSelector: "#pass",
}],
});
mm.addMessageListener("loadedRecipes", function loadedRecipes() {
ok(true, "Starting test #" + testNum);
iframe.src = subtests[testNum-1];
})
SimpleTest.waitForExplicitFinish();
</script>