diff options
Diffstat (limited to 'browser/components/aboutlogins/tests/unit')
3 files changed, 356 insertions, 0 deletions
diff --git a/browser/components/aboutlogins/tests/unit/head.js b/browser/components/aboutlogins/tests/unit/head.js new file mode 100644 index 0000000000..938e06e3c0 --- /dev/null +++ b/browser/components/aboutlogins/tests/unit/head.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { LoginTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/LoginTestUtils.sys.mjs" +); +const { LoginHelper } = ChromeUtils.importESModule( + "resource://gre/modules/LoginHelper.sys.mjs" +); + +const TestData = LoginTestUtils.testData; +const newPropertyBag = LoginHelper.newPropertyBag; + +/** + * All the tests are implemented with add_task, this starts them automatically. + */ +function run_test() { + do_get_profile(); + run_next_test(); +} diff --git a/browser/components/aboutlogins/tests/unit/test_getPotentialBreachesByLoginGUID.js b/browser/components/aboutlogins/tests/unit/test_getPotentialBreachesByLoginGUID.js new file mode 100644 index 0000000000..a868572a6a --- /dev/null +++ b/browser/components/aboutlogins/tests/unit/test_getPotentialBreachesByLoginGUID.js @@ -0,0 +1,327 @@ +/** + * Test LoginBreaches.getPotentialBreachesByLoginGUID + */ + +"use strict"; + +const { RemoteSettings } = ChromeUtils.importESModule( + "resource://services-settings/remote-settings.sys.mjs" +); + +// Initializing BrowserGlue requires a profile on Windows. +do_get_profile(); + +const gBrowserGlue = Cc["@mozilla.org/browser/browserglue;1"].getService( + Ci.nsIObserver +); + +ChromeUtils.defineESModuleGetters(this, { + LoginBreaches: "resource:///modules/LoginBreaches.sys.mjs", +}); + +const TEST_BREACHES = [ + { + AddedDate: "2018-12-20T23:56:26Z", + BreachDate: "2018-12-16", + Domain: "breached.com", + Name: "Breached", + PwnCount: 1643100, + DataClasses: ["Email addresses", "Usernames", "Passwords", "IP addresses"], + _status: "synced", + id: "047940fe-d2fd-4314-b636-b4a952ee0043", + last_modified: "1541615610052", + schema: "1541615609018", + }, + { + AddedDate: "2018-12-20T23:56:26Z", + BreachDate: "2018-12-16", + Domain: "breached-subdomain.host.com", + Name: "Only a Sub-Domain was Breached", + PwnCount: 2754200, + DataClasses: ["Email addresses", "Usernames", "Passwords", "IP addresses"], + _status: "synced", + id: "047940fe-d2fd-4314-b636-b4a952ee0044", + last_modified: "1541615610052", + schema: "1541615609018", + }, + { + AddedDate: "2018-12-20T23:56:26Z", + BreachDate: "2018-12-16", + Domain: "breached-site-without-passwords.com", + Name: "Breached Site without passwords", + PwnCount: 987654, + DataClasses: ["Email addresses", "Usernames", "IP addresses"], + _status: "synced", + id: "047940fe-d2fd-4314-b636-b4a952ee0045", + last_modified: "1541615610052", + schema: "1541615609018", + }, +]; + +const CRASHING_URI_LOGIN = LoginTestUtils.testData.formLogin({ + origin: "chrome://grwatcher", + formActionOrigin: "https://www.example.com", + username: "username", + password: "password", + timePasswordChanged: new Date("2018-12-15").getTime(), +}); +const NOT_BREACHED_LOGIN = LoginTestUtils.testData.formLogin({ + origin: "https://www.example.com", + formActionOrigin: "https://www.example.com", + username: "username", + password: "password", + timePasswordChanged: new Date("2018-12-15").getTime(), +}); +const BREACHED_LOGIN = LoginTestUtils.testData.formLogin({ + origin: "https://www.breached.com", + formActionOrigin: "https://www.breached.com", + username: "username", + password: "password", + timePasswordChanged: new Date("2018-12-15").getTime(), +}); +const NOT_BREACHED_SUBDOMAIN_LOGIN = LoginTestUtils.testData.formLogin({ + origin: "https://not-breached-subdomain.host.com", + formActionOrigin: "https://not-breached-subdomain.host.com", + username: "username", + password: "password", +}); +const BREACHED_SUBDOMAIN_LOGIN = LoginTestUtils.testData.formLogin({ + origin: "https://breached-subdomain.host.com", + formActionOrigin: "https://breached-subdomain.host.com", + username: "username", + password: "password", + timePasswordChanged: new Date("2018-12-15").getTime(), +}); +const LOGIN_FOR_BREACHED_SITE_WITHOUT_PASSWORDS = + LoginTestUtils.testData.formLogin({ + origin: "https://breached-site-without-passwords.com", + formActionOrigin: "https://breached-site-without-passwords.com", + username: "username", + password: "password", + timePasswordChanged: new Date("2018-12-15").getTime(), + }); +const LOGIN_WITH_NON_STANDARD_URI = LoginTestUtils.testData.formLogin({ + origin: "someApp://random/path/to/login", + formActionOrigin: "someApp://random/path/to/login", + username: "username", + password: "password", + timePasswordChanged: new Date("2018-12-15").getTime(), +}); + +add_task(async function test_notBreachedLogin() { + await Services.logins.addLoginAsync(NOT_BREACHED_LOGIN); + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [NOT_BREACHED_LOGIN], + TEST_BREACHES + ); + Assert.strictEqual( + breachesByLoginGUID.size, + 0, + "Should be 0 breached logins." + ); +}); + +add_task(async function test_breachedLogin() { + await Services.logins.addLoginAsync(BREACHED_LOGIN); + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [NOT_BREACHED_LOGIN, BREACHED_LOGIN], + TEST_BREACHES + ); + Assert.strictEqual( + breachesByLoginGUID.size, + 1, + "Should be 1 breached login: " + BREACHED_LOGIN.origin + ); + Assert.strictEqual( + breachesByLoginGUID.get(BREACHED_LOGIN.guid).breachAlertURL, + "https://monitor.firefox.com/breach-details/Breached?utm_source=firefox-desktop&utm_medium=referral&utm_campaign=about-logins&utm_content=about-logins", + "Breach alert link should be equal to the breachAlertURL" + ); +}); + +add_task(async function test_breachedLoginAfterCrashingUriLogin() { + await Services.logins.addLoginAsync(CRASHING_URI_LOGIN); + + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [CRASHING_URI_LOGIN, BREACHED_LOGIN], + TEST_BREACHES + ); + Assert.strictEqual( + breachesByLoginGUID.size, + 1, + "Should be 1 breached login: " + BREACHED_LOGIN.origin + ); + Assert.strictEqual( + breachesByLoginGUID.get(BREACHED_LOGIN.guid).breachAlertURL, + "https://monitor.firefox.com/breach-details/Breached?utm_source=firefox-desktop&utm_medium=referral&utm_campaign=about-logins&utm_content=about-logins", + "Breach alert link should be equal to the breachAlertURL" + ); +}); + +add_task(async function test_notBreachedSubdomain() { + await Services.logins.addLoginAsync(NOT_BREACHED_SUBDOMAIN_LOGIN); + + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [NOT_BREACHED_LOGIN, NOT_BREACHED_SUBDOMAIN_LOGIN], + TEST_BREACHES + ); + Assert.strictEqual( + breachesByLoginGUID.size, + 0, + "Should be 0 breached logins." + ); +}); + +add_task(async function test_breachedSubdomain() { + await Services.logins.addLoginAsync(BREACHED_SUBDOMAIN_LOGIN); + + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [NOT_BREACHED_SUBDOMAIN_LOGIN, BREACHED_SUBDOMAIN_LOGIN], + TEST_BREACHES + ); + Assert.strictEqual( + breachesByLoginGUID.size, + 1, + "Should be 1 breached login: " + BREACHED_SUBDOMAIN_LOGIN.origin + ); +}); + +add_task(async function test_breachedSiteWithoutPasswords() { + await Services.logins.addLoginAsync( + LOGIN_FOR_BREACHED_SITE_WITHOUT_PASSWORDS + ); + + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [LOGIN_FOR_BREACHED_SITE_WITHOUT_PASSWORDS], + TEST_BREACHES + ); + Assert.strictEqual( + breachesByLoginGUID.size, + 0, + "Should be 0 breached login: " + + LOGIN_FOR_BREACHED_SITE_WITHOUT_PASSWORDS.origin + ); +}); + +add_task(async function test_breachAlertHiddenAfterDismissal() { + BREACHED_LOGIN.guid = "{d2de5ac1-4de6-e544-a7af-1f75abcba92b}"; + + await Services.logins.initializationPromise; + const storageJSON = Services.logins.wrappedJSObject._storage.wrappedJSObject; + + storageJSON.recordBreachAlertDismissal(BREACHED_LOGIN.guid); + + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [BREACHED_LOGIN, NOT_BREACHED_LOGIN], + TEST_BREACHES + ); + Assert.strictEqual( + breachesByLoginGUID.size, + 0, + "Should be 0 breached logins after dismissal: " + BREACHED_LOGIN.origin + ); + + info("Clear login storage"); + Services.logins.removeAllUserFacingLogins(); + + const breachesByLoginGUID2 = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [BREACHED_LOGIN, NOT_BREACHED_LOGIN], + TEST_BREACHES + ); + Assert.strictEqual( + breachesByLoginGUID2.size, + 1, + "Breached login should re-appear after clearing storage: " + + BREACHED_LOGIN.origin + ); +}); + +add_task(async function test_newBreachAfterDismissal() { + TEST_BREACHES[0].AddedDate = new Date().toISOString(); + + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [BREACHED_LOGIN, NOT_BREACHED_LOGIN], + TEST_BREACHES + ); + + Assert.strictEqual( + breachesByLoginGUID.size, + 1, + "Should be 1 breached login after new breach following the dismissal of a previous breach: " + + BREACHED_LOGIN.origin + ); +}); + +add_task(async function test_ExceptionsThrownByNonStandardURIsAreCaught() { + await Services.logins.addLoginAsync(LOGIN_WITH_NON_STANDARD_URI); + + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID( + [LOGIN_WITH_NON_STANDARD_URI, BREACHED_LOGIN], + TEST_BREACHES + ); + + Assert.strictEqual( + breachesByLoginGUID.size, + 1, + "Exceptions thrown by logins with non-standard URIs should be caught." + ); +}); + +add_task(async function test_setBreachesFromRemoteSettingsSync() { + const login = NOT_BREACHED_SUBDOMAIN_LOGIN; + const nowExampleIsInBreachedRecords = [ + { + AddedDate: "2018-12-20T23:56:26Z", + BreachDate: "2018-12-16", + Domain: "not-breached-subdomain.host.com", + Name: "not-breached-subdomain.host.com is now breached!", + PwnCount: 1643100, + DataClasses: [ + "Email addresses", + "Usernames", + "Passwords", + "IP addresses", + ], + _status: "synced", + id: "047940fe-d2fd-4314-b636-b4a952ee0044", + last_modified: "1541615610052", + schema: "1541615609018", + }, + ]; + async function emitSync() { + await RemoteSettings(LoginBreaches.REMOTE_SETTINGS_COLLECTION).emit( + "sync", + { data: { current: nowExampleIsInBreachedRecords } } + ); + } + + const beforeSyncBreachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID([login]); + Assert.strictEqual( + beforeSyncBreachesByLoginGUID.size, + 0, + "Should be 0 breached login before not-breached-subdomain.host.com is added to fxmonitor-breaches collection and synced: " + ); + gBrowserGlue.observe(null, "browser-glue-test", "add-breaches-sync-handler"); + const db = RemoteSettings(LoginBreaches.REMOTE_SETTINGS_COLLECTION).db; + await db.importChanges({}, Date.now(), [nowExampleIsInBreachedRecords[0]]); + await emitSync(); + + const breachesByLoginGUID = + await LoginBreaches.getPotentialBreachesByLoginGUID([login]); + Assert.strictEqual( + breachesByLoginGUID.size, + 1, + "Should be 1 breached login after not-breached-subdomain.host.com is added to fxmonitor-breaches collection and synced: " + ); +}); diff --git a/browser/components/aboutlogins/tests/unit/xpcshell.ini b/browser/components/aboutlogins/tests/unit/xpcshell.ini new file mode 100644 index 0000000000..e827d6d688 --- /dev/null +++ b/browser/components/aboutlogins/tests/unit/xpcshell.ini @@ -0,0 +1,7 @@ +[DEFAULT] +skip-if = toolkit == 'android' # bug 1730213 +head = head.js +firefox-appdir = browser + +[test_getPotentialBreachesByLoginGUID.js] +tags = remote-settings |