forked from mirrors/gecko-dev
This patch changes the cooldown mechansim. The original behavior is stop executing cookie banner clicking after loading the site in the browsing session. We modify it to that the cooldown mechanism takes effect after loading the site several times in the browsing session.. Differential Revision: https://phabricator.services.mozilla.com/D193906
257 lines
7.2 KiB
JavaScript
257 lines
7.2 KiB
JavaScript
/* 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/. */
|
|
|
|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
|
});
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
lazy,
|
|
"serviceMode",
|
|
"cookiebanners.service.mode",
|
|
Ci.nsICookieBannerService.MODE_DISABLED
|
|
);
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
lazy,
|
|
"serviceModePBM",
|
|
"cookiebanners.service.mode.privateBrowsing",
|
|
Ci.nsICookieBannerService.MODE_DISABLED
|
|
);
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
lazy,
|
|
"maxTriesPerSiteAndSession",
|
|
"cookiebanners.bannerClicking.maxTriesPerSiteAndSession",
|
|
3
|
|
);
|
|
|
|
ChromeUtils.defineLazyGetter(lazy, "CookieBannerL10n", () => {
|
|
return new Localization([
|
|
"branding/brand.ftl",
|
|
"toolkit/global/cookieBannerHandling.ftl",
|
|
]);
|
|
});
|
|
|
|
export class CookieBannerParent extends JSWindowActorParent {
|
|
/**
|
|
* Get the browser associated with this window which is the top level embedder
|
|
* element. Returns null if the top embedder isn't a browser.
|
|
*/
|
|
get #browserElement() {
|
|
let topBC = this.browsingContext.top;
|
|
|
|
// Not all embedders are browsers.
|
|
if (topBC.embedderElementType != "browser") {
|
|
return null;
|
|
}
|
|
|
|
return topBC.embedderElement;
|
|
}
|
|
|
|
get #isTopLevel() {
|
|
return !this.manager.browsingContext.parent;
|
|
}
|
|
|
|
#isPrivateBrowsingCached;
|
|
get #isPrivateBrowsing() {
|
|
if (this.#isPrivateBrowsingCached !== undefined) {
|
|
return this.#isPrivateBrowsingCached;
|
|
}
|
|
let browser = this.#browserElement;
|
|
if (!browser) {
|
|
return false;
|
|
}
|
|
|
|
this.#isPrivateBrowsingCached =
|
|
lazy.PrivateBrowsingUtils.isBrowserPrivate(browser);
|
|
|
|
return this.#isPrivateBrowsingCached;
|
|
}
|
|
|
|
/**
|
|
* Dispatches a custom "cookiebannerhandled" event on the chrome window.
|
|
*/
|
|
#notifyCookieBannerState(eventType) {
|
|
let chromeWin = this.browsingContext.topChromeWindow;
|
|
if (!chromeWin) {
|
|
return;
|
|
}
|
|
let windowUtils = chromeWin.windowUtils;
|
|
if (!windowUtils) {
|
|
return;
|
|
}
|
|
let event = new CustomEvent(eventType, {
|
|
bubbles: true,
|
|
cancelable: false,
|
|
detail: {
|
|
windowContext: this.manager,
|
|
},
|
|
});
|
|
windowUtils.dispatchEventToChromeOnly(chromeWin, event);
|
|
}
|
|
|
|
/**
|
|
* Logs a warning to the web console that a cookie banner has been handled.
|
|
*/
|
|
async #logCookieBannerHandledToWebConsole() {
|
|
let consoleMsg = Cc["@mozilla.org/scripterror;1"].createInstance(
|
|
Ci.nsIScriptError
|
|
);
|
|
let [message] = await lazy.CookieBannerL10n.formatMessages([
|
|
{ id: "cookie-banner-handled-webconsole" },
|
|
]);
|
|
|
|
if (!this.manager?.innerWindowId) {
|
|
return;
|
|
}
|
|
consoleMsg.initWithWindowID(
|
|
message.value,
|
|
this.manager.documentURI?.spec,
|
|
null,
|
|
null,
|
|
null,
|
|
Ci.nsIScriptError.warningFlag,
|
|
"cookiebannerhandling",
|
|
this.manager?.innerWindowId
|
|
);
|
|
Services.console.logMessage(consoleMsg);
|
|
}
|
|
|
|
async receiveMessage(message) {
|
|
if (message.name == "CookieBanner::Test-FinishClicking") {
|
|
Services.obs.notifyObservers(
|
|
null,
|
|
"cookie-banner-test-clicking-finish",
|
|
this.manager.documentPrincipal?.baseDomain
|
|
);
|
|
return undefined;
|
|
}
|
|
|
|
// Forwards cookie banner detected signals to frontend consumers.
|
|
if (message.name == "CookieBanner::DetectedBanner") {
|
|
this.#notifyCookieBannerState("cookiebannerdetected");
|
|
return undefined;
|
|
}
|
|
|
|
// Forwards cookie banner handled signals to frontend consumers.
|
|
if (message.name == "CookieBanner::HandledBanner") {
|
|
this.#notifyCookieBannerState("cookiebannerhandled");
|
|
this.#logCookieBannerHandledToWebConsole();
|
|
return undefined;
|
|
}
|
|
|
|
let domain = this.manager.documentPrincipal?.baseDomain;
|
|
|
|
if (message.name == "CookieBanner::MarkSiteExecuted") {
|
|
if (!domain) {
|
|
return undefined;
|
|
}
|
|
|
|
Services.cookieBanners.markSiteExecuted(
|
|
domain,
|
|
this.#isTopLevel,
|
|
this.#isPrivateBrowsing
|
|
);
|
|
return undefined;
|
|
}
|
|
|
|
if (message.name != "CookieBanner::GetClickRules") {
|
|
return undefined;
|
|
}
|
|
|
|
// TODO: Bug 1790688: consider moving this logic to the cookie banner service.
|
|
let mode;
|
|
if (this.#isPrivateBrowsing) {
|
|
mode = lazy.serviceModePBM;
|
|
} else {
|
|
mode = lazy.serviceMode;
|
|
}
|
|
|
|
// Check if we have a site preference of the top-level URI. If so, it
|
|
// takes precedence over the pref setting.
|
|
let topBrowsingContext = this.manager.browsingContext.top;
|
|
let topURI = topBrowsingContext.currentWindowGlobal?.documentURI;
|
|
|
|
// We don't need to check the domain preference if the cookie banner
|
|
// handling was disabled by pref.
|
|
if (mode != Ci.nsICookieBannerService.MODE_DISABLED && topURI) {
|
|
try {
|
|
let perDomainMode = Services.cookieBanners.getDomainPref(
|
|
topURI,
|
|
this.#isPrivateBrowsing
|
|
);
|
|
|
|
if (perDomainMode != Ci.nsICookieBannerService.MODE_UNSET) {
|
|
mode = perDomainMode;
|
|
}
|
|
} catch (e) {
|
|
// getPerSitePref could throw with NS_ERROR_NOT_AVAILABLE if the service
|
|
// is disabled. We will fallback to global pref setting if any errors
|
|
// occur.
|
|
if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
|
|
console.error("The cookie banner handling service is not available");
|
|
} else {
|
|
console.error("Fail on getting domain pref:", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if we previously executed banner clicking for the site. If the pref
|
|
// instructs to always execute banner clicking, we will set it to
|
|
// false.
|
|
let hasExecuted = false;
|
|
if (lazy.maxTriesPerSiteAndSession > 0) {
|
|
hasExecuted = Services.cookieBanners.shouldStopBannerClickingForSite(
|
|
domain,
|
|
this.#isTopLevel,
|
|
this.#isPrivateBrowsing
|
|
);
|
|
}
|
|
|
|
// If we have previously executed banner clicking or the service is disabled
|
|
// for current context (normal or private browsing), return empty array.
|
|
if (hasExecuted || mode == Ci.nsICookieBannerService.MODE_DISABLED) {
|
|
return { rules: [], hasExecuted };
|
|
}
|
|
|
|
if (!domain) {
|
|
return { rules: [], hasExecuted };
|
|
}
|
|
|
|
let rules = Services.cookieBanners.getClickRulesForDomain(
|
|
domain,
|
|
this.#isTopLevel
|
|
);
|
|
|
|
if (!rules.length) {
|
|
return { rules: [], hasExecuted };
|
|
}
|
|
|
|
// Determine whether we can fall back to opt-in rules. This includes the
|
|
// detect-only mode where don't interact with the banner.
|
|
let modeAllowsOptIn =
|
|
mode == Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT;
|
|
|
|
rules = rules.map(rule => {
|
|
let target = rule.optOut;
|
|
|
|
if (modeAllowsOptIn && !target) {
|
|
target = rule.optIn;
|
|
}
|
|
return {
|
|
id: rule.id,
|
|
hide: rule.hide ?? rule.presence,
|
|
presence: rule.presence,
|
|
skipPresenceVisibilityCheck: rule.skipPresenceVisibilityCheck,
|
|
target,
|
|
isGlobalRule: rule.isGlobalRule,
|
|
};
|
|
});
|
|
|
|
return { rules, hasExecuted };
|
|
}
|
|
}
|