mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 18:04:46 +00:00
Bug 1783019 - Implement cookie banner handling components. r=timhuang,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
This commit is contained in:
parent
4a75c4c2b3
commit
017ccb0be2
@ -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."
|
||||
#---------------------------------------------------------------------------
|
||||
|
@ -36,6 +36,7 @@ pref_groups = [
|
||||
"clipboard",
|
||||
"content",
|
||||
"converter",
|
||||
"cookiebanners",
|
||||
"datareporting",
|
||||
"device",
|
||||
"devtools",
|
||||
|
@ -20,6 +20,7 @@ XPIDL_MODULE = "necko_cookie"
|
||||
|
||||
|
||||
EXPORTS.mozilla.net = [
|
||||
"Cookie.h",
|
||||
"CookieJarSettings.h",
|
||||
"CookieKey.h",
|
||||
"CookiePersistentStorage.h",
|
||||
|
106
toolkit/components/cookiebanners/CookieBannerListService.jsm
Normal file
106
toolkit/components/cookiebanners/CookieBannerListService.jsm
Normal file
@ -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
toolkit/components/cookiebanners/components.conf
Normal file
28
toolkit/components/cookiebanners/components.conf
Normal file
@ -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
toolkit/components/cookiebanners/moz.build
Normal file
47
toolkit/components/cookiebanners/moz.build
Normal file
@ -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
toolkit/components/cookiebanners/nsCookieBannerRule.cpp
Normal file
88
toolkit/components/cookiebanners/nsCookieBannerRule.cpp
Normal file
@ -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
toolkit/components/cookiebanners/nsCookieBannerRule.h
Normal file
35
toolkit/components/cookiebanners/nsCookieBannerRule.h
Normal file
@ -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
|
249
toolkit/components/cookiebanners/nsCookieBannerService.cpp
Normal file
249
toolkit/components/cookiebanners/nsCookieBannerService.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
/* 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 "nsCookieBannerService.h"
|
||||
|
||||
#include "nsCookieBannerRule.h"
|
||||
#include "nsCookieInjector.h"
|
||||
#include "nsICookieBannerListService.h"
|
||||
#include "nsICookieBannerRule.h"
|
||||
#include "nsICookie.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "mozilla/StaticPrefs_cookiebanners.h"
|
||||
#include "ErrorList.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsCRT.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsCookieBannerService, nsICookieBannerService, nsIObserver)
|
||||
|
||||
LazyLogModule gCookieBannerLog("nsCookieBannerService");
|
||||
|
||||
static const char kCookieBannerServiceModePref[] = "cookiebanners.service.mode";
|
||||
|
||||
static StaticRefPtr<nsCookieBannerService> sCookieBannerServiceSingleton;
|
||||
|
||||
// static
|
||||
already_AddRefed<nsCookieBannerService> nsCookieBannerService::GetSingleton() {
|
||||
if (!sCookieBannerServiceSingleton) {
|
||||
sCookieBannerServiceSingleton = new nsCookieBannerService();
|
||||
|
||||
RunOnShutdown([] {
|
||||
MOZ_LOG(gCookieBannerLog, LogLevel::Debug,
|
||||
("RunOnShutdown. Mode: %d",
|
||||
StaticPrefs::cookiebanners_service_mode()));
|
||||
|
||||
// Unregister pref listeners.
|
||||
DebugOnly<nsresult> rv = Preferences::UnregisterCallback(
|
||||
&nsCookieBannerService::OnPrefChange, kCookieBannerServiceModePref);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"Unregistering kCookieBannerServiceModePref callback failed");
|
||||
|
||||
rv = sCookieBannerServiceSingleton->Shutdown();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsCookieBannerService::Shutdown failed.");
|
||||
|
||||
sCookieBannerServiceSingleton = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
return do_AddRef(sCookieBannerServiceSingleton);
|
||||
}
|
||||
|
||||
// static
|
||||
void nsCookieBannerService::OnPrefChange(const char* aPref, void* aData) {
|
||||
RefPtr<nsCookieBannerService> service = GetSingleton();
|
||||
|
||||
if (StaticPrefs::cookiebanners_service_mode() !=
|
||||
nsICookieBannerService::MODE_DISABLED) {
|
||||
MOZ_LOG(
|
||||
gCookieBannerLog, LogLevel::Info,
|
||||
("Initializing nsCookieBannerService after pref change. %s", aPref));
|
||||
DebugOnly<nsresult> rv = service->Init();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsCookieBannerService::Init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LOG(gCookieBannerLog, LogLevel::Info,
|
||||
("Disabling nsCookieBannerService after pref change. %s", aPref));
|
||||
|
||||
DebugOnly<nsresult> rv = service->Shutdown();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsCookieBannerService::Shutdown failed");
|
||||
}
|
||||
|
||||
// This method initializes the cookie banner service on startup on
|
||||
// "profile-after-change".
|
||||
NS_IMETHODIMP
|
||||
nsCookieBannerService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData) {
|
||||
if (nsCRT::strcmp(aTopic, "profile-after-change") != 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return Preferences::RegisterCallbackAndCall(
|
||||
&nsCookieBannerService::OnPrefChange, kCookieBannerServiceModePref);
|
||||
}
|
||||
|
||||
nsresult nsCookieBannerService::Init() {
|
||||
MOZ_LOG(gCookieBannerLog, LogLevel::Debug,
|
||||
("%s. Mode: %d", __FUNCTION__,
|
||||
StaticPrefs::cookiebanners_service_mode()));
|
||||
|
||||
// Check if already initialized.
|
||||
if (mIsInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Initialize the service which fetches cookie banner rules.
|
||||
mListService = do_GetService(NS_COOKIEBANNERLISTSERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(mListService, NS_ERROR_FAILURE);
|
||||
|
||||
// Setting mIsInitialized before importing rules, because the list service
|
||||
// needs to call nsCookieBannerService methods that would throw if not marked
|
||||
// initialized.
|
||||
mIsInitialized = true;
|
||||
|
||||
// Import initial rule-set.
|
||||
mListService->ImportRules();
|
||||
|
||||
// Initialize the cookie injector.
|
||||
RefPtr<nsCookieInjector> injector = nsCookieInjector::GetSingleton();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsCookieBannerService::Shutdown() {
|
||||
MOZ_LOG(gCookieBannerLog, LogLevel::Debug,
|
||||
("%s. Mode: %d", __FUNCTION__,
|
||||
StaticPrefs::cookiebanners_service_mode()));
|
||||
|
||||
// Check if already shutdown.
|
||||
if (!mIsInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
mIsInitialized = false;
|
||||
|
||||
// Clear all stored cookie banner rules. They will be imported again on Init.
|
||||
mRules.Clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCookieBannerService::GetRules(nsTArray<RefPtr<nsICookieBannerRule>>& aRules) {
|
||||
aRules.Clear();
|
||||
|
||||
// Service is disabled, throw with empty array.
|
||||
if (!mIsInitialized) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
AppendToArray(aRules, mRules.Values());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsCookieBannerService::GetRuleForDomain(const nsACString& aDomain,
|
||||
nsICookieBannerRule** aRule) {
|
||||
NS_ENSURE_ARG_POINTER(aRule);
|
||||
*aRule = nullptr;
|
||||
|
||||
// Service is disabled, throw with null.
|
||||
if (!mIsInitialized) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICookieBannerRule> rule = mRules.Get(aDomain);
|
||||
if (rule) {
|
||||
rule.forget(aRule);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsCookieBannerService::GetRuleForURI(nsIURI* aURI,
|
||||
nsICookieBannerRule** aRule) {
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
NS_ENSURE_ARG_POINTER(aRule);
|
||||
*aRule = nullptr;
|
||||
|
||||
// Service is disabled, throw with null.
|
||||
if (!mIsInitialized) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIEffectiveTLDService> eTLDService(
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCString baseDomain;
|
||||
rv = eTLDService->GetBaseDomain(aURI, 0, baseDomain);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return GetRuleForDomain(baseDomain, aRule);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCookieBannerService::GetCookiesForURI(
|
||||
nsIURI* aURI, nsTArray<RefPtr<nsICookieRule>>& aCookies) {
|
||||
aCookies.Clear();
|
||||
|
||||
// Service is disabled, throw with empty array.
|
||||
if (!mIsInitialized) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICookieBannerRule> rule;
|
||||
nsresult rv = GetRuleForURI(aURI, getter_AddRefs(rule));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!rule) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// MODE_REJECT: In this mode we only handle the banner if we can reject. We
|
||||
// don't care about the opt-in cookies.
|
||||
rv = rule->GetCookiesOptOut(aCookies);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// MODE_REJECT_OR_ACCEPT: In this mode we will try to opt-out, but if we don't
|
||||
// have any opt-out cookies we will fallback to the opt-in cookies.
|
||||
if (StaticPrefs::cookiebanners_service_mode() ==
|
||||
nsICookieBannerService::MODE_REJECT_OR_ACCEPT &&
|
||||
aCookies.IsEmpty()) {
|
||||
return rule->GetCookiesOptIn(aCookies);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCookieBannerService::LookupOrInsertRuleForDomain(
|
||||
const nsACString& aDomain, nsICookieBannerRule** aRule) {
|
||||
NS_ENSURE_ARG_POINTER(aRule);
|
||||
|
||||
// Service is disabled, throw with null.
|
||||
if (!mIsInitialized) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICookieBannerRule> rule =
|
||||
mRules.LookupOrInsert(aDomain, RefPtr{new nsCookieBannerRule(aDomain)});
|
||||
NS_ENSURE_TRUE(rule, NS_ERROR_FAILURE);
|
||||
|
||||
rule.forget(aRule);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
60
toolkit/components/cookiebanners/nsCookieBannerService.h
Normal file
60
toolkit/components/cookiebanners/nsCookieBannerService.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* 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_nsCookieBannerService_h__
|
||||
#define mozilla_nsCookieBannerService_h__
|
||||
|
||||
#include "nsICookieBannerRule.h"
|
||||
#include "nsICookieBannerService.h"
|
||||
#include "nsICookieBannerListService.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTHashMap.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class nsCookieBannerService final : public nsIObserver,
|
||||
public nsICookieBannerService {
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
NS_DECL_NSICOOKIEBANNERSERVICE
|
||||
|
||||
public:
|
||||
static already_AddRefed<nsCookieBannerService> GetSingleton();
|
||||
|
||||
private:
|
||||
nsCookieBannerService() = default;
|
||||
~nsCookieBannerService() = default;
|
||||
|
||||
// Whether the service is enabled and ready to accept requests.
|
||||
bool mIsInitialized = false;
|
||||
|
||||
nsCOMPtr<nsICookieBannerListService> mListService;
|
||||
nsTHashMap<nsCStringHashKey, nsCOMPtr<nsICookieBannerRule>> mRules;
|
||||
|
||||
// Pref change callback which initializes and shuts down the service. This is
|
||||
// also called on startup.
|
||||
static void OnPrefChange(const char* aPref, void* aData);
|
||||
|
||||
/**
|
||||
* Initializes internal state. Will be called on profile-after-change and on
|
||||
* pref changes.
|
||||
*/
|
||||
[[nodiscard]] nsresult Init();
|
||||
|
||||
/**
|
||||
* Cleanup method to be called on shutdown or pref change.
|
||||
*/
|
||||
[[nodiscard]] nsresult Shutdown();
|
||||
|
||||
nsresult GetRuleForDomain(const nsACString& aDomain,
|
||||
nsICookieBannerRule** aRule);
|
||||
|
||||
nsresult GetRuleForURI(nsIURI* aURI, nsICookieBannerRule** aRule);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
275
toolkit/components/cookiebanners/nsCookieInjector.cpp
Normal file
275
toolkit/components/cookiebanners/nsCookieInjector.cpp
Normal file
@ -0,0 +1,275 @@
|
||||
/* 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 "nsCookieInjector.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsICookieBannerService.h"
|
||||
#include "nsICookieManager.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "Cookie.h"
|
||||
#include "nsIHttpProtocolHandler.h"
|
||||
#include "mozilla/StaticPrefs_cookiebanners.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
LazyLogModule gCookieInjectorLog("nsCookieInjector");
|
||||
|
||||
StaticRefPtr<nsCookieInjector> sCookieInjectorSingleton;
|
||||
|
||||
static constexpr auto kHttpObserverMessage =
|
||||
NS_HTTP_ON_MODIFY_REQUEST_BEFORE_COOKIES_TOPIC;
|
||||
static const char kCookieInjectorEnabledPref[] =
|
||||
"cookiebanners.cookieInjector.enabled";
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsCookieInjector, nsIObserver);
|
||||
|
||||
already_AddRefed<nsCookieInjector> nsCookieInjector::GetSingleton() {
|
||||
if (!sCookieInjectorSingleton) {
|
||||
sCookieInjectorSingleton = new nsCookieInjector();
|
||||
|
||||
// Register pref listeners.
|
||||
DebugOnly<nsresult> rv = Preferences::RegisterCallbackAndCall(
|
||||
&nsCookieInjector::OnPrefChange, kCookieInjectorEnabledPref);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"Failed to register pref listener for kCookieInjectorEnabledPref.");
|
||||
rv = Preferences::RegisterCallbackAndCall(&nsCookieInjector::OnPrefChange,
|
||||
kCookieBannerServiceModePref);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"Failed to register pref listener for kCookieBannerServiceModePref.");
|
||||
|
||||
// Clean up on shutdown.
|
||||
RunOnShutdown([] {
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Debug, ("RunOnShutdown"));
|
||||
|
||||
// Unregister pref listeners.
|
||||
DebugOnly<nsresult> rv = Preferences::UnregisterCallback(
|
||||
&nsCookieInjector::OnPrefChange, kCookieInjectorEnabledPref);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"Failed to unregister pref listener for kCookieInjectorEnabledPref.");
|
||||
rv = Preferences::UnregisterCallback(&nsCookieInjector::OnPrefChange,
|
||||
kCookieBannerServiceModePref);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to unregister pref listener for "
|
||||
"kCookieBannerServiceModePref.");
|
||||
|
||||
rv = sCookieInjectorSingleton->Shutdown();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsCookieInjector::Shutdown failed.");
|
||||
sCookieInjectorSingleton = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
return do_AddRef(sCookieInjectorSingleton);
|
||||
}
|
||||
|
||||
// static
|
||||
void nsCookieInjector::OnPrefChange(const char* aPref, void* aData) {
|
||||
RefPtr<nsCookieInjector> injector = nsCookieInjector::GetSingleton();
|
||||
|
||||
if (StaticPrefs::cookiebanners_service_mode() !=
|
||||
nsICookieBannerService::MODE_DISABLED &&
|
||||
StaticPrefs::cookiebanners_cookieInjector_enabled()) {
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Info,
|
||||
("Initializing cookie injector after pref change. %s", aPref));
|
||||
|
||||
DebugOnly<nsresult> rv = injector->Init();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "nsCookieInjector::Init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Info,
|
||||
("Disabling cookie injector after pref change. %s", aPref));
|
||||
DebugOnly<nsresult> rv = injector->Shutdown();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "nsCookieInjector::Shutdown failed");
|
||||
}
|
||||
|
||||
nsresult nsCookieInjector::Init() {
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Debug, ("%s", __FUNCTION__));
|
||||
|
||||
// Check if already initialized.
|
||||
if (mIsInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
mIsInitialized = true;
|
||||
|
||||
// Add http observer.
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
|
||||
|
||||
return observerService->AddObserver(this, kHttpObserverMessage, false);
|
||||
}
|
||||
|
||||
nsresult nsCookieInjector::Shutdown() {
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Debug, ("%s", __FUNCTION__));
|
||||
|
||||
// Check if already shutdown.
|
||||
if (!mIsInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
mIsInitialized = false;
|
||||
|
||||
// Remove http observer.
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
|
||||
|
||||
return observerService->RemoveObserver(this, kHttpObserverMessage);
|
||||
}
|
||||
|
||||
// nsIObserver
|
||||
NS_IMETHODIMP
|
||||
nsCookieInjector::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData) {
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Verbose, ("Observe topic %s", aTopic));
|
||||
if (nsCRT::strcmp(aTopic, kHttpObserverMessage) == 0) {
|
||||
nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aSubject);
|
||||
NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
|
||||
|
||||
return MaybeInjectCookies(channel, aTopic);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsCookieInjector::MaybeInjectCookies(nsIHttpChannel* aChannel,
|
||||
const char* aTopic) {
|
||||
NS_ENSURE_ARG_POINTER(aChannel);
|
||||
NS_ENSURE_ARG_POINTER(aTopic);
|
||||
|
||||
// Skip non-document loads.
|
||||
if (!aChannel->IsDocument()) {
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Verbose,
|
||||
("%s: Skip non-document load.", aTopic));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
||||
NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
|
||||
|
||||
// Skip non-toplevel loads.
|
||||
if (!loadInfo->GetIsTopLevelLoad()) {
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Debug,
|
||||
("%s: Skip non-top-level load.", aTopic));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get hostPort string, used for logging only.
|
||||
nsCString hostPort;
|
||||
rv = uri->GetHostPort(hostPort);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Cookie banner handling rules are fetched from the cookie banner service.
|
||||
nsCOMPtr<nsICookieBannerService> cookieBannerService =
|
||||
components::CookieBannerService::Service(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Debug,
|
||||
("Looking up rules for %s.", hostPort.get()));
|
||||
nsTArray<RefPtr<nsICookieRule>> rules;
|
||||
rv = cookieBannerService->GetCookiesForURI(uri, rules);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// No cookie rules found.
|
||||
if (rules.IsEmpty()) {
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Debug,
|
||||
("Abort: No cookie rules for %s.", hostPort.get()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Info,
|
||||
("Got rules for %s.", hostPort.get()));
|
||||
|
||||
// Get the OA from the channel. We may need to set the cookie in a specific
|
||||
// bucket, for example Private Browsing Mode.
|
||||
OriginAttributes attr = loadInfo->GetOriginAttributes();
|
||||
|
||||
return InjectCookiesFromRules(hostPort, rules, attr);
|
||||
}
|
||||
|
||||
nsresult nsCookieInjector::InjectCookiesFromRules(
|
||||
const nsCString& aHostPort, const nsTArray<RefPtr<nsICookieRule>>& aRules,
|
||||
OriginAttributes& aOriginAttributes) {
|
||||
NS_ENSURE_TRUE(aRules.Length(), NS_ERROR_FAILURE);
|
||||
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Info,
|
||||
("Injecting cookies for %s.", aHostPort.get()));
|
||||
|
||||
// Write cookies from aRules to storage via the cookie manager.
|
||||
nsCOMPtr<nsICookieManager> cookieManager =
|
||||
do_GetService("@mozilla.org/cookiemanager;1");
|
||||
NS_ENSURE_TRUE(cookieManager, NS_ERROR_FAILURE);
|
||||
|
||||
for (nsICookieRule* cookieRule : aRules) {
|
||||
nsCOMPtr<nsICookie> cookie;
|
||||
nsresult rv = cookieRule->GetCookie(getter_AddRefs(cookie));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(!cookie)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert to underlying implementer class to get fast non-xpcom property
|
||||
// access.
|
||||
net::Cookie* c = static_cast<net::Cookie*>(cookie.get());
|
||||
|
||||
// Check if the cookie is already set to avoid overwriting any custom
|
||||
// settings.
|
||||
bool exists = false;
|
||||
rv = cookieManager->CookieExistsNative(c->Host(), c->Path(), c->Name(),
|
||||
&aOriginAttributes, &exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If a cookie with the same name already exists we need to perform further
|
||||
// checks. We can only overwrite if the rule defines the cookie's value as
|
||||
// the "unset" state.
|
||||
if (exists) {
|
||||
nsCString unsetValue;
|
||||
rv = cookieRule->GetUnsetValue(unsetValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// No defined unset value means we shouldn't overwrite the cookie if it is
|
||||
// set. Skip setting this cookie.
|
||||
if (unsetValue.IsEmpty()) {
|
||||
MOZ_LOG(
|
||||
gCookieInjectorLog, LogLevel::Info,
|
||||
("Skip setting already existing cookie. Cookie: %s, %s, %s, %s\n",
|
||||
c->Host().get(), c->Name().get(), c->Path().get(),
|
||||
c->Value().get()));
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Bug 1784874
|
||||
// Check if cookie value == unsetValue. In this case we can
|
||||
// overwrite the cookie. Otherwise log a message and skip setting this
|
||||
// cookie. This might require extending CookieExistsNative and
|
||||
// CookieStorage::FindCookie to take an optional "value" argument or
|
||||
// passing in a lambda that can inspect cookies found.
|
||||
}
|
||||
|
||||
MOZ_LOG(gCookieInjectorLog, LogLevel::Info,
|
||||
("Setting cookie: %s, %s, %s, %s\n", c->Host().get(),
|
||||
c->Name().get(), c->Path().get(), c->Value().get()));
|
||||
rv = cookieManager->AddNative(
|
||||
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()));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
47
toolkit/components/cookiebanners/nsCookieInjector.h
Normal file
47
toolkit/components/cookiebanners/nsCookieInjector.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* 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_nsCookieInjector_h__
|
||||
#define mozilla_nsCookieInjector_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICookieBannerRule.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class nsCookieInjector final : public nsIObserver {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static already_AddRefed<nsCookieInjector> GetSingleton();
|
||||
|
||||
[[nodiscard]] nsresult Init();
|
||||
|
||||
[[nodiscard]] nsresult Shutdown();
|
||||
|
||||
private:
|
||||
nsCookieInjector() = default;
|
||||
~nsCookieInjector() = default;
|
||||
|
||||
// Whether the component is enabled and ready to inject cookies.
|
||||
bool mIsInitialized = false;
|
||||
|
||||
// Enables or disables the component when the relevant prefs change.
|
||||
static void OnPrefChange(const char* aPref, void* aData);
|
||||
|
||||
// Called when the http observer topic is dispatched.
|
||||
nsresult MaybeInjectCookies(nsIHttpChannel* aChannel, const char* aTopic);
|
||||
|
||||
// Inserts cookies via the cookie manager given a list of cookie injection
|
||||
// rules.
|
||||
nsresult InjectCookiesFromRules(const nsCString& aHostPort,
|
||||
const nsTArray<RefPtr<nsICookieRule>>& aRules,
|
||||
OriginAttributes& aOriginAttributes);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
83
toolkit/components/cookiebanners/nsCookieRule.cpp
Normal file
83
toolkit/components/cookiebanners/nsCookieRule.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/* 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 "nsCookieRule.h"
|
||||
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "nsICookie.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "Cookie.h"
|
||||
#include "prtime.h"
|
||||
#include "mozilla/StaticPrefs_cookiebanners.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsCookieRule, nsICookieRule)
|
||||
|
||||
nsCookieRule::nsCookieRule(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) {
|
||||
// Default expiry time is defined by pref.
|
||||
if (aExpiryRelative <= 0) {
|
||||
aExpiryRelative =
|
||||
StaticPrefs::cookiebanners_cookieInjector_defaultExpiryRelative();
|
||||
}
|
||||
mExpiryRelative = aExpiryRelative;
|
||||
|
||||
nsCString path(aPath);
|
||||
if (path.IsEmpty()) {
|
||||
path.AssignLiteral("/");
|
||||
}
|
||||
|
||||
mUnsetValue = aUnsetValue;
|
||||
|
||||
net::CookieStruct cookieData(
|
||||
nsCString(aName), nsCString(aValue), nsCString(aHost), path, 0, 0, 0,
|
||||
aIsHttpOnly, aIsSession, aIsSecure, aSameSite, aSameSite, aSchemeMap);
|
||||
|
||||
OriginAttributes attrs;
|
||||
mCookie = net::Cookie::Create(cookieData, attrs);
|
||||
}
|
||||
|
||||
/* readonly attribute int64_t expiryRelative; */
|
||||
NS_IMETHODIMP nsCookieRule::GetExpiryRelative(int64_t* aExpiryRelative) {
|
||||
NS_ENSURE_ARG_POINTER(aExpiryRelative);
|
||||
|
||||
*aExpiryRelative = mExpiryRelative;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute AUTF8String unsetValue; */
|
||||
NS_IMETHODIMP nsCookieRule::GetUnsetValue(nsACString& aUnsetValue) {
|
||||
aUnsetValue = mUnsetValue;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute nsICookie cookie; */
|
||||
NS_IMETHODIMP nsCookieRule::GetCookie(nsICookie** aCookie) {
|
||||
NS_ENSURE_ARG_POINTER(aCookie);
|
||||
|
||||
// Copy cookie and update expiry, creation and last accessed time.
|
||||
nsICookie* cookie = mCookie;
|
||||
RefPtr<net::Cookie> cookieNative = static_cast<net::Cookie*>(cookie)->Clone();
|
||||
|
||||
int64_t currentTimeInUsec = PR_Now();
|
||||
cookieNative->SetCreationTime(
|
||||
net::Cookie::GenerateUniqueCreationTime(currentTimeInUsec));
|
||||
cookieNative->SetLastAccessed(currentTimeInUsec);
|
||||
cookieNative->SetExpiry((currentTimeInUsec / PR_USEC_PER_SEC) +
|
||||
mExpiryRelative);
|
||||
|
||||
cookieNative.forget(aCookie);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
42
toolkit/components/cookiebanners/nsCookieRule.h
Normal file
42
toolkit/components/cookiebanners/nsCookieRule.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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_nsCookieRule_h__
|
||||
#define mozilla_nsCookieRule_h__
|
||||
|
||||
#include "nsICookieRule.h"
|
||||
#include "nsICookie.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/StaticPrefs_cookiebanners.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class nsCookieRule final : public nsICookieRule {
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICOOKIERULE
|
||||
|
||||
public:
|
||||
nsCookieRule() = default;
|
||||
|
||||
explicit nsCookieRule(
|
||||
bool aIsOptOut, const nsACString& aHost, const nsACString& aName,
|
||||
const nsACString& aValue, const nsACString& aPath = "/"_ns,
|
||||
int64_t aExpiryRelative =
|
||||
StaticPrefs::cookiebanners_cookieInjector_defaultExpiryRelative(),
|
||||
const nsACString& aUnsetValue = ""_ns, bool aIsSecure = true,
|
||||
bool aIsHttpOnly = false, bool aIsSession = false,
|
||||
int32_t aSameSite = nsICookie::SAMESITE_LAX,
|
||||
nsICookie::schemeType aSchemeMap = nsICookie::SCHEME_HTTPS);
|
||||
|
||||
private:
|
||||
~nsCookieRule() = default;
|
||||
|
||||
nsCOMPtr<nsICookie> mCookie;
|
||||
int64_t mExpiryRelative{};
|
||||
nsCString mUnsetValue;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -0,0 +1,19 @@
|
||||
/* 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"
|
||||
|
||||
/**
|
||||
* Service singleton for initializing and updating the list of cookie banner
|
||||
* handling rules.
|
||||
*/
|
||||
[scriptable, uuid(1d8d9470-97d3-4885-a108-44a5c4fb36e2)]
|
||||
interface nsICookieBannerListService : nsISupports {
|
||||
// Import the initial rule list.
|
||||
void importRules();
|
||||
};
|
||||
|
||||
%{C++
|
||||
#define NS_COOKIEBANNERLISTSERVICE_CONTRACTID "@mozilla.org/cookie-banner-list-service;1"
|
||||
%}
|
53
toolkit/components/cookiebanners/nsICookieBannerRule.idl
Normal file
53
toolkit/components/cookiebanners/nsICookieBannerRule.idl
Normal file
@ -0,0 +1,53 @@
|
||||
/* -*- 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"
|
||||
#include "nsICookieRule.idl"
|
||||
|
||||
/**
|
||||
* A rule containing instructions on how to handle a cookie banner for a specific
|
||||
* domain.
|
||||
*/
|
||||
|
||||
[builtinclass, scriptable, uuid(eb1904db-e0d1-4760-a721-db76b1ca3e94)]
|
||||
interface nsICookieBannerRule : nsISupports {
|
||||
// Domain of the site to handle the cookie banner for.
|
||||
readonly attribute ACString domain;
|
||||
|
||||
// Cookies that reflect the opt-out or "reject all" state for the cookie baner.
|
||||
readonly attribute Array<nsICookieRule> cookiesOptOut;
|
||||
// Cookies that reflect the opt-in or "accept all" state for the cookie banner.
|
||||
readonly attribute Array<nsICookieRule> cookiesOptIn;
|
||||
|
||||
/**
|
||||
* Clear both lists of opt-in and opt-out cookies.
|
||||
*/
|
||||
void clearCookies();
|
||||
|
||||
/**
|
||||
* Add an opt-in or opt-out cookie to the rule.
|
||||
|
||||
* aIsOptOut - Whether this is an opt-out cookie (true) or opt-in cookie (false).
|
||||
* aExpiryRelative - See nsICookieRule.
|
||||
* aUnsetValue - See nsICookieRule.
|
||||
* For a description of the other fields see nsICookieManager#addNative.
|
||||
*/
|
||||
void addCookie(in boolean aIsOptOut,
|
||||
in AUTF8String aHost,
|
||||
in ACString aName,
|
||||
in AUTF8String aValue,
|
||||
[optional] in AUTF8String aPath,
|
||||
[optional] in int64_t aExpiryRelative,
|
||||
[optional] in AUTF8String aUnsetValue,
|
||||
[optional] in boolean aIsSecure,
|
||||
[optional] in boolean aIsHttpOnly,
|
||||
[optional] in boolean aIsSession,
|
||||
[optional] in int32_t aSameSite,
|
||||
[optional] in nsICookie_schemeType aSchemeMap);
|
||||
|
||||
// TODO: additional rule types here e.g. for clicking.
|
||||
};
|
||||
|
49
toolkit/components/cookiebanners/nsICookieBannerService.idl
Normal file
49
toolkit/components/cookiebanners/nsICookieBannerService.idl
Normal file
@ -0,0 +1,49 @@
|
||||
/* 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"
|
||||
#include "nsICookieBannerRule.idl"
|
||||
#include "nsICookieRule.idl"
|
||||
#include "nsIURI.idl"
|
||||
|
||||
/**
|
||||
* Service singleton which owns the cookie banner feature.
|
||||
* This service owns the cookie banner handling rules.
|
||||
* It initializes both the component for importing rules
|
||||
* (nsICookieBannerListService) and injecting cookies (nsICookieInjector).
|
||||
*/
|
||||
[scriptable, uuid(eac9cdc4-ecee-49f2-91da-7627e15c1f3c)]
|
||||
interface nsICookieBannerService : nsISupports {
|
||||
|
||||
/**
|
||||
* Modes for cookie banner handling
|
||||
* MODE_DISABLED - No cookie banner handling, service disabled.
|
||||
* MODE_REJECT - Only handle banners where selecting "reject all" is possible.
|
||||
* MODE_REJECT_OR_ACCEPT - Prefer selecting "reject all", if not possible
|
||||
* fall back to "accept all".
|
||||
*/
|
||||
cenum Modes : 8 {
|
||||
MODE_DISABLED,
|
||||
MODE_REJECT,
|
||||
MODE_REJECT_OR_ACCEPT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Getter for a list of all cookie banner rules. This includes both opt-in and opt-out rules.
|
||||
*/
|
||||
readonly attribute Array<nsICookieBannerRule> rules;
|
||||
|
||||
/**
|
||||
* Look up all cookie rules for a given URI. Depending on the MODE_ this will
|
||||
* return none, only reject rules or accept rules if there is no reject rule
|
||||
* available.
|
||||
*/
|
||||
Array<nsICookieRule> getCookiesForURI(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Lookup or insert an empty nsICookieBannerRule and return it.
|
||||
* Used by the CookieBannerListService to create and populate the rules.
|
||||
*/
|
||||
nsICookieBannerRule lookupOrInsertRuleForDomain(in ACString aDomain);
|
||||
};
|
38
toolkit/components/cookiebanners/nsICookieRule.idl
Normal file
38
toolkit/components/cookiebanners/nsICookieRule.idl
Normal file
@ -0,0 +1,38 @@
|
||||
/* -*- 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"
|
||||
#include "nsICookie.idl"
|
||||
|
||||
/**
|
||||
* Rule which specifies a cookie to be set in order to handle a cookie banner.
|
||||
*/
|
||||
|
||||
[builtinclass, scriptable, uuid(bf049b1e-8a05-481f-a120-332ea1bd65ef)]
|
||||
interface nsICookieRule : nsISupports {
|
||||
/**
|
||||
* The cookie to set.
|
||||
* When calling this getter creation, expiry and last accessed time are
|
||||
* computed.
|
||||
*/
|
||||
readonly attribute nsICookie cookie;
|
||||
|
||||
/**
|
||||
* Expiry time of the cookie in seconds relative to the injection time.
|
||||
* If you want a cookie to expire in 1 month after it has been set, set this
|
||||
* to 2592000.
|
||||
* Defaults to 'cookiebanners.cookieInjector.defaultExpiryRelative'.
|
||||
*/
|
||||
readonly attribute int64_t expiryRelative;
|
||||
|
||||
/**
|
||||
* If an existing cookie sets this value it may be overwritten.
|
||||
* This is used for sites which set an explicit cookie state, even if a
|
||||
* cookie banner is still pending.
|
||||
*/
|
||||
readonly attribute AUTF8String unsetValue;
|
||||
};
|
||||
|
@ -27,6 +27,7 @@ DIRS += [
|
||||
"certviewer",
|
||||
"cleardata",
|
||||
"clearsitedata",
|
||||
"cookiebanners",
|
||||
"commandlines",
|
||||
"contentprefs",
|
||||
"contextualidentity",
|
||||
|
@ -11,6 +11,7 @@
|
||||
"nsIClearDataService": "clearData",
|
||||
"nsIClipboard": "clipboard",
|
||||
"nsIConsoleService": "console",
|
||||
"nsICookieBannerService": "cookieBanners",
|
||||
"nsICookieManager": "cookies",
|
||||
"nsICookieService": "cookies",
|
||||
"nsIDOMRequestService": "DOMRequest",
|
||||
|
Loading…
Reference in New Issue
Block a user