diff options
Diffstat (limited to '')
-rw-r--r-- | toolkit/components/passwordmgr/test/browser/browser_deleteLoginsBackup.js | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/browser/browser_deleteLoginsBackup.js b/toolkit/components/passwordmgr/test/browser/browser_deleteLoginsBackup.js new file mode 100644 index 0000000000..608329f482 --- /dev/null +++ b/toolkit/components/passwordmgr/test/browser/browser_deleteLoginsBackup.js @@ -0,0 +1,282 @@ +/** + * Test that logins backup is deleted as expected when logins are deleted. + */ + +XPCOMUtils.defineLazyModuleGetters(this, { + FXA_PWDMGR_HOST: "resource://gre/modules/FxAccountsCommon.js", + FXA_PWDMGR_REALM: "resource://gre/modules/FxAccountsCommon.js", +}); + +const nsLoginInfo = new Components.Constructor( + "@mozilla.org/login-manager/loginInfo;1", + Ci.nsILoginInfo, + "init" +); + +const login1 = new nsLoginInfo( + "https://example.com", + "https://example.com", + null, + "notifyu1", + "notifyp1", + "user", + "pass" +); +const login2 = new nsLoginInfo( + "https://example.com", + "https://example.com", + null, + "", + "notifyp1", + "", + "pass" +); + +const fxaKey = new nsLoginInfo( + FXA_PWDMGR_HOST, + null, + FXA_PWDMGR_REALM, + "foo@bar.com", + "pass2", + "", + "" +); + +const loginStorePath = PathUtils.join(PathUtils.profileDir, "logins.json"); +const loginBackupPath = PathUtils.join( + PathUtils.profileDir, + "logins-backup.json" +); + +async function waitForBackupUpdate() { + return new Promise(resolve => { + Services.obs.addObserver(function observer(subject, topic) { + Services.obs.removeObserver(observer, "logins-backup-updated"); + resolve(); + }, "logins-backup-updated"); + }); +} + +async function loginStoreExists() { + return TestUtils.waitForCondition(() => IOUtils.exists(loginStorePath)); +} + +async function loginBackupExists() { + return TestUtils.waitForCondition(() => IOUtils.exists(loginBackupPath)); +} + +async function loginBackupDeleted() { + return TestUtils.waitForCondition( + async () => !(await IOUtils.exists(loginBackupPath)) + ); +} + +// If a fxa key is stored as a login, test that logins backup is updated to only store +// the fxa key when the last user facing login is deleted. +add_task( + async function test_deleteLoginsBackup_removeAllUserFacingLogins_fxaKey() { + info( + "Testing removeAllUserFacingLogins() case when there is a saved fxa key" + ); + info("Adding two logins: fxa key and one user facing login"); + let storageUpdatePromise = TestUtils.topicObserved( + "password-storage-updated" + ); + await Services.logins.addLoginAsync(login1); + Assert.ok(true, "added login1"); + await loginStoreExists(); + await Services.logins.addLoginAsync(fxaKey); + Assert.ok(true, "added fxaKey"); + await loginBackupExists(); + Assert.ok(true, "logins-backup.json now exists"); + await storageUpdatePromise; + info("Writes to storage are complete for addLogin calls"); + + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + info("Removing all user facing logins"); + Services.logins.removeAllUserFacingLogins(); + await storageUpdatePromise; + info("Writes to storage are complete after removeAllUserFacingLogins call"); + await waitForBackupUpdate(); + Assert.ok( + true, + "logins-backup.json was updated to only store the fxa key, as expected" + ); + + // Clean up. + // Since there is a fxa key left, we need to call removeAllLogins() or removeLogin(fxaKey) + // to remove the fxa key. Otherwise the test will fail in verify mode when trying to add login1 + Services.logins.removeAllLogins(); + await IOUtils.remove(loginStorePath); + } +); + +// Test that logins backup is deleted when Services.logins.removeAllUserFacingLogins() is called. +add_task(async function test_deleteLoginsBackup_removeAllUserFacingLogins() { + // Remove logins.json and logins-backup.json before starting. + info("Testing the removeAllUserFacingLogins() case"); + + await IOUtils.remove(loginStorePath, { ignoreAbsent: true }); + await IOUtils.remove(loginBackupPath, { ignoreAbsent: true }); + + let storageUpdatePromise = TestUtils.topicObserved( + "password-storage-updated" + ); + info("Add a login to create logins.json"); + await Services.logins.addLoginAsync(login1); + await loginStoreExists(); + Assert.ok(true, "logins.json now exists"); + + info("Add a second login to create logins-backup.json"); + await Services.logins.addLoginAsync(login2); + await loginBackupExists(); + info("logins-backup.json now exists"); + + await storageUpdatePromise; + info("Writes to storage are complete for addLogin calls"); + + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + info("Removing all user facing logins"); + Services.logins.removeAllUserFacingLogins(); + + await storageUpdatePromise; + info( + "Writes to storage are complete when removeAllUserFacingLogins() is called" + ); + await loginBackupDeleted(); + info( + "logins-backup.json was deleted as expected when all logins were removed" + ); + + // Clean up. + await IOUtils.remove(loginStorePath); +}); + +// 1. Test that logins backup is deleted when Services.logins.removeAllLogins() is called +// 2. If a FxA key is stored as a login, test that logins backup is deleted when +// Services.logins.removeAllLogins() is called +add_task(async function test_deleteLoginsBackup_removeAllLogins() { + // Remove logins.json and logins-backup.json before starting. + info("Testing the removeAllLogins() case"); + + await IOUtils.remove(loginStorePath, { ignoreAbsent: true }); + await IOUtils.remove(loginBackupPath, { ignoreAbsent: true }); + + let storageUpdatePromise = TestUtils.topicObserved( + "password-storage-updated" + ); + info("Add a login to create logins.json"); + await Services.logins.addLoginAsync(login1); + Assert.ok(true, "added login1"); + await loginStoreExists(); + Assert.ok(true, "logins.json now exists"); + await Services.logins.addLoginAsync(login2); + Assert.ok(true, "added login2"); + await loginBackupExists(); + info("logins-backup.json now exists"); + + await storageUpdatePromise; + info("Writes to storage are complete for addLogin calls"); + + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + info("Removing all logins"); + Services.logins.removeAllLogins(); + + await storageUpdatePromise; + info("Writes to storage are complete when removeAllLogins() is called"); + + await loginBackupDeleted(); + info( + "logins-backup.json was deleted as expected when all logins were removed" + ); + await IOUtils.remove(loginStorePath); + + info("Testing the removeAllLogins() case when FxA key is present"); + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + await Services.logins.addLoginAsync(login1); + await loginStoreExists(); + await Services.logins.addLoginAsync(fxaKey); + await loginBackupExists(); + info("logins-backup.json now exists"); + await storageUpdatePromise; + info("Write to storage are complete for addLogin calls"); + + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + info("Removing all logins, including FxA key"); + Services.logins.removeAllLogins(); + await storageUpdatePromise; + info("Writes to storage are complete after the last removeAllLogins call"); + await loginBackupDeleted(); + info( + "logins-backup.json was deleted when the last logins were removed, as expected" + ); + + // Clean up. + await IOUtils.remove(loginStorePath); +}); + +// 1. Test that logins backup is deleted when the last saved login is removed using +// Services.logins.removeLogin() when no fxa key is saved. +// 2. Test that logins backup is updated when the last saved login is removed using +// Services.logins.removeLogin() when a fxa key is present. +add_task(async function test_deleteLoginsBackup_removeLogin() { + info("Testing the removeLogin() case when there is no saved fxa key"); + info("Adding two logins"); + let storageUpdatePromise = TestUtils.topicObserved( + "password-storage-updated" + ); + await Services.logins.addLoginAsync(login1); + await loginStoreExists(); + await Services.logins.addLoginAsync(login2); + await loginBackupExists(); + info("logins-backup.json now exists"); + + await storageUpdatePromise; + info("Writes to storage are complete for addLogin calls"); + + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + info("Removing one login"); + Services.logins.removeLogin(login1); + await storageUpdatePromise; + info("Writes to storage are complete after one removeLogin call"); + await loginBackupExists(); + + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + info("Removing the last login"); + Services.logins.removeLogin(login2); + await storageUpdatePromise; + info("Writes to storage are complete after the last removeLogin call"); + await loginBackupDeleted(); + info( + "logins-backup.json was deleted as expected when the last saved login was removed" + ); + await IOUtils.remove(loginStorePath); + + info("Testing the removeLogin() case when there is a saved fxa key"); + info("Adding two logins: one user facing and the fxa key"); + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + await Services.logins.addLoginAsync(login1); + await loginStoreExists(); + await Services.logins.addLoginAsync(fxaKey); + await loginBackupExists(); + info("logins-backup.json now exists"); + + await storageUpdatePromise; + info("Writes to storage are complete for addLogin calls"); + + storageUpdatePromise = TestUtils.topicObserved("password-storage-updated"); + let backupUpdate = waitForBackupUpdate(); + Services.logins.removeLogin(login1); + await storageUpdatePromise; + info("Writes to storage are complete after one removeLogin call"); + await backupUpdate; + + await loginBackupExists(); + info("logins-backup.json was updated to contain only the fxa key"); + + // Clean up. + // Since there is a fxa key left, we need to call removeAllLogins() or removeLogin(fxaKey) + // to remove the fxa key. Otherwise the test will fail in verify mode when trying to add login1 + Services.logins.removeAllLogins(); + await IOUtils.remove(loginStorePath); +}); |