diff options
Diffstat (limited to '')
-rw-r--r-- | toolkit/components/passwordmgr/test/unit/test_logins_metainfo.js | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/unit/test_logins_metainfo.js b/toolkit/components/passwordmgr/test/unit/test_logins_metainfo.js new file mode 100644 index 0000000000..8f31fba02b --- /dev/null +++ b/toolkit/components/passwordmgr/test/unit/test_logins_metainfo.js @@ -0,0 +1,295 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests the handling of nsILoginMetaInfo by methods that add, remove, modify, + * and find logins. + */ + +"use strict"; + +// Globals + +const gLooksLikeUUIDRegex = /^\{\w{8}-\w{4}-\w{4}-\w{4}-\w{12}\}$/; + +/** + * Retrieves the only login among the current data that matches the origin of + * the given nsILoginInfo. In case there is more than one login for the + * origin, the test fails. + */ +function retrieveLoginMatching(aLoginInfo) { + let logins = Services.logins.findLogins(aLoginInfo.origin, "", ""); + Assert.equal(logins.length, 1); + return logins[0].QueryInterface(Ci.nsILoginMetaInfo); +} + +/** + * Checks that the nsILoginInfo and nsILoginMetaInfo properties of two different + * login instances are equal. + */ +function assertMetaInfoEqual(aActual, aExpected) { + Assert.notEqual(aActual, aExpected); + + // Check the nsILoginInfo properties. + Assert.ok(aActual.equals(aExpected)); + + // Check the nsILoginMetaInfo properties. + Assert.equal(aActual.guid, aExpected.guid); + Assert.equal(aActual.timeCreated, aExpected.timeCreated); + Assert.equal(aActual.timeLastUsed, aExpected.timeLastUsed); + Assert.equal(aActual.timePasswordChanged, aExpected.timePasswordChanged); + Assert.equal(aActual.timesUsed, aExpected.timesUsed); +} + +/** + * nsILoginInfo instances with or without nsILoginMetaInfo properties. + */ +let gLoginInfo1; +let gLoginInfo2; +let gLoginInfo3; + +/** + * nsILoginInfo instances reloaded with all the nsILoginMetaInfo properties. + * These are often used to provide the reference values to test against. + */ +let gLoginMetaInfo1; +let gLoginMetaInfo2; +let gLoginMetaInfo3; + +// Tests + +/** + * Prepare the test objects that will be used by the following tests. + */ +add_task(function test_initialize() { + // Use a reference time from ten minutes ago to initialize one instance of + // nsILoginMetaInfo, to test that reference times are updated when needed. + let baseTimeMs = Date.now() - 600000; + + gLoginInfo1 = TestData.formLogin(); + gLoginInfo2 = TestData.formLogin({ + origin: "http://other.example.com", + guid: Services.uuid.generateUUID().toString(), + timeCreated: baseTimeMs, + timeLastUsed: baseTimeMs + 2, + timePasswordChanged: baseTimeMs + 1, + timesUsed: 2, + }); + gLoginInfo3 = TestData.authLogin(); +}); + +/** + * Tests the behavior of addLogin with regard to metadata. The logins added + * here are also used by the following tests. + */ +add_task(async function test_addLogin_metainfo() { + // Add a login without metadata to the database. + await Services.logins.addLoginAsync(gLoginInfo1); + + // The object provided to addLogin should not have been modified. + Assert.equal(gLoginInfo1.guid, null); + Assert.equal(gLoginInfo1.timeCreated, 0); + Assert.equal(gLoginInfo1.timeLastUsed, 0); + Assert.equal(gLoginInfo1.timePasswordChanged, 0); + Assert.equal(gLoginInfo1.timesUsed, 0); + + // A login with valid metadata should have been stored. + gLoginMetaInfo1 = retrieveLoginMatching(gLoginInfo1); + Assert.ok(gLooksLikeUUIDRegex.test(gLoginMetaInfo1.guid)); + let creationTime = gLoginMetaInfo1.timeCreated; + LoginTestUtils.assertTimeIsAboutNow(creationTime); + Assert.equal(gLoginMetaInfo1.timeLastUsed, creationTime); + Assert.equal(gLoginMetaInfo1.timePasswordChanged, creationTime); + Assert.equal(gLoginMetaInfo1.timesUsed, 1); + + // Add a login without metadata to the database. + let originalLogin = gLoginInfo2.clone().QueryInterface(Ci.nsILoginMetaInfo); + await Services.logins.addLoginAsync(gLoginInfo2); + + // The object provided to addLogin should not have been modified. + assertMetaInfoEqual(gLoginInfo2, originalLogin); + + // A login with the provided metadata should have been stored. + gLoginMetaInfo2 = retrieveLoginMatching(gLoginInfo2); + assertMetaInfoEqual(gLoginMetaInfo2, gLoginInfo2); + + // Add an authentication login to the database before continuing. + await Services.logins.addLoginAsync(gLoginInfo3); + gLoginMetaInfo3 = retrieveLoginMatching(gLoginInfo3); + LoginTestUtils.checkLogins([gLoginInfo1, gLoginInfo2, gLoginInfo3]); +}); + +/** + * Tests that adding a login with a duplicate GUID throws an exception. + */ +add_task(async function test_addLogin_metainfo_duplicate() { + let loginInfo = TestData.formLogin({ + origin: "http://duplicate.example.com", + guid: gLoginMetaInfo2.guid, + }); + await Assert.rejects( + Services.logins.addLoginAsync(loginInfo), + /specified GUID already exists/ + ); + + // Verify that no data was stored by the previous call. + LoginTestUtils.checkLogins([gLoginInfo1, gLoginInfo2, gLoginInfo3]); +}); + +/** + * Tests that the existing metadata is not changed when modifyLogin is called + * with an nsILoginInfo argument. + */ +add_task(function test_modifyLogin_nsILoginInfo_metainfo_ignored() { + let newLoginInfo = gLoginInfo1.clone().QueryInterface(Ci.nsILoginMetaInfo); + newLoginInfo.guid = Services.uuid.generateUUID().toString(); + newLoginInfo.timeCreated = Date.now(); + newLoginInfo.timeLastUsed = Date.now(); + newLoginInfo.timePasswordChanged = Date.now(); + newLoginInfo.timesUsed = 12; + Services.logins.modifyLogin(gLoginInfo1, newLoginInfo); + + newLoginInfo = retrieveLoginMatching(gLoginInfo1); + assertMetaInfoEqual(newLoginInfo, gLoginMetaInfo1); +}); + +/** + * Tests the modifyLogin function with an nsIProperyBag argument. + */ +add_task(function test_modifyLogin_nsIProperyBag_metainfo() { + // Use a new reference time that is two minutes from now. + let newTimeMs = Date.now() + 120000; + let newUUIDValue = Services.uuid.generateUUID().toString(); + + // Check that properties are changed as requested. + Services.logins.modifyLogin( + gLoginInfo1, + newPropertyBag({ + guid: newUUIDValue, + timeCreated: newTimeMs, + timeLastUsed: newTimeMs + 2, + timePasswordChanged: newTimeMs + 1, + timesUsed: 2, + }) + ); + + gLoginMetaInfo1 = retrieveLoginMatching(gLoginInfo1); + Assert.equal(gLoginMetaInfo1.guid, newUUIDValue); + Assert.equal(gLoginMetaInfo1.timeCreated, newTimeMs); + Assert.equal(gLoginMetaInfo1.timeLastUsed, newTimeMs + 2); + Assert.equal(gLoginMetaInfo1.timePasswordChanged, newTimeMs + 1); + Assert.equal(gLoginMetaInfo1.timesUsed, 2); + + // Check that timePasswordChanged is updated when changing the password. + let originalLogin = gLoginInfo2.clone().QueryInterface(Ci.nsILoginMetaInfo); + Services.logins.modifyLogin( + gLoginInfo2, + newPropertyBag({ + password: "new password", + }) + ); + gLoginInfo2.password = "new password"; + + gLoginMetaInfo2 = retrieveLoginMatching(gLoginInfo2); + Assert.equal(gLoginMetaInfo2.password, gLoginInfo2.password); + Assert.equal(gLoginMetaInfo2.timeCreated, originalLogin.timeCreated); + Assert.equal(gLoginMetaInfo2.timeLastUsed, originalLogin.timeLastUsed); + LoginTestUtils.assertTimeIsAboutNow(gLoginMetaInfo2.timePasswordChanged); + + // Check that timePasswordChanged is not set to the current time when changing + // the password and specifying a new value for the property at the same time. + Services.logins.modifyLogin( + gLoginInfo2, + newPropertyBag({ + password: "other password", + timePasswordChanged: newTimeMs, + }) + ); + gLoginInfo2.password = "other password"; + + gLoginMetaInfo2 = retrieveLoginMatching(gLoginInfo2); + Assert.equal(gLoginMetaInfo2.password, gLoginInfo2.password); + Assert.equal(gLoginMetaInfo2.timeCreated, originalLogin.timeCreated); + Assert.equal(gLoginMetaInfo2.timeLastUsed, originalLogin.timeLastUsed); + Assert.equal(gLoginMetaInfo2.timePasswordChanged, newTimeMs); + + // Check the special timesUsedIncrement property. + Services.logins.modifyLogin( + gLoginInfo2, + newPropertyBag({ + timesUsedIncrement: 2, + }) + ); + + gLoginMetaInfo2 = retrieveLoginMatching(gLoginInfo2); + Assert.equal(gLoginMetaInfo2.timeCreated, originalLogin.timeCreated); + Assert.equal(gLoginMetaInfo2.timeLastUsed, originalLogin.timeLastUsed); + Assert.equal(gLoginMetaInfo2.timePasswordChanged, newTimeMs); + Assert.equal(gLoginMetaInfo2.timesUsed, 4); +}); + +/** + * Tests that modifying a login to a duplicate GUID throws an exception. + */ +add_task(function test_modifyLogin_nsIProperyBag_metainfo_duplicate() { + Assert.throws( + () => + Services.logins.modifyLogin( + gLoginInfo1, + newPropertyBag({ + guid: gLoginInfo2.guid, + }) + ), + /specified GUID already exists/ + ); + LoginTestUtils.checkLogins([gLoginInfo1, gLoginInfo2, gLoginInfo3]); +}); + +/** + * Tests searching logins using nsILoginMetaInfo properties. + */ +add_task(function test_searchLogins_metainfo() { + // Find by GUID. + let logins = Services.logins.searchLogins( + newPropertyBag({ + guid: gLoginMetaInfo1.guid, + }) + ); + Assert.equal(logins.length, 1); + let foundLogin = logins[0].QueryInterface(Ci.nsILoginMetaInfo); + assertMetaInfoEqual(foundLogin, gLoginMetaInfo1); + + // Find by timestamp. + logins = Services.logins.searchLogins( + newPropertyBag({ + timePasswordChanged: gLoginMetaInfo2.timePasswordChanged, + }) + ); + Assert.equal(logins.length, 1); + foundLogin = logins[0].QueryInterface(Ci.nsILoginMetaInfo); + assertMetaInfoEqual(foundLogin, gLoginMetaInfo2); + + // Find using two properties at the same time. + logins = Services.logins.searchLogins( + newPropertyBag({ + guid: gLoginMetaInfo3.guid, + timePasswordChanged: gLoginMetaInfo3.timePasswordChanged, + }) + ); + Assert.equal(logins.length, 1); + foundLogin = logins[0].QueryInterface(Ci.nsILoginMetaInfo); + assertMetaInfoEqual(foundLogin, gLoginMetaInfo3); +}); + +/** + * Tests that the default nsILoginManagerStorage module attached to the Login + * Manager service is able to save and reload nsILoginMetaInfo properties. + */ +add_task(async function test_storage_metainfo() { + await LoginTestUtils.reloadData(); + LoginTestUtils.checkLogins([gLoginInfo1, gLoginInfo2, gLoginInfo3]); + + assertMetaInfoEqual(retrieveLoginMatching(gLoginInfo1), gLoginMetaInfo1); + assertMetaInfoEqual(retrieveLoginMatching(gLoginInfo2), gLoginMetaInfo2); + assertMetaInfoEqual(retrieveLoginMatching(gLoginInfo3), gLoginMetaInfo3); +}); |