summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js')
-rw-r--r--toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js172
1 files changed, 172 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js b/toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js
new file mode 100644
index 0000000000..30c7aa1be9
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/unit/test_logins_decrypt_failure.js
@@ -0,0 +1,172 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * 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.
+ Assert.equal(Services.logins.getAllLogins().length, 0);
+ Assert.equal(
+ (await Services.logins.getAllLoginsAsync()).length,
+ 0,
+ "getAllLoginsAsync length"
+ );
+ Assert.equal(Services.logins.findLogins("", "", "").length, 0);
+ 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);
+ LoginTestUtils.checkLogins(logins);
+ Assert.equal(
+ (await Services.logins.getAllLoginsAsync()).length,
+ logins.length,
+ "getAllLoginsAsync length"
+ );
+ Assert.equal(Services.logins.countLogins("", "", ""), logins.length * 2);
+
+ // Finding logins doesn't return the non-decryptable duplicates.
+ Assert.equal(
+ Services.logins.findLogins("http://www.example.com", "", "").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(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(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(
+ "http://www.example2.com",
+ "http://www.example2.com",
+ 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(
+ "http://www.example3.com",
+ "http://www.example3.com",
+ 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");
+});