summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/browser/browser_deleteLoginsBackup.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/test/browser/browser_deleteLoginsBackup.js')
-rw-r--r--toolkit/components/passwordmgr/test/browser/browser_deleteLoginsBackup.js282
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..a122f52845
--- /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.
+ */
+
+ChromeUtils.defineESModuleGetters(this, {
+ FXA_PWDMGR_HOST: "resource://gre/modules/FxAccountsCommon.sys.mjs",
+ FXA_PWDMGR_REALM: "resource://gre/modules/FxAccountsCommon.sys.mjs",
+});
+
+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);
+});