/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ const { PasswordEngine, LoginRec } = ChromeUtils.importESModule( "resource://services-sync/engines/passwords.sys.mjs" ); const { Service } = ChromeUtils.importESModule( "resource://services-sync/service.sys.mjs" ); let engine; let store; let tracker; add_task(async function setup() { await Service.engineManager.register(PasswordEngine); engine = Service.engineManager.get("passwords"); store = engine._store; tracker = engine._tracker; }); add_task(async function test_tracking() { let recordNum = 0; _("Verify we've got an empty tracker to work with."); let changes = await engine.getChangedIDs(); do_check_empty(changes); let exceptionHappened = false; try { await tracker.getChangedIDs(); } catch (ex) { exceptionHappened = true; } ok(exceptionHappened, "tracker does not keep track of changes"); async function createPassword() { _("RECORD NUM: " + recordNum); let record = new LoginRec("passwords", "GUID" + recordNum); record.cleartext = { id: "GUID" + recordNum, hostname: "http://foo.bar.com", formSubmitURL: "http://foo.bar.com", username: "john" + recordNum, password: "smith", usernameField: "username", passwordField: "password", }; recordNum++; let login = store._nsLoginInfoFromRecord(record); await Services.logins.addLoginAsync(login); await tracker.asyncObserver.promiseObserversComplete(); } try { tracker.start(); await createPassword(); changes = await engine.getChangedIDs(); do_check_attribute_count(changes, 1); Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE); Assert.equal(changes.GUID0.counter, 1); Assert.ok(typeof changes.GUID0.modified, "number"); _("Starting twice won't do any harm."); tracker.start(); await createPassword(); changes = await engine.getChangedIDs(); do_check_attribute_count(changes, 2); Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 2); Assert.equal(changes.GUID0.counter, 1); Assert.equal(changes.GUID1.counter, 1); // The tracker doesn't keep track of changes, so 3 changes // should still be returned, but the score is not updated. _("Let's stop tracking again."); tracker.resetScore(); await tracker.stop(); await createPassword(); changes = await engine.getChangedIDs(); do_check_attribute_count(changes, 3); Assert.equal(tracker.score, 0); Assert.equal(changes.GUID0.counter, 1); Assert.equal(changes.GUID1.counter, 1); Assert.equal(changes.GUID2.counter, 1); _("Stopping twice won't do any harm."); await tracker.stop(); await createPassword(); changes = await engine.getChangedIDs(); do_check_attribute_count(changes, 4); Assert.equal(tracker.score, 0); } finally { _("Clean up."); await store.wipe(); tracker.resetScore(); await tracker.stop(); } }); add_task(async function test_onWipe() { _("Verify we've got an empty tracker to work with."); const changes = await engine.getChangedIDs(); do_check_empty(changes); Assert.equal(tracker.score, 0); try { _("A store wipe should increment the score"); tracker.start(); await store.wipe(); await tracker.asyncObserver.promiseObserversComplete(); Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE); } finally { tracker.resetScore(); await tracker.stop(); } }); add_task(async function test_removeAllLogins() { let recordNum = 0; _("Verify that all tracked logins are removed."); // Perform this test twice, the first time where a sync is not performed // between adding and removing items and the second time where a sync is // performed. In the former case, the logins will just be deleted because // they have never been synced, so they won't be detected as changes. In // the latter case, the logins have been synced so they will be marked for // deletion. for (let syncBeforeRemove of [false, true]) { async function createPassword() { _("RECORD NUM: " + recordNum); let record = new LoginRec("passwords", "GUID" + recordNum); record.cleartext = { id: "GUID" + recordNum, hostname: "http://foo.bar.com", formSubmitURL: "http://foo.bar.com", username: "john" + recordNum, password: "smith", usernameField: "username", passwordField: "password", }; recordNum++; let login = store._nsLoginInfoFromRecord(record); await Services.logins.addLoginAsync(login); await tracker.asyncObserver.promiseObserversComplete(); } try { _("Tell tracker to start tracking changes"); tracker.start(); await createPassword(); await createPassword(); let changes = await engine.getChangedIDs(); do_check_attribute_count(changes, 2); Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 2); if (syncBeforeRemove) { let logins = await Services.logins.getAllLogins(); for (let login of logins) { engine.markSynced(login.guid); } } _("Tell sync to remove all logins"); Services.logins.removeAllUserFacingLogins(); await tracker.asyncObserver.promiseObserversComplete(); changes = await engine.getChangedIDs(); do_check_attribute_count(changes, syncBeforeRemove ? 2 : 0); Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 5); let deletedGuids = await engine._store.getAllIDs(); if (syncBeforeRemove) { for (let guid in deletedGuids) { let deletedLogin = await engine._store._getLoginFromGUID(guid); Assert.equal(deletedLogin.hostname, null, "deleted login hostname"); Assert.equal( deletedLogin.formActionOrigin, null, "deleted login formActionOrigin" ); Assert.equal( deletedLogin.formSubmitURL, null, "deleted login formSubmitURL" ); Assert.equal(deletedLogin.httpRealm, null, "deleted login httpRealm"); Assert.equal(deletedLogin.username, null, "deleted login username"); Assert.equal(deletedLogin.password, null, "deleted login password"); Assert.equal( deletedLogin.usernameField, "", "deleted login usernameField" ); Assert.equal( deletedLogin.passwordField, "", "deleted login passwordField" ); Assert.equal( deletedLogin.unknownFields, null, "deleted login unknownFields" ); Assert.equal( deletedLogin.timeCreated, 0, "deleted login timeCreated" ); Assert.equal( deletedLogin.timeLastUsed, 0, "deleted login timeLastUsed" ); Assert.equal(deletedLogin.timesUsed, 0, "deleted login timesUsed"); // These fields are not reset when the login is removed. Assert.ok(deletedLogin.guid.startsWith("GUID"), "deleted login guid"); Assert.equal( deletedLogin.everSynced, true, "deleted login everSynced" ); Assert.equal( deletedLogin.syncCounter, 2, "deleted login syncCounter" ); Assert.ok( deletedLogin.timePasswordChanged > 0, "deleted login timePasswordChanged" ); } } else { Assert.equal( Object.keys(deletedGuids).length, 0, "no logins remain after removeAllUserFacingLogins" ); } } finally { _("Clean up."); await store.wipe(); tracker.resetScore(); await tracker.stop(); } } });