Skip to content

Commit

Permalink
Bug 1783019 - Implement cookie banner handling components. r=timhuang…
Browse files Browse the repository at this point in the history
…,necko-reviewers,valentin

This patch adds the following components:
 - nsICookieBannerService: Main service singleton managing the rules and initiating other components.
   It's exposed via Services.cookieBanners and can be configured via the cookiebanners.* prefs.
   To enable it set "cookiebanners.service.mode" to 1 or 2 and restart the browser.
 - nsCookieInjector: Looks up rules and injects cookies for matching top level loads.
 - nsICookieBannerListService: Imports and updates the cookie banner rules.
 - nsICookieBannerRule: Rules for a given domain.
 - nsICookieRule: Part of nsICookieBannerRule. Holds cookie specific rules.

Depends on D153641

Differential Revision: https://phabricator.services.mozilla.com/D153642
  • Loading branch information
Trikolon committed Aug 16, 2022
1 parent 4a75c4c commit 017ccb0
Show file tree
Hide file tree
Showing 20 changed files with 1,250 additions and 0 deletions.
27 changes: 27 additions & 0 deletions modules/libpref/init/StaticPrefList.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1849,6 +1849,33 @@
value: false
mirror: always

#---------------------------------------------------------------------------
# Prefs starting with "cookiebanners."
#---------------------------------------------------------------------------

# Controls the cookie banner handling mode.
# 0: Disables all cookie banner handling.
# 1: Reject-all if possible, otherwise do nothing.
# 2: Reject-all if possible, otherwise accept-all.
- name: cookiebanners.service.mode
type: uint32_t
value: 0
mirror: always

# Enables the cookie banner cookie injector.
- name: cookiebanners.cookieInjector.enabled
type: bool
value: true
mirror: always

# By default, how many seconds in the future cookies should expire after they
# have been injected. Defaults to 12 months. Individual cookie rules may
# override this.
- name: cookiebanners.cookieInjector.defaultExpiryRelative
type: uint32_t
value: 31536000
mirror: always

#---------------------------------------------------------------------------
# Prefs starting with "datareporting."
#---------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions modules/libpref/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pref_groups = [
"clipboard",
"content",
"converter",
"cookiebanners",
"datareporting",
"device",
"devtools",
Expand Down
1 change: 1 addition & 0 deletions netwerk/cookie/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ XPIDL_MODULE = "necko_cookie"


