Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/**
* Test LoginBreaches.getPotentialBreachesByLoginGUID
*/
"use strict";
const { RemoteSettings } = ChromeUtils.importESModule(
);
// 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({
formActionOrigin: "https://www.example.com",
username: "username",
password: "password",
timePasswordChanged: new Date("2018-12-15").getTime(),
});
const BREACHED_LOGIN = LoginTestUtils.testData.formLogin({
formActionOrigin: "https://www.breached.com",
username: "username",
password: "password",
timePasswordChanged: new Date("2018-12-15").getTime(),
});
const NOT_BREACHED_SUBDOMAIN_LOGIN = LoginTestUtils.testData.formLogin({
username: "username",
password: "password",
});
const BREACHED_SUBDOMAIN_LOGIN = LoginTestUtils.testData.formLogin({
username: "username",
password: "password",
timePasswordChanged: new Date("2018-12-15").getTime(),
});
const LOGIN_FOR_BREACHED_SITE_WITHOUT_PASSWORDS =
LoginTestUtils.testData.formLogin({
username: "username",
password: "password",
timePasswordChanged: new Date("2018-12-15").getTime(),
});
const LOGIN_WITH_NON_STANDARD_URI = LoginTestUtils.testData.formLogin({
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,
"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,
"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;
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: "
);
});