Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
/**
* Tests the case where there are logins that cannot be decrypted.
*/
"use strict";
// Globals
/**
* Resets the token used to decrypt logins. This is equivalent to resetting the
* primary password when it is not known.
*/
function resetPrimaryPassword() {
let token = Cc["@mozilla.org/security/pk11tokendb;1"]
.getService(Ci.nsIPK11TokenDB)
.getInternalKeyToken();
token.reset();
token.initPassword("");
}
// Tests
/**
* Resets the primary password after some logins were added to the database.
*/
add_task(async function test_logins_decrypt_failure() {
let logins = TestData.loginList();
await Services.logins.addLogins(logins);
// This makes the existing logins non-decryptable.
resetPrimaryPassword();
// These functions don't see the non-decryptable entries anymore.
let savedLogins = await Services.logins.getAllLogins();
Assert.equal(savedLogins.length, 0, "getAllLogins length");
await Assert.rejects(Services.logins.searchLoginsAsync({}), /is required/);
Assert.equal(Services.logins.searchLogins(newPropertyBag()).length, 0);
Assert.throws(
() => Services.logins.modifyLogin(logins[0], newPropertyBag()),
/No matching logins/
);
Assert.throws(
() => Services.logins.removeLogin(logins[0]),
/No matching logins/
);
// The function that counts logins sees the non-decryptable entries also.
Assert.equal(Services.logins.countLogins("", "", ""), logins.length);
// Equivalent logins can be added.
await Services.logins.addLogins(logins);
await LoginTestUtils.checkLogins(logins);
Assert.equal(
(await Services.logins.getAllLogins()).length,
logins.length,
"getAllLogins length"
);
Assert.equal(Services.logins.countLogins("", "", ""), logins.length * 2);
// Finding logins doesn't return the non-decryptable duplicates.
Assert.equal(
(
await Services.logins.searchLoginsAsync({
})
).length,
1
);
let matchData = newPropertyBag({ origin: "http://www.example.com" });
Assert.equal(Services.logins.searchLogins(matchData).length, 1);
// Removing single logins does not remove non-decryptable logins.
for (let loginInfo of TestData.loginList()) {
Services.logins.removeLogin(loginInfo);
}
Assert.equal((await Services.logins.getAllLogins()).length, 0);
Assert.equal(Services.logins.countLogins("", "", ""), logins.length);
// Removing all logins removes the non-decryptable entries also.
Services.logins.removeAllUserFacingLogins();
Assert.equal((await Services.logins.getAllLogins()).length, 0);
Assert.equal(Services.logins.countLogins("", "", ""), 0);
});
// Bug 621846 - If a login has a GUID but can't be decrypted, a search for
// that GUID will (correctly) fail. Ensure we can add a new login with that
// same GUID.
add_task(async function test_add_logins_with_decrypt_failure() {
// a login with a GUID.
let login = new LoginInfo(
null,
"the username",
"the password for www.example.com",
"form_field_username",
"form_field_password"
);
login.QueryInterface(Ci.nsILoginMetaInfo);
login.guid = "{4bc50d2f-dbb6-4aa3-807c-c4c2065a2c35}";
// A different login but with the same GUID.
let loginDupeGuid = new LoginInfo(
null,
"the username",
"the password",
"form_field_username",
"form_field_password"
);
loginDupeGuid.QueryInterface(Ci.nsILoginMetaInfo);
loginDupeGuid.guid = login.guid;
await Services.logins.addLoginAsync(login);
// We can search for this login by GUID.
let searchProp = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
Ci.nsIWritablePropertyBag2
);
searchProp.setPropertyAsAUTF8String("guid", login.guid);
equal(Services.logins.searchLogins(searchProp).length, 1);
// We should fail to re-add it as it remains good.
await Assert.rejects(
Services.logins.addLoginAsync(login),
/This login already exists./
);
// We should fail to re-add a different login with the same GUID.
await Assert.rejects(
Services.logins.addLoginAsync(loginDupeGuid),
/specified GUID already exists/
);
// This makes the existing login non-decryptable.
resetPrimaryPassword();
// We can no longer find it in our search.
equal(Services.logins.searchLogins(searchProp).length, 0);
// So we should be able to re-add a login with that same GUID.
await Services.logins.addLoginAsync(login);
equal(Services.logins.searchLogins(searchProp).length, 1);
Services.logins.removeAllUserFacingLogins();
});
// Test the "syncID" metadata works as expected on decryption failure.
add_task(async function test_sync_metadata_with_decrypt_failure() {
// And some sync metadata
await Services.logins.setSyncID("sync-id");
await Services.logins.setLastSync(123);
equal(await Services.logins.getSyncID(), "sync-id");
equal(await Services.logins.getLastSync(), 123);
// This makes the existing login and syncID non-decryptable.
resetPrimaryPassword();
// The syncID is now null.
equal(await Services.logins.getSyncID(), null);
// The sync timestamp isn't impacted.
equal(await Services.logins.getLastSync(), 123);
// But we should be able to set it again.
await Services.logins.setSyncID("new-id");
equal(await Services.logins.getSyncID(), "new-id");
});