EXPORTS.mozilla.net = [
"Cookie.h",
"CookieJarSettings.h",
"CookieKey.h",
"CookiePersistentStorage.h",
Expand Down
106 changes: 106 additions & 0 deletions toolkit/components/cookiebanners/CookieBannerListService.jsm
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* 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/. */

"use strict";

const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");

// Some test rules for cookie injection.
const RULES_TESTING = [
// {
// domain: "example.com",
// cookies: {
// optOut: [
// {
// name: "consentCookieTest",
// value: "rejectAll",
// unsetValue: "UNSET",
// },
// {
// name: "consentCookieTestSecondary",
// value: "true",
// },
// ],
// optIn: [
// {
// name: "consentCookieTest",
// value: "acceptAll",
// expiryRelative: 3600,
// unsetValue: "UNSET",
// },
// ],
// },
// },
// {
// domain: "example.org",
// cookies: {
// optIn: [
// {
// host: "example.org",
// isSecure: false,
// name: "consentCookieTest",
// path: "/foo",
// value: "acceptAll",
// expiryRelative: 3600,
// unsetValue: "UNSET",
// },
// ],
// },
// },
];

/**
* See nsICookieBannerListService
*/
class CookieBannerListService {
classId = Components.ID("{1d8d9470-97d3-4885-a108-44a5c4fb36e2}");
QueryInterface = ChromeUtils.generateQI(["nsICookieBannerListService"]);

/**
* Iterate over RULES_TESTING and insert rules via nsICookieBannerService.
*/
importRules() {
RULES_TESTING.forEach(({ domain, cookies }) => {
let rule = Services.cookieBanners.lookupOrInsertRuleForDomain(domain);

// Clear any previously stored cookie rules.
rule.clearCookies();

// Skip rules that don't have cookies.
if (!cookies) {
return;
}

// Import opt-in and opt-out cookies if defined.
for (let category of ["optOut", "optIn"]) {
if (!cookies[category]) {
continue;
}

let isOptOut = category == "optOut";

for (let c of cookies[category]) {
rule.addCookie(
isOptOut,
c.host,
c.name,
c.value,
// The following fields are optional and may not be defined by the
// rule. They will fall back to defaults.
c.path,
c.expiryRelative,
c.unsetValue,
c.isSecure,
c.isHTTPOnly,
c.isSession,
c.sameSite,
c.schemeMap
);
}
}
});
}
}

var EXPORTED_SYMBOLS = ["CookieBannerListService"];
28 changes: 28 additions & 0 deletions toolkit/components/cookiebanners/components.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.

Classes = [
{
'name': 'CookieBannerService',
'cid': '{eac9cdc4-ecee-49f2-91da-7627e15c1f3c}',
'interfaces': ['nsICookieBannerService'],
'contract_ids': ['@mozilla.org/cookie-banner-service;1'],
'type': 'mozilla::nsCookieBannerService',
'headers': ['/toolkit/components/cookiebanners/nsCookieBannerService.h'],
'singleton': True,
'constructor': 'mozilla::nsCookieBannerService::GetSingleton',
'js_name': 'cookieBanners',
'categories': {'profile-after-change': 'nsCookieBannerService'},
'processes': ProcessSelector.MAIN_PROCESS_ONLY,
},
{
'cid': '{1d8d9470-97d3-4885-a108-44a5c4fb36e2}',
'contract_ids': ['@mozilla.org/cookie-banner-list-service;1'],
'jsm': 'resource://gre/modules/CookieBannerListService.jsm',
'constructor': 'CookieBannerListService',
'processes': ProcessSelector.MAIN_PROCESS_ONLY,
},
]
47 changes: 47 additions & 0 deletions toolkit/components/cookiebanners/moz.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.

with Files("**"):
BUG_COMPONENT = ("Core", "Privacy: Anti-Tracking")

XPIDL_SOURCES += [
"nsICookieBannerListService.idl",
"nsICookieBannerRule.idl",
"nsICookieBannerService.idl",
"nsICookieRule.idl",
]

XPIDL_MODULE = "toolkit_cookiebanners"

EXTRA_JS_MODULES += [
"CookieBannerListService.jsm",
]

XPCOM_MANIFESTS += [
"components.conf",
]

EXPORTS.mozilla += [
"nsCookieBannerRule.h",
"nsCookieBannerService.h",
"nsCookieInjector.h",
"nsCookieRule.h",
]

UNIFIED_SOURCES += [
"nsCookieBannerRule.cpp",
"nsCookieBannerService.cpp",
"nsCookieInjector.cpp",
"nsCookieRule.cpp",
]

include("/ipc/chromium/chromium-config.mozbuild")

LOCAL_INCLUDES += ["/netwerk/base", "/netwerk/cookie"]

FINAL_LIBRARY = "xul"

REQUIRES_UNIFIED_BUILD = True
88 changes: 88 additions & 0 deletions toolkit/components/cookiebanners/nsCookieBannerRule.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/* 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 "nsCookieBannerRule.h"

#include "mozilla/Logging.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsCookieRule.h"

namespace mozilla {

NS_IMPL_ISUPPORTS(nsCookieBannerRule, nsICookieBannerRule)

LazyLogModule gCookieRuleLog("nsCookieBannerRule");

NS_IMETHODIMP
nsCookieBannerRule::ClearCookies() {
mCookiesOptOut.Clear();
mCookiesOptIn.Clear();

return NS_OK;
}

NS_IMETHODIMP
nsCookieBannerRule::AddCookie(bool aIsOptOut, const nsACString& aHost,
const nsACString& aName, const nsACString& aValue,
// Optional
const nsACString& aPath, int64_t aExpiryRelative,
const nsACString& aUnsetValue, bool aIsSecure,
bool aIsHttpOnly, bool aIsSession,
int32_t aSameSite,
nsICookie::schemeType aSchemeMap) {
MOZ_LOG(gCookieRuleLog, LogLevel::Debug,
("%s: mDomain: %s, aIsOptOut: %d, aHost: %s, aName: %s", __FUNCTION__,
mDomain.get(), aIsOptOut, nsPromiseFlatCString(aHost).get(),
nsPromiseFlatCString(aName).get()));

// Default cookie host to .<domain>
nsAutoCString host(aHost);
if (host.IsEmpty()) {
host.AppendLiteral(".");
host.Append(mDomain);
}

// Create and insert cookie rule.
nsCOMPtr<nsICookieRule> cookieRule = new nsCookieRule(
aIsOptOut, host, aName, aValue, aPath, aExpiryRelative, aUnsetValue,
aIsSecure, aIsHttpOnly, aIsSession, aSameSite, aSchemeMap);
Cookies(aIsOptOut).AppendElement(cookieRule);

return NS_OK;
}

NS_IMETHODIMP
nsCookieBannerRule::GetDomain(nsACString& aDomain) {
aDomain.Assign(mDomain);
return NS_OK;
}

nsTArray<nsCOMPtr<nsICookieRule>>& nsCookieBannerRule::Cookies(bool isOptOut) {
if (isOptOut) {
return mCookiesOptOut;
}
return mCookiesOptIn;
}

NS_IMETHODIMP
nsCookieBannerRule::GetCookiesOptOut(
nsTArray<RefPtr<nsICookieRule>>& aCookies) {
nsTArray<nsCOMPtr<nsICookieRule>>& cookies = Cookies(true);
for (nsICookieRule* cookie : cookies) {
aCookies.AppendElement(cookie);
}
return NS_OK;
}

NS_IMETHODIMP
nsCookieBannerRule::GetCookiesOptIn(nsTArray<RefPtr<nsICookieRule>>& aCookies) {
nsTArray<nsCOMPtr<nsICookieRule>>& cookies = Cookies(false);
for (nsICookieRule* cookie : cookies) {
aCookies.AppendElement(cookie);
}
return NS_OK;
}

} // namespace mozilla
35 changes: 35 additions & 0 deletions toolkit/components/cookiebanners/nsCookieBannerRule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* 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_nsCookieBannerRule_h__
#define mozilla_nsCookieBannerRule_h__

#include "nsICookieBannerRule.h"
#include "nsICookieRule.h"
#include "nsString.h"
#include "nsCOMPtr.h"

namespace mozilla {

class nsCookieBannerRule final : public nsICookieBannerRule {
NS_DECL_ISUPPORTS
NS_DECL_NSICOOKIEBANNERRULE

public:
nsCookieBannerRule() = default;
explicit nsCookieBannerRule(const nsACString& aDomain) : mDomain(aDomain) {}

private:
~nsCookieBannerRule() = default;

nsCString mDomain;
nsTArray<nsCOMPtr<nsICookieRule>> mCookiesOptOut;
nsTArray<nsCOMPtr<nsICookieRule>> mCookiesOptIn;

// Internal getter for easy access of cookie rule arrays.
nsTArray<nsCOMPtr<nsICookieRule>>& Cookies(bool isOptOut);
};

} // namespace mozilla

#endif
Loading

0 comments on commit 017ccb0

Please sign in to comment.