@duckduckgo/autoconsent 1.0.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +14 -0
- package/.vscode/settings.json +7 -0
- package/Jenkinsfile +68 -39
- package/api.md +104 -0
- package/dist/autoconsent.cjs.js +1 -1371
- package/dist/autoconsent.esm.js +1 -1363
- package/dist/autoconsent.playwright.js +1 -0
- package/dist/autoconsent.standalone.js +1 -0
- package/lib/cmps/all.ts +15 -10
- package/lib/cmps/base.ts +91 -91
- package/lib/cmps/consentmanager.ts +31 -19
- package/lib/cmps/consentomatic.ts +89 -0
- package/lib/cmps/cookiebot.ts +62 -53
- package/lib/cmps/evidon.ts +29 -18
- package/lib/cmps/onetrust.ts +37 -19
- package/lib/cmps/sourcepoint-frame.ts +102 -0
- package/lib/cmps/sourcepoint-top.ts +47 -0
- package/lib/cmps/trustarc-frame.ts +115 -0
- package/lib/cmps/trustarc-top.ts +91 -0
- package/lib/consentomatic/index.ts +233 -70
- package/lib/{web/consentomatic → consentomatic}/tools.ts +0 -0
- package/lib/eval-handler.ts +58 -0
- package/lib/index.ts +0 -2
- package/lib/messages.ts +100 -0
- package/lib/rule-executors.ts +108 -0
- package/lib/rules.ts +82 -0
- package/lib/types.ts +35 -0
- package/lib/utils.ts +64 -0
- package/lib/web.ts +283 -74
- package/package.json +17 -14
- package/playwright/content.ts +27 -0
- package/playwright/runner.ts +131 -0
- package/playwright/standalone.ts +36 -0
- package/playwright.config.ts +7 -0
- package/readme.md +57 -47
- package/rollup.config.js +23 -15
- package/rules/autoconsent/192.json +17 -0
- package/rules/autoconsent/ausopen.json +7 -0
- package/rules/autoconsent/aws-amazon.json +1 -1
- package/rules/autoconsent/baden-wuerttemberg-de.json +7 -3
- package/rules/autoconsent/bing.json +14 -0
- package/rules/autoconsent/bundesregierung-de.json +6 -2
- package/rules/autoconsent/cc-banner.json +0 -1
- package/rules/autoconsent/cookie-notice.json +0 -1
- package/rules/autoconsent/cookieconsent.json +5 -6
- package/rules/autoconsent/destatis-de.json +0 -1
- package/rules/autoconsent/dunelm.json +18 -0
- package/rules/autoconsent/etsy.json +3 -2
- package/rules/autoconsent/eu-cookie-compliance.json +0 -1
- package/rules/autoconsent/gov-uk.json +10 -0
- package/rules/autoconsent/hl-co-uk.json +8 -9
- package/rules/autoconsent/johnlewis.json +5 -2
- package/rules/autoconsent/marksandspencer.json +7 -0
- package/rules/autoconsent/notice-cookie.json +0 -1
- package/rules/autoconsent/osano.json +0 -1
- package/rules/autoconsent/{paypal-de.json → paypal.json} +6 -2
- package/rules/autoconsent/tealium.json +4 -5
- package/rules/autoconsent/uswitch.json +8 -0
- package/rules/autoconsent/waitrose.json +28 -0
- package/rules/autoconsent/wetransfer.json +7 -0
- package/rules/rules.json +314 -39
- package/tests/192.spec.ts +7 -0
- package/tests/arzt-auskunft.spec.ts +1 -1
- package/tests/asus.spec.ts +1 -1
- package/tests/ausopen.spec.ts +7 -0
- package/tests/aws.amazon.spec.ts +1 -1
- package/tests/baden-wuerttemberg.spec.ts +1 -1
- package/tests/borlabs.spec.ts +1 -1
- package/tests/bundesregierung.spec.ts +5 -2
- package/tests/ccbanner.spec.ts +1 -1
- package/tests/consentmanager.spec.ts +3 -3
- package/tests/cookiebot.spec.ts +8 -1
- package/tests/cookieconsent.spec.ts +1 -1
- package/tests/cookielawinfo.spec.ts +1 -1
- package/tests/cookienotice.spec.ts +1 -1
- package/tests/corona-in-zahlen.spec.ts +1 -1
- package/tests/deepl.spec.ts +1 -1
- package/tests/destatis.spec.ts +1 -1
- package/tests/didomi.spec.ts +6 -2
- package/tests/drupal.spec.ts +8 -0
- package/tests/dunelm.spec.ts +7 -0
- package/tests/etsy.spec.ts +1 -1
- package/tests/eu-cookie-compliance-banner.spec.ts +1 -1
- package/tests/evidon.spec.ts +1 -1
- package/tests/fundingchoices.spec.ts +2 -1
- package/tests/gov-uk.spec.ts +9 -0
- package/tests/hl-co-uk.spec.ts +1 -1
- package/tests/hubspot.spec.ts +1 -1
- package/tests/ionos.spec.ts +1 -1
- package/tests/johnlewis.spec.ts +2 -2
- package/tests/klaro.spec.ts +1 -1
- package/tests/marksandspencer.spec.ts +7 -0
- package/tests/mediamarkt.spec.ts +1 -1
- package/tests/metoffice-gov-uk.spec.ts +1 -1
- package/tests/microsoft.spec.ts +1 -1
- package/tests/moneysavingexpert.spec.ts +1 -1
- package/tests/motor-talk.spec.ts +1 -1
- package/tests/national-lottery.spec.ts +1 -1
- package/tests/netflix.spec.ts +1 -1
- package/tests/nhs.spec.ts +1 -1
- package/tests/notice-cookie.spec.ts +1 -1
- package/tests/obi.spec.ts +1 -1
- package/tests/oil.spec.ts +1 -1
- package/tests/onetrust.spec.ts +10 -1
- package/tests/osano.spec.ts +1 -1
- package/tests/otto.spec.ts +1 -1
- package/tests/paypal.spec.ts +8 -6
- package/tests/quantcast.spec.ts +4 -1
- package/tests/snigel.spec.ts +1 -1
- package/tests/sourcepoint.spec.ts +8 -8
- package/tests/springer.spec.ts +1 -1
- package/tests/steampowered.spec.ts +1 -1
- package/tests/tealium.spec.ts +1 -1
- package/tests/testcmp.spec.ts +1 -1
- package/tests/thalia.spec.ts +1 -1
- package/tests/thefreedictionary.spec.ts +1 -1
- package/tests/trustarc.spec.ts +25 -3
- package/tests/usercentrics-1.spec.ts +1 -1
- package/tests/uswitch.spec.ts +7 -0
- package/tests/vodafone.spec.ts +1 -1
- package/tests/waitrose.spec.ts +7 -0
- package/tests/wetransfer.spec.ts +7 -0
- package/tests/wordpressgdpr.spec.ts +1 -1
- package/tests/xing.spec.ts +1 -1
- package/tsconfig.json +2 -2
- package/.eslintrc +0 -12
- package/cosmetics/rules.json +0 -110
- package/dist/autoconsent.puppet.js +0 -1072
- package/lib/cmps/all.js +0 -19
- package/lib/cmps/base.js +0 -174
- package/lib/cmps/consentmanager.js +0 -31
- package/lib/cmps/cookiebot.js +0 -73
- package/lib/cmps/evidon.js +0 -26
- package/lib/cmps/onetrust.js +0 -32
- package/lib/cmps/sourcepoint.js +0 -82
- package/lib/cmps/sourcepoint.ts +0 -95
- package/lib/cmps/trustarc.js +0 -106
- package/lib/cmps/trustarc.ts +0 -147
- package/lib/config.js +0 -1
- package/lib/consentomatic/index.js +0 -52
- package/lib/detector.js +0 -33
- package/lib/detector.ts +0 -34
- package/lib/hider.js +0 -13
- package/lib/hider.ts +0 -16
- package/lib/index.js +0 -4
- package/lib/messages.d.ts +0 -61
- package/lib/node.js +0 -35
- package/lib/node.ts +0 -43
- package/lib/puppet/tab.js +0 -121
- package/lib/puppet/tab.ts +0 -146
- package/lib/rules.d.ts +0 -80
- package/lib/tabwrapper.js +0 -67
- package/lib/tabwrapper.ts +0 -74
- package/lib/types.d.ts +0 -61
- package/lib/web/consentomatic/index.js +0 -188
- package/lib/web/consentomatic/index.ts +0 -249
- package/lib/web/consentomatic/tools.js +0 -177
- package/lib/web/content-utils.js +0 -29
- package/lib/web/content-utils.ts +0 -31
- package/lib/web/content.js +0 -79
- package/lib/web/content.ts +0 -71
- package/lib/web/tab.js +0 -112
- package/lib/web/tab.ts +0 -178
- package/lib/web.js +0 -95
- package/tests/runner.ts +0 -61
package/lib/types.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ContentScriptMessage } from "./messages";
|
|
2
|
+
import { ConsentOMaticConfig } from "./cmps/consentomatic";
|
|
3
|
+
import { AutoConsentCMPRule, RunContext } from "./rules";
|
|
4
|
+
|
|
5
|
+
export type MessageSender = (message: ContentScriptMessage) => Promise<void>;
|
|
6
|
+
|
|
7
|
+
export interface AutoCMP {
|
|
8
|
+
name: string
|
|
9
|
+
hasSelfTest: boolean
|
|
10
|
+
isIntermediate: boolean;
|
|
11
|
+
prehideSelectors?: string[];
|
|
12
|
+
runContext: RunContext;
|
|
13
|
+
checkRunContext(): boolean;
|
|
14
|
+
detectCmp(): Promise<boolean>
|
|
15
|
+
detectPopup(): Promise<boolean>
|
|
16
|
+
optOut(): Promise<boolean>
|
|
17
|
+
optIn(): Promise<boolean>
|
|
18
|
+
openCmp(): Promise<boolean>
|
|
19
|
+
test(): Promise<boolean>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type RuleBundle = {
|
|
23
|
+
autoconsent: AutoConsentCMPRule[];
|
|
24
|
+
consentomatic: { [name: string]: ConsentOMaticConfig };
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type AutoAction = 'optOut' | 'optIn' | null;
|
|
28
|
+
|
|
29
|
+
export type Config = {
|
|
30
|
+
enabled: boolean;
|
|
31
|
+
autoAction: AutoAction;
|
|
32
|
+
disabledCmps: string[];
|
|
33
|
+
enablePrehide: boolean;
|
|
34
|
+
detectRetries: number;
|
|
35
|
+
}
|
package/lib/utils.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { HideMethod } from "./rules";
|
|
2
|
+
|
|
3
|
+
// get or create a style container for CSS overrides
|
|
4
|
+
export function getStyleElement(styleOverrideElementId = "autoconsent-css-rules"): HTMLStyleElement {
|
|
5
|
+
const styleSelector = `style#${styleOverrideElementId}`;
|
|
6
|
+
const existingElement = document.querySelector(styleSelector);
|
|
7
|
+
if (existingElement && existingElement instanceof HTMLStyleElement) {
|
|
8
|
+
return existingElement;
|
|
9
|
+
} else {
|
|
10
|
+
const parent =
|
|
11
|
+
document.head ||
|
|
12
|
+
document.getElementsByTagName("head")[0] ||
|
|
13
|
+
document.documentElement;
|
|
14
|
+
const css = document.createElement("style");
|
|
15
|
+
css.id = styleOverrideElementId;
|
|
16
|
+
parent.appendChild(css);
|
|
17
|
+
return css;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// hide elements with a CSS rule
|
|
22
|
+
export function hideElements(
|
|
23
|
+
styleEl: HTMLStyleElement,
|
|
24
|
+
selectors: string[],
|
|
25
|
+
method: HideMethod = 'display',
|
|
26
|
+
): boolean {
|
|
27
|
+
const hidingSnippet = method === "opacity" ? `opacity: 0` : `display: none`; // use display by default
|
|
28
|
+
const rule = `${selectors.join(
|
|
29
|
+
","
|
|
30
|
+
)} { ${hidingSnippet} !important; z-index: -1 !important; pointer-events: none !important; } `;
|
|
31
|
+
|
|
32
|
+
if (styleEl instanceof HTMLStyleElement) {
|
|
33
|
+
styleEl.innerText += rule;
|
|
34
|
+
return selectors.length > 0;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function waitFor(predicate: () => Promise<boolean> | boolean, maxTimes: number, interval: number): Promise<boolean> {
|
|
40
|
+
const result = await predicate();
|
|
41
|
+
if (!result && maxTimes > 0) {
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
setTimeout(async () => {
|
|
44
|
+
resolve(waitFor(predicate, maxTimes - 1, interval));
|
|
45
|
+
}, interval);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return Promise.resolve(result);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isElementVisible(elem: HTMLElement): boolean {
|
|
52
|
+
if (!elem) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (elem.offsetParent !== null) {
|
|
56
|
+
return true;
|
|
57
|
+
} else {
|
|
58
|
+
const css = window.getComputedStyle(elem);
|
|
59
|
+
if (css.position === 'fixed' && css.display !== "none") { // fixed elements may be visible even if the parent is not
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
package/lib/web.ts
CHANGED
|
@@ -1,35 +1,89 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import detectDialog from './detector';
|
|
5
|
-
import { rules, createAutoCMP } from './index';
|
|
6
|
-
import { Browser, MessageSender, AutoCMP, TabActor } from './types';
|
|
7
|
-
import { ConsentOMaticCMP, ConsentOMaticConfig } from './consentomatic/index';
|
|
1
|
+
import { rules as dynamicRules, createAutoCMP } from './index';
|
|
2
|
+
import { MessageSender, AutoCMP, RuleBundle, Config } from './types';
|
|
3
|
+
import { ConsentOMaticCMP, ConsentOMaticConfig } from './cmps/consentomatic';
|
|
8
4
|
import { AutoConsentCMPRule } from './rules';
|
|
9
|
-
import prehideElements from './hider';
|
|
10
5
|
import { enableLogs } from './config';
|
|
6
|
+
import { BackgroundMessage, InitMessage } from './messages';
|
|
7
|
+
import { prehide, undoPrehide } from './rule-executors';
|
|
8
|
+
import { evalState, resolveEval } from './eval-handler';
|
|
11
9
|
|
|
12
10
|
export * from './index';
|
|
13
|
-
export {
|
|
14
|
-
Tab,
|
|
15
|
-
handleContentMessage,
|
|
16
|
-
}
|
|
17
11
|
|
|
18
12
|
export default class AutoConsent {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
rules: AutoCMP[] = [];
|
|
14
|
+
config: Config;
|
|
15
|
+
foundCmp: AutoCMP = null;
|
|
16
|
+
protected sendContentMessage: MessageSender;
|
|
22
17
|
|
|
23
|
-
constructor(
|
|
18
|
+
constructor(sendContentMessage: MessageSender, config: Config = null, declarativeRules: RuleBundle = null) {
|
|
19
|
+
evalState.sendContentMessage = sendContentMessage;
|
|
24
20
|
this.sendContentMessage = sendContentMessage;
|
|
25
|
-
this.rules = [...
|
|
21
|
+
this.rules = [...dynamicRules];
|
|
22
|
+
|
|
23
|
+
enableLogs && console.log('autoconsent init', window.location.href);
|
|
24
|
+
if (config) {
|
|
25
|
+
this.initialize(config, declarativeRules);
|
|
26
|
+
} else {
|
|
27
|
+
const initMsg: InitMessage = {
|
|
28
|
+
type: "init",
|
|
29
|
+
url: window.location.href,
|
|
30
|
+
};
|
|
31
|
+
sendContentMessage(initMsg);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
initialize(config: Config, declarativeRules: RuleBundle) {
|
|
36
|
+
this.config = config;
|
|
37
|
+
if (!config.enabled) {
|
|
38
|
+
enableLogs && console.log("autoconsent is disabled");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.parseRules(declarativeRules);
|
|
43
|
+
if (config.disabledCmps?.length > 0) {
|
|
44
|
+
this.disableCMPs(config.disabledCmps);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (config.enablePrehide) {
|
|
48
|
+
if (document.documentElement) {
|
|
49
|
+
this.prehideElements(); // prehide as early as possible to prevent flickering
|
|
50
|
+
} else {
|
|
51
|
+
// we're injected really early
|
|
52
|
+
const delayedPrehide = () => {
|
|
53
|
+
window.removeEventListener('DOMContentLoaded', delayedPrehide);
|
|
54
|
+
this.prehideElements();
|
|
55
|
+
}
|
|
56
|
+
window.addEventListener('DOMContentLoaded', delayedPrehide);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// start detection
|
|
61
|
+
if (document.readyState === 'loading') {
|
|
62
|
+
const onReady = () => {
|
|
63
|
+
window.removeEventListener('DOMContentLoaded', onReady);
|
|
64
|
+
this.start();
|
|
65
|
+
}
|
|
66
|
+
window.addEventListener('DOMContentLoaded', onReady);
|
|
67
|
+
} else {
|
|
68
|
+
this.start();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
parseRules(declarativeRules: RuleBundle) {
|
|
73
|
+
Object.keys(declarativeRules.consentomatic).forEach((name) => {
|
|
74
|
+
this.addConsentomaticCMP(name, declarativeRules.consentomatic[name]);
|
|
75
|
+
});
|
|
76
|
+
declarativeRules.autoconsent.forEach((rule) => {
|
|
77
|
+
this.addCMP(rule);
|
|
78
|
+
});
|
|
79
|
+
enableLogs && console.log("added rules", this.rules);
|
|
26
80
|
}
|
|
27
81
|
|
|
28
82
|
addCMP(config: AutoConsentCMPRule) {
|
|
29
83
|
this.rules.push(createAutoCMP(config));
|
|
30
84
|
}
|
|
31
85
|
|
|
32
|
-
disableCMPs(cmpNames:
|
|
86
|
+
disableCMPs(cmpNames: string[]) {
|
|
33
87
|
this.rules = this.rules.filter((cmp) => !cmpNames.includes(cmp.name))
|
|
34
88
|
}
|
|
35
89
|
|
|
@@ -37,78 +91,233 @@ export default class AutoConsent {
|
|
|
37
91
|
this.rules.push(new ConsentOMaticCMP(`com_${name}`, config));
|
|
38
92
|
}
|
|
39
93
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.
|
|
44
|
-
|
|
94
|
+
// start the detection process, possibly with a delay
|
|
95
|
+
start() {
|
|
96
|
+
if (window.requestIdleCallback) {
|
|
97
|
+
window.requestIdleCallback(() => this._start(), { timeout: 500 });
|
|
98
|
+
} else {
|
|
99
|
+
this._start();
|
|
100
|
+
}
|
|
45
101
|
}
|
|
46
102
|
|
|
47
|
-
async
|
|
48
|
-
enableLogs && console.log(
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
enableLogs && console.log(
|
|
60
|
-
if (
|
|
61
|
-
|
|
103
|
+
async _start() {
|
|
104
|
+
enableLogs && console.log(`Detecting CMPs on ${window.location.href}`)
|
|
105
|
+
const cmp = await this.findCmp(this.config.detectRetries);
|
|
106
|
+
if (cmp) {
|
|
107
|
+
enableLogs && console.log("detected CMP:", cmp.name, window.location.href);
|
|
108
|
+
this.sendContentMessage({
|
|
109
|
+
type: 'cmpDetected',
|
|
110
|
+
url: location.href,
|
|
111
|
+
cmp: cmp.name,
|
|
112
|
+
}); // notify the browser
|
|
113
|
+
const isOpen = await this.waitForPopup(cmp);
|
|
114
|
+
if (!isOpen) {
|
|
115
|
+
enableLogs && console.log('no popup found');
|
|
116
|
+
if (this.config.enablePrehide) {
|
|
117
|
+
undoPrehide();
|
|
62
118
|
}
|
|
119
|
+
return false;
|
|
63
120
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
121
|
+
|
|
122
|
+
this.foundCmp = cmp;
|
|
123
|
+
this.sendContentMessage({
|
|
124
|
+
type: 'popupFound',
|
|
125
|
+
cmp: cmp.name,
|
|
126
|
+
url: location.href,
|
|
127
|
+
}); // notify the browser
|
|
128
|
+
|
|
129
|
+
if (this.config.autoAction === 'optOut') {
|
|
130
|
+
return await this.doOptOut();
|
|
131
|
+
} else if (this.config.autoAction === 'optIn') {
|
|
132
|
+
return await this.doOptIn();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
enableLogs && console.log("waiting for opt-out signal...", location.href);
|
|
136
|
+
return true;
|
|
137
|
+
} else {
|
|
138
|
+
enableLogs && console.log("no CMP found", location.href);
|
|
139
|
+
if (this.config.enablePrehide) {
|
|
140
|
+
undoPrehide();
|
|
69
141
|
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async findCmp(retries: number): Promise<AutoCMP> {
|
|
147
|
+
let foundCmp: AutoCMP = null;
|
|
148
|
+
const allFoundCmps: AutoCMP[] = [];
|
|
149
|
+
|
|
150
|
+
for (const cmp of this.rules) {
|
|
151
|
+
try {
|
|
152
|
+
if (!cmp.checkRunContext()) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const result = await cmp.detectCmp();
|
|
156
|
+
if (result) {
|
|
157
|
+
enableLogs && console.log(`Found CMP: ${cmp.name}`);
|
|
158
|
+
allFoundCmps.push(cmp);
|
|
159
|
+
if (!foundCmp) {
|
|
160
|
+
foundCmp = cmp;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} catch (e) {
|
|
164
|
+
enableLogs && console.warn(`error detecting ${cmp.name}`, e);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (allFoundCmps.length > 1) {
|
|
169
|
+
const errorDetails = {
|
|
170
|
+
msg: `Found multiple CMPs, check the detection rules.`,
|
|
171
|
+
cmps: allFoundCmps.map((cmp) => cmp.name),
|
|
172
|
+
};
|
|
173
|
+
enableLogs && console.warn(errorDetails.msg, errorDetails.cmps);
|
|
174
|
+
this.sendContentMessage({
|
|
175
|
+
type: 'autoconsentError',
|
|
176
|
+
details: errorDetails,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (!foundCmp && retries > 0) {
|
|
181
|
+
return new Promise((resolve) => {
|
|
182
|
+
setTimeout(async () => {
|
|
183
|
+
const result = this.findCmp(retries - 1);
|
|
184
|
+
resolve(result);
|
|
185
|
+
}, 500);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return foundCmp;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async doOptOut(): Promise<boolean> {
|
|
193
|
+
let optOutResult;
|
|
194
|
+
if (!this.foundCmp) {
|
|
195
|
+
enableLogs && console.log('no CMP to opt out');
|
|
196
|
+
optOutResult = false;
|
|
197
|
+
} else {
|
|
198
|
+
enableLogs && console.log(`CMP ${this.foundCmp.name}: opt out on ${window.location.href}`);
|
|
199
|
+
optOutResult = await this.foundCmp.optOut();
|
|
200
|
+
enableLogs && console.log(`${this.foundCmp.name}: opt out result ${optOutResult}`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (this.config.enablePrehide) {
|
|
204
|
+
undoPrehide();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.sendContentMessage({
|
|
208
|
+
type: 'optOutResult',
|
|
209
|
+
cmp: this.foundCmp ? this.foundCmp.name : 'none',
|
|
210
|
+
result: optOutResult,
|
|
211
|
+
scheduleSelfTest: this.foundCmp && this.foundCmp.hasSelfTest,
|
|
212
|
+
url: location.href,
|
|
70
213
|
});
|
|
71
214
|
|
|
72
|
-
|
|
215
|
+
if (optOutResult && !this.foundCmp.isIntermediate) {
|
|
216
|
+
this.sendContentMessage({
|
|
217
|
+
type: 'autoconsentDone',
|
|
218
|
+
cmp: this.foundCmp.name,
|
|
219
|
+
url: location.href,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return optOutResult;
|
|
73
224
|
}
|
|
74
225
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.
|
|
226
|
+
async doOptIn(): Promise<boolean> {
|
|
227
|
+
let optInResult;
|
|
228
|
+
if (!this.foundCmp) {
|
|
229
|
+
enableLogs && console.log('no CMP to opt in');
|
|
230
|
+
optInResult = false;
|
|
231
|
+
} else {
|
|
232
|
+
enableLogs && console.log(`CMP ${this.foundCmp.name}: opt in on ${window.location.href}`);
|
|
233
|
+
optInResult = await this.foundCmp.optIn();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (this.config.enablePrehide) {
|
|
237
|
+
undoPrehide();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.sendContentMessage({
|
|
241
|
+
type: 'optInResult',
|
|
242
|
+
cmp: this.foundCmp ? this.foundCmp.name : 'none',
|
|
243
|
+
result: optInResult,
|
|
244
|
+
scheduleSelfTest: this.foundCmp && this.foundCmp.hasSelfTest,
|
|
245
|
+
url: location.href,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
if (optInResult && !this.foundCmp.isIntermediate) {
|
|
249
|
+
this.sendContentMessage({
|
|
250
|
+
type: 'autoconsentDone',
|
|
251
|
+
cmp: this.foundCmp.name,
|
|
252
|
+
url: location.href,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return optInResult;
|
|
78
257
|
}
|
|
79
258
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
259
|
+
async doSelfTest(): Promise<boolean> {
|
|
260
|
+
let selfTestResult;
|
|
261
|
+
if (!this.foundCmp) {
|
|
262
|
+
enableLogs && console.log('no CMP to self test');
|
|
263
|
+
selfTestResult = false;
|
|
264
|
+
} else {
|
|
265
|
+
enableLogs && console.log(`CMP ${this.foundCmp.name}: self-test on ${window.location.href}`);
|
|
266
|
+
selfTestResult = await this.foundCmp.test();
|
|
84
267
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
} catch (e) {
|
|
103
|
-
console.error(e);
|
|
268
|
+
|
|
269
|
+
this.sendContentMessage({
|
|
270
|
+
type: 'selfTestResult',
|
|
271
|
+
cmp: this.foundCmp ? this.foundCmp.name : 'none',
|
|
272
|
+
result: selfTestResult,
|
|
273
|
+
url: location.href,
|
|
274
|
+
});
|
|
275
|
+
return selfTestResult;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async waitForPopup(cmp: AutoCMP, retries = 5, interval = 500): Promise<boolean> {
|
|
279
|
+
enableLogs && console.log('checking if popup is open...', cmp.name);
|
|
280
|
+
const isOpen = await cmp.detectPopup();
|
|
281
|
+
if (!isOpen && retries > 0) {
|
|
282
|
+
return new Promise((resolve) => setTimeout(() => resolve(this.waitForPopup(cmp, retries - 1, interval)), interval));
|
|
104
283
|
}
|
|
284
|
+
enableLogs && console.log(`popup is ${isOpen ? 'open' : 'not open'}`);
|
|
285
|
+
return isOpen;
|
|
105
286
|
}
|
|
106
287
|
|
|
107
|
-
|
|
108
|
-
|
|
288
|
+
prehideElements(): boolean {
|
|
289
|
+
// hide rules not specific to a single CMP rule
|
|
290
|
+
const globalHidden = [
|
|
291
|
+
"#didomi-popup,.didomi-popup-container,.didomi-popup-notice,.didomi-consent-popup-preferences,#didomi-notice,.didomi-popup-backdrop,.didomi-screen-medium",
|
|
292
|
+
]
|
|
293
|
+
|
|
294
|
+
const selectors = this.rules.reduce((selectorList, rule) => {
|
|
295
|
+
if (rule.prehideSelectors) {
|
|
296
|
+
return [...selectorList, ...rule.prehideSelectors];
|
|
297
|
+
}
|
|
298
|
+
return selectorList;
|
|
299
|
+
}, globalHidden);
|
|
300
|
+
|
|
301
|
+
return prehide(selectors);
|
|
109
302
|
}
|
|
110
303
|
|
|
111
|
-
async
|
|
112
|
-
|
|
304
|
+
async receiveMessageCallback(message: BackgroundMessage) {
|
|
305
|
+
if (enableLogs && message.type !== 'evalResp' /* evals are noisy */) {
|
|
306
|
+
console.log('received from background', message, window.location.href);
|
|
307
|
+
}
|
|
308
|
+
switch (message.type) {
|
|
309
|
+
case 'initResp':
|
|
310
|
+
this.initialize(message.config, message.rules);
|
|
311
|
+
break;
|
|
312
|
+
case 'optOut':
|
|
313
|
+
await this.doOptOut();
|
|
314
|
+
break;
|
|
315
|
+
case 'selfTest':
|
|
316
|
+
await this.doSelfTest();
|
|
317
|
+
break;
|
|
318
|
+
case 'evalResp':
|
|
319
|
+
resolveEval(message.id, message.result);
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
113
322
|
}
|
|
114
323
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duckduckgo/autoconsent",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/autoconsent.cjs.js",
|
|
6
6
|
"module": "dist/autoconsent.esm.js",
|
|
@@ -8,34 +8,37 @@
|
|
|
8
8
|
"lib": "lib"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"clean": "rm -r dist lib/**/*.js lib/*.js",
|
|
12
|
-
"build": "tsc",
|
|
11
|
+
"clean": "rm -r dist lib/**/*.js lib/*.js addon/*.js",
|
|
13
12
|
"bundle": "rollup -c",
|
|
14
13
|
"watch": "rollup -c -w",
|
|
15
|
-
"start": "web-ext run -s ./addon --firefox firefoxdeveloperedition",
|
|
16
14
|
"test": "playwright test",
|
|
17
15
|
"test:webkit": "playwright test --project webkit",
|
|
18
16
|
"test:firefox": "playwright test --project firefox",
|
|
17
|
+
"test:chrome": "playwright test --project chrome",
|
|
19
18
|
"fetch-fanboy-list": "wget https://www.fanboy.co.nz/fanboy-cookiemonster.txt",
|
|
20
19
|
"fetch-site-list": "curl https://s3.amazonaws.com/cdn.cliqz.com/re-consent/supported_sites.txt > sites.txt",
|
|
21
20
|
"build-rules": "node rules/build.js && cp rules/rules.json addon/",
|
|
22
21
|
"version": "node update_version.js && git add addon/manifest.json",
|
|
23
22
|
"vendor-copy": "mkdir -p addon/vendor && cp node_modules/mocha/mocha.* addon/vendor/ && cp node_modules/chai/chai.js addon/vendor/",
|
|
24
|
-
"prepublish": "npm run build-rules && npm run
|
|
23
|
+
"prepublish": "npm run build-rules && npm run bundle"
|
|
25
24
|
},
|
|
26
25
|
"author": "Sam Macbeth",
|
|
27
26
|
"license": "MPL-2.0",
|
|
28
|
-
"dependencies": {},
|
|
29
27
|
"devDependencies": {
|
|
30
28
|
"@playwright/test": "^1.17.1",
|
|
31
|
-
"@rollup/plugin-
|
|
32
|
-
"@
|
|
33
|
-
"@types/
|
|
29
|
+
"@rollup/plugin-json": "^4.1.0",
|
|
30
|
+
"@rollup/plugin-typescript": "^8.3.2",
|
|
31
|
+
"@types/chai": "^4.3.1",
|
|
32
|
+
"@types/chrome": "^0.0.188",
|
|
33
|
+
"@types/mocha": "^9.1.1",
|
|
34
|
+
"@typescript-eslint/eslint-plugin": "^5.25.0",
|
|
35
|
+
"@typescript-eslint/parser": "^5.25.0",
|
|
34
36
|
"chai": "^4.2.0",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
37
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
38
|
+
"mocha": "^10.0.0",
|
|
39
|
+
"rollup": "^2.73.0",
|
|
40
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
41
|
+
"tslib": "^2.4.0",
|
|
42
|
+
"typescript": "^4.6.4"
|
|
40
43
|
}
|
|
41
44
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import AutoConsent from "../lib/web";
|
|
2
|
+
import { BackgroundMessage } from "../lib/messages";
|
|
3
|
+
import { MessageSender, RuleBundle } from "../lib/types";
|
|
4
|
+
import * as rules from '../rules/rules.json';
|
|
5
|
+
|
|
6
|
+
declare global {
|
|
7
|
+
interface Window {
|
|
8
|
+
autoconsentSendMessage: MessageSender;
|
|
9
|
+
autoconsentReceiveMessage: (message: BackgroundMessage) => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!window.autoconsentReceiveMessage) {
|
|
14
|
+
const consent = new AutoConsent(window.autoconsentSendMessage, {
|
|
15
|
+
enabled: true,
|
|
16
|
+
autoAction: 'optOut',
|
|
17
|
+
disabledCmps: [],
|
|
18
|
+
enablePrehide: true,
|
|
19
|
+
detectRetries: 20,
|
|
20
|
+
}, <RuleBundle>rules);
|
|
21
|
+
|
|
22
|
+
window.autoconsentReceiveMessage = (message: BackgroundMessage) => {
|
|
23
|
+
return Promise.resolve(consent.receiveMessageCallback(message));
|
|
24
|
+
};
|
|
25
|
+
} else {
|
|
26
|
+
console.warn('autoconsent already initialized', window.autoconsentReceiveMessage);
|
|
27
|
+
}
|