From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../passwordmgr/test/unit/test_dedupeLogins.js | 411 +++++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 toolkit/components/passwordmgr/test/unit/test_dedupeLogins.js (limited to 'toolkit/components/passwordmgr/test/unit/test_dedupeLogins.js') diff --git a/toolkit/components/passwordmgr/test/unit/test_dedupeLogins.js b/toolkit/components/passwordmgr/test/unit/test_dedupeLogins.js new file mode 100644 index 0000000000..f0305e3c69 --- /dev/null +++ b/toolkit/components/passwordmgr/test/unit/test_dedupeLogins.js @@ -0,0 +1,411 @@ +/** + * Test LoginHelper.dedupeLogins + */ + +"use strict"; + +const DOMAIN1_HTTP_TO_HTTP_U1_P1 = TestData.formLogin({ + timePasswordChanged: 3000, + timeLastUsed: 2000, +}); +const DOMAIN1_HTTP_TO_HTTP_U1_P2 = TestData.formLogin({ + password: "password two", +}); +const DOMAIN2_HTTP_TO_HTTP_U2_P2 = TestData.formLogin({ + origin: "http://www4.example.com", + formActionOrigin: "http://www4.example.com", + password: "password two", + username: "username two", +}); + +const DOMAIN1_HTTPS_TO_HTTP_U1_P1 = TestData.formLogin({ + formActionOrigin: "http://www.example.com", + origin: "https://www3.example.com", + timePasswordChanged: 4000, + timeLastUsed: 1000, +}); +const DOMAIN1_HTTPS_TO_HTTPS_U1_P1 = TestData.formLogin({ + formActionOrigin: "https://www.example.com", + origin: "https://www3.example.com", + timePasswordChanged: 4000, + timeLastUsed: 1000, +}); + +const DOMAIN1_HTTPS_TO_EMPTY_U1_P1 = TestData.formLogin({ + formActionOrigin: "", + origin: "https://www3.example.com", +}); +const DOMAIN1_HTTPS_TO_EMPTYU_P1 = TestData.formLogin({ + origin: "https://www3.example.com", + username: "", +}); +const DOMAIN1_HTTP_AUTH = TestData.authLogin({ + origin: "http://www3.example.com", +}); +const DOMAIN1_HTTPS_AUTH = TestData.authLogin({ + origin: "https://www3.example.com", +}); +const DOMAIN1_HTTPS_LOGIN = TestData.formLogin({ + origin: "https://www3.example.com", + formActionOrigin: "https://www3.example.com", +}); +const DOMAIN1_HTTP_LOGIN = TestData.formLogin({ + origin: "http://www3.example.com", + formActionOrigin: "http://www3.example.com", +}); +const DOMAIN1_HTTPS_NONSTANDARD_PORT1 = TestData.formLogin({ + origin: "https://www3.example.com:8001", + formActionOrigin: "https://www3.example.com:8001", +}); +const DOMAIN1_HTTPS_NONSTANDARD_PORT2 = TestData.formLogin({ + origin: "https://www3.example.com:8008", + formActionOrigin: "https://www3.example.com:8008", +}); +const DOMAIN2_HTTPS_LOGIN = TestData.formLogin({ + origin: "https://www4.example.com", + formActionOrigin: "https://www4.example.com", +}); +const DOMAIN2_HTTPS_LOGIN_NEWER = TestData.formLogin({ + origin: "https://www4.example.com", + formActionOrigin: "https://www4.example.com", + timePasswordChanged: 4000, + timeLastUsed: 4000, +}); +const DOMAIN2_HTTPS_TO_HTTPS_U2_P2 = TestData.formLogin({ + origin: "https://www4.example.com", + formActionOrigin: "https://www4.example.com", + password: "password two", + username: "username two", +}); + +add_task(function test_dedupeLogins() { + // [description, expectedOutput, dedupe arg. 0, dedupe arg 1, ...] + let testcases = [ + [ + "exact dupes", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + [], // force no resolveBy logic to test behavior of preferring the first.. + ], + [ + "default uniqueKeys is un + pw", + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P2], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P2], + undefined, + [], + ], + [ + "same usernames, different passwords, dedupe username only", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P2], + ["username"], + [], + ], + [ + "same un+pw, different scheme", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + undefined, + [], + ], + [ + "same un+pw, different scheme, reverse order", + [DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + [], + ], + [ + "same un+pw, different scheme, include origin", + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + ["origin", "username", "password"], + [], + ], + [ + "empty username is not deduped with non-empty", + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_EMPTYU_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_EMPTYU_P1], + undefined, + [], + ], + [ + "empty username is deduped with same passwords", + [DOMAIN1_HTTPS_TO_EMPTYU_P1], + [DOMAIN1_HTTPS_TO_EMPTYU_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + ["password"], + [], + ], + [ + "mix of form and HTTP auth", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTP_AUTH], + undefined, + [], + ], + ]; + + for (let tc of testcases) { + let description = tc.shift(); + let expected = tc.shift(); + let actual = LoginHelper.dedupeLogins(...tc); + Assert.strictEqual(actual.length, expected.length, `Check: ${description}`); + for (let [i, login] of expected.entries()) { + Assert.strictEqual(actual[i], login, `Check index ${i}`); + } + } +}); + +add_task(async function test_dedupeLogins_resolveBy() { + Assert.ok( + DOMAIN1_HTTP_TO_HTTP_U1_P1.timeLastUsed > + DOMAIN1_HTTPS_TO_HTTP_U1_P1.timeLastUsed, + "Sanity check timeLastUsed difference" + ); + Assert.ok( + DOMAIN1_HTTP_TO_HTTP_U1_P1.timePasswordChanged < + DOMAIN1_HTTPS_TO_HTTP_U1_P1.timePasswordChanged, + "Sanity check timePasswordChanged difference" + ); + Assert.ok( + DOMAIN1_HTTPS_LOGIN.timePasswordChanged < + DOMAIN2_HTTPS_LOGIN_NEWER.timePasswordChanged, + "Sanity check timePasswordChanged difference" + ); + + let testcases = [ + [ + "default resolveBy is timeLastUsed", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + ], + [ + "default resolveBy is timeLastUsed, reversed input", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + ], + [ + "resolveBy timeLastUsed + timePasswordChanged", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + ["timeLastUsed", "timePasswordChanged"], + ], + [ + "resolveBy timeLastUsed + timePasswordChanged, reversed input", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + undefined, + ["timeLastUsed", "timePasswordChanged"], + ], + [ + "resolveBy timePasswordChanged", + [DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + ["timePasswordChanged"], + ], + [ + "resolveBy timePasswordChanged, reversed", + [DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + undefined, + ["timePasswordChanged"], + ], + [ + "resolveBy timePasswordChanged + timeLastUsed", + [DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + ["timePasswordChanged", "timeLastUsed"], + ], + [ + "resolveBy timePasswordChanged + timeLastUsed, reversed", + [DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + undefined, + ["timePasswordChanged", "timeLastUsed"], + ], + [ + "resolveBy scheme + timePasswordChanged, prefer HTTP", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + ["scheme", "timePasswordChanged"], + DOMAIN1_HTTP_TO_HTTP_U1_P1.origin, + ], + [ + "resolveBy scheme + timePasswordChanged, prefer HTTP, reversed input", + [DOMAIN1_HTTP_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + undefined, + ["scheme", "timePasswordChanged"], + DOMAIN1_HTTP_TO_HTTP_U1_P1.origin, + ], + [ + "resolveBy scheme + timePasswordChanged, prefer HTTPS", + [DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + ["scheme", "timePasswordChanged"], + DOMAIN1_HTTPS_TO_HTTP_U1_P1.origin, + ], + [ + "resolveBy scheme + timePasswordChanged, prefer HTTPS, reversed input", + [DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTP_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_HTTP_U1_P1], + undefined, + ["scheme", "timePasswordChanged"], + DOMAIN1_HTTPS_TO_HTTP_U1_P1.origin, + ], + [ + "resolveBy scheme HTTP auth", + [DOMAIN1_HTTPS_AUTH], + [DOMAIN1_HTTP_AUTH, DOMAIN1_HTTPS_AUTH], + undefined, + ["scheme"], + DOMAIN1_HTTPS_AUTH.origin, + ], + [ + "resolveBy scheme HTTP auth, reversed input", + [DOMAIN1_HTTPS_AUTH], + [DOMAIN1_HTTPS_AUTH, DOMAIN1_HTTP_AUTH], + undefined, + ["scheme"], + DOMAIN1_HTTPS_AUTH.origin, + ], + [ + "resolveBy scheme, empty form submit URL", + [DOMAIN1_HTTPS_TO_HTTP_U1_P1], + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTPS_TO_EMPTY_U1_P1], + undefined, + ["scheme"], + DOMAIN1_HTTPS_TO_HTTP_U1_P1.origin, + ], + [ + "resolveBy subdomain, different subdomains, same login, subdomain1 preferred", + [DOMAIN1_HTTPS_LOGIN], + [DOMAIN1_HTTPS_LOGIN, DOMAIN2_HTTPS_LOGIN], + undefined, + ["subdomain"], + DOMAIN1_HTTPS_LOGIN.origin, + ], + [ + "resolveBy subdomain, different subdomains, same login, subdomain2 preferred", + [DOMAIN2_HTTPS_LOGIN], + [DOMAIN1_HTTPS_LOGIN, DOMAIN2_HTTPS_LOGIN], + undefined, + ["subdomain"], + DOMAIN2_HTTPS_LOGIN.origin, + ], + [ + "resolveBy subdomain+timePasswordChanged, different subdomains, same login, subdomain1 preferred", + [DOMAIN1_HTTPS_LOGIN], + [DOMAIN1_HTTPS_LOGIN, DOMAIN2_HTTPS_LOGIN_NEWER], + undefined, + ["subdomain", "timePasswordChanged"], + DOMAIN1_HTTPS_LOGIN.origin, + ], + [ + "resolveBy subdomain, same subdomain, different schemes", + [DOMAIN1_HTTPS_LOGIN], + [DOMAIN1_HTTPS_LOGIN, DOMAIN1_HTTP_LOGIN], + undefined, + ["subdomain"], + DOMAIN1_HTTPS_LOGIN.origin, + ], + [ + "resolveBy subdomain, same subdomain, different ports", + [DOMAIN1_HTTPS_LOGIN], + [ + DOMAIN1_HTTPS_LOGIN, + DOMAIN1_HTTPS_NONSTANDARD_PORT1, + DOMAIN1_HTTPS_NONSTANDARD_PORT2, + ], + undefined, + ["subdomain"], + DOMAIN1_HTTPS_LOGIN.origin, + ], + [ + "resolveBy subdomain, same subdomain, different schemes, different ports", + [DOMAIN1_HTTPS_LOGIN], + [ + DOMAIN1_HTTPS_LOGIN, + DOMAIN1_HTTPS_NONSTANDARD_PORT1, + DOMAIN1_HTTPS_NONSTANDARD_PORT2, + ], + undefined, + ["subdomain"], + DOMAIN1_HTTPS_AUTH.origin, + ], + [ + "resolveBy matching searchAndDedupeLogins, prefer domain matches then https: scheme over http:", + // expected: + [DOMAIN1_HTTPS_TO_HTTPS_U1_P1, DOMAIN2_HTTPS_TO_HTTPS_U2_P2], + // logins: + [ + DOMAIN1_HTTP_TO_HTTP_U1_P1, + DOMAIN1_HTTPS_TO_HTTPS_U1_P1, + DOMAIN2_HTTP_TO_HTTP_U2_P2, + DOMAIN2_HTTPS_TO_HTTPS_U2_P2, + ], + // uniqueKeys: + undefined, + // resolveBy: + ["subdomain", "actionOrigin", "scheme", "timePasswordChanged"], + // preferredOrigin: + DOMAIN1_HTTPS_TO_HTTPS_U1_P1.origin, + ], + ]; + + for (let tc of testcases) { + let description = tc.shift(); + let expected = tc.shift(); + let actual = LoginHelper.dedupeLogins(...tc); + info(`'${description}' actual:\n ${JSON.stringify(actual, null, 2)}`); + Assert.strictEqual(actual.length, expected.length, `Check: ${description}`); + for (let [i, login] of expected.entries()) { + Assert.strictEqual(actual[i], login, `Check index ${i}`); + } + } +}); + +add_task(async function test_dedupeLogins_preferredOriginMissing() { + let testcases = [ + [ + "resolveBy scheme + timePasswordChanged, missing preferredOrigin", + /preferredOrigin/, + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + ["scheme", "timePasswordChanged"], + ], + [ + "resolveBy timePasswordChanged + scheme, missing preferredOrigin", + /preferredOrigin/, + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + ["timePasswordChanged", "scheme"], + ], + [ + "resolveBy scheme + timePasswordChanged, empty preferredOrigin", + /preferredOrigin/, + [DOMAIN1_HTTPS_TO_HTTP_U1_P1, DOMAIN1_HTTP_TO_HTTP_U1_P1], + undefined, + ["scheme", "timePasswordChanged"], + "", + ], + ]; + + for (let tc of testcases) { + let description = tc.shift(); + let expectedException = tc.shift(); + Assert.throws( + () => { + LoginHelper.dedupeLogins(...tc); + }, + expectedException, + `Check: ${description}` + ); + } +}); -- cgit v1.2.3