Revert "Bug 1955685 - Improve cookie validation - part 7 - Fix existing tests, r=valentin,webdriver-reviewers,extension-reviewers,settings-reviewers,devtools-reviewers,cookie-reviewers,sessionstore-reviewers,migration-reviewers,backup-reviewers,sthompson,robwu,ochameau" for causing multiple failures
This reverts commit585626d8fc. Revert "Bug 1955685 - Improve cookie validation - part 6 - CookieValidation for web-ext, r=robwu,cookie-reviewers,valentin" This reverts commitb38d308433. Revert "Bug 1955685 - Improve cookie validation - part 5 - 0x20 as invalid chars for cookie names and values r=valentin,cookie-reviewers" This reverts commit3578880f65. Revert "Bug 1955685 - Improve cookie validation - part 4 - expiry validation, r=edgul,cookie-reviewers,valentin" This reverts commit26e16d402f. Revert "Bug 1955685 - Improve cookie validation - part 3 - nsICookieValidation in cookieManager.add, r=edgul,extension-reviewers,settings-reviewers,search-reviewers,devtools-reviewers,cookie-reviewers,sessionstore-reviewers,backup-reviewers,nchevobbe,mconley,Standard8,webdriver-reviewers,whimboo,valentin,sfoster,robwu" This reverts commit433a4d736d. Revert "Bug 1955685 - Improve cookie validation - part 2 - nsICookieValidation in cookieManager.addNative, r=edgul,cookie-reviewers,geckoview-reviewers,nalexander,glandium" This reverts commit818c2c1769. Revert "Bug 1955685 - Improve cookie validation - part 1 - nsICookieValidation, r=edgul,cookie-reviewers" This reverts commit55ad680779.
This commit is contained in:
committed by
amarc@mozilla.com
parent
a4d8da212e
commit
43acd12a3b
@@ -59,7 +59,7 @@ function checkIndexedDB(host, originAttributes) {
|
||||
}
|
||||
|
||||
function createHostCookie(host, originAttributes) {
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
host,
|
||||
"/test",
|
||||
"foo",
|
||||
@@ -69,14 +69,13 @@ function createHostCookie(host, originAttributes) {
|
||||
false,
|
||||
Date.now() + 24000 * 60 * 60,
|
||||
originAttributes,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
is(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
}
|
||||
|
||||
function createDomainCookie(host, originAttributes) {
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"." + host,
|
||||
"/test",
|
||||
"foo",
|
||||
@@ -86,10 +85,9 @@ function createDomainCookie(host, originAttributes) {
|
||||
false,
|
||||
Date.now() + 24000 * 60 * 60,
|
||||
originAttributes,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
is(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
}
|
||||
|
||||
function checkCookie(host, originAttributes) {
|
||||
|
||||
@@ -316,7 +316,7 @@ class BackupTest(MarionetteTestCase):
|
||||
false,
|
||||
Date.now() / 1000 + 1,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
})().then(outerResolve);
|
||||
|
||||
@@ -94,7 +94,7 @@ function addTestCookie(isSessionCookie) {
|
||||
gCookieCounter++;
|
||||
let name = `Cookie name: ${gCookieCounter}`;
|
||||
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
COOKIE_HOST,
|
||||
COOKIE_PATH,
|
||||
name,
|
||||
@@ -104,10 +104,9 @@ function addTestCookie(isSessionCookie) {
|
||||
isSessionCookie,
|
||||
Date.now() / 1000 + 1,
|
||||
COOKIE_ORIGIN_ATTRIBUTES,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ const { FileTestUtils } = ChromeUtils.importESModule(
|
||||
|
||||
add_task(async function test_save_jsonview() {
|
||||
// Create a cookie that will be valid for the given JSON Document
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.org",
|
||||
"/",
|
||||
"cookieKey",
|
||||
@@ -20,12 +20,11 @@ add_task(async function test_save_jsonview() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Date.now() + 24000 * 60 * 60,
|
||||
Number.MAX_SAFE_INTEGER,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_LAX,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
// Set up the download
|
||||
let MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
|
||||
@@ -7,7 +7,7 @@ const ORIGIN_DOMAIN = "browser_policy_clear_blocked_cookies.org";
|
||||
|
||||
add_task(async function setup() {
|
||||
const expiry = Date.now() + 24 * 60 * 60;
|
||||
let cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
HOSTNAME_DOMAIN,
|
||||
"/",
|
||||
"secure",
|
||||
@@ -17,12 +17,10 @@ add_task(async function setup() {
|
||||
false,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
HOSTNAME_DOMAIN,
|
||||
"/",
|
||||
"insecure",
|
||||
@@ -32,12 +30,10 @@ add_task(async function setup() {
|
||||
false,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
ORIGIN_DOMAIN,
|
||||
"/",
|
||||
"secure",
|
||||
@@ -47,12 +43,10 @@ add_task(async function setup() {
|
||||
false,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
ORIGIN_DOMAIN,
|
||||
"/",
|
||||
"insecure",
|
||||
@@ -62,12 +56,10 @@ add_task(async function setup() {
|
||||
false,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.net",
|
||||
"/",
|
||||
"secure",
|
||||
@@ -77,11 +69,9 @@ add_task(async function setup() {
|
||||
false,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
await setupPolicyEngineWithJson({
|
||||
policies: {
|
||||
Cookies: {
|
||||
|
||||
@@ -163,7 +163,7 @@ class TestFirefoxRefresh(MarionetteTestCase):
|
||||
let expireTime = Math.floor(Date.now() / 1000) + 15 * 60;
|
||||
Services.cookies.add(arguments[0], arguments[1], arguments[2], arguments[3],
|
||||
true, false, false, expireTime, {},
|
||||
Ci.nsICookie.SAMESITE_UNSET, Ci.nsICookie.SCHEME_UNSET);
|
||||
Ci.nsICookie.SAMESITE_NONE, Ci.nsICookie.SCHEME_UNSET);
|
||||
""",
|
||||
script_args=(
|
||||
self._cookieHost,
|
||||
|
||||
@@ -190,7 +190,7 @@ add_task(async function () {
|
||||
// Add some test cookies.
|
||||
let uri = Services.io.newURI("https://example.com");
|
||||
let uri2 = Services.io.newURI("https://example.org");
|
||||
let cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
uri.host,
|
||||
uri.pathQueryRef,
|
||||
"test1",
|
||||
@@ -200,12 +200,10 @@ add_task(async function () {
|
||||
false,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
uri.host,
|
||||
uri.pathQueryRef,
|
||||
"test2",
|
||||
@@ -215,12 +213,10 @@ add_task(async function () {
|
||||
false,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
uri2.host,
|
||||
uri2.pathQueryRef,
|
||||
"test1",
|
||||
@@ -230,13 +226,12 @@ add_task(async function () {
|
||||
false,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
// Ensure that private browsing cookies are ignored.
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
uri.host,
|
||||
uri.pathQueryRef,
|
||||
"test3",
|
||||
@@ -246,10 +241,9 @@ add_task(async function () {
|
||||
false,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{ privateBrowsingId: 1 },
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
|
||||
// Get the exact creation date from the cookies (to avoid intermittents
|
||||
// from minimal time differences, since we round up to minutes).
|
||||
|
||||
@@ -47,7 +47,7 @@ async function openTabInUserContext(uri, userContextId) {
|
||||
function simulateGoogleAccountSignIn(originAttributes = {}) {
|
||||
// Manually set the cookie that is present when the client is signed in to a
|
||||
// Google account.
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"accounts.google.com",
|
||||
"",
|
||||
"SID",
|
||||
@@ -57,10 +57,9 @@ function simulateGoogleAccountSignIn(originAttributes = {}) {
|
||||
false,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
originAttributes,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
is(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
}
|
||||
|
||||
add_setup(async function () {
|
||||
|
||||
@@ -81,7 +81,7 @@ const TESTS = [
|
||||
{
|
||||
setUp() {
|
||||
Services.cookies.removeAll();
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"www.bing.com",
|
||||
"/",
|
||||
"SRCHS",
|
||||
@@ -91,10 +91,9 @@ const TESTS = [
|
||||
false,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
},
|
||||
tearDown() {
|
||||
Services.cookies.removeAll();
|
||||
|
||||
@@ -190,7 +190,7 @@ const TESTS = [
|
||||
{
|
||||
setUp() {
|
||||
Services.cookies.removeAll();
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"www.example3.com",
|
||||
"/",
|
||||
"_dummyCookieName",
|
||||
@@ -198,12 +198,11 @@ const TESTS = [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Math.round(Date.now() / 1000) + 10 * 60 * 60,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
},
|
||||
tearDown() {
|
||||
Services.cookies.removeAll();
|
||||
@@ -229,7 +228,45 @@ const TESTS = [
|
||||
{
|
||||
setUp() {
|
||||
Services.cookies.removeAll();
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"www.example3.com",
|
||||
"/",
|
||||
"_dummyCookieName",
|
||||
"def=ghi&abc=tb",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
},
|
||||
tearDown() {
|
||||
Services.cookies.removeAll();
|
||||
},
|
||||
title: "Tagged follow-on with cookie param at end",
|
||||
trackingUrl:
|
||||
"https://www.example3.com/search?q=test&a=next&dummyExtraCodeParamName=xyz",
|
||||
expectedSearchCountEntry: "example3:tagged-follow-on:tb",
|
||||
expectedAdKey: "example3:tagged-follow-on",
|
||||
adUrls: ["https://www.example.com/ad2"],
|
||||
nonAdUrls: ["https://www.example.com/ad3"],
|
||||
impression: {
|
||||
provider: "example3",
|
||||
tagged: "true",
|
||||
partner_code: "tb",
|
||||
source: "unknown",
|
||||
is_shopping_page: "false",
|
||||
is_private: "false",
|
||||
shopping_tab_displayed: "false",
|
||||
is_signed_in: "false",
|
||||
},
|
||||
},
|
||||
{
|
||||
setUp() {
|
||||
Services.cookies.removeAll();
|
||||
Services.cookies.add(
|
||||
"www.example4.com",
|
||||
"/",
|
||||
"_dummyCookieName",
|
||||
@@ -237,12 +274,11 @@ const TESTS = [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Math.round(Date.now() / 1000) + 10 * 60 * 60,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
},
|
||||
tearDown() {
|
||||
Services.cookies.removeAll();
|
||||
@@ -277,9 +313,9 @@ const TESTS = [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Math.round(Date.now() / 1000) + 10 * 60 * 60,
|
||||
Date.now() + 1000 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
},
|
||||
|
||||
@@ -71,7 +71,7 @@ var SessionCookiesInternal = {
|
||||
cookie.originAttributes?.partitionKey?.length > 0;
|
||||
|
||||
try {
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
cookie.host,
|
||||
cookie.path || "",
|
||||
cookie.name || "",
|
||||
@@ -81,20 +81,10 @@ var SessionCookiesInternal = {
|
||||
/* isSession = */ true,
|
||||
expiry,
|
||||
cookie.originAttributes || {},
|
||||
// If sameSite is undefined, we are migrating from a pre bug 1955685 session).
|
||||
cookie.sameSite === undefined
|
||||
? Ci.nsICookie.SAMESITE_NONE
|
||||
: cookie.sameSite,
|
||||
cookie.sameSite || Ci.nsICookie.SAMESITE_NONE,
|
||||
cookie.schemeMap || Ci.nsICookie.SCHEME_HTTPS,
|
||||
isPartitioned
|
||||
);
|
||||
if (cv.result !== Ci.nsICookieValidation.eOK) {
|
||||
console.error(
|
||||
`CookieService::Add failed with error '${cv.result}' for cookie ${JSON.stringify(
|
||||
cookie
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error(
|
||||
`CookieService::Add failed with error '${ex}' for cookie ${JSON.stringify(
|
||||
@@ -267,7 +257,9 @@ var CookieStore = {
|
||||
jscookie.originAttributes = cookie.originAttributes;
|
||||
}
|
||||
|
||||
if (cookie.sameSite) {
|
||||
jscookie.sameSite = cookie.sameSite;
|
||||
}
|
||||
|
||||
if (cookie.schemeMap) {
|
||||
jscookie.schemeMap = cookie.schemeMap;
|
||||
|
||||
@@ -8,7 +8,6 @@ function createTestState() {
|
||||
path: "/",
|
||||
name: `name${r}`,
|
||||
value: `value${r}`,
|
||||
sameSite: Ci.nsICookie.SAMESITE_UNSET,
|
||||
};
|
||||
|
||||
let state = {
|
||||
|
||||
@@ -27,12 +27,12 @@ add_task(async function runTest() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
|
||||
|
||||
// Add a partitioned cookie.
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
TEST_HOST,
|
||||
"/",
|
||||
"foo",
|
||||
"bar",
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
MAX_EXPIRY,
|
||||
@@ -41,8 +41,6 @@ add_task(async function runTest() {
|
||||
Ci.nsICookie.SCHEME_HTTPS,
|
||||
true
|
||||
);
|
||||
is(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
await TabStateFlusher.flush(tab.linkedBrowser);
|
||||
|
||||
// Get the sessionstore state for the window.
|
||||
|
||||
@@ -5,7 +5,7 @@ const MAX_EXPIRY = Math.pow(2, 62);
|
||||
|
||||
function addCookie(scheme, secure = false) {
|
||||
let cookie = createTestCookie(scheme, secure);
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
cookie.host,
|
||||
cookie.path,
|
||||
cookie.name,
|
||||
@@ -15,10 +15,9 @@ function addCookie(scheme, secure = false) {
|
||||
/* isSession = */ true,
|
||||
MAX_EXPIRY,
|
||||
/* originAttributes = */ {},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
is(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
return cookie;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ async function verifyRestore(url, sameSiteSetting) {
|
||||
|
||||
// Add a cookie with specific same-site setting.
|
||||
let r = Math.floor(Math.random() * MAX_EXPIRY);
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
url,
|
||||
"/",
|
||||
"name" + r,
|
||||
@@ -39,8 +39,6 @@ async function verifyRestore(url, sameSiteSetting) {
|
||||
? Ci.nsICookie.SCHEME_HTTPS
|
||||
: Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
is(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
await TabStateFlusher.flush(tab.linkedBrowser);
|
||||
|
||||
// Get the sessionstore state for the window.
|
||||
@@ -81,11 +79,11 @@ async function verifyRestore(url, sameSiteSetting) {
|
||||
*/
|
||||
add_task(async function () {
|
||||
// Test for various possible values of cookie.sameSite and schemeMap.
|
||||
await verifyRestore(TEST_HTTP_URL, Ci.nsICookie.SAMESITE_UNSET);
|
||||
await verifyRestore(TEST_HTTP_URL, Ci.nsICookie.SAMESITE_NONE);
|
||||
await verifyRestore(TEST_HTTP_URL, Ci.nsICookie.SAMESITE_LAX);
|
||||
await verifyRestore(TEST_HTTP_URL, Ci.nsICookie.SAMESITE_STRICT);
|
||||
|
||||
await verifyRestore(TEST_HTTPS_URL, Ci.nsICookie.SAMESITE_UNSET);
|
||||
await verifyRestore(TEST_HTTPS_URL, Ci.nsICookie.SAMESITE_NONE);
|
||||
await verifyRestore(TEST_HTTPS_URL, Ci.nsICookie.SAMESITE_LAX);
|
||||
await verifyRestore(TEST_HTTPS_URL, Ci.nsICookie.SAMESITE_STRICT);
|
||||
});
|
||||
|
||||
@@ -9,7 +9,6 @@ const COOKIE = {
|
||||
name: "test1",
|
||||
value: "yes1",
|
||||
path: "/browser/browser/components/sessionstore/test/",
|
||||
sameSite: Ci.nsICookie.SAMESITE_UNSET,
|
||||
};
|
||||
const SESSION_DATA = JSON.stringify({
|
||||
version: ["sessionrestore", 1],
|
||||
@@ -59,7 +58,6 @@ const SESSION_DATA = JSON.stringify({
|
||||
value: "yes1",
|
||||
path: "/browser/browser/components/sessionstore/test/",
|
||||
name: "test1",
|
||||
sameSite: Ci.nsICookie.SAMESITE_UNSET,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -122,7 +120,6 @@ const SESSION_DATA_OA = JSON.stringify({
|
||||
value: "yes1",
|
||||
path: "/browser/browser/components/sessionstore/test/",
|
||||
name: "test1",
|
||||
sameSite: Ci.nsICookie.SAMESITE_UNSET,
|
||||
originAttributes: {
|
||||
addonId: "",
|
||||
inIsolatedMozBrowser: false,
|
||||
|
||||
@@ -314,7 +314,6 @@
|
||||
@RESPATH@/res/locale/layout/MediaDocument.properties
|
||||
@RESPATH@/res/locale/layout/xmlparser.properties
|
||||
@RESPATH@/res/locale/dom/dom.properties
|
||||
@RESPATH@/res/locale/necko/necko.properties
|
||||
#ifdef XP_MACOSX
|
||||
@RESPATH@/res/MainMenu.nib/
|
||||
#endif
|
||||
|
||||
@@ -136,8 +136,8 @@ add_task(async function testInvalidSameSiteMessage() {
|
||||
|
||||
await checkConsoleOutputForWarningGroup(hud, [
|
||||
`▼︎⚠ ${COOKIE_GROUP} 2`,
|
||||
`| ${message2}`,
|
||||
`| ${message1}`,
|
||||
`| ${message2}`,
|
||||
]);
|
||||
|
||||
// Source map are being resolved in background and we might have
|
||||
|
||||
@@ -4785,9 +4785,7 @@ static const char* gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT] = {
|
||||
"chrome://global/locale/security/security.properties",
|
||||
"chrome://necko/locale/necko.properties",
|
||||
"resource://gre/res/locale/layout/HtmlForm.properties",
|
||||
"resource://gre/res/locale/dom/dom.properties",
|
||||
"resource://gre/res/locale/necko/necko.properties",
|
||||
};
|
||||
"resource://gre/res/locale/dom/dom.properties"};
|
||||
|
||||
/* static */
|
||||
nsresult nsContentUtils::EnsureStringBundle(PropertiesFile aFile) {
|
||||
|
||||
@@ -1312,7 +1312,6 @@ class nsContentUtils {
|
||||
eNECKO_PROPERTIES,
|
||||
eFORMS_PROPERTIES_en_US,
|
||||
eDOM_PROPERTIES_en_US,
|
||||
eNECKO_PROPERTIES_en_US,
|
||||
PropertiesFile_COUNT
|
||||
};
|
||||
static nsresult ReportToConsole(
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "mozilla/net/CookieParser.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/net/CookieCommons.h"
|
||||
#include "mozilla/net/CookieValidation.h"
|
||||
#include "mozilla/net/CookieServiceParent.h"
|
||||
#include "mozilla/net/NeckoParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
@@ -356,9 +355,10 @@ bool CookieStoreParent::SetRequestOnMainThread(
|
||||
const nsAString& aValue, bool aSession, int64_t aExpires,
|
||||
const nsAString& aPath, int32_t aSameSite, bool aPartitioned,
|
||||
const nsID& aOperationID) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv;
|
||||
|
||||
bool requireMatch = false;
|
||||
NS_ConvertUTF16toUTF8 domain(aDomain);
|
||||
nsAutoCString domainWithDot;
|
||||
|
||||
@@ -379,6 +379,7 @@ bool CookieStoreParent::SetRequestOnMainThread(
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
requireMatch = true;
|
||||
}
|
||||
domainWithDot.Append(domain);
|
||||
|
||||
@@ -413,28 +414,18 @@ bool CookieStoreParent::SetRequestOnMainThread(
|
||||
notificationWatcher->CallbackWhenNotified(aOperationID, notificationCb);
|
||||
|
||||
OriginAttributes attrs(aOriginAttributes);
|
||||
|
||||
nsCOMPtr<nsICookieValidation> validation;
|
||||
rv = service->AddNative(
|
||||
aCookieURI, domainWithDot, NS_ConvertUTF16toUTF8(aPath),
|
||||
NS_ConvertUTF16toUTF8(aName), NS_ConvertUTF16toUTF8(aValue),
|
||||
/* secure: */ true,
|
||||
/* http-only: */ false, aSession, aSession ? INT64_MAX : aExpires, &attrs,
|
||||
aSameSite, nsICookie::SCHEME_HTTPS, aPartitioned, /* from http: */ false,
|
||||
&aOperationID, getter_AddRefs(validation));
|
||||
|
||||
&aOperationID, [&](mozilla::net::CookieStruct& aCookieStruct) -> bool {
|
||||
return CookieParser::CheckCookieStruct(aCookieStruct, aCookieURI, ""_ns,
|
||||
domain, requireMatch, false) ==
|
||||
CookieParser::NoRejection;
|
||||
});
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (rv == NS_ERROR_ILLEGAL_VALUE && validation &&
|
||||
CookieValidation::Cast(validation)->Result() !=
|
||||
nsICookieValidation::eOK) {
|
||||
RefPtr<ContentParent> contentParent = aParent->GetContentParent();
|
||||
if (contentParent) {
|
||||
contentParent->KillHard(
|
||||
"CookieStore does not accept invalid cookies in the parent "
|
||||
"process");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ const RESOURCE_URL =
|
||||
add_task(async function test_fetch_defaults_to_credentialless() {
|
||||
// Ensure cookie is set up:
|
||||
let expiry = Date.now() / 1000 + 24 * 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.com",
|
||||
"/",
|
||||
"foo",
|
||||
@@ -22,10 +22,9 @@ add_task(async function test_fetch_defaults_to_credentialless() {
|
||||
false,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
is(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
// Explicitly send cookie header by using `same-origin` in the init dict, to
|
||||
// ensure cookies are stored correctly and can be sent.
|
||||
|
||||
@@ -156,7 +156,6 @@
|
||||
@BINPATH@/res/locale/layout/MediaDocument.properties
|
||||
@BINPATH@/res/locale/layout/xmlparser.properties
|
||||
@BINPATH@/res/locale/dom/dom.properties
|
||||
@BINPATH@/res/locale/necko/necko.properties
|
||||
|
||||
#ifndef MOZ_ANDROID_EXCLUDE_FONTS
|
||||
@BINPATH@/res/fonts/*
|
||||
|
||||
@@ -1808,10 +1808,6 @@ pref("extensions.install_origins.enabled", false);
|
||||
pref("extensions.browser_style_mv3.supported", false);
|
||||
pref("extensions.browser_style_mv3.same_as_mv2", false);
|
||||
|
||||
// If set to true, browser.cookies.set() will throw exceptions if the cookie is
|
||||
// invalid. Otherwise, a warning message will be shown in the console.
|
||||
pref("extensions.cookie.rejectWhenInvalid", false);
|
||||
|
||||
// Experimental Inference API
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("extensions.ml.enabled", true);
|
||||
|
||||
@@ -206,6 +206,61 @@ void CookieCommons::NotifyRejected(nsIURI* aHostURI, nsIChannel* aChannel,
|
||||
aRejectedReason);
|
||||
}
|
||||
|
||||
bool CookieCommons::CheckPathSize(const CookieStruct& aCookieData) {
|
||||
return aCookieData.path().Length() <= kMaxBytesPerPath;
|
||||
}
|
||||
|
||||
bool CookieCommons::CheckNameAndValueSize(const CookieStruct& aCookieData) {
|
||||
// reject cookie if it's over the size limit, per RFC2109
|
||||
return (aCookieData.name().Length() + aCookieData.value().Length()) <=
|
||||
kMaxBytesPerCookie;
|
||||
}
|
||||
|
||||
bool CookieCommons::CheckName(const CookieStruct& aCookieData) {
|
||||
const char illegalNameCharacters[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D,
|
||||
0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
|
||||
0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x3B, 0x3D, 0x7F, 0x00};
|
||||
|
||||
const auto* start = aCookieData.name().BeginReading();
|
||||
const auto* end = aCookieData.name().EndReading();
|
||||
|
||||
auto charFilter = [&](unsigned char c) {
|
||||
if (StaticPrefs::network_cookie_blockUnicode() && c >= 0x80) {
|
||||
return true;
|
||||
}
|
||||
return std::find(std::begin(illegalNameCharacters),
|
||||
std::end(illegalNameCharacters),
|
||||
c) != std::end(illegalNameCharacters);
|
||||
};
|
||||
|
||||
return std::find_if(start, end, charFilter) == end;
|
||||
}
|
||||
|
||||
bool CookieCommons::CheckValue(const CookieStruct& aCookieData) {
|
||||
// reject cookie if value contains an RFC 6265 disallowed character - see
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1191423
|
||||
// NOTE: this is not the full set of characters disallowed by 6265 - notably
|
||||
// 0x09, 0x20, 0x22, 0x2C, and 0x5C are missing from this list.
|
||||
const char illegalCharacters[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C,
|
||||
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x3B, 0x7F, 0x00};
|
||||
|
||||
const auto* start = aCookieData.value().BeginReading();
|
||||
const auto* end = aCookieData.value().EndReading();
|
||||
|
||||
auto charFilter = [&](unsigned char c) {
|
||||
if (StaticPrefs::network_cookie_blockUnicode() && c >= 0x80) {
|
||||
return true;
|
||||
}
|
||||
return std::find(std::begin(illegalCharacters), std::end(illegalCharacters),
|
||||
c) != std::end(illegalCharacters);
|
||||
};
|
||||
|
||||
return std::find_if(start, end, charFilter) == end;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieCommons::CheckCookiePermission(nsIChannel* aChannel,
|
||||
CookieStruct& aCookieData) {
|
||||
@@ -1016,16 +1071,5 @@ int64_t CookieCommons::MaybeReduceExpiry(int64_t aCurrentTimeInSec,
|
||||
return aExpiryInSec;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieCommons::IsSubdomainOf(const nsACString& a, const nsACString& b) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
if (a.Length() > b.Length()) {
|
||||
return a[a.Length() - b.Length() - 1] == '.' && StringEndsWith(a, b);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -57,6 +57,8 @@ static const char kPrefCookiePurgeAge[] = "network.cookie.purgeAge";
|
||||
static const uint32_t kMaxCookiesPerHost = 180;
|
||||
static const uint32_t kCookieQuotaPerHost = 150;
|
||||
static const uint32_t kMaxNumberOfCookies = 3000;
|
||||
static const uint32_t kMaxBytesPerCookie = 4096;
|
||||
static const uint32_t kMaxBytesPerPath = 1024;
|
||||
|
||||
static const int64_t kCookiePurgeAge =
|
||||
int64_t(30 * 24 * 60 * 60) * PR_USEC_PER_SEC; // 30 days in microseconds
|
||||
@@ -89,6 +91,14 @@ class CookieCommons final {
|
||||
uint32_t aRejectedReason,
|
||||
CookieOperation aOperation);
|
||||
|
||||
static bool CheckPathSize(const CookieStruct& aCookieData);
|
||||
|
||||
static bool CheckNameAndValueSize(const CookieStruct& aCookieData);
|
||||
|
||||
static bool CheckName(const CookieStruct& aCookieData);
|
||||
|
||||
static bool CheckValue(const CookieStruct& aCookieData);
|
||||
|
||||
static bool CheckCookiePermission(nsIChannel* aChannel,
|
||||
CookieStruct& aCookieData);
|
||||
|
||||
@@ -177,10 +187,6 @@ class CookieCommons final {
|
||||
// Return a reduced expiry attribute value if needed.
|
||||
static int64_t MaybeReduceExpiry(int64_t aCurrentTimeInSec,
|
||||
int64_t aExpiryInSec);
|
||||
|
||||
// returns true if 'a' is equal to or a subdomain of 'b',
|
||||
// assuming no leading dots are present.
|
||||
static bool IsSubdomainOf(const nsACString& a, const nsACString& b);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
#include "CookieParser.h"
|
||||
#include "CookieLogging.h"
|
||||
#include "CookieValidation.h"
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/dom/nsMixedContentBlocker.h"
|
||||
#include "mozilla/glean/NetwerkMetrics.h"
|
||||
#include "mozilla/net/Cookie.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
@@ -21,7 +21,14 @@
|
||||
constexpr char ATTRIBUTE_PATH[] = "path";
|
||||
constexpr uint64_t ATTRIBUTE_MAX_LENGTH = 1024;
|
||||
|
||||
constexpr auto CONSOLE_CHIPS_CATEGORY = "cookiesCHIPS"_ns;
|
||||
constexpr auto CONSOLE_OVERSIZE_CATEGORY = "cookiesOversize"_ns;
|
||||
constexpr auto CONSOLE_REJECTION_CATEGORY = "cookiesRejection"_ns;
|
||||
constexpr auto CONSOLE_SAMESITE_CATEGORY = "cookieSameSite"_ns;
|
||||
constexpr auto CONSOLE_INVALID_ATTRIBUTE_CATEGORY = "cookieInvalidAttribute"_ns;
|
||||
constexpr auto SAMESITE_MDN_URL =
|
||||
"https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Set-Cookie#"
|
||||
u"samesitesamesite-value"_ns;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
@@ -36,10 +43,6 @@ CookieParser::CookieParser(nsIConsoleReportCollector* aCRC, nsIURI* aHostURI)
|
||||
CookieParser::~CookieParser() {
|
||||
MOZ_COUNT_DTOR(CookieParser);
|
||||
|
||||
if (mValidation) {
|
||||
mValidation->ReportErrorsAndWarnings(mCRC, mHostURI);
|
||||
}
|
||||
|
||||
#define COOKIE_LOGGING_WITH_NAME(category, x) \
|
||||
CookieLogging::LogMessageToConsole( \
|
||||
mCRC, mHostURI, nsIScriptError::errorFlag, category, x, \
|
||||
@@ -54,11 +57,77 @@ CookieParser::~CookieParser() {
|
||||
"CookieRejectedInvalidCharAttributes"_ns);
|
||||
break;
|
||||
|
||||
case RejectedNoneRequiresSecure:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieRejectedNonRequiresSecure2"_ns);
|
||||
break;
|
||||
|
||||
case RejectedPartitionedRequiresSecure:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedPartitionedRequiresSecure"_ns);
|
||||
break;
|
||||
|
||||
case RejectedEmptyNameAndValue:
|
||||
CookieLogging::LogMessageToConsole(
|
||||
mCRC, mHostURI, nsIScriptError::warningFlag,
|
||||
CONSOLE_REJECTION_CATEGORY, "CookieRejectedEmptyNameAndValue"_ns,
|
||||
nsTArray<nsString>());
|
||||
|
||||
break;
|
||||
|
||||
case RejectedNameValueOversize: {
|
||||
AutoTArray<nsString, 2> params = {
|
||||
NS_ConvertUTF8toUTF16(mCookieData.name())};
|
||||
|
||||
nsString size;
|
||||
size.AppendInt(kMaxBytesPerCookie);
|
||||
params.AppendElement(size);
|
||||
|
||||
CookieLogging::LogMessageToConsole(
|
||||
mCRC, mHostURI, nsIScriptError::warningFlag,
|
||||
CONSOLE_OVERSIZE_CATEGORY, "CookieOversize"_ns, params);
|
||||
break;
|
||||
}
|
||||
|
||||
case RejectedInvalidCharName:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidCharName"_ns);
|
||||
break;
|
||||
|
||||
case RejectedInvalidDomain:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidDomain"_ns);
|
||||
break;
|
||||
|
||||
case RejectedInvalidPrefix:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidPrefix"_ns);
|
||||
break;
|
||||
case RejectedInvalidPath:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidPath"_ns);
|
||||
break;
|
||||
|
||||
case RejectedInvalidCharValue:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidCharValue"_ns);
|
||||
break;
|
||||
|
||||
case RejectedHttpOnlyButFromScript:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedHttpOnlyButFromScript"_ns);
|
||||
break;
|
||||
|
||||
case RejectedSecureButNonHttps:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedSecureButNonHttps"_ns);
|
||||
break;
|
||||
|
||||
case RejectedForNonSameSiteness:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieRejectedForNonSameSiteness"_ns);
|
||||
break;
|
||||
|
||||
case RejectedForeignNoPartitionedError:
|
||||
COOKIE_LOGGING_WITH_NAME(CONSOLE_CHIPS_CATEGORY,
|
||||
"CookieForeignNoPartitionedError"_ns);
|
||||
@@ -77,8 +146,7 @@ CookieParser::~CookieParser() {
|
||||
|
||||
#undef COOKIE_LOGGING_WITH_NAME
|
||||
|
||||
if (mRejection != NoRejection || !mValidation ||
|
||||
mValidation->Result() != nsICookieValidation::eOK) {
|
||||
if (mRejection != NoRejection || !mContainsCookie) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -117,6 +185,29 @@ CookieParser::~CookieParser() {
|
||||
AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(mCookieData.name())});
|
||||
}
|
||||
|
||||
if (mWarnings.mSameSiteNoneRequiresSecureForBeta) {
|
||||
CookieLogging::LogMessageToConsole(
|
||||
mCRC, mHostURI, nsIScriptError::warningFlag, CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieRejectedNonRequiresSecureForBeta3"_ns,
|
||||
AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(mCookieData.name()),
|
||||
SAMESITE_MDN_URL});
|
||||
}
|
||||
|
||||
if (mWarnings.mSameSiteLaxForced) {
|
||||
CookieLogging::LogMessageToConsole(
|
||||
mCRC, mHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieLaxForced2"_ns,
|
||||
AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(mCookieData.name())});
|
||||
}
|
||||
|
||||
if (mWarnings.mSameSiteLaxForcedForBeta) {
|
||||
CookieLogging::LogMessageToConsole(
|
||||
mCRC, mHostURI, nsIScriptError::warningFlag, CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieLaxForcedForBeta2"_ns,
|
||||
AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(mCookieData.name()),
|
||||
SAMESITE_MDN_URL});
|
||||
}
|
||||
|
||||
if (mWarnings.mForeignNoPartitionedWarning) {
|
||||
CookieLogging::LogMessageToConsole(
|
||||
mCRC, mHostURI, nsIScriptError::warningFlag, CONSOLE_CHIPS_CATEGORY,
|
||||
@@ -401,6 +492,43 @@ void CookieParser::ParseAttributes(nsCString& aCookieHeader,
|
||||
}
|
||||
}
|
||||
|
||||
// re-assign aCookieHeader, in case we need to process another cookie
|
||||
aCookieHeader.Assign(Substring(cookieStart, cookieEnd));
|
||||
|
||||
// If same-site is explicitly set to 'none' but this is not a secure context,
|
||||
// let's abort the parsing.
|
||||
if (!mCookieData.isSecure() &&
|
||||
mCookieData.sameSite() == nsICookie::SAMESITE_NONE) {
|
||||
if (StaticPrefs::network_cookie_sameSite_noneRequiresSecure()) {
|
||||
RejectCookie(RejectedNoneRequiresSecure);
|
||||
return;
|
||||
}
|
||||
|
||||
// Still warn about the missing Secure attribute when not enforcing.
|
||||
mWarnings.mSameSiteNoneRequiresSecureForBeta = true;
|
||||
}
|
||||
|
||||
// Ensure the partitioned cookie is set with the secure attribute if CHIPS
|
||||
// is enabled.
|
||||
if (StaticPrefs::network_cookie_CHIPS_enabled() &&
|
||||
mCookieData.isPartitioned() && !mCookieData.isSecure()) {
|
||||
RejectCookie(RejectedPartitionedRequiresSecure);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCookieData.sameSite() == nsICookie::SAMESITE_UNSET) {
|
||||
bool laxByDefault =
|
||||
StaticPrefs::network_cookie_sameSite_laxByDefault() &&
|
||||
!nsContentUtils::IsURIInPrefList(
|
||||
mHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
|
||||
if (laxByDefault) {
|
||||
mWarnings.mSameSiteLaxForced = true;
|
||||
} else if (StaticPrefs::
|
||||
network_cookie_sameSite_laxByDefaultWarningsForBeta()) {
|
||||
mWarnings.mSameSiteLaxForcedForBeta = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Cookie accepted.
|
||||
aAcceptedByParser = true;
|
||||
}
|
||||
@@ -439,14 +567,73 @@ nsAutoCString GetPathFromURI(nsIURI* aHostURI) {
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void CookieParser::FixPath(CookieStruct& aCookieData, nsIURI* aHostURI) {
|
||||
bool CookieParser::CheckPath(CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
CookieParser* aParser) {
|
||||
// if a path is given, check the host has permission
|
||||
if (aCookieData.path().IsEmpty() || aCookieData.path().First() != '/') {
|
||||
nsAutoCString path = GetPathFromURI(aHostURI);
|
||||
if (CheckAttributeSize(aCookieData.path(), ATTRIBUTE_PATH, path)) {
|
||||
if (CheckAttributeSize(aCookieData.path(), ATTRIBUTE_PATH, path, aParser)) {
|
||||
aCookieData.path() = path;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(CookieCommons::CheckPathSize(aCookieData));
|
||||
|
||||
return !aCookieData.path().Contains('\t');
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieParser::HasSecurePrefix(const nsACString& aString) {
|
||||
return StringBeginsWith(aString, "__Secure-"_ns,
|
||||
nsCaseInsensitiveCStringComparator);
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieParser::HasHostPrefix(const nsACString& aString) {
|
||||
return StringBeginsWith(aString, "__Host-"_ns,
|
||||
nsCaseInsensitiveCStringComparator);
|
||||
}
|
||||
|
||||
// CheckPrefixes
|
||||
//
|
||||
// Reject cookies whose name starts with the magic prefixes from
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis
|
||||
// if they do not meet the criteria required by the prefix.
|
||||
//
|
||||
// Must not be called until after CheckDomain() and CheckPath() have
|
||||
// regularized and validated the CookieStruct values!
|
||||
|
||||
// static
|
||||
bool CookieParser::CheckPrefixes(CookieStruct& aCookieData,
|
||||
bool aSecureRequest) {
|
||||
bool hasSecurePrefix = HasSecurePrefix(aCookieData.name());
|
||||
bool hasHostPrefix = HasHostPrefix(aCookieData.name());
|
||||
|
||||
if (!hasSecurePrefix && !hasHostPrefix) {
|
||||
// not one of the magic prefixes: carry on
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aSecureRequest || !aCookieData.isSecure()) {
|
||||
// the magic prefixes may only be used from a secure request and
|
||||
// the secure attribute must be set on the cookie
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasHostPrefix) {
|
||||
// The host prefix requires that the path is "/" and that the cookie
|
||||
// had no domain attribute. CheckDomain() and CheckPath() MUST be run
|
||||
// first to make sure invalid attributes are rejected and to regularlize
|
||||
// them. In particular all explicit domain attributes result in a host
|
||||
// that starts with a dot, and if the host doesn't start with a dot it
|
||||
// correctly matches the true host.
|
||||
if (aCookieData.host()[0] == '.' ||
|
||||
!aCookieData.path().EqualsLiteral("/")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CookieParser::ParseMaxAgeAttribute(const nsACString& aMaxage,
|
||||
@@ -569,8 +756,22 @@ bool CookieParser::GetExpiry(CookieStruct& aCookieData,
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns true if 'a' is equal to or a subdomain of 'b',
|
||||
// assuming no leading dots are present.
|
||||
static inline bool IsSubdomainOf(const nsACString& a, const nsACString& b) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
if (a.Length() > b.Length()) {
|
||||
return a[a.Length() - b.Length() - 1] == '.' && StringEndsWith(a, b);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// processes domain attribute, and returns true if host has permission to set
|
||||
// for this domain.
|
||||
// static
|
||||
void CookieParser::FixDomain(CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
bool CookieParser::CheckDomain(CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain,
|
||||
bool aRequireHostMatch) {
|
||||
// Note: The logic in this function is mirrored in
|
||||
@@ -582,44 +783,32 @@ void CookieParser::FixDomain(CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
nsAutoCString hostFromURI;
|
||||
nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI);
|
||||
|
||||
// no domain specified, use hostFromURI
|
||||
if (aCookieData.host().IsEmpty()) {
|
||||
aCookieData.host() = hostFromURI;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCString cookieHost = aCookieData.host();
|
||||
|
||||
// if a domain is given, check the host has permission
|
||||
if (!aCookieData.host().IsEmpty()) {
|
||||
// Tolerate leading '.' characters, but not if it's otherwise an empty host.
|
||||
if (cookieHost.Length() > 1 && cookieHost.First() == '.') {
|
||||
cookieHost.Cut(0, 1);
|
||||
if (aCookieData.host().Length() > 1 && aCookieData.host().First() == '.') {
|
||||
aCookieData.host().Cut(0, 1);
|
||||
}
|
||||
|
||||
// switch to lowercase now, to avoid case-insensitive compares everywhere
|
||||
ToLowerCase(cookieHost);
|
||||
ToLowerCase(aCookieData.host());
|
||||
|
||||
if (aRequireHostMatch) {
|
||||
// check whether the host is either an IP address, an alias such as
|
||||
// 'localhost', an eTLD such as 'co.uk', or the empty string. in these
|
||||
// cases, require an exact string match for the domain, and leave the cookie
|
||||
// as a non-domain one. bug 105917 originally noted the requirement to deal
|
||||
// with IP addresses.
|
||||
if (hostFromURI.Equals(cookieHost)) {
|
||||
aCookieData.host() = cookieHost;
|
||||
}
|
||||
|
||||
// If the match fails, we keep the aCookieData.Host() as it was. The
|
||||
// Validator will reject the cookie with the correct reason.
|
||||
return;
|
||||
if (aRequireHostMatch) {
|
||||
return hostFromURI.Equals(aCookieData.host());
|
||||
}
|
||||
|
||||
// ensure the proposed domain is derived from the base domain; and also
|
||||
// that the host domain is derived from the proposed domain (per RFC2109).
|
||||
if (CookieCommons::IsSubdomainOf(cookieHost, aBaseDomain) &&
|
||||
CookieCommons::IsSubdomainOf(hostFromURI, cookieHost)) {
|
||||
if (IsSubdomainOf(aCookieData.host(), aBaseDomain) &&
|
||||
IsSubdomainOf(hostFromURI, aCookieData.host())) {
|
||||
// prepend a dot to indicate a domain cookie
|
||||
cookieHost.InsertLiteral(".", 0);
|
||||
aCookieData.host() = cookieHost;
|
||||
aCookieData.host().InsertLiteral(".", 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -629,6 +818,12 @@ void CookieParser::FixDomain(CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
* entire .co.nz domain. however, it's only a only a partial solution and
|
||||
* it breaks sites (IE doesn't enforce it), so we don't perform this check.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
// no domain specified, use hostFromURI
|
||||
aCookieData.host() = hostFromURI;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void RecordPartitionedTelemetry(const CookieStruct& aCookieData,
|
||||
@@ -646,6 +841,90 @@ static void RecordPartitionedTelemetry(const CookieStruct& aCookieData,
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
CookieParser::Rejection CookieParser::CheckCookieStruct(
|
||||
CookieStruct& aCookieStruct, nsIURI* aHostURI,
|
||||
const nsCString& aCookieString, const nsACString& aBaseDomain,
|
||||
bool aRequireHostMatch, bool aFromHttp, CookieParser* aParser) {
|
||||
// reject cookie if name and value are empty, per RFC6265bis
|
||||
if (aCookieStruct.name().IsEmpty() && aCookieStruct.value().IsEmpty()) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"cookie name and value are empty");
|
||||
|
||||
return RejectedEmptyNameAndValue;
|
||||
}
|
||||
|
||||
// reject cookie if it's over the size limit, per RFC2109
|
||||
if (!CookieCommons::CheckNameAndValueSize(aCookieStruct)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"cookie too big (> 4kb)");
|
||||
return RejectedNameValueOversize;
|
||||
}
|
||||
|
||||
if (!CookieCommons::CheckName(aCookieStruct)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"invalid name character");
|
||||
return RejectedInvalidCharName;
|
||||
}
|
||||
|
||||
// domain & path checks
|
||||
if (!CheckDomain(aCookieStruct, aHostURI, aBaseDomain, aRequireHostMatch)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"failed the domain tests");
|
||||
return RejectedInvalidDomain;
|
||||
}
|
||||
|
||||
if (!CheckPath(aCookieStruct, aHostURI, aParser)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"failed the path tests");
|
||||
return RejectedInvalidPath;
|
||||
}
|
||||
|
||||
// If a cookie is nameless, then its value must not start with
|
||||
// `__Host-` or `__Secure-`
|
||||
if (aCookieStruct.name().IsEmpty() &&
|
||||
(HasSecurePrefix(aCookieStruct.value()) ||
|
||||
HasHostPrefix(aCookieStruct.value()))) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"failed hidden prefix tests");
|
||||
return RejectedInvalidPrefix;
|
||||
}
|
||||
|
||||
bool potentiallyTrustworthy =
|
||||
nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
|
||||
|
||||
// magic prefix checks. MUST be run after CheckDomain() and CheckPath()
|
||||
if (!CheckPrefixes(aCookieStruct, potentiallyTrustworthy)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"failed the prefix tests");
|
||||
return RejectedInvalidPrefix;
|
||||
}
|
||||
|
||||
if (!CookieCommons::CheckValue(aCookieStruct)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"invalid value character");
|
||||
return RejectedInvalidCharValue;
|
||||
}
|
||||
|
||||
// if the new cookie is httponly, make sure we're not coming from script
|
||||
if (!aFromHttp && aCookieStruct.isHttpOnly()) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"cookie is httponly; coming from script");
|
||||
return RejectedHttpOnlyButFromScript;
|
||||
}
|
||||
|
||||
// If the new cookie is non-https and wants to set secure flag,
|
||||
// browser have to ignore this new cookie.
|
||||
// (draft-ietf-httpbis-cookie-alone section 3.1)
|
||||
if (aCookieStruct.isSecure() && !potentiallyTrustworthy) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
||||
"non-https cookie can't set secure flag");
|
||||
return RejectedSecureButNonHttps;
|
||||
}
|
||||
|
||||
return NoRejection;
|
||||
}
|
||||
|
||||
// processes a single cookie, and returns true if there are more cookies
|
||||
// to be processed
|
||||
void CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
||||
@@ -653,7 +932,7 @@ void CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
||||
const nsACString& aDateHeader, bool aFromHttp,
|
||||
bool aIsForeignAndNotAddon, bool aPartitionedOnly,
|
||||
bool aIsInPrivateBrowsing, bool aOn3pcbException) {
|
||||
MOZ_ASSERT(!mValidation);
|
||||
MOZ_ASSERT(!mContainsCookie);
|
||||
|
||||
// init expiryTime such that session cookies won't prematurely expire
|
||||
mCookieData.expiry() = INT64_MAX;
|
||||
@@ -686,8 +965,38 @@ void CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
||||
mCookieData.isSession() = true;
|
||||
}
|
||||
|
||||
FixDomain(mCookieData, mHostURI, aBaseDomain, aRequireHostMatch);
|
||||
FixPath(mCookieData, mHostURI);
|
||||
// We count SetCookie operations in the parent process only for HTTP set
|
||||
// cookies to prevent double counting.
|
||||
if (XRE_IsParentProcess() || !aFromHttp) {
|
||||
RecordPartitionedTelemetry(mCookieData, aIsForeignAndNotAddon);
|
||||
}
|
||||
|
||||
auto result =
|
||||
CheckCookieStruct(mCookieData, mHostURI, mCookieString, aBaseDomain,
|
||||
aRequireHostMatch, aFromHttp, this);
|
||||
if (result != NoRejection) {
|
||||
RejectCookie(result);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the new cookie is same-site but in a cross site context,
|
||||
// browser must ignore the cookie.
|
||||
bool laxByDefault =
|
||||
StaticPrefs::network_cookie_sameSite_laxByDefault() &&
|
||||
!nsContentUtils::IsURIInPrefList(
|
||||
mHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
|
||||
uint32_t sameSite = mCookieData.sameSite();
|
||||
if (sameSite == nsICookie::SAMESITE_UNSET) {
|
||||
sameSite =
|
||||
laxByDefault ? nsICookie::SAMESITE_LAX : nsICookie::SAMESITE_NONE;
|
||||
}
|
||||
|
||||
if (sameSite != nsICookie::SAMESITE_NONE && aIsForeignAndNotAddon) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"failed the samesite tests");
|
||||
RejectCookie(RejectedForNonSameSiteness);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the cookie is on the 3pcd exception list, we apply partitioned
|
||||
// attribute to the cookie.
|
||||
@@ -712,6 +1021,8 @@ void CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
||||
(aIsInPrivateBrowsing &&
|
||||
StaticPrefs::
|
||||
network_cookie_cookieBehavior_optInPartitioning_pbmode())) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"foreign cookies must be partitioned");
|
||||
RejectCookie(RejectedForeignNoPartitionedError);
|
||||
return;
|
||||
}
|
||||
@@ -719,20 +1030,7 @@ void CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
||||
mWarnings.mForeignNoPartitionedWarning = true;
|
||||
}
|
||||
|
||||
mValidation = CookieValidation::ValidateInContext(
|
||||
mCookieData, mHostURI, aBaseDomain, aRequireHostMatch, aFromHttp,
|
||||
aIsForeignAndNotAddon, aPartitionedOnly, aIsInPrivateBrowsing);
|
||||
MOZ_ASSERT(mValidation);
|
||||
|
||||
if (mValidation->Result() != nsICookieValidation::eOK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We count SetCookie operations in the parent process only for HTTP set
|
||||
// cookies to prevent double counting.
|
||||
if (XRE_IsParentProcess() || !aFromHttp) {
|
||||
RecordPartitionedTelemetry(mCookieData, aIsForeignAndNotAddon);
|
||||
}
|
||||
mContainsCookie = true;
|
||||
}
|
||||
|
||||
void CookieParser::RejectCookie(Rejection aRejection) {
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
|
||||
#include "CookieCommons.h"
|
||||
|
||||
#include "CookieValidation.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIConsoleReportCollector;
|
||||
class nsIURI;
|
||||
@@ -26,7 +25,18 @@ class CookieParser final {
|
||||
NoRejection,
|
||||
|
||||
RejectedInvalidCharAttributes,
|
||||
RejectedNoneRequiresSecure,
|
||||
RejectedPartitionedRequiresSecure,
|
||||
RejectedEmptyNameAndValue,
|
||||
RejectedNameValueOversize,
|
||||
RejectedInvalidCharName,
|
||||
RejectedInvalidDomain,
|
||||
RejectedInvalidPrefix,
|
||||
RejectedInvalidPath,
|
||||
RejectedInvalidCharValue,
|
||||
RejectedHttpOnlyButFromScript,
|
||||
RejectedSecureButNonHttps,
|
||||
RejectedForNonSameSiteness,
|
||||
RejectedForeignNoPartitionedError,
|
||||
RejectedByPermissionManager,
|
||||
RejectedNonsecureOverSecure,
|
||||
@@ -44,7 +54,8 @@ class CookieParser final {
|
||||
bool aIsInPrivateBrowsing, bool aOn3pcbException);
|
||||
|
||||
bool ContainsCookie() const {
|
||||
return mValidation && mValidation->Result() == nsICookieValidation::eOK;
|
||||
MOZ_ASSERT_IF(mContainsCookie, mRejection == NoRejection);
|
||||
return mContainsCookie;
|
||||
}
|
||||
|
||||
void RejectCookie(Rejection aRejection);
|
||||
@@ -59,6 +70,13 @@ class CookieParser final {
|
||||
// Public for testing
|
||||
bool ParseMaxAgeAttribute(const nsACString& aMaxage, int64_t* aValue);
|
||||
|
||||
static Rejection CheckCookieStruct(CookieStruct& aCookieStruct,
|
||||
nsIURI* aHostURI,
|
||||
const nsCString& aCookieString,
|
||||
const nsACString& aBaseDomain,
|
||||
bool aRequireHostMatch, bool aFromHttp,
|
||||
CookieParser* aParser = nullptr);
|
||||
|
||||
private:
|
||||
static void GetTokenValue(nsACString::const_char_iterator& aIter,
|
||||
nsACString::const_char_iterator& aEndIter,
|
||||
@@ -73,19 +91,26 @@ class CookieParser final {
|
||||
const nsACString& aMaxage, int64_t aCurrentTime,
|
||||
const nsACString& aDateHeader, bool aFromHttp);
|
||||
|
||||
static bool CheckPath(CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
CookieParser* aParser = nullptr);
|
||||
static bool CheckAttributeSize(const nsACString& currentValue,
|
||||
const char* aAttribute,
|
||||
const nsACString& aValue,
|
||||
CookieParser* aParser = nullptr);
|
||||
static void FixPath(CookieStruct& aCookieData, nsIURI* aHostURI);
|
||||
static void FixDomain(CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain, bool aRequireHostMatch);
|
||||
static bool CheckDomain(CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain,
|
||||
bool aRequireHostMatch);
|
||||
static bool HasSecurePrefix(const nsACString& aString);
|
||||
static bool HasHostPrefix(const nsACString& aString);
|
||||
static bool CheckPrefixes(CookieStruct& aCookieData, bool aSecureRequest);
|
||||
|
||||
nsCOMPtr<nsIConsoleReportCollector> mCRC;
|
||||
nsCOMPtr<nsIURI> mHostURI;
|
||||
|
||||
// True if the parsing succeeded.
|
||||
bool mContainsCookie = false;
|
||||
|
||||
Rejection mRejection = NoRejection;
|
||||
RefPtr<CookieValidation> mValidation;
|
||||
|
||||
struct Warnings {
|
||||
nsTArray<const char*> mAttributeOversize;
|
||||
@@ -93,6 +118,9 @@ class CookieParser final {
|
||||
|
||||
bool mInvalidSameSiteAttribute = false;
|
||||
bool mInvalidMaxAgeAttribute = false;
|
||||
bool mSameSiteNoneRequiresSecureForBeta = false;
|
||||
bool mSameSiteLaxForced = false;
|
||||
bool mSameSiteLaxForcedForBeta = false;
|
||||
bool mForeignNoPartitionedWarning = false;
|
||||
} mWarnings;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "CookieLogging.h"
|
||||
#include "CookieParser.h"
|
||||
#include "CookieService.h"
|
||||
#include "CookieValidation.h"
|
||||
#include "mozilla/AppShutdown.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Components.h"
|
||||
@@ -136,6 +135,8 @@ namespace net {
|
||||
|
||||
static StaticRefPtr<CookieService> gCookieService;
|
||||
|
||||
constexpr auto CONSOLE_REJECTION_CATEGORY = "cookiesRejection"_ns;
|
||||
|
||||
namespace {
|
||||
|
||||
// Return false if the cookie should be ignored for the current channel.
|
||||
@@ -712,67 +713,17 @@ CookieService::Add(const nsACString& aHost, const nsACString& aPath,
|
||||
bool aIsSecure, bool aIsHttpOnly, bool aIsSession,
|
||||
int64_t aExpiry, JS::Handle<JS::Value> aOriginAttributes,
|
||||
int32_t aSameSite, nsICookie::schemeType aSchemeMap,
|
||||
bool aIsPartitioned, JSContext* aCx,
|
||||
nsICookieValidation** aValidation) {
|
||||
NS_ENSURE_ARG_POINTER(aCx);
|
||||
NS_ENSURE_ARG_POINTER(aValidation);
|
||||
|
||||
bool aIsPartitioned, JSContext* aCx) {
|
||||
OriginAttributes attrs;
|
||||
|
||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICookieValidation> validation;
|
||||
nsresult rv =
|
||||
AddInternal(nullptr, aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly,
|
||||
return AddNative(nullptr, aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly,
|
||||
aIsSession, aExpiry, &attrs, aSameSite, aSchemeMap,
|
||||
aIsPartitioned, /* from-http: */ true, nullptr,
|
||||
/* reject when invalid: */ true, getter_AddRefs(validation));
|
||||
if (rv != NS_ERROR_ILLEGAL_VALUE || !validation ||
|
||||
CookieValidation::Cast(validation)->Result() ==
|
||||
nsICookieValidation::eOK) {
|
||||
validation.forget(aValidation);
|
||||
return rv;
|
||||
}
|
||||
|
||||
validation.forget(aValidation);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieService::AddForAddOn(const nsACString& aHost, const nsACString& aPath,
|
||||
const nsACString& aName, const nsACString& aValue,
|
||||
bool aIsSecure, bool aIsHttpOnly, bool aIsSession,
|
||||
int64_t aExpiry,
|
||||
JS::Handle<JS::Value> aOriginAttributes,
|
||||
int32_t aSameSite, nsICookie::schemeType aSchemeMap,
|
||||
bool aIsPartitioned, JSContext* aCx,
|
||||
nsICookieValidation** aValidation) {
|
||||
NS_ENSURE_ARG_POINTER(aCx);
|
||||
NS_ENSURE_ARG_POINTER(aValidation);
|
||||
|
||||
OriginAttributes attrs;
|
||||
|
||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICookieValidation> validation;
|
||||
nsresult rv = AddInternal(nullptr, aHost, aPath, aName, aValue, aIsSecure,
|
||||
aIsHttpOnly, aIsSession, aExpiry, &attrs, aSameSite,
|
||||
aSchemeMap, aIsPartitioned, /* from-http: */
|
||||
true, nullptr, /* reject when invalid: */ false,
|
||||
getter_AddRefs(validation));
|
||||
if (rv != NS_ERROR_ILLEGAL_VALUE || !validation ||
|
||||
CookieValidation::Cast(validation)->Result() ==
|
||||
nsICookieValidation::eOK) {
|
||||
validation.forget(aValidation);
|
||||
return rv;
|
||||
}
|
||||
|
||||
validation.forget(aValidation);
|
||||
return NS_OK;
|
||||
[](CookieStruct&) -> bool { return true; });
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsresult)
|
||||
@@ -783,24 +734,7 @@ CookieService::AddNative(nsIURI* aCookieURI, const nsACString& aHost,
|
||||
OriginAttributes* aOriginAttributes, int32_t aSameSite,
|
||||
nsICookie::schemeType aSchemeMap, bool aIsPartitioned,
|
||||
bool aFromHttp, const nsID* aOperationID,
|
||||
nsICookieValidation** aValidation) {
|
||||
return AddInternal(aCookieURI, aHost, aPath, aName, aValue, aIsSecure,
|
||||
aIsHttpOnly, aIsSession, aExpiry, aOriginAttributes,
|
||||
aSameSite, aSchemeMap, aIsPartitioned, aFromHttp,
|
||||
aOperationID,
|
||||
/* reject when invalid: */ true, aValidation);
|
||||
}
|
||||
|
||||
nsresult CookieService::AddInternal(
|
||||
nsIURI* aCookieURI, const nsACString& aHost, const nsACString& aPath,
|
||||
const nsACString& aName, const nsACString& aValue, bool aIsSecure,
|
||||
bool aIsHttpOnly, bool aIsSession, int64_t aExpiry,
|
||||
OriginAttributes* aOriginAttributes, int32_t aSameSite,
|
||||
nsICookie::schemeType aSchemeMap, bool aIsPartitioned, bool aFromHttp,
|
||||
const nsID* aOperationID, bool aRejectWhenInvalid,
|
||||
nsICookieValidation** aValidation) {
|
||||
NS_ENSURE_ARG_POINTER(aValidation);
|
||||
|
||||
const std::function<bool(CookieStruct&)>& aCheck) {
|
||||
if (NS_WARN_IF(!aOriginAttributes)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@@ -827,11 +761,8 @@ nsresult CookieService::AddInternal(
|
||||
aIsHttpOnly, aIsSession, aIsSecure, aIsPartitioned,
|
||||
aSameSite, aSchemeMap);
|
||||
|
||||
RefPtr<CookieValidation> cv = CookieValidation::Validate(cookieData);
|
||||
|
||||
if (aRejectWhenInvalid && cv->Result() != nsICookieValidation::eOK) {
|
||||
cv.forget(aValidation);
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
if (!aCheck(cookieData)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<Cookie> cookie = Cookie::Create(cookieData, *aOriginAttributes);
|
||||
@@ -842,8 +773,6 @@ nsresult CookieService::AddInternal(
|
||||
currentTimeInUsec, aCookieURI, VoidCString(), aFromHttp,
|
||||
!aOriginAttributes->mPartitionKey.IsEmpty(), nullptr,
|
||||
aOperationID);
|
||||
|
||||
cv.forget(aValidation);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -1720,11 +1649,20 @@ bool CookieService::SetCookiesFromIPC(const nsACString& aBaseDomain,
|
||||
int64_t currentTimeInUsec = PR_Now();
|
||||
|
||||
for (const CookieStruct& cookieData : aCookies) {
|
||||
RefPtr<CookieValidation> validation = CookieValidation::ValidateForHost(
|
||||
cookieData, aHostURI, aBaseDomain, false, aFromHttp);
|
||||
MOZ_ASSERT(validation);
|
||||
if (!CookieCommons::CheckPathSize(cookieData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (validation->Result() != nsICookieValidation::eOK) {
|
||||
// reject cookie if it's over the size limit, per RFC2109
|
||||
if (!CookieCommons::CheckNameAndValueSize(cookieData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CookieCommons::CheckName(cookieData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CookieCommons::CheckValue(cookieData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -140,17 +140,6 @@ class CookieService final : public nsICookieService,
|
||||
// private browsing.
|
||||
RefPtr<CookieStorage> mPersistentStorage;
|
||||
RefPtr<CookieStorage> mPrivateStorage;
|
||||
|
||||
private:
|
||||
nsresult AddInternal(nsIURI* aCookieURI, const nsACString& aHost,
|
||||
const nsACString& aPath, const nsACString& aName,
|
||||
const nsACString& aValue, bool aIsSecure,
|
||||
bool aIsHttpOnly, bool aIsSession, int64_t aExpiry,
|
||||
OriginAttributes* aOriginAttributes, int32_t aSameSite,
|
||||
nsICookie::schemeType aSchemeMap, bool aIsPartitioned,
|
||||
bool aFromHttp, const nsID* aOperationID,
|
||||
bool aRejectWhenInvalid,
|
||||
nsICookieValidation** aValidation);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
||||
@@ -1,559 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CookieValidation.h"
|
||||
#include "CookieLogging.h"
|
||||
#include "CookieService.h"
|
||||
#include "mozilla/dom/nsMixedContentBlocker.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
|
||||
constexpr uint32_t kMaxBytesPerCookie = 4096;
|
||||
constexpr uint32_t kMaxBytesPerDomain = 1024;
|
||||
constexpr uint32_t kMaxBytesPerPath = 1024;
|
||||
|
||||
using namespace mozilla::net;
|
||||
|
||||
NS_IMPL_ISUPPORTS(CookieValidation, nsICookieValidation)
|
||||
|
||||
CookieValidation::CookieValidation(const CookieStruct& aCookieData)
|
||||
: mCookieData(aCookieData) {}
|
||||
|
||||
// static
|
||||
already_AddRefed<CookieValidation> CookieValidation::Validate(
|
||||
const CookieStruct& aCookieData) {
|
||||
RefPtr<CookieValidation> cv = new CookieValidation(aCookieData);
|
||||
cv->ValidateInternal();
|
||||
return cv.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<CookieValidation> CookieValidation::ValidateForHost(
|
||||
const CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain, bool aRequireHostMatch, bool aFromHttp) {
|
||||
RefPtr<CookieValidation> cv = new CookieValidation(aCookieData);
|
||||
cv->ValidateForHostInternal(aHostURI, aBaseDomain, aRequireHostMatch,
|
||||
aFromHttp);
|
||||
return cv.forget();
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<CookieValidation> CookieValidation::ValidateInContext(
|
||||
const CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain, bool aRequireHostMatch, bool aFromHttp,
|
||||
bool aIsForeignAndNotAddon, bool aPartitionedOnly,
|
||||
bool aIsInPrivateBrowsing) {
|
||||
RefPtr<CookieValidation> cv = new CookieValidation(aCookieData);
|
||||
cv->ValidateInContextInternal(aHostURI, aBaseDomain, aRequireHostMatch,
|
||||
aFromHttp, aIsForeignAndNotAddon,
|
||||
aPartitionedOnly, aIsInPrivateBrowsing);
|
||||
return cv.forget();
|
||||
}
|
||||
|
||||
void CookieValidation::ValidateInternal() {
|
||||
MOZ_ASSERT(mResult == eOK);
|
||||
|
||||
// reject cookie if name and value are empty, per RFC6265bis
|
||||
if (mCookieData.name().IsEmpty() && mCookieData.value().IsEmpty()) {
|
||||
mResult = eRejectedEmptyNameAndValue;
|
||||
return;
|
||||
}
|
||||
|
||||
// reject cookie if it's over the size limit, per RFC2109
|
||||
if (!CheckNameAndValueSize(mCookieData)) {
|
||||
mResult = eRejectedNameValueOversize;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckName(mCookieData)) {
|
||||
mResult = eRejectedInvalidCharName;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CheckValue(mCookieData)) {
|
||||
mResult = eRejectedInvalidCharValue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCookieData.path().Length() > kMaxBytesPerPath) {
|
||||
mResult = eRejectedAttributePathOversize;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCookieData.path().Contains('\t')) {
|
||||
mResult = eRejectedInvalidPath;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCookieData.host().Length() > kMaxBytesPerDomain) {
|
||||
mResult = eRejectedAttributeDomainOversize;
|
||||
return;
|
||||
}
|
||||
|
||||
// If a cookie is nameless, then its value must not start with
|
||||
// `__Host-` or `__Secure-`
|
||||
if (mCookieData.name().IsEmpty() && (HasSecurePrefix(mCookieData.value()) ||
|
||||
HasHostPrefix(mCookieData.value()))) {
|
||||
mResult = eRejectedInvalidPrefix;
|
||||
return;
|
||||
}
|
||||
|
||||
// If same-site is explicitly set to 'none' but this is not a secure context,
|
||||
// let's abort the parsing.
|
||||
if (!mCookieData.isSecure() &&
|
||||
mCookieData.sameSite() == nsICookie::SAMESITE_NONE) {
|
||||
if (StaticPrefs::network_cookie_sameSite_noneRequiresSecure()) {
|
||||
mResult = eRejectedNoneRequiresSecure;
|
||||
return;
|
||||
}
|
||||
|
||||
// Still warn about the missing Secure attribute when not enforcing.
|
||||
mWarnings.mSameSiteNoneRequiresSecureForBeta = true;
|
||||
}
|
||||
|
||||
// This part checks if the caleers have set the expiry value to max 400 days.
|
||||
if (!mCookieData.isSession()) {
|
||||
int64_t maxageCap = StaticPrefs::network_cookie_maxageCap();
|
||||
int64_t currentTimeInSec = PR_Now() / PR_USEC_PER_SEC;
|
||||
int64_t expiry = mCookieData.expiry() / PR_USEC_PER_SEC;
|
||||
if (maxageCap && expiry > currentTimeInSec + maxageCap) {
|
||||
mResult = eRejectedAttributeExpiryOversize;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CookieValidation::ValidateForHostInternal(nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain,
|
||||
bool aRequireHostMatch,
|
||||
bool aFromHttp) {
|
||||
MOZ_ASSERT(mResult == eOK);
|
||||
|
||||
ValidateInternal();
|
||||
if (mResult != eOK) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aBaseDomain.IsEmpty() &&
|
||||
!CheckDomain(mCookieData, aHostURI, aBaseDomain, aRequireHostMatch)) {
|
||||
mResult = eRejectedInvalidDomain;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the new cookie is httponly, make sure we're not coming from script
|
||||
if (!aFromHttp && mCookieData.isHttpOnly()) {
|
||||
mResult = eRejectedHttpOnlyButFromScript;
|
||||
return;
|
||||
}
|
||||
|
||||
bool potentiallyTrustworthy =
|
||||
nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
|
||||
|
||||
if (!CheckPrefixes(mCookieData, potentiallyTrustworthy)) {
|
||||
mResult = eRejectedInvalidPrefix;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the new cookie is non-https and wants to set secure flag,
|
||||
// browser have to ignore this new cookie.
|
||||
// (draft-ietf-httpbis-cookie-alone section 3.1)
|
||||
if (mCookieData.isSecure() && !potentiallyTrustworthy) {
|
||||
mResult = eRejectedSecureButNonHttps;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCookieData.sameSite() == nsICookie::SAMESITE_UNSET) {
|
||||
bool laxByDefault =
|
||||
StaticPrefs::network_cookie_sameSite_laxByDefault() &&
|
||||
!nsContentUtils::IsURIInPrefList(
|
||||
aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
|
||||
if (laxByDefault) {
|
||||
mWarnings.mSameSiteLaxForced = true;
|
||||
} else if (StaticPrefs::
|
||||
network_cookie_sameSite_laxByDefaultWarningsForBeta()) {
|
||||
mWarnings.mSameSiteLaxForcedForBeta = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CookieValidation::ValidateInContextInternal(
|
||||
nsIURI* aHostURI, const nsACString& aBaseDomain, bool aRequireHostMatch,
|
||||
bool aFromHttp, bool aIsForeignAndNotAddon, bool aPartitionedOnly,
|
||||
bool aIsInPrivateBrowsing) {
|
||||
MOZ_ASSERT(mResult == eOK);
|
||||
|
||||
ValidateForHostInternal(aHostURI, aBaseDomain, aRequireHostMatch, aFromHttp);
|
||||
if (mResult != eOK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the cookie is same-site but in a cross site context, browser must
|
||||
// ignore the cookie.
|
||||
bool laxByDefault =
|
||||
StaticPrefs::network_cookie_sameSite_laxByDefault() &&
|
||||
!nsContentUtils::IsURIInPrefList(
|
||||
aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
|
||||
uint32_t sameSite = mCookieData.sameSite();
|
||||
if (sameSite == nsICookie::SAMESITE_UNSET) {
|
||||
sameSite =
|
||||
laxByDefault ? nsICookie::SAMESITE_LAX : nsICookie::SAMESITE_NONE;
|
||||
}
|
||||
|
||||
if (sameSite != nsICookie::SAMESITE_NONE && aIsForeignAndNotAddon) {
|
||||
mResult = eRejectedForNonSameSiteness;
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the partitioned cookie is set with the secure attribute if CHIPS
|
||||
// is enabled. This check should be part of ValidateInternal but it's not
|
||||
// because of bug 1965880.
|
||||
if (StaticPrefs::network_cookie_CHIPS_enabled() &&
|
||||
mCookieData.isPartitioned() && !mCookieData.isSecure()) {
|
||||
mResult = eRejectedPartitionedRequiresSecure;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieValidation::GetResult(nsICookieValidation::ValidationError* aRetval) {
|
||||
NS_ENSURE_ARG_POINTER(aRetval);
|
||||
*aRetval = mResult;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieValidation::CheckDomain(const CookieStruct& aCookieData,
|
||||
nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain,
|
||||
bool aRequireHostMatch) {
|
||||
// Note: The logic in this function is mirrored in
|
||||
// toolkit/components/extensions/ext-cookies.js:checkSetCookiePermissions().
|
||||
// If it changes, please update that function, or file a bug for someone
|
||||
// else to do so.
|
||||
|
||||
if (aCookieData.host().IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get host from aHostURI
|
||||
nsAutoCString hostFromURI;
|
||||
nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI);
|
||||
|
||||
// check whether the host is either an IP address, an alias such as
|
||||
// 'localhost', an eTLD such as 'co.uk', or the empty string. in these
|
||||
// cases, require an exact string match for the domain, and leave the cookie
|
||||
// as a non-domain one. bug 105917 originally noted the requirement to deal
|
||||
// with IP addresses.
|
||||
if (aRequireHostMatch) {
|
||||
return hostFromURI.Equals(aCookieData.host());
|
||||
}
|
||||
|
||||
nsCString cookieHost = aCookieData.host();
|
||||
// Tolerate leading '.' characters, but not if it's otherwise an empty host.
|
||||
if (aCookieData.host().Length() > 1 && aCookieData.host().First() == '.') {
|
||||
cookieHost.Cut(0, 1);
|
||||
}
|
||||
|
||||
// ensure the proposed domain is derived from the base domain; and also
|
||||
// that the host domain is derived from the proposed domain (per RFC2109).
|
||||
if (CookieCommons::IsSubdomainOf(cookieHost, aBaseDomain) &&
|
||||
CookieCommons::IsSubdomainOf(hostFromURI, cookieHost)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* note: RFC2109 section 4.3.2 requires that we check the following:
|
||||
* that the portion of host not in domain does not contain a dot.
|
||||
* this prevents hosts of the form x.y.co.nz from setting cookies in the
|
||||
* entire .co.nz domain. however, it's only a only a partial solution and
|
||||
* it breaks sites (IE doesn't enforce it), so we don't perform this check.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieValidation::HasSecurePrefix(const nsACString& aString) {
|
||||
return StringBeginsWith(aString, "__Secure-"_ns,
|
||||
nsCaseInsensitiveCStringComparator);
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieValidation::HasHostPrefix(const nsACString& aString) {
|
||||
return StringBeginsWith(aString, "__Host-"_ns,
|
||||
nsCaseInsensitiveCStringComparator);
|
||||
}
|
||||
|
||||
// CheckPrefixes
|
||||
//
|
||||
// Reject cookies whose name starts with the magic prefixes from
|
||||
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis
|
||||
// if they do not meet the criteria required by the prefix.
|
||||
bool CookieValidation::CheckPrefixes(const CookieStruct& aCookieData,
|
||||
bool aSecureRequest) {
|
||||
bool hasSecurePrefix = HasSecurePrefix(aCookieData.name());
|
||||
bool hasHostPrefix = HasHostPrefix(aCookieData.name());
|
||||
|
||||
if (!hasSecurePrefix && !hasHostPrefix) {
|
||||
// not one of the magic prefixes: carry on
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!aSecureRequest || !aCookieData.isSecure()) {
|
||||
// the magic prefixes may only be used from a secure request and
|
||||
// the secure attribute must be set on the cookie
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasHostPrefix) {
|
||||
// The host prefix requires that the path is "/" and that the cookie had no
|
||||
// domain attribute. FixDomain() and FixPath() from CookieParser MUST be
|
||||
// run first to make sure invalid attributes are rejected and to
|
||||
// regularlize them. In particular all explicit domain attributes result in
|
||||
// a host that starts with a dot, and if the host doesn't start with a dot
|
||||
// it correctly matches the true host.
|
||||
if (aCookieData.host()[0] == '.' ||
|
||||
!aCookieData.path().EqualsLiteral("/")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CookieValidation::RetrieveErrorLogData(uint32_t* aFlags,
|
||||
nsACString& aCategory,
|
||||
nsACString& aKey,
|
||||
nsTArray<nsString>& aParams) const {
|
||||
MOZ_ASSERT(aFlags);
|
||||
MOZ_ASSERT(aParams.IsEmpty());
|
||||
|
||||
*aFlags = nsIScriptError::errorFlag;
|
||||
|
||||
#define SET_LOG_DATA(category, x) \
|
||||
aCategory = category; \
|
||||
aKey = x; \
|
||||
aParams.AppendElement(NS_ConvertUTF8toUTF16(mCookieData.name()));
|
||||
|
||||
switch (mResult) {
|
||||
case eOK:
|
||||
return;
|
||||
|
||||
case eRejectedEmptyNameAndValue: {
|
||||
*aFlags = nsIScriptError::warningFlag;
|
||||
aCategory.Assign(CONSOLE_REJECTION_CATEGORY);
|
||||
aKey.Assign("CookieRejectedEmptyNameAndValue"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedNoneRequiresSecure: {
|
||||
SET_LOG_DATA(CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieRejectedNonRequiresSecure2"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedPartitionedRequiresSecure: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedPartitionedRequiresSecure"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedNameValueOversize: {
|
||||
*aFlags = nsIScriptError::warningFlag;
|
||||
aCategory.Assign(CONSOLE_OVERSIZE_CATEGORY);
|
||||
aKey.Assign("CookieOversize"_ns);
|
||||
|
||||
aParams.AppendElement(NS_ConvertUTF8toUTF16(mCookieData.name()));
|
||||
|
||||
nsString size;
|
||||
size.AppendInt(kMaxBytesPerCookie);
|
||||
aParams.AppendElement(size);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedInvalidCharName: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidCharName"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedInvalidCharValue: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidCharValue"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedAttributePathOversize: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedAttributePathOversize"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedAttributeDomainOversize: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedAttributeDomainOversize"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedAttributeExpiryOversize: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedAttributeExpiryOversize"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedInvalidPath: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY, "CookieRejectedInvalidPath"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedInvalidDomain: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidDomain"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedInvalidPrefix: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedInvalidPrefix"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedHttpOnlyButFromScript: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedHttpOnlyButFromScript"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedSecureButNonHttps: {
|
||||
SET_LOG_DATA(CONSOLE_REJECTION_CATEGORY,
|
||||
"CookieRejectedSecureButNonHttps"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
case eRejectedForNonSameSiteness: {
|
||||
SET_LOG_DATA(CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieRejectedForNonSameSiteness"_ns);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SET_LOG_DATA
|
||||
}
|
||||
|
||||
void CookieValidation::ReportErrorsAndWarnings(nsIConsoleReportCollector* aCRC,
|
||||
nsIURI* aHostURI) const {
|
||||
if (mResult != eOK) {
|
||||
uint32_t flags;
|
||||
nsAutoCString category;
|
||||
nsAutoCString key;
|
||||
nsTArray<nsString> params;
|
||||
|
||||
RetrieveErrorLogData(&flags, category, key, params);
|
||||
|
||||
CookieLogging::LogMessageToConsole(aCRC, aHostURI, flags, category, key,
|
||||
params);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWarnings.mSameSiteNoneRequiresSecureForBeta) {
|
||||
CookieLogging::LogMessageToConsole(
|
||||
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieRejectedNonRequiresSecureForBeta3"_ns,
|
||||
AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(mCookieData.name()),
|
||||
SAMESITE_MDN_URL});
|
||||
}
|
||||
|
||||
if (mWarnings.mSameSiteLaxForced) {
|
||||
CookieLogging::LogMessageToConsole(
|
||||
aCRC, aHostURI, nsIScriptError::infoFlag, CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieLaxForced2"_ns,
|
||||
AutoTArray<nsString, 1>{NS_ConvertUTF8toUTF16(mCookieData.name())});
|
||||
}
|
||||
|
||||
if (mWarnings.mSameSiteLaxForcedForBeta) {
|
||||
CookieLogging::LogMessageToConsole(
|
||||
aCRC, aHostURI, nsIScriptError::warningFlag, CONSOLE_SAMESITE_CATEGORY,
|
||||
"CookieLaxForcedForBeta2"_ns,
|
||||
AutoTArray<nsString, 2>{NS_ConvertUTF8toUTF16(mCookieData.name()),
|
||||
SAMESITE_MDN_URL});
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieValidation::GetErrorString(nsAString& aResult) {
|
||||
if (mResult == eOK) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t flags;
|
||||
nsAutoCString category;
|
||||
nsAutoCString key;
|
||||
nsTArray<nsString> params;
|
||||
|
||||
RetrieveErrorLogData(&flags, category, key, params);
|
||||
|
||||
return nsContentUtils::FormatLocalizedString(
|
||||
nsContentUtils::eNECKO_PROPERTIES_en_US, key.get(), params, aResult);
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieValidation::CheckNameAndValueSize(const CookieStruct& aCookieData) {
|
||||
// reject cookie if it's over the size limit, per RFC2109
|
||||
return (aCookieData.name().Length() + aCookieData.value().Length()) <=
|
||||
kMaxBytesPerCookie;
|
||||
}
|
||||
|
||||
bool CookieValidation::CheckName(const CookieStruct& aCookieData) {
|
||||
if (!aCookieData.name().IsEmpty() && (aCookieData.name().First() == 0x20 ||
|
||||
aCookieData.name().Last() == 0x20)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char illegalNameCharacters[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D,
|
||||
0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
|
||||
0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x3B, 0x3D, 0x7F, 0x00};
|
||||
|
||||
const auto* start = aCookieData.name().BeginReading();
|
||||
const auto* end = aCookieData.name().EndReading();
|
||||
|
||||
auto charFilter = [&](unsigned char c) {
|
||||
if (StaticPrefs::network_cookie_blockUnicode() && c >= 0x80) {
|
||||
return true;
|
||||
}
|
||||
return std::find(std::begin(illegalNameCharacters),
|
||||
std::end(illegalNameCharacters),
|
||||
c) != std::end(illegalNameCharacters);
|
||||
};
|
||||
|
||||
return std::find_if(start, end, charFilter) == end;
|
||||
}
|
||||
|
||||
bool CookieValidation::CheckValue(const CookieStruct& aCookieData) {
|
||||
if (!aCookieData.value().IsEmpty() && (aCookieData.value().First() == 0x20 ||
|
||||
aCookieData.value().Last() == 0x20)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// reject cookie if value contains an RFC 6265 disallowed character - see
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1191423
|
||||
// NOTE: this is not the full set of characters disallowed by 6265 - notably
|
||||
// 0x09, 0x20, 0x22, 0x2C, and 0x5C are missing from this list.
|
||||
const char illegalCharacters[] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C,
|
||||
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x3B, 0x7F, 0x00};
|
||||
|
||||
const auto* start = aCookieData.value().BeginReading();
|
||||
const auto* end = aCookieData.value().EndReading();
|
||||
|
||||
auto charFilter = [&](unsigned char c) {
|
||||
if (StaticPrefs::network_cookie_blockUnicode() && c >= 0x80) {
|
||||
return true;
|
||||
}
|
||||
return std::find(std::begin(illegalCharacters), std::end(illegalCharacters),
|
||||
c) != std::end(illegalCharacters);
|
||||
};
|
||||
|
||||
return std::find_if(start, end, charFilter) == end;
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_CookieValidation_h
|
||||
#define mozilla_net_CookieValidation_h
|
||||
|
||||
#include "nsICookieValidation.h"
|
||||
#include "Cookie.h"
|
||||
|
||||
class nsIConsoleReportCollector;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
constexpr auto CONSOLE_CHIPS_CATEGORY = "cookiesCHIPS"_ns;
|
||||
constexpr auto CONSOLE_OVERSIZE_CATEGORY = "cookiesOversize"_ns;
|
||||
constexpr auto CONSOLE_REJECTION_CATEGORY = "cookiesRejection"_ns;
|
||||
constexpr auto CONSOLE_SAMESITE_CATEGORY = "cookieSameSite"_ns;
|
||||
constexpr auto SAMESITE_MDN_URL =
|
||||
"https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Set-Cookie#"
|
||||
u"samesitesamesite-value"_ns;
|
||||
|
||||
class CookieValidation final : public nsICookieValidation {
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICOOKIEVALIDATION
|
||||
|
||||
public:
|
||||
static already_AddRefed<CookieValidation> Validate(
|
||||
const CookieStruct& aCookieData);
|
||||
|
||||
static already_AddRefed<CookieValidation> ValidateForHost(
|
||||
const CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain, bool aRequireHostMatch, bool aFromHttp);
|
||||
|
||||
static already_AddRefed<CookieValidation> ValidateInContext(
|
||||
const CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain, bool aRequireHostMatch, bool aFromHttp,
|
||||
bool aIsForeignAndNotAddon, bool aPartitionedOnly,
|
||||
bool aIsInPrivateBrowsing);
|
||||
|
||||
static CookieValidation* Cast(nsICookieValidation* aValidation) {
|
||||
return static_cast<CookieValidation*>(aValidation);
|
||||
}
|
||||
|
||||
nsICookieValidation::ValidationError Result() const { return mResult; }
|
||||
|
||||
void ReportErrorsAndWarnings(nsIConsoleReportCollector* aCRC,
|
||||
nsIURI* aHostURI) const;
|
||||
|
||||
private:
|
||||
explicit CookieValidation(const CookieStruct& aCookieData);
|
||||
~CookieValidation() = default;
|
||||
|
||||
void ValidateInternal();
|
||||
|
||||
void ValidateForHostInternal(nsIURI* aHostURI, const nsACString& aBaseDomain,
|
||||
bool aRequireHostMatch, bool aFromHttp);
|
||||
|
||||
void ValidateInContextInternal(
|
||||
nsIURI* aHostURI, const nsACString& aBaseDomain, bool aRequireHostMatch,
|
||||
bool aFromHttp, bool aIsForeignAndNotAddon, bool aPartitionedOnly,
|
||||
bool aIsInPrivateBrowsing);
|
||||
|
||||
static bool CheckNameAndValueSize(const CookieStruct& aCookieData);
|
||||
|
||||
static bool CheckName(const CookieStruct& aCookieData);
|
||||
|
||||
static bool CheckValue(const CookieStruct& aCookieData);
|
||||
|
||||
static bool CheckDomain(const CookieStruct& aCookieData, nsIURI* aHostURI,
|
||||
const nsACString& aBaseDomain,
|
||||
bool aRequireHostMatch);
|
||||
|
||||
static bool CheckPrefixes(const CookieStruct& aCookieData,
|
||||
bool aSecureRequest);
|
||||
|
||||
static bool HasSecurePrefix(const nsACString& aString);
|
||||
static bool HasHostPrefix(const nsACString& aString);
|
||||
|
||||
CookieStruct mCookieData;
|
||||
|
||||
nsICookieValidation::ValidationError mResult = eOK;
|
||||
|
||||
void RetrieveErrorLogData(uint32_t* aFlags, nsACString& aCategory,
|
||||
nsACString& aKey,
|
||||
nsTArray<nsString>& aParams) const;
|
||||
|
||||
struct Warnings {
|
||||
bool mSameSiteLaxForced = false;
|
||||
bool mSameSiteLaxForcedForBeta = false;
|
||||
bool mSameSiteNoneRequiresSecureForBeta = false;
|
||||
} mWarnings;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_CookieValidation_h
|
||||
@@ -15,7 +15,6 @@ XPIDL_SOURCES += [
|
||||
"nsICookieNotification.idl",
|
||||
"nsICookiePermission.idl",
|
||||
"nsICookieService.idl",
|
||||
"nsICookieValidation.idl",
|
||||
"nsIThirdPartyCookieBlockingExceptionListService.idl",
|
||||
]
|
||||
|
||||
@@ -35,7 +34,6 @@ EXPORTS.mozilla.net = [
|
||||
"CookieServiceChild.h",
|
||||
"CookieServiceParent.h",
|
||||
"CookieStorage.h",
|
||||
"CookieValidation.h",
|
||||
"ThirdPartyCookieBlockingExceptions.h",
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
@@ -51,7 +49,6 @@ UNIFIED_SOURCES += [
|
||||
"CookieServiceChild.cpp",
|
||||
"CookieServiceParent.cpp",
|
||||
"CookieStorage.cpp",
|
||||
"CookieValidation.cpp",
|
||||
"ThirdPartyCookieBlockingExceptions.cpp",
|
||||
]
|
||||
XPCSHELL_TESTS_MANIFESTS += [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@ class CookieStruct;
|
||||
%}
|
||||
|
||||
[ptr] native OriginAttributesPtr(mozilla::OriginAttributes);
|
||||
|
||||
interface nsICookieValidation;
|
||||
native CheckStructFunctionRef(const std::function< bool(mozilla::net::CookieStruct&) > &);
|
||||
|
||||
/**
|
||||
* An optional interface for accessing or removing the cookies
|
||||
@@ -133,7 +132,7 @@ interface nsICookieManager : nsISupports
|
||||
* true if the cookie should be stored with the Partitioned attribute.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
nsICookieValidation add(in AUTF8String aHost,
|
||||
void add(in AUTF8String aHost,
|
||||
in AUTF8String aPath,
|
||||
in ACString aName,
|
||||
in AUTF8String aValue,
|
||||
@@ -146,29 +145,6 @@ interface nsICookieManager : nsISupports
|
||||
in nsICookie_schemeType aSchemeMap,
|
||||
[optional] in boolean aIsPartitioned);
|
||||
|
||||
/**
|
||||
* Similar to the previous method but without validation as a blocker.
|
||||
* This method is a temporary thing. See bug XXX.
|
||||
*/
|
||||
[implicit_jscontext]
|
||||
nsICookieValidation addForAddOn(in AUTF8String aHost,
|
||||
in AUTF8String aPath,
|
||||
in ACString aName,
|
||||
in AUTF8String aValue,
|
||||
in boolean aIsSecure,
|
||||
in boolean aIsHttpOnly,
|
||||
in boolean aIsSession,
|
||||
in int64_t aExpiry,
|
||||
in jsval aOriginAttributes,
|
||||
in int32_t aSameSite,
|
||||
in nsICookie_schemeType aSchemeMap,
|
||||
[optional] in boolean aIsPartitioned);
|
||||
|
||||
/**
|
||||
* This method is the non-xpcom version of add(). In case of an invalid
|
||||
* cookie, it returns a nsICookieValidation object and NS_ERROR_ILLEGAL_VALUE
|
||||
* as error code.
|
||||
*/
|
||||
[notxpcom]
|
||||
nsresult addNative(in nsIURI aCookieURI,
|
||||
in AUTF8String aHost,
|
||||
@@ -185,7 +161,7 @@ interface nsICookieManager : nsISupports
|
||||
in boolean aIsPartitioned,
|
||||
in boolean aFromHttp,
|
||||
in nsIDPtr aOperationID,
|
||||
out nsICookieValidation aValidation);
|
||||
in CheckStructFunctionRef aCheckValid);
|
||||
|
||||
/**
|
||||
* Find whether a given cookie already exists.
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(79c99e25-8b06-4e68-8935-bdbe22fa4010)]
|
||||
interface nsICookieValidation : nsISupports
|
||||
{
|
||||
cenum ValidationError : 32 {
|
||||
eOK,
|
||||
eRejectedEmptyNameAndValue,
|
||||
eRejectedNameValueOversize,
|
||||
eRejectedInvalidCharName,
|
||||
eRejectedInvalidCharValue,
|
||||
eRejectedInvalidPath,
|
||||
eRejectedInvalidDomain,
|
||||
eRejectedInvalidPrefix,
|
||||
eRejectedNoneRequiresSecure,
|
||||
eRejectedPartitionedRequiresSecure,
|
||||
eRejectedHttpOnlyButFromScript,
|
||||
eRejectedSecureButNonHttps,
|
||||
eRejectedForNonSameSiteness,
|
||||
eRejectedAttributePathOversize,
|
||||
eRejectedAttributeDomainOversize,
|
||||
eRejectedAttributeExpiryOversize,
|
||||
};
|
||||
|
||||
readonly attribute nsICookieValidation_ValidationError result;
|
||||
|
||||
// This returns an empty string if the result is `eOK`.
|
||||
readonly attribute AString errorString;
|
||||
};
|
||||
@@ -101,8 +101,8 @@ add_task(async () => {
|
||||
});
|
||||
await validateTelemetryValues(
|
||||
{
|
||||
setCookies: 5,
|
||||
setForeigns: 1,
|
||||
setCookies: 6,
|
||||
setForeigns: 2,
|
||||
setPartitioneds: 3,
|
||||
setForeignPartitioneds: 1,
|
||||
},
|
||||
@@ -121,8 +121,8 @@ add_task(async () => {
|
||||
|
||||
await validateTelemetryValues(
|
||||
{
|
||||
setCookies: 6,
|
||||
setForeigns: 2,
|
||||
setCookies: 8,
|
||||
setForeigns: 4,
|
||||
setPartitioneds: 4,
|
||||
setForeignPartitioneds: 2,
|
||||
},
|
||||
|
||||
@@ -176,7 +176,7 @@ add_task(async _ => {
|
||||
}
|
||||
|
||||
info("Let's set a cookie without scheme");
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.org",
|
||||
"/",
|
||||
"a",
|
||||
@@ -189,7 +189,6 @@ add_task(async _ => {
|
||||
Ci.nsICookie.SAMESITE_LAX,
|
||||
Ci.nsICookie.SCHEME_UNSET
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
let cookies = Services.cookies.getCookiesFromHost("example.org", {});
|
||||
Assert.equal(cookies.length, 1, "We expect 1 cookie only");
|
||||
|
||||
@@ -69,12 +69,6 @@ CookieRejectedInvalidPrefix=Cookie “%1$S” has been rejected for invalid pref
|
||||
CookieRejectedInvalidPath=Cookie “%1$S” has been rejected for invalid path.
|
||||
# LOCALIZATION NOTE (CookieRejectedInvalidCharValue): %1$S is the cookie name.
|
||||
CookieRejectedInvalidCharValue=Cookie “%1$S” has been rejected for invalid characters in the value.
|
||||
# LOCALIZATION NOTE (CookieRejectedAttributePathOversize): %1$S is the cookie name.
|
||||
CookieRejectedAttributePathOversize=Cookie “%1$S” has been rejected because its path attribute is too big.
|
||||
# LOCALIZATION NOTE (CookieRejectedAttributeDomainOversize): %1$S is the cookie name.
|
||||
CookieRejectedAttributeDomainOversize=Cookie “%1$S” has been rejected because its path attribute is too big.
|
||||
# LOCALIZATION NOTE (CookieRejectedAttributeExpiryOversize): %1$S is the cookie name.
|
||||
CookieRejectedAttributeExpiryOversize=Cookie “%1$S” has been rejected because its expiration date is over the limit.
|
||||
# LOCALIZATION NOTE (CookieRejectedHttpOnlyButFromScript): %1$S is the cookie name.
|
||||
CookieRejectedHttpOnlyButFromScript=Cookie “%1$S” has been rejected because there is already an HTTP-Only cookie but script tried to store a new one.
|
||||
# LOCALIZATION NOTE (CookieRejectedSecureButHttp): %1$S is the cookie name.
|
||||
|
||||
@@ -5,7 +5,3 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
JAR_MANIFESTS += ["jar.mn"]
|
||||
|
||||
RESOURCE_FILES.locale.necko += [
|
||||
"en-US/necko.properties",
|
||||
]
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/net/CookieJarSettings.h"
|
||||
#include "mozilla/net/CookieValidation.h"
|
||||
#include "Cookie.h"
|
||||
#include "CookieParser.h"
|
||||
#include "nsIURI.h"
|
||||
@@ -263,7 +262,7 @@ TEST(TestCookie, TestCookieMain)
|
||||
// test some variations of the domain & path, for different domains of
|
||||
// a domain cookie
|
||||
SetACookie(cookieService, "http://www.domain.com",
|
||||
"test=domain; domain=domain.com; sameSite=lax");
|
||||
"test=domain; domain=domain.com");
|
||||
GetACookie(cookieService, "http://domain.com", cookie);
|
||||
EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=domain"));
|
||||
GetACookie(cookieService, "http://domain.com.", cookie);
|
||||
@@ -758,11 +757,9 @@ TEST(TestCookie, TestCookieMain)
|
||||
|
||||
// first, ensure a clean slate
|
||||
EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll());
|
||||
|
||||
nsCOMPtr<nsICookieValidation> cv;
|
||||
|
||||
// add some cookies
|
||||
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(uri,
|
||||
EXPECT_TRUE(NS_SUCCEEDED(
|
||||
cookieMgr2->AddNative(uri,
|
||||
"cookiemgr.test"_ns, // domain
|
||||
"/foo"_ns, // path
|
||||
"test1"_ns, // name
|
||||
@@ -772,15 +769,11 @@ TEST(TestCookie, TestCookieMain)
|
||||
true, // is session
|
||||
INT64_MAX, // expiry time
|
||||
&attrs, // originAttributes
|
||||
nsICookie::SAMESITE_LAX,
|
||||
nsICookie::SCHEME_HTTP,
|
||||
nsICookie::SAMESITE_NONE, nsICookie::SCHEME_HTTPS,
|
||||
false, // is partitioned
|
||||
true, // from http
|
||||
nullptr, // operation ID
|
||||
getter_AddRefs(cv))));
|
||||
EXPECT_TRUE(!!cv);
|
||||
EXPECT_EQ(CookieValidation::Cast(cv)->Result(), nsICookieValidation::eOK);
|
||||
|
||||
[](CookieStruct&) -> bool { return true; })));
|
||||
EXPECT_TRUE(NS_SUCCEEDED(
|
||||
cookieMgr2->AddNative(uri,
|
||||
"cookiemgr.test"_ns, // domain
|
||||
@@ -792,15 +785,13 @@ TEST(TestCookie, TestCookieMain)
|
||||
true, // is session
|
||||
PR_Now() / PR_USEC_PER_SEC + 2, // expiry time
|
||||
&attrs, // originAttributes
|
||||
nsICookie::SAMESITE_LAX, nsICookie::SCHEME_HTTP,
|
||||
nsICookie::SAMESITE_NONE, nsICookie::SCHEME_HTTPS,
|
||||
false, // is partitioned
|
||||
true, // from http
|
||||
nullptr, // operation ID
|
||||
getter_AddRefs(cv))));
|
||||
EXPECT_TRUE(!!cv);
|
||||
EXPECT_EQ(CookieValidation::Cast(cv)->Result(), nsICookieValidation::eOK);
|
||||
|
||||
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(uri,
|
||||
[](CookieStruct&) -> bool { return true; })));
|
||||
EXPECT_TRUE(NS_SUCCEEDED(
|
||||
cookieMgr2->AddNative(uri,
|
||||
"new.domain"_ns, // domain
|
||||
"/rabbit"_ns, // path
|
||||
"test3"_ns, // name
|
||||
@@ -810,15 +801,11 @@ TEST(TestCookie, TestCookieMain)
|
||||
true, // is session
|
||||
INT64_MAX, // expiry time
|
||||
&attrs, // originAttributes
|
||||
nsICookie::SAMESITE_LAX,
|
||||
nsICookie::SCHEME_HTTP,
|
||||
nsICookie::SAMESITE_NONE, nsICookie::SCHEME_HTTPS,
|
||||
false, // is partitioned
|
||||
true, // from http
|
||||
nullptr, // operation ID
|
||||
getter_AddRefs(cv))));
|
||||
EXPECT_TRUE(!!cv);
|
||||
EXPECT_EQ(CookieValidation::Cast(cv)->Result(), nsICookieValidation::eOK);
|
||||
|
||||
[](CookieStruct&) -> bool { return true; })));
|
||||
// confirm using enumerator
|
||||
nsTArray<RefPtr<nsICookie>> cookies;
|
||||
EXPECT_NS_SUCCEEDED(cookieMgr->GetCookies(cookies));
|
||||
@@ -1016,45 +1003,6 @@ TEST(TestCookie, TestCookieMain)
|
||||
// *** speed tests
|
||||
}
|
||||
|
||||
TEST(TestCookie, InvalidCharsInNameAndValue)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsICookieManager> cookieMgr =
|
||||
do_GetService(NS_COOKIEMANAGER_CONTRACTID, &rv);
|
||||
ASSERT_NS_SUCCEEDED(rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewURI(getter_AddRefs(uri), "https://cookie.test"_ns);
|
||||
|
||||
mozilla::OriginAttributes attrs;
|
||||
|
||||
// Test some invalid chars
|
||||
#define TEST_INVALID_CHARS(name, value, error) \
|
||||
{ \
|
||||
nsCOMPtr<nsICookieValidation> cv; \
|
||||
EXPECT_EQ( \
|
||||
cookieMgr->AddNative(uri, "cookiemgr.test"_ns, "/foo"_ns, name, value, \
|
||||
false, false, true, INT64_MAX, &attrs, \
|
||||
nsICookie::SAMESITE_LAX, nsICookie::SCHEME_HTTP, \
|
||||
false, true, nullptr, getter_AddRefs(cv)), \
|
||||
NS_ERROR_ILLEGAL_VALUE); \
|
||||
EXPECT_TRUE(!!cv); \
|
||||
EXPECT_EQ(CookieValidation::Cast(cv)->Result(), error); \
|
||||
}
|
||||
|
||||
TEST_INVALID_CHARS(" test invalid name"_ns, "test valid value"_ns,
|
||||
nsICookieValidation::eRejectedInvalidCharName)
|
||||
TEST_INVALID_CHARS("test invalid name "_ns, "test valid value"_ns,
|
||||
nsICookieValidation::eRejectedInvalidCharName)
|
||||
TEST_INVALID_CHARS("test valid name"_ns, " test invalid value"_ns,
|
||||
nsICookieValidation::eRejectedInvalidCharValue)
|
||||
TEST_INVALID_CHARS("test valid name"_ns, "test invalid value "_ns,
|
||||
nsICookieValidation::eRejectedInvalidCharValue)
|
||||
|
||||
#undef TEST_INVALID_CHARS
|
||||
}
|
||||
|
||||
TEST(TestCookie, OnionSite)
|
||||
{
|
||||
Preferences::SetBool("dom.securecontext.allowlist_onions", true);
|
||||
|
||||
@@ -114,7 +114,7 @@ addMessageListener("init", ({ domain }) => {
|
||||
true,
|
||||
Math.pow(2, 62),
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
is(
|
||||
|
||||
@@ -6,7 +6,7 @@ function run_test() {
|
||||
Assert.notEqual(cm, null, "Retrieving the cookie manager failed");
|
||||
|
||||
const time = new Date("Jan 1, 2030").getTime() / 1000;
|
||||
const cv = cm.add(
|
||||
cm.add(
|
||||
"example.com",
|
||||
"/",
|
||||
"C",
|
||||
@@ -16,10 +16,9 @@ function run_test() {
|
||||
false,
|
||||
time,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
const now = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
var found = false;
|
||||
|
||||
@@ -22,7 +22,7 @@ add_task(async () => {
|
||||
|
||||
// test that variants of 'baz.com' get normalized appropriately, but that
|
||||
// malformed hosts are rejected
|
||||
let cv = cm.add(
|
||||
cm.add(
|
||||
"baz.com",
|
||||
"/",
|
||||
"foo",
|
||||
@@ -32,10 +32,9 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
Assert.equal(cm.countCookiesFromHost("baz.com"), 1);
|
||||
Assert.equal(cm.countCookiesFromHost("BAZ.com"), 1);
|
||||
Assert.equal(cm.countCookiesFromHost(".baz.com"), 1);
|
||||
@@ -56,7 +55,7 @@ add_task(async () => {
|
||||
Assert.equal(cm.countCookiesFromHost("baz.com"), 0);
|
||||
|
||||
// Test that 'baz.com' and 'baz.com.' are treated differently
|
||||
cv = cm.add(
|
||||
cm.add(
|
||||
"baz.com.",
|
||||
"/",
|
||||
"foo",
|
||||
@@ -66,10 +65,9 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
Assert.equal(cm.countCookiesFromHost("baz.com"), 0);
|
||||
Assert.equal(cm.countCookiesFromHost("BAZ.com"), 0);
|
||||
Assert.equal(cm.countCookiesFromHost(".baz.com"), 0);
|
||||
@@ -82,7 +80,7 @@ add_task(async () => {
|
||||
|
||||
// test that domain cookies are illegal for IP addresses, aliases such as
|
||||
// 'localhost', and eTLD's such as 'co.uk'
|
||||
cv = cm.add(
|
||||
cm.add(
|
||||
"192.168.0.1",
|
||||
"/",
|
||||
"foo",
|
||||
@@ -92,10 +90,9 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
Assert.equal(cm.countCookiesFromHost("192.168.0.1"), 1);
|
||||
Assert.equal(cm.countCookiesFromHost("192.168.0.1."), 0);
|
||||
do_check_throws(function () {
|
||||
@@ -105,7 +102,7 @@ add_task(async () => {
|
||||
cm.countCookiesFromHost(".192.168.0.1.");
|
||||
}, Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
cv = cm.add(
|
||||
cm.add(
|
||||
"localhost",
|
||||
"/",
|
||||
"foo",
|
||||
@@ -115,10 +112,9 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
Assert.equal(cm.countCookiesFromHost("localhost"), 1);
|
||||
Assert.equal(cm.countCookiesFromHost("localhost."), 0);
|
||||
do_check_throws(function () {
|
||||
@@ -128,7 +124,7 @@ add_task(async () => {
|
||||
cm.countCookiesFromHost(".localhost.");
|
||||
}, Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
|
||||
cv = cm.add(
|
||||
cm.add(
|
||||
"co.uk",
|
||||
"/",
|
||||
"foo",
|
||||
@@ -138,10 +134,9 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
Assert.equal(cm.countCookiesFromHost("co.uk"), 1);
|
||||
Assert.equal(cm.countCookiesFromHost("co.uk."), 0);
|
||||
do_check_throws(function () {
|
||||
@@ -201,7 +196,7 @@ add_task(async () => {
|
||||
|
||||
// test that an empty host to add() or remove() works,
|
||||
// but a host of '.' doesn't
|
||||
cv = cm.add(
|
||||
cm.add(
|
||||
"",
|
||||
"/",
|
||||
"foo2",
|
||||
@@ -211,13 +206,12 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
Assert.equal(getCookieCount(), 1);
|
||||
do_check_throws(function () {
|
||||
const cv = cm.add(
|
||||
cm.add(
|
||||
".",
|
||||
"/",
|
||||
"foo3",
|
||||
@@ -227,10 +221,9 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK);
|
||||
}, Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
Assert.equal(getCookieCount(), 1);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ add_task(async () => {
|
||||
|
||||
// Test our handling of host names with a single character at the beginning
|
||||
// followed by a dot.
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"e.com",
|
||||
"/",
|
||||
"foo",
|
||||
@@ -21,10 +21,9 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
Assert.equal(Services.cookies.countCookiesFromHost("e.com"), 1);
|
||||
|
||||
CookieXPCShellUtils.createServer({ hosts: ["e.com"] });
|
||||
|
||||
@@ -9,7 +9,7 @@ add_task(async () => {
|
||||
|
||||
// Test our handling of host names with a single character consisting only
|
||||
// of a single character
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"a",
|
||||
"/",
|
||||
"foo",
|
||||
@@ -19,10 +19,9 @@ add_task(async () => {
|
||||
true,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
Assert.equal(Services.cookies.countCookiesFromHost("a"), 1);
|
||||
|
||||
CookieXPCShellUtils.createServer({ hosts: ["a"] });
|
||||
|
||||
@@ -140,7 +140,7 @@ async function run_test_1() {
|
||||
db.close();
|
||||
|
||||
// Attempt to insert a cookie with the same (name, host, path) triplet.
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
cookie.host,
|
||||
cookie.path,
|
||||
cookie.name,
|
||||
@@ -150,10 +150,9 @@ async function run_test_1() {
|
||||
cookie.isSession,
|
||||
cookie.expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
// Check that the cookie service accepted the new cookie.
|
||||
Assert.equal(Services.cookies.countCookiesFromHost(cookie.host), 1);
|
||||
|
||||
@@ -36,7 +36,7 @@ add_task(async function test_chips_migration() {
|
||||
false,
|
||||
false,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
false // isPartitioned
|
||||
);
|
||||
@@ -56,7 +56,7 @@ add_task(async function test_chips_migration() {
|
||||
false,
|
||||
false,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
true // isPartitioned
|
||||
);
|
||||
@@ -76,7 +76,7 @@ add_task(async function test_chips_migration() {
|
||||
false,
|
||||
false,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
true // isPartitioned
|
||||
);
|
||||
@@ -96,7 +96,7 @@ add_task(async function test_chips_migration() {
|
||||
false,
|
||||
false,
|
||||
{ partitionKey: "(https,example.com)" },
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
true // isPartitioned
|
||||
);
|
||||
|
||||
@@ -71,7 +71,7 @@ add_task(async () => {
|
||||
}, Cr.NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
do_check_throws(function () {
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"foo.com",
|
||||
"",
|
||||
"oh4",
|
||||
@@ -81,10 +81,9 @@ add_task(async () => {
|
||||
false,
|
||||
0,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
}, Cr.NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
do_check_throws(function () {
|
||||
|
||||
@@ -48,7 +48,7 @@ add_task(async function test_purge_counting() {
|
||||
Assert.equal(validCookies, totalCookies);
|
||||
|
||||
// add a valid cookie - this triggers the purge
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"cookie-host0.com", // any host
|
||||
"/", // path
|
||||
"cookie-name-x",
|
||||
@@ -58,10 +58,9 @@ add_task(async function test_purge_counting() {
|
||||
true, // isSession
|
||||
futureExpiry,
|
||||
{}, // OA
|
||||
Ci.nsICookie.SAMESITE_UNSET, // SameSite
|
||||
Ci.nsICookie.SAMESITE_NONE, // SameSite
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
// check that we purge all the expired cookies and not the unexpired
|
||||
validCookies = Services.cookies.cookies.length;
|
||||
|
||||
@@ -55,7 +55,7 @@ add_task(async function test_purge_counting_per_host() {
|
||||
Assert.equal(validCookies, cookieCountMax);
|
||||
|
||||
// add a cookie - this will trigger the purge
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
host,
|
||||
"/", // path
|
||||
"cookie-name-x",
|
||||
@@ -65,10 +65,9 @@ add_task(async function test_purge_counting_per_host() {
|
||||
true, // isSession
|
||||
futureExpiry,
|
||||
{}, // OA
|
||||
Ci.nsICookie.SAMESITE_UNSET, // SameSite
|
||||
Ci.nsICookie.SAMESITE_NONE, // SameSite
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
// check that we purge down to the cookieMax (plus the cookie added)
|
||||
validCookies = Services.cookies.countCookiesFromHost(host);
|
||||
|
||||
@@ -67,7 +67,7 @@ function* do_run_test() {
|
||||
// Test that expired cookies for a domain are evicted before live ones.
|
||||
let shortExpiry = Math.floor(Date.now() / 1000 + 2);
|
||||
setCookies("captchart.com", 49, futureExpiry);
|
||||
let cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"captchart.com",
|
||||
"",
|
||||
"test100",
|
||||
@@ -77,16 +77,14 @@ function* do_run_test() {
|
||||
false,
|
||||
shortExpiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
do_timeout(2100, continue_test);
|
||||
yield;
|
||||
|
||||
Assert.equal(countCookies("captchart.com", "captchart.com"), 50);
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"captchart.com",
|
||||
"",
|
||||
"test200",
|
||||
@@ -96,11 +94,9 @@ function* do_run_test() {
|
||||
false,
|
||||
futureExpiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
Assert.equal(countCookies("captchart.com", "captchart.com"), 50);
|
||||
|
||||
for (let cookie of Services.cookies.getCookiesFromHost("captchart.com", {})) {
|
||||
@@ -113,7 +109,7 @@ function* do_run_test() {
|
||||
// set 'aNumber' cookies with host 'aHost', with distinct names.
|
||||
function setCookies(aHost, aNumber, aExpiry) {
|
||||
for (let i = 0; i < aNumber; ++i) {
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
aHost,
|
||||
"",
|
||||
"test" + i,
|
||||
@@ -123,10 +119,9 @@ function setCookies(aHost, aNumber, aExpiry) {
|
||||
false,
|
||||
aExpiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ function set_cookies(begin, end, expiry) {
|
||||
let beginTime;
|
||||
for (let i = begin; i < end; ++i) {
|
||||
let host = "eviction." + i + ".tests";
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
host,
|
||||
"",
|
||||
"test",
|
||||
@@ -201,10 +201,9 @@ function set_cookies(begin, end, expiry) {
|
||||
false,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
if (i == begin) {
|
||||
beginTime = get_creationTime(i);
|
||||
|
||||
@@ -39,7 +39,7 @@ add_task(async function run_test() {
|
||||
false, // isHttpOnly
|
||||
false, // isBrowserElement
|
||||
{ partitionKey: "(https,example.com)" },
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
false // isPartitioned
|
||||
);
|
||||
@@ -59,7 +59,7 @@ add_task(async function run_test() {
|
||||
false, // isHttpOnly
|
||||
false, // isBrowserElement
|
||||
{ partitionKey: "(https,example.com)" },
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
true // isPartitioned
|
||||
);
|
||||
@@ -79,7 +79,7 @@ add_task(async function run_test() {
|
||||
false, // isHttpOnly
|
||||
false, // isBrowserElement
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
false // isPartitioned
|
||||
);
|
||||
@@ -99,7 +99,7 @@ add_task(async function run_test() {
|
||||
false, // isHttpOnly
|
||||
false, // isBrowserElement
|
||||
{ partitionKey: "(https,example.org)" },
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
false // isPartitioned
|
||||
);
|
||||
@@ -119,7 +119,7 @@ add_task(async function run_test() {
|
||||
false, // isHttpOnly
|
||||
false, // isBrowserElement
|
||||
{ partitionKey: "(https,example.org)" },
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
true // isPartitioned
|
||||
);
|
||||
|
||||
@@ -49,7 +49,7 @@ add_task(async function test_schema_13_db() {
|
||||
false,
|
||||
false,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
!!(i % 2) // isPartitioned
|
||||
);
|
||||
|
||||
@@ -41,7 +41,7 @@ add_task(async function test_schema_14_migration() {
|
||||
false,
|
||||
false,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET,
|
||||
!!(i % 2) // isPartitioned
|
||||
);
|
||||
|
||||
@@ -73,7 +73,7 @@ function run_test() {
|
||||
// Sets a cookie for the test domain
|
||||
do_await_remote_message("set-cookie").then(() => {
|
||||
const expiry = Date.now() + 24 * 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
TEST_DOMAIN,
|
||||
"/",
|
||||
"cookieName",
|
||||
@@ -83,10 +83,9 @@ function run_test() {
|
||||
false,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
do_send_remote_message("set-cookie-done");
|
||||
});
|
||||
|
||||
|
||||
@@ -312,9 +312,8 @@ export class Network extends Domain {
|
||||
]);
|
||||
|
||||
let success = true;
|
||||
let cv;
|
||||
try {
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
hostname,
|
||||
cookie.path,
|
||||
cookie.name,
|
||||
@@ -331,10 +330,6 @@ export class Network extends Domain {
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (cv && cv.result != Ci.nsICookieValidation.eOK) {
|
||||
throw new TypeError(cv.errorString);
|
||||
}
|
||||
|
||||
return { success };
|
||||
}
|
||||
|
||||
|
||||
@@ -301,9 +301,8 @@ class StorageModule extends RootBiDiModule {
|
||||
|
||||
const isPartitioned = originAttributes.partitionKey?.length > 0;
|
||||
|
||||
let cv;
|
||||
try {
|
||||
cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
domain,
|
||||
path === null ? "/" : path,
|
||||
name,
|
||||
@@ -322,12 +321,6 @@ class StorageModule extends RootBiDiModule {
|
||||
throw new lazy.error.UnableToSetCookieError(e);
|
||||
}
|
||||
|
||||
if (cv.result !== Ci.nsICookieValidation.eOK) {
|
||||
throw new lazy.error.UnableToSetCookieError(
|
||||
`Invalid cookie: ${cv.errorString}`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
partitionKey: this.#formatPartitionKey(partitionKey, originAttributes),
|
||||
};
|
||||
@@ -797,12 +790,9 @@ class StorageModule extends RootBiDiModule {
|
||||
case "strict": {
|
||||
return Ci.nsICookie.SAMESITE_STRICT;
|
||||
}
|
||||
case "none": {
|
||||
return Ci.nsICookie.SAMESITE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return Ci.nsICookie.SAMESITE_UNSET;
|
||||
return Ci.nsICookie.SAMESITE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,7 +40,6 @@ async def test_partition_context(
|
||||
domain=domain_value(),
|
||||
name=cookie_name,
|
||||
value=NetworkStringValue(cookie_value),
|
||||
secure=True,
|
||||
),
|
||||
partition=partition,
|
||||
)
|
||||
@@ -74,7 +73,6 @@ async def test_partition_context_iframe_with_set_cookie(
|
||||
domain=domain_value(domain),
|
||||
name=cookie_name,
|
||||
value=NetworkStringValue(cookie_value),
|
||||
secure=True,
|
||||
),
|
||||
partition=frame_partition,
|
||||
)
|
||||
|
||||
@@ -42,7 +42,6 @@ async def test_partition_context(
|
||||
domain=cookie_domain,
|
||||
name=cookie_name,
|
||||
value=NetworkStringValue(cookie_value),
|
||||
secure=True,
|
||||
),
|
||||
partition=new_tab_partition,
|
||||
)
|
||||
@@ -63,7 +62,7 @@ async def test_partition_context(
|
||||
"name": cookie_name,
|
||||
"path": "/",
|
||||
"sameSite": "none",
|
||||
"secure": True,
|
||||
"secure": False,
|
||||
"size": 6,
|
||||
"value": {"type": "string", "value": cookie_value},
|
||||
}
|
||||
@@ -110,7 +109,6 @@ async def test_partition_context_iframe(
|
||||
domain=domain_value(domain),
|
||||
name=cookie_name,
|
||||
value=NetworkStringValue(cookie_value),
|
||||
secure=True,
|
||||
),
|
||||
partition=iframe_partition,
|
||||
)
|
||||
@@ -125,7 +123,7 @@ async def test_partition_context_iframe(
|
||||
"name": cookie_name,
|
||||
"path": "/",
|
||||
"sameSite": "none",
|
||||
"secure": True,
|
||||
"secure": False,
|
||||
"size": 6,
|
||||
"value": {"type": "string", "value": cookie_value},
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ async def test_partition_context(bidi_session, set_cookie, top_context, test_pag
|
||||
domain=domain_value(),
|
||||
name=cookie_name,
|
||||
value=NetworkStringValue(cookie_value),
|
||||
secure=True,
|
||||
),
|
||||
partition=partition,
|
||||
)
|
||||
|
||||
@@ -237,8 +237,7 @@ def test_add_cookie_with_valid_samesite_flag(session, url, same_site):
|
||||
new_cookie = {
|
||||
"name": "hello",
|
||||
"value": "world",
|
||||
"secure": True,
|
||||
"sameSite": same_site,
|
||||
"sameSite": same_site
|
||||
}
|
||||
|
||||
session.url = url("/common/blank.html")
|
||||
|
||||
@@ -99,7 +99,7 @@ export var SiteDataTestUtils = {
|
||||
: principal.originAttributes;
|
||||
}
|
||||
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
host,
|
||||
path,
|
||||
name,
|
||||
@@ -109,12 +109,9 @@ export var SiteDataTestUtils = {
|
||||
false,
|
||||
Math.floor(Date.now() / 1000) + 24 * 60 * 60,
|
||||
originAttributes,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET
|
||||
);
|
||||
if (cv.result !== Ci.nsICookieValidation.eOK) {
|
||||
throw new Error(`Invalid cookie: ${cv.result}`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ class MovedOriginDirectoryCleanupTestCase(MarionetteTestCase):
|
||||
false,
|
||||
Math.floor(Date.now() / 1000) + 24 * 60 * 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_UNSET
|
||||
);
|
||||
return promise;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
add_task(async function test_all_cookies() {
|
||||
const expiry = Date.now() + 24 * 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.net",
|
||||
"path",
|
||||
"name",
|
||||
@@ -22,7 +22,6 @@ add_task(async function test_all_cookies() {
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1);
|
||||
|
||||
await new Promise(aResolve => {
|
||||
@@ -40,7 +39,7 @@ add_task(async function test_all_cookies() {
|
||||
|
||||
add_task(async function test_range_cookies() {
|
||||
const expiry = Date.now() + 24 * 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.net",
|
||||
"path",
|
||||
"name",
|
||||
@@ -53,7 +52,6 @@ add_task(async function test_range_cookies() {
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1);
|
||||
|
||||
// The cookie is out of time range here.
|
||||
@@ -93,7 +91,7 @@ add_task(async function test_range_cookies() {
|
||||
|
||||
add_task(async function test_principal_cookies() {
|
||||
const expiry = Date.now() + 24 * 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.net",
|
||||
"path",
|
||||
"name",
|
||||
@@ -106,7 +104,6 @@ add_task(async function test_principal_cookies() {
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1);
|
||||
|
||||
let uri = Services.io.newURI("http://example.com");
|
||||
@@ -148,7 +145,7 @@ add_task(async function test_principal_cookies() {
|
||||
|
||||
add_task(async function test_localfile_cookies() {
|
||||
const expiry = Date.now() + 24 * 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"", // local file
|
||||
"path",
|
||||
"name",
|
||||
@@ -158,10 +155,10 @@ add_task(async function test_localfile_cookies() {
|
||||
false /* session */,
|
||||
expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
Assert.notEqual(Services.cookies.countCookiesFromHost(""), 0);
|
||||
|
||||
await new Promise(aResolve => {
|
||||
@@ -399,7 +396,7 @@ add_task(async function test_baseDomain_cookies_subdomain() {
|
||||
|
||||
function addCookiesForHost(host) {
|
||||
const expiry = Date.now() + 24 * 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
host,
|
||||
"path",
|
||||
"name",
|
||||
@@ -412,7 +409,6 @@ function addCookiesForHost(host) {
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
}
|
||||
|
||||
function addIpv6Cookies() {
|
||||
|
||||
@@ -25,7 +25,7 @@ const COOKIE = {
|
||||
};
|
||||
|
||||
function createCookie(userContextId) {
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
COOKIE.host,
|
||||
COOKIE.path,
|
||||
COOKIE.name,
|
||||
@@ -35,10 +35,9 @@ function createCookie(userContextId) {
|
||||
COOKIE.isSession,
|
||||
COOKIE.expiry,
|
||||
{ userContextId },
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
}
|
||||
|
||||
function hasCookie(userContextId) {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "mozilla/Components.h"
|
||||
#include "Cookie.h"
|
||||
#include "nsIHttpProtocolHandler.h"
|
||||
#include "mozilla/net/CookieValidation.h"
|
||||
#include "mozilla/StaticPrefs_cookiebanners.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
@@ -324,29 +323,12 @@ nsresult nsCookieInjector::InjectCookiesFromRules(
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Info,
|
||||
("Setting cookie: %s, %s, %s, %s\n", c.Host().get(), c.Name().get(),
|
||||
c.Path().get(), c.Value().get()));
|
||||
|
||||
nsCOMPtr<nsICookieValidation> validation;
|
||||
rv = cookieManager->AddNative(
|
||||
nullptr, c.Host(), c.Path(), c.Name(), c.Value(), c.IsSecure(),
|
||||
c.IsHttpOnly(), c.IsSession(), c.Expiry(), &aOriginAttributes,
|
||||
c.SameSite(), static_cast<nsICookie::schemeType>(c.SchemeMap()),
|
||||
/* is partitioned: */ false, /* is from http: */ true, nullptr,
|
||||
getter_AddRefs(validation));
|
||||
if (rv == NS_ERROR_ILLEGAL_VALUE) {
|
||||
net::CookieValidation* cv = net::CookieValidation::Cast(validation);
|
||||
MOZ_ASSERT(cv);
|
||||
MOZ_ASSERT(cv->Result() != nsICookieValidation::eOK);
|
||||
|
||||
nsAutoString errorString;
|
||||
rv = cv->GetErrorString(errorString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Error,
|
||||
("Invalid cookie: %s",
|
||||
NS_ConvertUTF16toUTF8(errorString).BeginReading()));
|
||||
continue;
|
||||
}
|
||||
|
||||
[](mozilla::net::CookieStruct&) { return true; });
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aHasInjectedCookie = true;
|
||||
|
||||
@@ -81,7 +81,7 @@ add_task(async function test_insertAndGetRule() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
rule.addCookie(
|
||||
@@ -95,7 +95,7 @@ add_task(async function test_insertAndGetRule() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
rule.addCookie(
|
||||
@@ -109,7 +109,7 @@ add_task(async function test_insertAndGetRule() {
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
@@ -153,7 +153,7 @@ add_task(async function test_insertAndGetRule() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
@@ -412,7 +412,7 @@ add_task(async function test_overwriteRule() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
@@ -444,7 +444,7 @@ add_task(async function test_overwriteRule() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
@@ -498,7 +498,7 @@ add_task(async function test_globalRules() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
rule.addClickRule(
|
||||
@@ -529,7 +529,7 @@ add_task(async function test_globalRules() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
ruleGlobalA.addClickRule(
|
||||
|
||||
@@ -330,7 +330,7 @@ function insertTestCookieRules() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
ruleA.addCookie(
|
||||
@@ -344,7 +344,7 @@ function insertTestCookieRules() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
@@ -366,7 +366,7 @@ function insertTestCookieRules() {
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,19 +4,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"gCookiesRejectWhenInvalid",
|
||||
"extensions.cookie.rejectWhenInvalid",
|
||||
false
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"gCookiesMaxageCap",
|
||||
"network.cookie.maxageCap",
|
||||
0
|
||||
);
|
||||
|
||||
var { ExtensionError } = ExtensionUtils;
|
||||
|
||||
const SAME_SITE_STATUSES = new Map([
|
||||
@@ -693,14 +680,6 @@ this.cookies = class extends ExtensionAPIPersistent {
|
||||
? Number.MAX_SAFE_INTEGER
|
||||
: details.expirationDate;
|
||||
|
||||
// maxage cap for expiry
|
||||
if (gCookiesMaxageCap > 0) {
|
||||
expiry = Math.min(
|
||||
expiry,
|
||||
Math.round(Date.now() / 1000) + gCookiesMaxageCap
|
||||
);
|
||||
}
|
||||
|
||||
let { originAttributes } = oaFromDetails(details, context);
|
||||
|
||||
let cookieAttrs = {
|
||||
@@ -739,10 +718,7 @@ this.cookies = class extends ExtensionAPIPersistent {
|
||||
|
||||
// The permission check may have modified the domain, so use
|
||||
// the new value instead.
|
||||
let fn = gCookiesRejectWhenInvalid
|
||||
? Services.cookies.add
|
||||
: Services.cookies.addForAddOn;
|
||||
const cv = fn(
|
||||
Services.cookies.add(
|
||||
cookieAttrs.host,
|
||||
path,
|
||||
name,
|
||||
@@ -757,16 +733,6 @@ this.cookies = class extends ExtensionAPIPersistent {
|
||||
isPartitioned
|
||||
);
|
||||
|
||||
if (cv.result !== Ci.nsICookieValidation.eOK) {
|
||||
if (gCookiesRejectWhenInvalid) {
|
||||
return Promise.reject({ message: cv.errorString });
|
||||
}
|
||||
|
||||
Services.console.logStringMessage(
|
||||
`Extension ${extension.id} tried to create an invalid cookie: ${cv.errorString}`
|
||||
);
|
||||
}
|
||||
|
||||
return self.cookies.get(details);
|
||||
},
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ async function testCookies(options) {
|
||||
false,
|
||||
options.expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
options.url.startsWith("https")
|
||||
? Ci.nsICookie.SCHEME_HTTPS
|
||||
: Ci.nsICookie.SCHEME_HTTP
|
||||
@@ -147,7 +147,7 @@ async function testCookies(options) {
|
||||
false,
|
||||
options.expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
options.url.startsWith("https")
|
||||
? Ci.nsICookie.SCHEME_HTTPS
|
||||
: Ci.nsICookie.SCHEME_HTTP
|
||||
@@ -163,7 +163,7 @@ async function testCookies(options) {
|
||||
false,
|
||||
options.expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
options.url.startsWith("https")
|
||||
? Ci.nsICookie.SCHEME_HTTPS
|
||||
: Ci.nsICookie.SCHEME_HTTP
|
||||
@@ -195,7 +195,7 @@ async function testCookies(options) {
|
||||
false,
|
||||
options.expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
options.url.startsWith("https")
|
||||
? Ci.nsICookie.SCHEME_HTTPS
|
||||
: Ci.nsICookie.SCHEME_HTTP
|
||||
@@ -211,7 +211,7 @@ async function testCookies(options) {
|
||||
false,
|
||||
options.expiry,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
options.url.startsWith("https")
|
||||
? Ci.nsICookie.SCHEME_HTTPS
|
||||
: Ci.nsICookie.SCHEME_HTTP
|
||||
|
||||
@@ -38,7 +38,7 @@ add_task(async function test_cookies() {
|
||||
async function testIpCookie(ipAddress, setHostOnly) {
|
||||
const IP_TEST_HOST = ipAddress;
|
||||
const IP_TEST_URL = `http://${IP_TEST_HOST}/`;
|
||||
const IP_THE_FUTURE = Math.round(Date.now()/1000) + 5 * 60;
|
||||
const IP_THE_FUTURE = Date.now() + 5 * 60;
|
||||
const IP_STORE_ID = "firefox-default";
|
||||
|
||||
let expectedCookie = {
|
||||
@@ -122,7 +122,7 @@ add_task(async function test_cookies() {
|
||||
|
||||
const TEST_URL = "http://example.org/";
|
||||
const TEST_SECURE_URL = "https://example.org/";
|
||||
const THE_FUTURE = Math.round(Date.now()/1000) + 5 * 60;
|
||||
const THE_FUTURE = Date.now() + 5 * 60;
|
||||
const TEST_PATH = "set_path";
|
||||
const TEST_URL_WITH_PATH = TEST_URL + TEST_PATH;
|
||||
const TEST_COOKIE_PATH = `/${TEST_PATH}`;
|
||||
|
||||
@@ -34,7 +34,7 @@ add_task(async function test_cookie_containers() {
|
||||
}
|
||||
|
||||
const TEST_URL = "http://example.org/";
|
||||
const THE_FUTURE = Math.round(Date.now()/1000) + 5 * 60;
|
||||
const THE_FUTURE = Date.now() + 5 * 60;
|
||||
|
||||
let expected = {
|
||||
name: "name1",
|
||||
|
||||
@@ -45,7 +45,7 @@ add_task(async function test_cookies_expiry() {
|
||||
|
||||
let chromeScript = loadChromeScript(() => {
|
||||
const {sendAsyncMessage} = this;
|
||||
Services.cookies.add(".example.com", "/", "first", "one", false, false, false, Date.now() / 1000 + 1, {}, Ci.nsICookie.SAMESITE_UNSET, Ci.nsICookie.SCHEME_HTTP);
|
||||
Services.cookies.add(".example.com", "/", "first", "one", false, false, false, Date.now() / 1000 + 1, {}, Ci.nsICookie.SAMESITE_NONE, Ci.nsICookie.SCHEME_HTTP);
|
||||
sendAsyncMessage("done");
|
||||
});
|
||||
await chromeScript.promiseOneMessage("done");
|
||||
@@ -56,7 +56,7 @@ add_task(async function test_cookies_expiry() {
|
||||
|
||||
chromeScript = loadChromeScript(() => {
|
||||
const {sendAsyncMessage} = this;
|
||||
Services.cookies.add(".example.com", "/", "first", "one-again", false, false, false, Date.now() / 1000 + 10, {}, Ci.nsICookie.SAMESITE_UNSET, Ci.nsICookie.SCHEME_HTTP);
|
||||
Services.cookies.add(".example.com", "/", "first", "one-again", false, false, false, Date.now() / 1000 + 10, {}, Ci.nsICookie.SAMESITE_NONE, Ci.nsICookie.SCHEME_HTTP);
|
||||
sendAsyncMessage("done");
|
||||
});
|
||||
await chromeScript.promiseOneMessage("done");
|
||||
|
||||
@@ -86,10 +86,10 @@ add_task(async function test_cookies_incognito_not_allowed() {
|
||||
/* eslint-env mozilla/chrome-script */
|
||||
Services.cookies.add("example.org", "/", "public", `foo${Math.random()}`,
|
||||
false, false, false, Number.MAX_SAFE_INTEGER, {},
|
||||
Ci.nsICookie.SAMESITE_UNSET);
|
||||
Ci.nsICookie.SAMESITE_NONE);
|
||||
Services.cookies.add("example.org", "/", "private", `foo${Math.random()}`,
|
||||
false, false, false, Number.MAX_SAFE_INTEGER, {privateBrowsingId: 1},
|
||||
Ci.nsICookie.SAMESITE_UNSET);
|
||||
Ci.nsICookie.SAMESITE_NONE);
|
||||
});
|
||||
extension.sendMessage("test-cookie-store");
|
||||
await extension.awaitFinish("cookies");
|
||||
|
||||
@@ -25,7 +25,7 @@ const COOKIE_ORG = {
|
||||
let since, oldCookie;
|
||||
|
||||
function addCookie(cookie) {
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
cookie.host,
|
||||
cookie.path,
|
||||
cookie.name,
|
||||
@@ -35,10 +35,9 @@ function addCookie(cookie) {
|
||||
false,
|
||||
Date.now() / 1000 + 10000,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.strictEqual(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
ok(
|
||||
Services.cookies.cookieExists(cookie.host, cookie.path, cookie.name, {}),
|
||||
`Cookie ${cookie.name} was created.`
|
||||
|
||||
@@ -41,7 +41,7 @@ function cookieExists(cookie) {
|
||||
function addCookie(cookie) {
|
||||
const THE_FUTURE = Date.now() + 5 * 60;
|
||||
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
cookie.host,
|
||||
cookie.path,
|
||||
cookie.name,
|
||||
@@ -51,11 +51,10 @@ function addCookie(cookie) {
|
||||
false,
|
||||
THE_FUTURE,
|
||||
cookie.originAttributes,
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
|
||||
Assert.strictEqual(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
ok(cookieExists(cookie), `Cookie ${cookie.name} was created.`);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
add_task(async function test_no_reject_invalid_cookies() {
|
||||
async function backgroundScript() {
|
||||
const kOneDay = 60 * 60 * 24;
|
||||
const kTenDays = kOneDay * 10;
|
||||
const kFourHundredDays = kTenDays * 40;
|
||||
const kNow = Math.round(Date.now() / 1000);
|
||||
|
||||
await browser.cookies.set({
|
||||
url: "https://example.com",
|
||||
name: "a",
|
||||
value: "b",
|
||||
// kFourHundredDays * 10 exceeds the limit from network.cookie.maxageCap
|
||||
expirationDate: kNow + kFourHundredDays * 10,
|
||||
});
|
||||
|
||||
let cookie = await browser.cookies.getAll({
|
||||
url: "https://example.com",
|
||||
name: "a",
|
||||
});
|
||||
|
||||
browser.test.assertEq(cookie.length, 1, "Cookie with 400-days expiry");
|
||||
// The extra day is just to avoid out-of-sync timing between parent and content processes.
|
||||
browser.test.assertTrue(
|
||||
cookie[0].expirationDate <= kNow + kFourHundredDays + kOneDay,
|
||||
"ExpirationDate is normalized to max 400 days"
|
||||
);
|
||||
|
||||
await browser.cookies.set({
|
||||
url: "https://example.com",
|
||||
name: "a",
|
||||
value: "b",
|
||||
expirationDate: kNow + kTenDays,
|
||||
});
|
||||
|
||||
cookie = await browser.cookies.getAll({
|
||||
url: "https://example.com",
|
||||
name: "a",
|
||||
});
|
||||
|
||||
browser.test.assertEq(cookie.length, 1, "Cookie with 10-day expiry");
|
||||
browser.test.assertTrue(
|
||||
cookie[0].expirationDate <= kNow + kTenDays,
|
||||
"ExpirationDate is around 10 days"
|
||||
);
|
||||
|
||||
browser.test.sendMessage("done");
|
||||
}
|
||||
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
background: backgroundScript,
|
||||
manifest: {
|
||||
permissions: ["cookies", "https://example.com/*"],
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
await extension.awaitMessage("done");
|
||||
await extension.unload();
|
||||
});
|
||||
@@ -1,119 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
add_task(
|
||||
{ pref_set: [["extensions.cookie.rejectWhenInvalid", true]] },
|
||||
async function test_no_reject_invalid_cookies() {
|
||||
await do_test_invalid_cookies({ failure: true });
|
||||
}
|
||||
);
|
||||
|
||||
add_task(
|
||||
{ pref_set: [["extensions.cookie.rejectWhenInvalid", false]] },
|
||||
async function test_warn_on_invalid_cookies() {
|
||||
await do_test_invalid_cookies({ failure: false });
|
||||
}
|
||||
);
|
||||
|
||||
async function do_test_invalid_cookies(options) {
|
||||
async function backgroundScript() {
|
||||
browser.test.onMessage.addListener(async message => {
|
||||
let failure = true;
|
||||
try {
|
||||
await browser.cookies.set({
|
||||
...message.cookie,
|
||||
url: "https://example.com",
|
||||
});
|
||||
failure = false;
|
||||
} catch (e) {
|
||||
browser.test.assertEq(
|
||||
e.message,
|
||||
message.errorString,
|
||||
`${message.title} - correct exception`
|
||||
);
|
||||
} finally {
|
||||
browser.test.assertEq(failure, message.failure, message.title);
|
||||
browser.test.sendMessage("completed");
|
||||
}
|
||||
});
|
||||
|
||||
browser.test.sendMessage("ready");
|
||||
}
|
||||
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
background: backgroundScript,
|
||||
manifest: {
|
||||
permissions: ["cookies", "https://example.com/*"],
|
||||
},
|
||||
});
|
||||
|
||||
let readyPromise = extension.awaitMessage("ready");
|
||||
await extension.startup();
|
||||
await readyPromise;
|
||||
|
||||
const tests = [
|
||||
{
|
||||
cookie: { name: "", value: "" },
|
||||
title: "Empty name and value",
|
||||
errorString:
|
||||
"Cookie with an empty name and an empty value has been rejected.",
|
||||
},
|
||||
{
|
||||
cookie: { name: "a".repeat(3000), value: "a".repeat(3000) },
|
||||
title: "Name/value oversize",
|
||||
errorString: `Cookie “${"a".repeat(3000)}” is invalid because its size is too big. Max size is 4096 B.`,
|
||||
},
|
||||
{
|
||||
cookie: { name: ";", value: "a" },
|
||||
title: "Invalid chars in the name",
|
||||
errorString:
|
||||
"Cookie “;” has been rejected for invalid characters in the name.",
|
||||
},
|
||||
{
|
||||
cookie: { name: " ", value: "a" },
|
||||
title: "Invalid chars in the name (2)",
|
||||
errorString:
|
||||
"Cookie “ ” has been rejected for invalid characters in the name.",
|
||||
},
|
||||
{
|
||||
cookie: { name: "a", value: ";" },
|
||||
title: "Invalid chars in the value",
|
||||
errorString:
|
||||
"Cookie “a” has been rejected for invalid characters in the value.",
|
||||
},
|
||||
{
|
||||
cookie: { name: "a", value: " " },
|
||||
title: "Invalid chars in the value (2)",
|
||||
errorString:
|
||||
"Cookie “a” has been rejected for invalid characters in the value.",
|
||||
},
|
||||
{
|
||||
cookie: { name: "", value: "__Secure-wow" },
|
||||
title: "Invalid prefix (__Secure)",
|
||||
errorString: "Cookie “” has been rejected for invalid prefix.",
|
||||
},
|
||||
{
|
||||
cookie: { name: "", value: "__Host-wow" },
|
||||
title: "Invalid prefix (__Host)",
|
||||
errorString: "Cookie “” has been rejected for invalid prefix.",
|
||||
},
|
||||
{
|
||||
cookie: { name: "a", value: "b", sameSite: "no_restriction" },
|
||||
title: "None requires secure",
|
||||
errorString:
|
||||
"Cookie “a” rejected because it has the “SameSite=None” attribute but is missing the “secure” attribute.",
|
||||
},
|
||||
{
|
||||
cookie: { name: "a", value: "b", path: "a".repeat(1025) },
|
||||
title: "Path oversize",
|
||||
errorString:
|
||||
"Cookie “a” has been rejected because its path attribute is too big.",
|
||||
},
|
||||
];
|
||||
|
||||
for (const test of tests) {
|
||||
extension.sendMessage({ ...test, ...options });
|
||||
await extension.awaitMessage("completed");
|
||||
}
|
||||
|
||||
await extension.unload();
|
||||
}
|
||||
@@ -187,8 +187,6 @@ skip-if = [
|
||||
|
||||
["test_ext_cookies_errors.js"]
|
||||
|
||||
["test_ext_cookies_expirationDate.js"]
|
||||
|
||||
["test_ext_cookies_firstParty.js"]
|
||||
skip-if = [
|
||||
"appname == 'thunderbird'",
|
||||
@@ -203,8 +201,6 @@ skip-if = [
|
||||
|
||||
["test_ext_cookies_sort.js"]
|
||||
|
||||
["test_ext_cookies_validation.js"]
|
||||
|
||||
["test_ext_cors_mozextension.js"]
|
||||
|
||||
["test_ext_csp_frame_ancestors.js"]
|
||||
|
||||
@@ -46,7 +46,7 @@ const PREFERENCE_NAME = "test-pref";
|
||||
*/
|
||||
function add_cookie(aDomain) {
|
||||
check_cookie_exists(aDomain, false);
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
aDomain,
|
||||
COOKIE_PATH,
|
||||
COOKIE_NAME,
|
||||
@@ -56,10 +56,9 @@ function add_cookie(aDomain) {
|
||||
false,
|
||||
COOKIE_EXPIRY,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTPS
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
check_cookie_exists(aDomain, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -567,7 +567,7 @@ add_task(async function discopane_no_cookies() {
|
||||
let requestPromise = new Promise(resolve => {
|
||||
amoServer.registerPathHandler("/discoapi", resolve);
|
||||
});
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
AMO_TEST_HOST,
|
||||
"/",
|
||||
"name",
|
||||
@@ -577,10 +577,9 @@ add_task(async function discopane_no_cookies() {
|
||||
false,
|
||||
Date.now() / 1000 + 600,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
is(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
let win = await loadInitialView("discover");
|
||||
let request = await requestPromise;
|
||||
ok(!request.hasHeader("Cookie"), "discovery API should not receive cookies");
|
||||
|
||||
@@ -110,7 +110,7 @@ add_task(async function test_cookies() {
|
||||
|
||||
const COOKIE = "test";
|
||||
let expiration = Date.now() / 1000 + 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.com",
|
||||
"/",
|
||||
COOKIE,
|
||||
@@ -120,10 +120,9 @@ add_task(async function test_cookies() {
|
||||
false,
|
||||
expiration,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
await AddonRepository.getAvailableLangpacks();
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ add_task(async function test_cookies() {
|
||||
const COOKIE = "test";
|
||||
// cookies.add() takes a time in seconds
|
||||
let expiration = Date.now() / 1000 + 60 * 60;
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.com",
|
||||
"/",
|
||||
COOKIE,
|
||||
@@ -62,10 +62,9 @@ add_task(async function test_cookies() {
|
||||
false,
|
||||
expiration,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
await promiseStartupManager();
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ function test() {
|
||||
Harness.installsCompletedCallback = finish_test;
|
||||
Harness.setup();
|
||||
|
||||
const cv = Services.cookies.add(
|
||||
Services.cookies.add(
|
||||
"example.com",
|
||||
"/browser/" + RELATIVE_DIR,
|
||||
"xpinstall",
|
||||
@@ -20,10 +20,9 @@ function test() {
|
||||
true,
|
||||
Date.now() / 1000 + 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie");
|
||||
|
||||
PermissionTestUtils.add(
|
||||
"http://example.com/",
|
||||
|
||||
@@ -20,7 +20,7 @@ function test() {
|
||||
true,
|
||||
Date.now() / 1000 + 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ function test() {
|
||||
true,
|
||||
Date.now() / 1000 + 60,
|
||||
{},
|
||||
Ci.nsICookie.SAMESITE_UNSET,
|
||||
Ci.nsICookie.SAMESITE_NONE,
|
||||
Ci.nsICookie.SCHEME_HTTP
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user