Bug 378667: Better "passwords for given realm" query support. r=gavin

This commit is contained in:
dolske@mozilla.com 2007-08-23 11:57:42 -07:00
Родитель 91e5a21d63
Коммит e3136176b4
7 изменённых файлов: 157 добавлений и 32 удалений

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

@ -319,10 +319,7 @@ function realmHasPasswords(location) {
var realm = makeURI(location).prePath;
var passwordManager = Components.classes["@mozilla.org/login-manager;1"]
.getService(Components.interfaces.nsILoginManager);
var passwords = passwordManager.getAllLogins({});
// XXX untested
return passwords.some(function (login) { return (login.hostname == realm); });
return passwordManager.countLogins(realm, "", "");
}
/**

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

@ -180,6 +180,28 @@ interface nsILoginManager : nsISupports {
[retval, array, size_is(count)] out nsILoginInfo logins);
/**
* Search for logins matching the specified criteria, as with
* findLogins(). This interface only returns the number of matching
* logins (and not the logins themselves), which allows a caller to
* check for logins without causing the user to be prompted for a master
* password to decrypt the logins.
*
* @param aHostname
* The hostname to restrict searches to.
* @param aActionURL
* The URL to which a form login will be submitted. To match any
* form login, specify an empty string. To not match any form
* login, specify null.
* @param aHttpRealm
* The HTTP Realm for which the login applies. To match logins for
* any realm, specify an empty string. To not match logins for any
* realm, specify null.
*/
unsigned long countLogins(in AString aHostname, in AString aActionURL,
in AString aHttpRealm);
/**
* Generate results for a userfield autocomplete menu.
*

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

@ -202,4 +202,26 @@ interface nsILoginManagerStorage : nsISupports {
void findLogins(out unsigned long count, in AString aHostname,
in AString aActionURL, in AString aHttpRealm,
[retval, array, size_is(count)] out nsILoginInfo logins);
/**
* Search for logins matching the specified criteria, as with
* findLogins(). This interface only returns the number of matching
* logins (and not the logins themselves), which allows a caller to
* check for logins without causing the user to be prompted for a master
* password to decrypt the logins.
*
* @param aHostname
* The hostname to restrict searches to.
* @param aActionURL
* The URL to which a form login will be submitted. To match any
* form login, specify an empty string. To not match any form
* login, specify null.
* @param aHttpRealm
* The HTTP Realm for which the login applies. To match logins for
* any realm, specify an empty string. To not match logins for any
* realm, specify null.
*/
unsigned long countLogins(in AString aHostname, in AString aActionURL,
in AString aHttpRealm);
};

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

