diff options
Diffstat (limited to 'netwerk/cookie/test/unit')
-rw-r--r-- | netwerk/cookie/test/unit/test_baseDomain_publicsuffix.js | 105 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_bug1155169.js | 96 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_bug1321912.js | 99 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_bug643051.js | 43 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_eviction.js | 199 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_getCookieSince.js | 72 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_migrateCookieLifetimePref.js | 65 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_parser_0001.js | 32 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_parser_0019.js | 32 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_rawSameSite.js | 125 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_schemeMap.js | 216 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/test_timestamp_fixup.js | 130 | ||||
-rw-r--r-- | netwerk/cookie/test/unit/xpcshell.toml | 26 |
13 files changed, 1240 insertions, 0 deletions
diff --git a/netwerk/cookie/test/unit/test_baseDomain_publicsuffix.js b/netwerk/cookie/test/unit/test_baseDomain_publicsuffix.js new file mode 100644 index 0000000000..94f01b778e --- /dev/null +++ b/netwerk/cookie/test/unit/test_baseDomain_publicsuffix.js @@ -0,0 +1,105 @@ +"use strict"; + +add_task(async () => { + const HOST = "www.bbc.co.uk"; + Assert.equal( + Services.eTLD.getBaseDomainFromHost(HOST), + "bbc.co.uk", + "Sanity check: HOST is an eTLD + 1 with subdomain" + ); + + const tests = [ + { + // Correct baseDomain: eTLD + 1. + baseDomain: "bbc.co.uk", + name: "originally_bbc_co_uk", + }, + { + // Incorrect baseDomain: Part of public suffix list. + baseDomain: "uk", + name: "originally_uk", + }, + { + // Incorrect baseDomain: Part of public suffix list. + baseDomain: "co.uk", + name: "originally_co_uk", + }, + { + // Incorrect baseDomain: eTLD + 2. + baseDomain: "www.bbc.co.uk", + name: "originally_www_bbc_co_uk", + }, + ]; + + do_get_profile(); + + let dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + dbFile.append("cookies.sqlite"); + let conn = Services.storage.openDatabase(dbFile); + + conn.schemaVersion = 10; + conn.executeSimpleSQL("DROP TABLE IF EXISTS moz_cookies"); + conn.executeSimpleSQL( + "CREATE TABLE moz_cookies (" + + "id INTEGER PRIMARY KEY, " + + "baseDomain TEXT, " + + "originAttributes TEXT NOT NULL DEFAULT '', " + + "name TEXT, " + + "value TEXT, " + + "host TEXT, " + + "path TEXT, " + + "expiry INTEGER, " + + "lastAccessed INTEGER, " + + "creationTime INTEGER, " + + "isSecure INTEGER, " + + "isHttpOnly INTEGER, " + + "inBrowserElement INTEGER DEFAULT 0, " + + "sameSite INTEGER DEFAULT 0, " + + "rawSameSite INTEGER DEFAULT 0, " + + "CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)" + + ")" + ); + + function addCookie(baseDomain, host, name) { + conn.executeSimpleSQL( + "INSERT INTO moz_cookies(" + + "baseDomain, host, name, value, path, expiry, " + + "lastAccessed, creationTime, isSecure, isHttpOnly) VALUES (" + + `'${baseDomain}', '${host}', '${name}', 'thevalue', '/', ` + + (Date.now() + 3600000) + + "," + + Date.now() + + "," + + Date.now() + + ", 1, 1)" + ); + } + + // Prepare the database. + for (let { baseDomain, name } of tests) { + addCookie(baseDomain, HOST, name); + } + // Domain cookies are not supported for IP addresses. + addCookie("127.0.0.1", ".127.0.0.1", "invalid_host"); + conn.close(); + + let cs = Services.cookies; + + // Count excludes the invalid_host cookie. + Assert.equal(cs.cookies.length, tests.length, "Expected number of cookies"); + + // Check whether the database has the expected value, + // despite the incorrect baseDomain. + for (let { name } of tests) { + Assert.ok( + cs.cookieExists(HOST, "/", name, {}), + "Should find cookie with name: " + name + ); + } + + Assert.equal( + cs.cookieExists("127.0.0.1", "/", "invalid_host", {}), + false, + "Should ignore database row with invalid host name" + ); +}); diff --git a/netwerk/cookie/test/unit/test_bug1155169.js b/netwerk/cookie/test/unit/test_bug1155169.js new file mode 100644 index 0000000000..2bf8bd768d --- /dev/null +++ b/netwerk/cookie/test/unit/test_bug1155169.js @@ -0,0 +1,96 @@ +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); + +const URI = Services.io.newURI("http://example.org/"); + +const { COOKIE_CHANGED, COOKIE_ADDED } = Ci.nsICookieNotification; + +function run_test() { + // Allow all cookies. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + + // Clear cookies. + Services.cookies.removeAll(); + + // Add a new cookie. + setCookie("foo=bar", { + type: COOKIE_ADDED, + isSession: true, + isSecure: false, + isHttpOnly: false, + }); + + // Update cookie with isHttpOnly=true. + setCookie("foo=bar; HttpOnly", { + type: COOKIE_CHANGED, + isSession: true, + isSecure: false, + isHttpOnly: true, + }); + + // Update cookie with isSecure=true. + setCookie("foo=bar; Secure", { + type: COOKIE_CHANGED, + isSession: true, + isSecure: true, + isHttpOnly: false, + }); + + // Update cookie with isSession=false. + let expiry = new Date(); + expiry.setUTCFullYear(expiry.getUTCFullYear() + 2); + setCookie(`foo=bar; Expires=${expiry.toGMTString()}`, { + type: COOKIE_CHANGED, + isSession: false, + isSecure: false, + isHttpOnly: false, + }); + + // Reset cookie. + setCookie("foo=bar", { + type: COOKIE_CHANGED, + isSession: true, + isSecure: false, + isHttpOnly: false, + }); +} + +function setCookie(value, expected) { + function setCookieInternal(valueInternal, expectedInternal = null) { + function observer(subject) { + if (!expectedInternal) { + do_throw("no notification expected"); + return; + } + + let notification = subject.QueryInterface(Ci.nsICookieNotification); + + // Check we saw the right notification. + Assert.equal(notification.action, expectedInternal.type); + + // Check cookie details. + let cookie = notification.cookie.QueryInterface(Ci.nsICookie); + Assert.equal(cookie.isSession, expectedInternal.isSession); + Assert.equal(cookie.isSecure, expectedInternal.isSecure); + Assert.equal(cookie.isHttpOnly, expectedInternal.isHttpOnly); + } + + Services.obs.addObserver(observer, "cookie-changed"); + + let channel = NetUtil.newChannel({ + uri: URI, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, + }); + + Services.cookies.setCookieStringFromHttp(URI, valueInternal, channel); + Services.obs.removeObserver(observer, "cookie-changed"); + } + + // Check that updating/inserting the cookie works. + setCookieInternal(value, expected); + + // Check that we ignore identical cookies. + setCookieInternal(value); +} diff --git a/netwerk/cookie/test/unit/test_bug1321912.js b/netwerk/cookie/test/unit/test_bug1321912.js new file mode 100644 index 0000000000..fd24f15bbf --- /dev/null +++ b/netwerk/cookie/test/unit/test_bug1321912.js @@ -0,0 +1,99 @@ +do_get_profile(); +const dirSvc = Services.dirsvc; + +let dbFile = dirSvc.get("ProfD", Ci.nsIFile); +dbFile.append("cookies.sqlite"); + +let storage = Services.storage; +let properties = Cc["@mozilla.org/hash-property-bag;1"].createInstance( + Ci.nsIWritablePropertyBag +); +properties.setProperty("shared", true); +let conn = storage.openDatabase(dbFile); + +// Write the schema v7 to the database. +conn.schemaVersion = 7; +conn.executeSimpleSQL( + "CREATE TABLE moz_cookies (" + + "id INTEGER PRIMARY KEY, " + + "baseDomain TEXT, " + + "originAttributes TEXT NOT NULL DEFAULT '', " + + "name TEXT, " + + "value TEXT, " + + "host TEXT, " + + "path TEXT, " + + "expiry INTEGER, " + + "lastAccessed INTEGER, " + + "creationTime INTEGER, " + + "isSecure INTEGER, " + + "isHttpOnly INTEGER, " + + "appId INTEGER DEFAULT 0, " + + "inBrowserElement INTEGER DEFAULT 0, " + + "CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)" + + ")" +); +conn.executeSimpleSQL( + "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain, " + + "originAttributes)" +); + +conn.executeSimpleSQL("PRAGMA synchronous = OFF"); +conn.executeSimpleSQL("PRAGMA journal_mode = WAL"); +conn.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16"); + +let now = Date.now(); +conn.executeSimpleSQL( + "INSERT INTO moz_cookies(" + + "baseDomain, host, name, value, path, expiry, " + + "lastAccessed, creationTime, isSecure, isHttpOnly) VALUES (" + + "'foo.com', '.foo.com', 'foo', 'bar=baz', '/', " + + now + + ", " + + now + + ", " + + now + + ", 1, 1)" +); + +// Now start the cookie service, and then check the fields in the table. +// Get sessionCookies to wait for the initialization in cookie thread +Services.cookies.sessionCookies; + +Assert.equal(conn.schemaVersion, 13); +let stmt = conn.createStatement( + "SELECT sql FROM sqlite_master " + + "WHERE type = 'table' AND " + + " name = 'moz_cookies'" +); +try { + Assert.ok(stmt.executeStep()); + let sql = stmt.getString(0); + Assert.equal(sql.indexOf("appId"), -1); +} finally { + stmt.finalize(); +} + +stmt = conn.createStatement( + "SELECT * FROM moz_cookies " + + "WHERE host = '.foo.com' AND " + + " name = 'foo' AND " + + " value = 'bar=baz' AND " + + " path = '/' AND " + + " expiry = " + + now + + " AND " + + " lastAccessed = " + + now + + " AND " + + " creationTime = " + + now + + " AND " + + " isSecure = 1 AND " + + " isHttpOnly = 1" +); +try { + Assert.ok(stmt.executeStep()); +} finally { + stmt.finalize(); +} +conn.close(); diff --git a/netwerk/cookie/test/unit/test_bug643051.js b/netwerk/cookie/test/unit/test_bug643051.js new file mode 100644 index 0000000000..35b37a5889 --- /dev/null +++ b/netwerk/cookie/test/unit/test_bug643051.js @@ -0,0 +1,43 @@ +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); +const { CookieXPCShellUtils } = ChromeUtils.importESModule( + "resource://testing-common/CookieXPCShellUtils.sys.mjs" +); + +CookieXPCShellUtils.init(this); +CookieXPCShellUtils.createServer({ hosts: ["example.net"] }); + +add_task(async () => { + Services.prefs.setBoolPref("dom.security.https_first", false); + + // Allow all cookies. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + let uri = NetUtil.newURI("http://example.org/"); + let channel = NetUtil.newChannel({ + uri, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, + }); + + let set = "foo=bar\nbaz=foo"; + let expected = "foo=bar; baz=foo"; + Services.cookies.setCookieStringFromHttp(uri, set, channel); + + let actual = Services.cookies.getCookieStringFromHttp(uri, channel); + Assert.equal(actual, expected); + + await CookieXPCShellUtils.setCookieToDocument("http://example.net/", set); + actual = await CookieXPCShellUtils.getCookieStringFromDocument( + "http://example.net/" + ); + + expected = "foo=bar"; + Assert.equal(actual, expected); + Services.prefs.clearUserPref("dom.security.https_first"); +}); diff --git a/netwerk/cookie/test/unit/test_eviction.js b/netwerk/cookie/test/unit/test_eviction.js new file mode 100644 index 0000000000..8c0073a107 --- /dev/null +++ b/netwerk/cookie/test/unit/test_eviction.js @@ -0,0 +1,199 @@ +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); + +const BASE_HOST = "example.org"; + +const { CookieXPCShellUtils } = ChromeUtils.importESModule( + "resource://testing-common/CookieXPCShellUtils.sys.mjs" +); + +CookieXPCShellUtils.init(this); +CookieXPCShellUtils.createServer({ hosts: ["example.org"] }); + +add_task(async function test_basic_eviction() { + do_get_profile(); + + Services.prefs.setIntPref("network.cookie.staleThreshold", 0); + Services.prefs.setIntPref("network.cookie.quotaPerHost", 2); + Services.prefs.setIntPref("network.cookie.maxPerHost", 5); + + // We don't want to have CookieJarSettings blocking this test. + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + const BASE_URI = Services.io.newURI("http://" + BASE_HOST); + const FOO_PATH = Services.io.newURI("http://" + BASE_HOST + "/foo/"); + const BAR_PATH = Services.io.newURI("http://" + BASE_HOST + "/bar/"); + + await setCookie("session_foo_path_1", null, "/foo", null, FOO_PATH); + await setCookie("session_foo_path_2", null, "/foo", null, FOO_PATH); + await setCookie("session_foo_path_3", null, "/foo", null, FOO_PATH); + await setCookie("session_foo_path_4", null, "/foo", null, FOO_PATH); + await setCookie("session_foo_path_5", null, "/foo", null, FOO_PATH); + verifyCookies( + [ + "session_foo_path_1", + "session_foo_path_2", + "session_foo_path_3", + "session_foo_path_4", + "session_foo_path_5", + ], + BASE_URI + ); + + // Check if cookies are evicted by creation time. + await setCookie("session_foo_path_6", null, "/foo", null, FOO_PATH); + verifyCookies( + ["session_foo_path_4", "session_foo_path_5", "session_foo_path_6"], + BASE_URI + ); + + await setCookie("session_bar_path_1", null, "/bar", null, BAR_PATH); + await setCookie("session_bar_path_2", null, "/bar", null, BAR_PATH); + + verifyCookies( + [ + "session_foo_path_4", + "session_foo_path_5", + "session_foo_path_6", + "session_bar_path_1", + "session_bar_path_2", + ], + BASE_URI + ); + + // Check if cookies are evicted by last accessed time. + await CookieXPCShellUtils.getCookieStringFromDocument(FOO_PATH.spec); + + await setCookie("session_foo_path_7", null, "/foo", null, FOO_PATH); + verifyCookies( + ["session_foo_path_5", "session_foo_path_6", "session_foo_path_7"], + BASE_URI + ); + + const EXPIRED_TIME = 3; + + await setCookie( + "non_session_expired_foo_path_1", + null, + "/foo", + EXPIRED_TIME, + FOO_PATH + ); + await setCookie( + "non_session_expired_foo_path_2", + null, + "/foo", + EXPIRED_TIME, + FOO_PATH + ); + verifyCookies( + [ + "session_foo_path_5", + "session_foo_path_6", + "session_foo_path_7", + "non_session_expired_foo_path_1", + "non_session_expired_foo_path_2", + ], + BASE_URI + ); + + // Check if expired cookies are evicted first. + await new Promise(resolve => do_timeout(EXPIRED_TIME * 1000, resolve)); + await setCookie("session_foo_path_8", null, "/foo", null, FOO_PATH); + verifyCookies( + ["session_foo_path_6", "session_foo_path_7", "session_foo_path_8"], + BASE_URI + ); + + Services.cookies.removeAll(); +}); + +// Verify that the given cookie names exist, and are ordered from least to most recently accessed +function verifyCookies(names, uri) { + Assert.equal(Services.cookies.countCookiesFromHost(uri.host), names.length); + let actual_cookies = []; + for (let cookie of Services.cookies.getCookiesFromHost(uri.host, {})) { + actual_cookies.push(cookie); + } + if (names.length != actual_cookies.length) { + let left = names.filter(function (n) { + return ( + actual_cookies.findIndex(function (c) { + return c.name == n; + }) == -1 + ); + }); + let right = actual_cookies + .filter(function (c) { + return ( + names.findIndex(function (n) { + return c.name == n; + }) == -1 + ); + }) + .map(function (c) { + return c.name; + }); + if (left.length) { + info("unexpected cookies: " + left); + } + if (right.length) { + info("expected cookies: " + right); + } + } + Assert.equal(names.length, actual_cookies.length); + actual_cookies.sort(function (a, b) { + if (a.lastAccessed < b.lastAccessed) { + return -1; + } + if (a.lastAccessed > b.lastAccessed) { + return 1; + } + return 0; + }); + for (var i = 0; i < names.length; i++) { + Assert.equal(names[i], actual_cookies[i].name); + Assert.equal(names[i].startsWith("session"), actual_cookies[i].isSession); + } +} + +var lastValue = 0; +function setCookie(name, domain, path, maxAge, url) { + let value = name + "=" + ++lastValue; + var s = "setting cookie " + value; + if (domain) { + value += "; Domain=" + domain; + s += " (d=" + domain + ")"; + } + if (path) { + value += "; Path=" + path; + s += " (p=" + path + ")"; + } + if (maxAge) { + value += "; Max-Age=" + maxAge; + s += " (non-session)"; + } else { + s += " (session)"; + } + s += " for " + url.spec; + info(s); + + let channel = NetUtil.newChannel({ + uri: url, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, + }); + + Services.cookies.setCookieStringFromHttp(url, value, channel); + + return new Promise(function (resolve) { + // Windows XP has low precision timestamps that cause our cookie eviction + // algorithm to produce different results from other platforms. We work around + // this by ensuring that there's a clear gap between each cookie update. + do_timeout(10, resolve); + }); +} diff --git a/netwerk/cookie/test/unit/test_getCookieSince.js b/netwerk/cookie/test/unit/test_getCookieSince.js new file mode 100644 index 0000000000..e58624b6a1 --- /dev/null +++ b/netwerk/cookie/test/unit/test_getCookieSince.js @@ -0,0 +1,72 @@ +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); + +function setCookie(name, url) { + let value = `${name}=${Math.random()}; Path=/; Max-Age=1000; sameSite=none; Secure`; + info(`Setting cookie ${value} for ${url.spec}`); + + let channel = NetUtil.newChannel({ + uri: url, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, + }); + + Services.cookies.setCookieStringFromHttp(url, value, channel); +} + +async function sleep() { + await new Promise(resolve => do_timeout(1000, resolve)); +} + +function checkSorting(cookies) { + for (let i = 1; i < cookies.length; ++i) { + Assert.greater( + cookies[i].creationTime, + cookies[i - 1].creationTime, + "Cookie " + cookies[i].name + ); + } +} + +add_task(async function () { + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + + await setCookie("A", Services.io.newURI("https://example.com/A/")); + await sleep(); + + await setCookie("B", Services.io.newURI("https://foo.bar/B/")); + await sleep(); + + await setCookie("C", Services.io.newURI("https://example.org/C/")); + await sleep(); + + await setCookie("D", Services.io.newURI("https://example.com/D/")); + await sleep(); + + Assert.equal(Services.cookies.cookies.length, 4, "Cookie check"); + + const cookies = Services.cookies.getCookiesSince(0); + Assert.equal(cookies.length, 4, "We retrieve all the 4 cookies"); + checkSorting(cookies); + + let someCookies = Services.cookies.getCookiesSince( + cookies[0].creationTime + 1 + ); + Assert.equal(someCookies.length, 3, "We retrieve some cookies"); + checkSorting(someCookies); + + someCookies = Services.cookies.getCookiesSince(cookies[1].creationTime + 1); + Assert.equal(someCookies.length, 2, "We retrieve some cookies"); + checkSorting(someCookies); + + someCookies = Services.cookies.getCookiesSince(cookies[2].creationTime + 1); + Assert.equal(someCookies.length, 1, "We retrieve some cookies"); + checkSorting(someCookies); + + someCookies = Services.cookies.getCookiesSince(cookies[3].creationTime + 1); + Assert.equal(someCookies.length, 0, "We retrieve some cookies"); +}); diff --git a/netwerk/cookie/test/unit/test_migrateCookieLifetimePref.js b/netwerk/cookie/test/unit/test_migrateCookieLifetimePref.js new file mode 100644 index 0000000000..088a909709 --- /dev/null +++ b/netwerk/cookie/test/unit/test_migrateCookieLifetimePref.js @@ -0,0 +1,65 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + Tests that + - the migration code runs, + - the sanitize on shutdown prefs for profiles with the network.cookie.lifetimePolicy enabled are set to true, + - the previous settings for clearOnShutdown prefs will not be applied due to sanitizeOnShutdown being disabled + - the network.cookie.lifetimePolicy is disabled afterwards. +*/ +add_task(async function migrateSanitizationPrefsClearCleaningPrefs() { + // Former network.cookie.lifetimePolicy values ACCEPT_SESSION/ACCEPT_NORMALLY are not available anymore + // 2 = ACCEPT_SESSION + Services.prefs.setIntPref("network.cookie.lifetimePolicy", 2); + Services.prefs.setBoolPref("privacy.sanitize.sanitizeOnShutdown", false); + Services.prefs.setBoolPref("privacy.clearOnShutdown.cache", false); + Services.prefs.setBoolPref("privacy.clearOnShutdown.cookies", false); + Services.prefs.setBoolPref("privacy.clearOnShutdown.offlineApps", false); + Services.prefs.setBoolPref("privacy.clearOnShutdown.downloads", true); + Services.prefs.setBoolPref("privacy.clearOnShutdown.sessions", true); + + // The migration code is called in cookieService::Init + Services.cookies; + + // Former network.cookie.lifetimePolicy values ACCEPT_SESSION/ACCEPT_NORMALLY are not available anymore + // 0 = ACCEPT_NORMALLY + Assert.equal( + Services.prefs.getIntPref("network.cookie.lifetimePolicy", 0), + 0, + "Cookie lifetime policy is off" + ); + + Assert.ok( + Services.prefs.getBoolPref("privacy.sanitize.sanitizeOnShutdown"), + "Sanitize on shutdown is set" + ); + + Assert.ok( + Services.prefs.getBoolPref("privacy.clearOnShutdown.cookies"), + "Clearing cookies on shutdown is selected" + ); + + Assert.ok( + Services.prefs.getBoolPref("privacy.clearOnShutdown.cache"), + "Clearing cache on shutdown is still selected" + ); + + Assert.ok( + Services.prefs.getBoolPref("privacy.clearOnShutdown.offlineApps"), + "Clearing offline apps on shutdown is selected" + ); + + Assert.ok( + !Services.prefs.getBoolPref("privacy.clearOnShutdown.downloads"), + "Clearing downloads on shutdown is not set anymore" + ); + Assert.ok( + !Services.prefs.getBoolPref("privacy.clearOnShutdown.sessions"), + "Clearing active logins on shutdown is not set anymore" + ); + + Services.prefs.resetPrefs(); + + delete Services.cookies; +}); diff --git a/netwerk/cookie/test/unit/test_parser_0001.js b/netwerk/cookie/test/unit/test_parser_0001.js new file mode 100644 index 0000000000..acc2e919ef --- /dev/null +++ b/netwerk/cookie/test/unit/test_parser_0001.js @@ -0,0 +1,32 @@ +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); + +function inChildProcess() { + return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; +} + +function run_test() { + // Allow all cookies if the pref service is available in this process. + if (!inChildProcess()) { + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + } + + let uri = NetUtil.newURI("http://example.org/"); + let channel = NetUtil.newChannel({ + uri, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, + }); + + let set = "foo=bar"; + Services.cookies.setCookieStringFromHttp(uri, set, channel); + + let expected = "foo=bar"; + let actual = Services.cookies.getCookieStringFromHttp(uri, channel); + Assert.equal(actual, expected); +} diff --git a/netwerk/cookie/test/unit/test_parser_0019.js b/netwerk/cookie/test/unit/test_parser_0019.js new file mode 100644 index 0000000000..7ba0d4ef79 --- /dev/null +++ b/netwerk/cookie/test/unit/test_parser_0019.js @@ -0,0 +1,32 @@ +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); + +function inChildProcess() { + return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; +} + +function run_test() { + // Allow all cookies if the pref service is available in this process. + if (!inChildProcess()) { + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + } + + let uri = NetUtil.newURI("http://example.org/"); + let channel = NetUtil.newChannel({ + uri, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, + }); + + let set = "foo=b;max-age=3600, c=d;path=/"; + Services.cookies.setCookieStringFromHttp(uri, set, channel); + + let expected = "foo=b"; + let actual = Services.cookies.getCookieStringFromHttp(uri, channel); + Assert.equal(actual, expected); +} diff --git a/netwerk/cookie/test/unit/test_rawSameSite.js b/netwerk/cookie/test/unit/test_rawSameSite.js new file mode 100644 index 0000000000..dc739ef852 --- /dev/null +++ b/netwerk/cookie/test/unit/test_rawSameSite.js @@ -0,0 +1,125 @@ +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); + +function inChildProcess() { + return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; +} + +add_task(async _ => { + do_get_profile(); + + let dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + dbFile.append("cookies.sqlite"); + + let storage = Services.storage; + let properties = Cc["@mozilla.org/hash-property-bag;1"].createInstance( + Ci.nsIWritablePropertyBag + ); + properties.setProperty("shared", true); + let conn = storage.openDatabase(dbFile); + + conn.schemaVersion = 9; + conn.executeSimpleSQL("DROP TABLE IF EXISTS moz_cookies"); + conn.executeSimpleSQL( + "CREATE TABLE moz_cookies (" + + "id INTEGER PRIMARY KEY, " + + "baseDomain TEXT, " + + "originAttributes TEXT NOT NULL DEFAULT '', " + + "name TEXT, " + + "value TEXT, " + + "host TEXT, " + + "path TEXT, " + + "expiry INTEGER, " + + "lastAccessed INTEGER, " + + "creationTime INTEGER, " + + "isSecure INTEGER, " + + "isHttpOnly INTEGER, " + + "inBrowserElement INTEGER DEFAULT 0, " + + "sameSite INTEGER DEFAULT 0, " + + "CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)" + + ")" + ); + conn.close(); + + // Allow all cookies if the pref service is available in this process. + if (!inChildProcess()) { + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + Services.prefs.setBoolPref("network.cookie.sameSite.laxByDefault", true); + Services.prefs.setBoolPref( + "network.cookie.sameSite.noneRequiresSecure", + true + ); + } + + let uri = NetUtil.newURI("http://example.org/"); + + let principal = Services.scriptSecurityManager.createContentPrincipal( + uri, + {} + ); + + let channel = NetUtil.newChannel({ + uri, + loadingPrincipal: principal, + securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER, + }); + + let tests = [ + { + cookie: "foo=b;max-age=3600, c=d;path=/; sameSite=strict", + sameSite: 2, + rawSameSite: 2, + }, + { + cookie: "foo=b;max-age=3600, c=d;path=/; sameSite=lax", + sameSite: 1, + rawSameSite: 1, + }, + { cookie: "foo=b;max-age=3600, c=d;path=/", sameSite: 1, rawSameSite: 0 }, + ]; + + for (let i = 0; i < tests.length; ++i) { + let test = tests[i]; + + let promise = new Promise(resolve => { + function observer(subject, topic, data) { + Services.obs.removeObserver(observer, "cookie-saved-on-disk"); + resolve(); + } + + Services.obs.addObserver(observer, "cookie-saved-on-disk"); + }); + + Services.cookies.setCookieStringFromHttp(uri, test.cookie, channel); + + await promise; + + conn = storage.openDatabase(dbFile); + Assert.equal(conn.schemaVersion, 13); + + let stmt = conn.createStatement( + "SELECT sameSite, rawSameSite FROM moz_cookies" + ); + + let success = stmt.executeStep(); + Assert.ok(success); + + let sameSite = stmt.getInt32(0); + let rawSameSite = stmt.getInt32(1); + stmt.finalize(); + + Assert.equal(sameSite, test.sameSite); + Assert.equal(rawSameSite, test.rawSameSite); + + Services.cookies.removeAll(); + + stmt.finalize(); + conn.close(); + } +}); diff --git a/netwerk/cookie/test/unit/test_schemeMap.js b/netwerk/cookie/test/unit/test_schemeMap.js new file mode 100644 index 0000000000..041c24033a --- /dev/null +++ b/netwerk/cookie/test/unit/test_schemeMap.js @@ -0,0 +1,216 @@ +const { NetUtil } = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); + +function inChildProcess() { + return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; +} + +const { CookieXPCShellUtils } = ChromeUtils.importESModule( + "resource://testing-common/CookieXPCShellUtils.sys.mjs" +); + +let CookieXPCShellUtilsInitialized = false; +function maybeInitializeCookieXPCShellUtils() { + if (!CookieXPCShellUtilsInitialized) { + CookieXPCShellUtilsInitialized = true; + CookieXPCShellUtils.init(this); + + CookieXPCShellUtils.createServer({ hosts: ["example.org"] }); + } +} + +// Don't pick up default permissions from profile. +Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); + +add_task(async _ => { + do_get_profile(); + + // Allow all cookies if the pref service is available in this process. + if (!inChildProcess()) { + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + } + + info("Let's set a cookie from HTTP example.org"); + + let uri = NetUtil.newURI("http://example.org/"); + let principal = Services.scriptSecurityManager.createContentPrincipal( + uri, + {} + ); + let channel = NetUtil.newChannel({ + uri, + loadingPrincipal: principal, + securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER, + }); + + Services.cookies.setCookieStringFromHttp(uri, "a=b; sameSite=lax", channel); + + let cookies = Services.cookies.getCookiesFromHost("example.org", {}); + Assert.equal(cookies.length, 1, "We expect 1 cookie only"); + + Assert.equal(cookies[0].schemeMap, Ci.nsICookie.SCHEME_HTTP, "HTTP Scheme"); + + info("Let's set a cookie from HTTPS example.org"); + + uri = NetUtil.newURI("https://example.org/"); + principal = Services.scriptSecurityManager.createContentPrincipal(uri, {}); + channel = NetUtil.newChannel({ + uri, + loadingPrincipal: principal, + securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER, + }); + + Services.cookies.setCookieStringFromHttp(uri, "a=b; sameSite=lax", channel); + + cookies = Services.cookies.getCookiesFromHost("example.org", {}); + Assert.equal(cookies.length, 1, "We expect 1 cookie only"); + + Assert.equal( + cookies[0].schemeMap, + Ci.nsICookie.SCHEME_HTTP | Ci.nsICookie.SCHEME_HTTPS, + "HTTP + HTTPS Schemes" + ); + + Services.cookies.removeAll(); +}); + +[true, false].forEach(schemefulComparison => { + add_task(async () => { + do_get_profile(); + Services.prefs.setBoolPref("dom.security.https_first", false); + + maybeInitializeCookieXPCShellUtils(); + + // Allow all cookies if the pref service is available in this process. + if (!inChildProcess()) { + Services.prefs.setBoolPref( + "network.cookie.sameSite.schemeful", + schemefulComparison + ); + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + } + + info( + `Testing schemefulSameSite=${schemefulComparison}. Let's set a cookie from HTTPS example.org` + ); + + let https_uri = NetUtil.newURI("https://example.org/"); + let https_principal = Services.scriptSecurityManager.createContentPrincipal( + https_uri, + {} + ); + let same_site_channel = NetUtil.newChannel({ + uri: https_uri, + loadingPrincipal: https_principal, + securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER, + }); + + Services.cookies.setCookieStringFromHttp( + https_uri, + "a=b; sameSite=lax", + same_site_channel + ); + + let cookies = Services.cookies.getCookieStringFromHttp( + https_uri, + same_site_channel + ); + Assert.equal(cookies, "a=b", "Cookies match"); + + let http_uri = NetUtil.newURI("http://example.org/"); + let http_principal = Services.scriptSecurityManager.createContentPrincipal( + http_uri, + {} + ); + let cross_site_channel = NetUtil.newChannel({ + uri: https_uri, + loadingPrincipal: http_principal, + securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER, + }); + + cookies = Services.cookies.getCookieStringFromHttp( + http_uri, + cross_site_channel + ); + if (schemefulComparison) { + Assert.equal(cookies, "", "No http(s) cookie for different scheme!"); + } else { + Assert.equal(cookies, "a=b", "http(s) Cookie even for differentscheme!"); + } + + // SameSite cookies are included via document.domain + cookies = await CookieXPCShellUtils.getCookieStringFromDocument( + http_uri.spec + ); + Assert.equal(cookies, "a=b", "document.cookie even for different scheme!"); + + Services.cookies.removeAll(); + Services.prefs.clearUserPref("dom.security.https_first"); + }); +}); + +add_task(async _ => { + do_get_profile(); + Services.prefs.setBoolPref("dom.security.https_first", false); + + // Allow all cookies if the pref service is available in this process. + if (!inChildProcess()) { + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + } + + info("Let's set a cookie without scheme"); + Services.cookies.add( + "example.org", + "/", + "a", + "b", + false, + false, + false, + Math.floor(Date.now() / 1000 + 1000), + {}, + Ci.nsICookie.SAMESITE_LAX, + Ci.nsICookie.SCHEME_UNSET + ); + + let cookies = Services.cookies.getCookiesFromHost("example.org", {}); + Assert.equal(cookies.length, 1, "We expect 1 cookie only"); + Assert.equal(cookies[0].schemeMap, Ci.nsICookie.SCHEME_UNSET, "Unset scheme"); + + ["https", "http"].forEach(scheme => { + let uri = NetUtil.newURI(scheme + "://example.org/"); + let principal = Services.scriptSecurityManager.createContentPrincipal( + uri, + {} + ); + let channel = NetUtil.newChannel({ + uri, + loadingPrincipal: principal, + securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER, + }); + + cookies = Services.cookies.getCookieStringFromHttp(uri, channel); + Assert.equal(cookies, "a=b", "Cookie for unset scheme"); + }); + + Services.cookies.removeAll(); + Services.prefs.clearUserPref("dom.security.https_first"); +}); diff --git a/netwerk/cookie/test/unit/test_timestamp_fixup.js b/netwerk/cookie/test/unit/test_timestamp_fixup.js new file mode 100644 index 0000000000..a6e9642ad7 --- /dev/null +++ b/netwerk/cookie/test/unit/test_timestamp_fixup.js @@ -0,0 +1,130 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const { AppConstants } = ChromeUtils.importESModule( + "resource://gre/modules/AppConstants.sys.mjs" +); + +const USEC_PER_SEC = 1000 * 1000; +const ONE_DAY = 60 * 60 * 24 * USEC_PER_SEC; +const ONE_YEAR = ONE_DAY * 365; +const LAST_ACCESSED_DIFF = 10 * ONE_YEAR; +const CREATION_DIFF = 100 * ONE_YEAR; + +function initDB(conn, now) { + // Write the schema v7 to the database. + conn.schemaVersion = 7; + conn.executeSimpleSQL( + "CREATE TABLE moz_cookies (" + + "id INTEGER PRIMARY KEY, " + + "baseDomain TEXT, " + + "originAttributes TEXT NOT NULL DEFAULT '', " + + "name TEXT, " + + "value TEXT, " + + "host TEXT, " + + "path TEXT, " + + "expiry INTEGER, " + + "lastAccessed INTEGER, " + + "creationTime INTEGER, " + + "isSecure INTEGER, " + + "isHttpOnly INTEGER, " + + "appId INTEGER DEFAULT 0, " + + "inBrowserElement INTEGER DEFAULT 0, " + + "CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)" + + ")" + ); + conn.executeSimpleSQL( + "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain, " + + "originAttributes)" + ); + + conn.executeSimpleSQL("PRAGMA synchronous = OFF"); + conn.executeSimpleSQL("PRAGMA journal_mode = WAL"); + conn.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16"); + + conn.executeSimpleSQL( + `INSERT INTO moz_cookies(baseDomain, host, name, value, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly) + VALUES ('foo.com', '.foo.com', 'foo', 'bar=baz', '/', + ${now + ONE_DAY}, ${now + LAST_ACCESSED_DIFF} , ${ + now + CREATION_DIFF + } , 1, 1)` + ); +} + +add_task(async function test_timestamp_fixup() { + let now = Date.now() * 1000; // date in microseconds + Services.prefs.setBoolPref("network.cookie.fixup_on_db_load", true); + do_get_profile(); + let dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + dbFile.append("cookies.sqlite"); + let conn = Services.storage.openDatabase(dbFile); + initDB(conn, now); + + if (AppConstants.platform != "android") { + Services.fog.initializeFOG(); + } + Services.fog.testResetFOG(); + + // Now start the cookie service, and then check the fields in the table. + // Get sessionCookies to wait for the initialization in cookie thread + Assert.lessOrEqual( + Math.floor(Services.cookies.cookies[0].creationTime / 1000), + now + ); + Assert.equal(conn.schemaVersion, 13); + + Assert.equal( + await Glean.networking.cookieTimestampFixedCount.creationTime.testGetValue(), + 1, + "One fixup of creation time" + ); + Assert.equal( + await Glean.networking.cookieTimestampFixedCount.lastAccessed.testGetValue(), + 1, + "One fixup of lastAccessed" + ); + { + let { values } = + await Glean.networking.cookieCreationFixupDiff.testGetValue(); + info(JSON.stringify(values)); + let keys = Object.keys(values).splice(-2, 2); + Assert.equal(keys.length, 2, "There should be two entries in telemetry"); + Assert.equal(values[keys[0]], 1, "First entry should have value 1"); + Assert.equal(values[keys[1]], 0, "Second entry should have value 0"); + const creationDiffInSeconds = CREATION_DIFF / USEC_PER_SEC; + Assert.lessOrEqual( + parseInt(keys[0]), + creationDiffInSeconds, + "The bucket should be smaller than time diff" + ); + Assert.lessOrEqual( + creationDiffInSeconds, + parseInt(keys[1]), + "The next bucket should be larger than time diff" + ); + } + + { + let { values } = + await Glean.networking.cookieAccessFixupDiff.testGetValue(); + info(JSON.stringify(values)); + let keys = Object.keys(values).splice(-2, 2); + Assert.equal(keys.length, 2, "There should be two entries in telemetry"); + Assert.equal(values[keys[0]], 1, "First entry should have value 1"); + Assert.equal(values[keys[1]], 0, "Second entry should have value 0"); + info(now); + const lastAccessedDiffInSeconds = LAST_ACCESSED_DIFF / USEC_PER_SEC; + Assert.lessOrEqual( + parseInt(keys[0]), + lastAccessedDiffInSeconds, + "The bucket should be smaller than time diff" + ); + Assert.lessOrEqual( + lastAccessedDiffInSeconds, + parseInt(keys[1]), + "The next bucket should be larger than time diff" + ); + } + + conn.close(); +}); diff --git a/netwerk/cookie/test/unit/xpcshell.toml b/netwerk/cookie/test/unit/xpcshell.toml new file mode 100644 index 0000000000..694d3cb847 --- /dev/null +++ b/netwerk/cookie/test/unit/xpcshell.toml @@ -0,0 +1,26 @@ +[DEFAULT] +head = "" + +["test_baseDomain_publicsuffix.js"] + +["test_bug643051.js"] + +["test_bug1155169.js"] + +["test_bug1321912.js"] + +["test_eviction.js"] + +["test_getCookieSince.js"] + +["test_migrateCookieLifetimePref.js"] + +["test_parser_0001.js"] + +["test_parser_0019.js"] + +["test_rawSameSite.js"] + +["test_schemeMap.js"] + +["test_timestamp_fixup.js"] |