@ -470,8 +470,7 @@ LoginManager.prototype = {
/*
* findLogins
*
* Search the known logins for entries matching the specified criteria
* for a protocol login (eg HTTP Auth).
* Search for the known logins for entries matching the specified criteria.
*/
findLogins : function (count, hostname, formSubmitURL, httpRealm) {
this.log("Searching for logins matching host: " + hostname +
@ -482,6 +481,20 @@ LoginManager.prototype = {
},
/*
* countLogins
*
* Search for the known logins for entries matching the specified criteria,
* returns only the count.
*/
countLogins : function (hostname, formSubmitURL, httpRealm) {
this.log("Counting logins matching host: " + hostname +
", formSubmitURL: " + formSubmitURL + ", httpRealm: " + httpRealm);
return this._storage.countLogins(hostname, formSubmitURL, httpRealm);
},
/*
* getLoginSavingEnabled
*

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

@ -324,32 +324,12 @@ LoginManagerStorage_legacy.prototype = {
*
*/
findLogins : function (count, hostname, formSubmitURL, httpRealm) {
var hostLogins = this._logins[hostname];
if (hostLogins == null) {
count.value = 0;
return [];
}
var userCanceled;
var result = [], userCanceled;
for each (var login in hostLogins) {
// If looking for an HTTP login, make sure the httpRealms match.
if (httpRealm != login.httpRealm)
continue;
// If looking for a form login, make sure the action URLs match
// ...unless the stored login is blank (not null), which means
// login was stored before we started keeping the action URL.
if (formSubmitURL != login.formSubmitURL &&
login.formSubmitURL != "")
continue;
result.push(login);
}
var logins = this._searchLogins(hostname, formSubmitURL, httpRealm);
// Decrypt entries found for the caller.
[result, userCanceled] = this._decryptLogins(result);
[logins, userCanceled] = this._decryptLogins(logins);
// We want to throw in this case, so that the Login Manager
// knows to stop processing forms on the page so the user isn't
@ -357,8 +337,19 @@ LoginManagerStorage_legacy.prototype = {
if (userCanceled)
throw "User canceled Master Password entry";
count.value = result.length; // needed for XPCOM
return result;
count.value = logins.length; // needed for XPCOM
return logins;
},
/*
* countLogins
*
*/
countLogins : function (hostname, formSubmitURL, httpRealm) {
var logins = this._searchLogins(hostname, formSubmitURL, httpRealm);
return logins.length;
},
@ -369,6 +360,54 @@ LoginManagerStorage_legacy.prototype = {
/*
* _searchLogins
*
*/
_searchLogins : function (hostname, formSubmitURL, httpRealm) {
var hostLogins = this._logins[hostname];
if (hostLogins == null)
return [];
var result = [], userCanceled;
for each (var login in hostLogins) {
// If search arg is null, skip login unless it doesn't specify a
// httpRealm (ie, it's also null). If the seach arg is an empty
// string, always match.
if (httpRealm == null) {
if (login.httpRealm != null)
continue;
} else if (httpRealm != "") {
// Make sure the realms match. If search arg is null,
// only match if login doesn't specify a realm (is null)
if (httpRealm != login.httpRealm)
continue;
}
// If search arg is null, skip login unless it doesn't specify a
// action URL (ie, it's also null). If the seach arg is an empty
// string, always match.
if (formSubmitURL == null) {
if (login.formSubmitURL != null)
continue;
} else if (formSubmitURL != "") {
// If the stored login is blank (not null), that means the
// login was stored before we started keeping the action
// URL, so always match. Unless the search g
if (login.formSubmitURL != "" &&
formSubmitURL != login.formSubmitURL)
continue;
}
result.push(login);
}
return result;
},
/*
* _getSignonsFile
*
@ -547,7 +586,11 @@ LoginManagerStorage_legacy.prototype = {
// Line is the action URL
case STATE.ACTIONURL:
entry.formSubmitURL = line.value;
var formSubmitURL = line.value;
if (!formSubmitURL && entry.httpRealm)
entry.formSubmitURL = null;
else
entry.formSubmitURL = formSubmitURL;
processEntry = true;
parseState = STATE.USERFIELD;
break;

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

@ -112,6 +112,14 @@ testdesc = "Initialize with signons-05.txt (0 disabled, 1 login)";
LoginTest.initStorage(storage, INDIR, "signons-05.txt");
LoginTest.checkStorageData(storage, [], [testuser1]);
// counting logins matching host
do_check_eq(1, storage.countLogins("http://dummyhost.mozilla.org", "", null));
// counting logins matching host (login has blank actionURL)
do_check_eq(1, storage.countLogins("http://dummyhost.mozilla.org", "foo", null));
// counting logins (don't match form login for HTTP search)
do_check_eq(0, storage.countLogins("http://dummyhost.mozilla.org", null, ""));
// counting logins (don't match a bogus hostname)
do_check_eq(0, storage.countLogins("blah", "", ""));
/* ========== 9 ========== */
@ -128,6 +136,14 @@ testdesc = "Initialize with signons-07.txt (0 disabled, 2 logins on same host)";
LoginTest.initStorage(storage, INDIR, "signons-07.txt");
LoginTest.checkStorageData(storage, [], [testuser1, testuser2]);
// counting logins matching host
do_check_eq(2, storage.countLogins("http://dummyhost.mozilla.org", "", null));
// counting logins matching host (login has blank actionURL)
do_check_eq(2, storage.countLogins("http://dummyhost.mozilla.org", "foo", null));
// counting logins (don't match form login for HTTP search)
do_check_eq(0, storage.countLogins("http://dummyhost.mozilla.org", null, ""));
// counting logins (don't match a bogus hostname)
do_check_eq(0, storage.countLogins("blah", "", ""));
/* ========== 11 ========== */
@ -150,6 +166,10 @@ for (i = 1; i <= 500; i++) {
}
LoginTest.checkStorageData(storage, disabledHosts, logins);
// counting all logins for dummyhost
do_check_eq(500, storage.countLogins("http://dummyhost.site.org", "", ""));
// counting all logins for dummyhost-1
do_check_eq(1, storage.countLogins("http://dummyhost-1.site.org", "", ""));
} catch (e) {
throw "FAILED in test #" + testnum + " -- " + testdesc + ": " + e;

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

@ -198,6 +198,14 @@ LoginTest.initStorage(storage, OUTDIR, "output-05.txt", null, null);
testdesc = "Verify output-05.txt";
LoginTest.checkStorageData(storage, [], [dummyuser1, dummyuser2, dummyuser3]);
// count dummyhost2 logins
do_check_eq(2, storage.countLogins("http://dummyhost2.mozilla.org", "", ""));
// count dummyhost logins
do_check_eq(1, storage.countLogins("http://dummyhost.mozilla.org", "", ""));
// count dummyhost2 logins w/ specific formSubmitURL
do_check_eq(2, storage.countLogins("http://dummyhost2.mozilla.org", "http://cgi.site.com", ""));
/* ========== 10 ========== */
testnum++;