@duckduckgo/autoconsent 1.0.2
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 +12 -0
- package/Dockerfile +9 -0
- package/Jenkinsfile +50 -0
- package/LICENSE +373 -0
- package/cosmetics/rules.json +110 -0
- package/dist/autoconsent.cjs.js +1316 -0
- package/dist/autoconsent.esm.js +1308 -0
- package/dist/autoconsent.puppet.js +980 -0
- package/lib/cmps/all.js +17 -0
- package/lib/cmps/all.ts +21 -0
- package/lib/cmps/base.js +170 -0
- package/lib/cmps/base.ts +199 -0
- package/lib/cmps/consentmanager.js +31 -0
- package/lib/cmps/consentmanager.ts +39 -0
- package/lib/cmps/cookiebot.js +73 -0
- package/lib/cmps/cookiebot.ts +81 -0
- package/lib/cmps/evidon.js +26 -0
- package/lib/cmps/evidon.ts +32 -0
- package/lib/cmps/sourcepoint.js +82 -0
- package/lib/cmps/sourcepoint.ts +95 -0
- package/lib/cmps/trustarc.js +106 -0
- package/lib/cmps/trustarc.ts +147 -0
- package/lib/consentomatic/index.js +52 -0
- package/lib/consentomatic/index.ts +86 -0
- package/lib/detector.js +29 -0
- package/lib/detector.ts +30 -0
- package/lib/hider.js +13 -0
- package/lib/hider.ts +16 -0
- package/lib/index.js +4 -0
- package/lib/index.ts +6 -0
- package/lib/messages.d.ts +58 -0
- package/lib/node.js +30 -0
- package/lib/node.ts +38 -0
- package/lib/puppet/tab.js +114 -0
- package/lib/puppet/tab.ts +136 -0
- package/lib/rules.d.ts +80 -0
- package/lib/tabwrapper.js +61 -0
- package/lib/tabwrapper.ts +68 -0
- package/lib/types.d.ts +61 -0
- package/lib/web/consentomatic/index.js +188 -0
- package/lib/web/consentomatic/index.ts +249 -0
- package/lib/web/consentomatic/tools.js +177 -0
- package/lib/web/consentomatic/tools.ts +198 -0
- package/lib/web/content.js +91 -0
- package/lib/web/content.ts +83 -0
- package/lib/web/tab.js +106 -0
- package/lib/web/tab.ts +171 -0
- package/lib/web.js +90 -0
- package/lib/web.ts +109 -0
- package/package.json +41 -0
- package/playwright.config.ts +31 -0
- package/readme.md +151 -0
- package/rollup.config.js +54 -0
- package/rules/autoconsent/asus.json +7 -0
- package/rules/autoconsent/cc-banner.json +9 -0
- package/rules/autoconsent/cookie-law-info.json +14 -0
- package/rules/autoconsent/cookie-notice.json +9 -0
- package/rules/autoconsent/cookieconsent.json +9 -0
- package/rules/autoconsent/drupal.json +7 -0
- package/rules/autoconsent/eu-cookie-compliance.json +14 -0
- package/rules/autoconsent/fundingchoices.json +12 -0
- package/rules/autoconsent/hubspot.json +7 -0
- package/rules/autoconsent/klaro.json +10 -0
- package/rules/autoconsent/notice-cookie.json +9 -0
- package/rules/autoconsent/onetrust.json +24 -0
- package/rules/autoconsent/osano.json +11 -0
- package/rules/autoconsent/quantcast.json +14 -0
- package/rules/autoconsent/tealium.json +19 -0
- package/rules/autoconsent/testcmp.json +12 -0
- package/rules/build.js +63 -0
- package/rules/rules.json +3030 -0
- package/tests/asus.spec.ts +5 -0
- package/tests/ccbanner.spec.ts +11 -0
- package/tests/consentmanager.spec.ts +10 -0
- package/tests/cookiebot.spec.ts +9 -0
- package/tests/cookieconsent.spec.ts +8 -0
- package/tests/cookielawinfo.spec.ts +9 -0
- package/tests/cookienotice.spec.ts +6 -0
- package/tests/didomi.spec.ts +9 -0
- package/tests/eu-cookie-compliance-banner.spec.ts +7 -0
- package/tests/evidon.spec.ts +6 -0
- package/tests/fundingchoices.spec.ts +10 -0
- package/tests/hubspot.spec.ts +6 -0
- package/tests/klaro.spec.ts +5 -0
- package/tests/notice-cookie.spec.ts +7 -0
- package/tests/oil.spec.ts +10 -0
- package/tests/onetrust.spec.ts +15 -0
- package/tests/optanon.spec.ts +10 -0
- package/tests/osano.spec.ts +5 -0
- package/tests/quantcast.spec.ts +16 -0
- package/tests/runner.ts +61 -0
- package/tests/sourcepoint.spec.ts +17 -0
- package/tests/springer.spec.ts +11 -0
- package/tests/tealium.spec.ts +6 -0
- package/tests/testcmp.spec.ts +5 -0
- package/tests/trustarc.spec.ts +13 -0
- package/tests/wordpressgdpr.spec.ts +9 -0
- package/tsconfig.json +14 -0
- package/update_version.js +8 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import AutoConsentBase, { success, waitFor } from "./base";
|
|
2
|
+
export default class SourcePoint extends AutoConsentBase {
|
|
3
|
+
constructor() {
|
|
4
|
+
super("Sourcepoint");
|
|
5
|
+
this.ccpaMode = false;
|
|
6
|
+
this.prehideSelectors = ["div[id^='sp_message_container_'],.message-overlay"];
|
|
7
|
+
}
|
|
8
|
+
detectFrame(_, frame) {
|
|
9
|
+
try {
|
|
10
|
+
const url = new URL(frame.url);
|
|
11
|
+
if (url.searchParams.has('message_id') && url.hostname === 'ccpa-notice.sp-prod.net') {
|
|
12
|
+
this.ccpaMode = true;
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return (url.pathname === '/index.html' || url.pathname === '/privacy-manager/index.html')
|
|
16
|
+
&& url.searchParams.has('message_id') && url.searchParams.has('requestUUID');
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async detectCmp(tab) {
|
|
23
|
+
return await tab.elementExists("div[id^='sp_message_container_']") || !!tab.frame;
|
|
24
|
+
}
|
|
25
|
+
async detectPopup(tab) {
|
|
26
|
+
return await tab.elementsAreVisible("div[id^='sp_message_container_']");
|
|
27
|
+
}
|
|
28
|
+
async optIn(tab) {
|
|
29
|
+
return tab.clickElement(".sp_choice_type_11", tab.frame.id);
|
|
30
|
+
}
|
|
31
|
+
isManagerOpen(tab) {
|
|
32
|
+
return tab.frame && new URL(tab.frame.url).pathname === "/privacy-manager/index.html";
|
|
33
|
+
}
|
|
34
|
+
async optOut(tab) {
|
|
35
|
+
try {
|
|
36
|
+
tab.hideElements(["div[id^='sp_message_container_']"]);
|
|
37
|
+
if (!this.isManagerOpen(tab)) {
|
|
38
|
+
if (!await waitFor(() => !!tab.frame, 30, 100)) {
|
|
39
|
+
throw "Frame never opened";
|
|
40
|
+
}
|
|
41
|
+
if (!await tab.elementExists("button.sp_choice_type_12", tab.frame.id)) {
|
|
42
|
+
// do not sell button
|
|
43
|
+
return tab.clickElement('button.sp_choice_type_13', tab.frame.id);
|
|
44
|
+
}
|
|
45
|
+
await success(tab.clickElement("button.sp_choice_type_12", tab.frame.id));
|
|
46
|
+
await waitFor(() => new URL(tab.frame.url).pathname === "/privacy-manager/index.html", 200, 100);
|
|
47
|
+
}
|
|
48
|
+
await tab.waitForElement('.type-modal', 20000, tab.frame.id);
|
|
49
|
+
// reject all button is offered by some sites
|
|
50
|
+
try {
|
|
51
|
+
const path = await Promise.race([
|
|
52
|
+
tab.waitForElement('.sp_choice_type_REJECT_ALL', 2000, tab.frame.id).then(r => 0),
|
|
53
|
+
tab.waitForElement('.reject-toggle', 2000, tab.frame.id).then(() => 1),
|
|
54
|
+
tab.waitForElement('.pm-features', 2000, tab.frame.id).then(r => 2),
|
|
55
|
+
]);
|
|
56
|
+
if (path === 0) {
|
|
57
|
+
await tab.wait(1000);
|
|
58
|
+
return await success(tab.clickElement('.sp_choice_type_REJECT_ALL', tab.frame.id));
|
|
59
|
+
}
|
|
60
|
+
else if (path === 1) {
|
|
61
|
+
await tab.clickElement('.reject-toggle', tab.frame.id);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
await tab.waitForElement('.pm-features', 10000, tab.frame.id);
|
|
65
|
+
await tab.clickElements('.checked > span', tab.frame.id);
|
|
66
|
+
if (await tab.elementExists('.chevron', tab.frame.id)) {
|
|
67
|
+
await tab.clickElement('.chevron', tab.frame.id);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (e) { }
|
|
72
|
+
return await tab.clickElement('.sp_choice_type_SAVE_AND_EXIT', tab.frame.id);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
tab.undoHideElements();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async test(tab) {
|
|
79
|
+
await tab.eval("__tcfapi('getTCData', 2, r => window.__rcsResult = r)");
|
|
80
|
+
return tab.eval("Object.values(window.__rcsResult.purpose.consents).every(c => !c)");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import AutoConsentBase, { success, waitFor } from "./base";
|
|
2
|
+
import { TabActor } from "../types";
|
|
3
|
+
|
|
4
|
+
export default class SourcePoint extends AutoConsentBase {
|
|
5
|
+
|
|
6
|
+
ccpaMode = false;
|
|
7
|
+
prehideSelectors = ["div[id^='sp_message_container_'],.message-overlay"]
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
super("Sourcepoint");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
detectFrame(_: TabActor, frame: { url: string }) {
|
|
14
|
+
try {
|
|
15
|
+
const url = new URL(frame.url);
|
|
16
|
+
if (url.searchParams.has('message_id') && url.hostname === 'ccpa-notice.sp-prod.net') {
|
|
17
|
+
this.ccpaMode = true;
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return (url.pathname === '/index.html' || url.pathname === '/privacy-manager/index.html')
|
|
21
|
+
&& url.searchParams.has('message_id') && url.searchParams.has('requestUUID');
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async detectCmp(tab: TabActor) {
|
|
28
|
+
return await tab.elementExists("div[id^='sp_message_container_']") || !!tab.frame
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async detectPopup(tab: TabActor) {
|
|
32
|
+
return await tab.elementsAreVisible("div[id^='sp_message_container_']");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async optIn(tab: TabActor) {
|
|
36
|
+
return tab.clickElement(".sp_choice_type_11", tab.frame.id);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
isManagerOpen(tab: TabActor) {
|
|
40
|
+
return tab.frame && new URL(tab.frame.url).pathname === "/privacy-manager/index.html";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async optOut(tab: TabActor) {
|
|
44
|
+
try {
|
|
45
|
+
tab.hideElements(["div[id^='sp_message_container_']"])
|
|
46
|
+
if (!this.isManagerOpen(tab)) {
|
|
47
|
+
if (!await waitFor(() => !!tab.frame, 30, 100)) {
|
|
48
|
+
throw "Frame never opened";
|
|
49
|
+
}
|
|
50
|
+
if (!await tab.elementExists("button.sp_choice_type_12", tab.frame.id)) {
|
|
51
|
+
// do not sell button
|
|
52
|
+
return tab.clickElement('button.sp_choice_type_13', tab.frame.id);
|
|
53
|
+
}
|
|
54
|
+
await success(tab.clickElement("button.sp_choice_type_12", tab.frame.id));
|
|
55
|
+
await waitFor(
|
|
56
|
+
() =>
|
|
57
|
+
new URL(tab.frame.url).pathname === "/privacy-manager/index.html",
|
|
58
|
+
200,
|
|
59
|
+
100
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
await tab.waitForElement('.type-modal', 20000, tab.frame.id);
|
|
63
|
+
// reject all button is offered by some sites
|
|
64
|
+
try {
|
|
65
|
+
const path = await Promise.race([
|
|
66
|
+
tab.waitForElement('.sp_choice_type_REJECT_ALL', 2000, tab.frame.id).then(r => 0),
|
|
67
|
+
tab.waitForElement('.reject-toggle', 2000, tab.frame.id).then(() => 1),
|
|
68
|
+
tab.waitForElement('.pm-features', 2000, tab.frame.id).then(r => 2),
|
|
69
|
+
]);
|
|
70
|
+
if (path === 0) {
|
|
71
|
+
await tab.wait(1000);
|
|
72
|
+
return await success(tab.clickElement('.sp_choice_type_REJECT_ALL', tab.frame.id))
|
|
73
|
+
} else if (path === 1) {
|
|
74
|
+
await tab.clickElement('.reject-toggle', tab.frame.id)
|
|
75
|
+
} else {
|
|
76
|
+
await tab.waitForElement('.pm-features', 10000, tab.frame.id);
|
|
77
|
+
await tab.clickElements('.checked > span', tab.frame.id);
|
|
78
|
+
if (await tab.elementExists('.chevron', tab.frame.id)) {
|
|
79
|
+
await tab.clickElement('.chevron', tab.frame.id)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch(e) {}
|
|
83
|
+
return await tab.clickElement('.sp_choice_type_SAVE_AND_EXIT', tab.frame.id);
|
|
84
|
+
} finally {
|
|
85
|
+
tab.undoHideElements();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async test(tab: TabActor) {
|
|
90
|
+
await tab.eval("__tcfapi('getTCData', 2, r => window.__rcsResult = r)");
|
|
91
|
+
return tab.eval(
|
|
92
|
+
"Object.values(window.__rcsResult.purpose.consents).every(c => !c)"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import AutoConsentBase, { waitFor } from "./base";
|
|
2
|
+
export default class TrustArc extends AutoConsentBase {
|
|
3
|
+
constructor() {
|
|
4
|
+
super("TrustArc");
|
|
5
|
+
this.prehideSelectors = [
|
|
6
|
+
".trustarc-banner-container",
|
|
7
|
+
".truste_popframe,.truste_overlay,.truste_box_overlay,#truste-consent-track",
|
|
8
|
+
];
|
|
9
|
+
}
|
|
10
|
+
detectFrame(_, frame) {
|
|
11
|
+
return frame.url.startsWith("https://consent-pref.trustarc.com/?");
|
|
12
|
+
}
|
|
13
|
+
async detectCmp(tab) {
|
|
14
|
+
if (tab.frame &&
|
|
15
|
+
tab.frame.url.startsWith("https://consent-pref.trustarc.com/?")) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return tab.elementExists("#truste-show-consent");
|
|
19
|
+
}
|
|
20
|
+
async detectPopup(tab) {
|
|
21
|
+
return ((await tab.elementsAreVisible("#truste-consent-content,#trustarc-banner-overlay")) ||
|
|
22
|
+
(tab.frame &&
|
|
23
|
+
(await tab.waitForElement("#defaultpreferencemanager", 5000, tab.frame.id))));
|
|
24
|
+
}
|
|
25
|
+
async openFrame(tab) {
|
|
26
|
+
if (await tab.elementExists("#truste-show-consent")) {
|
|
27
|
+
await tab.clickElement("#truste-show-consent");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async navigateToSettings(tab, frameId) {
|
|
31
|
+
// wait for it to load
|
|
32
|
+
await waitFor(async () => {
|
|
33
|
+
return ((await tab.elementExists(".shp", frameId)) ||
|
|
34
|
+
(await tab.elementsAreVisible(".advance", "any", frameId)) ||
|
|
35
|
+
tab.elementExists(".switch span:first-child", frameId));
|
|
36
|
+
}, 10, 500);
|
|
37
|
+
// splash screen -> hit more information
|
|
38
|
+
if (await tab.elementExists(".shp", frameId)) {
|
|
39
|
+
await tab.clickElement(".shp", frameId);
|
|
40
|
+
}
|
|
41
|
+
await tab.waitForElement(".prefPanel", 5000, frameId);
|
|
42
|
+
// go to advanced settings if not yet shown
|
|
43
|
+
if (await tab.elementsAreVisible(".advance", "any", frameId)) {
|
|
44
|
+
await tab.clickElement(".advance", frameId);
|
|
45
|
+
}
|
|
46
|
+
// takes a while to load the opt-in/opt-out buttons
|
|
47
|
+
return await waitFor(() => tab.elementsAreVisible(".switch span:first-child", "any", frameId), 5, 1000);
|
|
48
|
+
}
|
|
49
|
+
async optOut(tab) {
|
|
50
|
+
// await tab.hideElements(['.truste_overlay', '.truste_box_overlay', '.trustarc-banner', '.truste-banner']);
|
|
51
|
+
if (await tab.elementExists("#truste-consent-required")) {
|
|
52
|
+
return tab.clickElement("#truste-consent-required");
|
|
53
|
+
}
|
|
54
|
+
if (!tab.frame) {
|
|
55
|
+
await tab.clickElement("#truste-show-consent");
|
|
56
|
+
await waitFor(async () => !!tab.frame &&
|
|
57
|
+
(await tab.elementsAreVisible(".mainContent", "any", tab.frame.id)), 50, 100);
|
|
58
|
+
}
|
|
59
|
+
const frameId = tab.frame.id;
|
|
60
|
+
await waitFor(() => tab.eval("document.readyState === 'complete'", frameId), 20, 100);
|
|
61
|
+
tab.hideElements([".truste_popframe", ".truste_overlay", ".truste_box_overlay", "#truste-consent-track"]);
|
|
62
|
+
if (await tab.elementExists('.rejectAll', frameId)) {
|
|
63
|
+
return tab.clickElement('.rejectAll', frameId);
|
|
64
|
+
}
|
|
65
|
+
if (await tab.waitForElement('#catDetails0', 1000, frameId)) {
|
|
66
|
+
await tab.clickElement("#catDetails0", frameId);
|
|
67
|
+
return tab.clickElement(".submit", frameId);
|
|
68
|
+
}
|
|
69
|
+
if (await tab.elementExists(".required", frameId)) {
|
|
70
|
+
await tab.clickElement(".required", frameId);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
await this.navigateToSettings(tab, frameId);
|
|
74
|
+
await tab.clickElements(".switch span:nth-child(1):not(.active)", frameId);
|
|
75
|
+
await tab.clickElement(".submit", frameId);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
await tab.waitForThenClick("#gwt-debug-close_id", 20000, tab.frame.id);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
// ignore frame disappearing
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
async optIn(tab) {
|
|
86
|
+
if (!tab.frame) {
|
|
87
|
+
await this.openFrame(tab);
|
|
88
|
+
await waitFor(() => !!tab.frame, 10, 200);
|
|
89
|
+
}
|
|
90
|
+
const frameId = tab.frame.id;
|
|
91
|
+
await this.navigateToSettings(tab, frameId);
|
|
92
|
+
await tab.clickElements(".switch span:nth-child(2)", frameId);
|
|
93
|
+
await tab.clickElement(".submit", frameId);
|
|
94
|
+
await waitFor(() => tab.elementExists("#gwt-debug-close_id", frameId), 300, 1000);
|
|
95
|
+
await tab.clickElement("#gwt-debug-close_id", frameId);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
async openCmp(tab) {
|
|
99
|
+
await tab.eval("truste.eu.clickListener()");
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
async test() {
|
|
103
|
+
// TODO: find out how to test TrustArc
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import AutoConsentBase, { waitFor } from "./base";
|
|
2
|
+
import { TabActor } from "../types";
|
|
3
|
+
|
|
4
|
+
export default class TrustArc extends AutoConsentBase {
|
|
5
|
+
|
|
6
|
+
prehideSelectors = [
|
|
7
|
+
".trustarc-banner-container",
|
|
8
|
+
".truste_popframe,.truste_overlay,.truste_box_overlay,#truste-consent-track",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
super("TrustArc");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
detectFrame(_: TabActor, frame: { url: string }) {
|
|
16
|
+
return frame.url.startsWith("https://consent-pref.trustarc.com/?");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async detectCmp(tab: TabActor) {
|
|
20
|
+
if (
|
|
21
|
+
tab.frame &&
|
|
22
|
+
tab.frame.url.startsWith("https://consent-pref.trustarc.com/?")
|
|
23
|
+
) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return tab.elementExists("#truste-show-consent");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async detectPopup(tab: TabActor) {
|
|
30
|
+
return (
|
|
31
|
+
(await tab.elementsAreVisible("#truste-consent-content,#trustarc-banner-overlay")) ||
|
|
32
|
+
(tab.frame &&
|
|
33
|
+
(await tab.waitForElement(
|
|
34
|
+
"#defaultpreferencemanager",
|
|
35
|
+
5000,
|
|
36
|
+
tab.frame.id
|
|
37
|
+
)))
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async openFrame(tab: TabActor) {
|
|
42
|
+
if (await tab.elementExists("#truste-show-consent")) {
|
|
43
|
+
await tab.clickElement("#truste-show-consent");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async navigateToSettings(tab: TabActor, frameId: number) {
|
|
48
|
+
// wait for it to load
|
|
49
|
+
await waitFor(
|
|
50
|
+
async () => {
|
|
51
|
+
return (
|
|
52
|
+
(await tab.elementExists(".shp", frameId)) ||
|
|
53
|
+
(await tab.elementsAreVisible(".advance", "any", frameId)) ||
|
|
54
|
+
tab.elementExists(".switch span:first-child", frameId)
|
|
55
|
+
);
|
|
56
|
+
},
|
|
57
|
+
10,
|
|
58
|
+
500
|
|
59
|
+
);
|
|
60
|
+
// splash screen -> hit more information
|
|
61
|
+
if (await tab.elementExists(".shp", frameId)) {
|
|
62
|
+
await tab.clickElement(".shp", frameId);
|
|
63
|
+
}
|
|
64
|
+
await tab.waitForElement(".prefPanel", 5000, frameId);
|
|
65
|
+
// go to advanced settings if not yet shown
|
|
66
|
+
if (await tab.elementsAreVisible(".advance", "any", frameId)) {
|
|
67
|
+
await tab.clickElement(".advance", frameId);
|
|
68
|
+
}
|
|
69
|
+
// takes a while to load the opt-in/opt-out buttons
|
|
70
|
+
return await waitFor(
|
|
71
|
+
() => tab.elementsAreVisible(".switch span:first-child", "any", frameId),
|
|
72
|
+
5,
|
|
73
|
+
1000
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async optOut(tab: TabActor) {
|
|
78
|
+
// await tab.hideElements(['.truste_overlay', '.truste_box_overlay', '.trustarc-banner', '.truste-banner']);
|
|
79
|
+
if (await tab.elementExists("#truste-consent-required")) {
|
|
80
|
+
return tab.clickElement("#truste-consent-required");
|
|
81
|
+
}
|
|
82
|
+
if (!tab.frame) {
|
|
83
|
+
await tab.clickElement("#truste-show-consent");
|
|
84
|
+
await waitFor(
|
|
85
|
+
async () =>
|
|
86
|
+
!!tab.frame &&
|
|
87
|
+
(await tab.elementsAreVisible(".mainContent", "any", tab.frame.id)),
|
|
88
|
+
50,
|
|
89
|
+
100
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const frameId = tab.frame!.id;
|
|
93
|
+
await waitFor(() => tab.eval("document.readyState === 'complete'", frameId), 20, 100);
|
|
94
|
+
tab.hideElements([".truste_popframe", ".truste_overlay", ".truste_box_overlay", "#truste-consent-track"]);
|
|
95
|
+
if (await tab.elementExists('.rejectAll', frameId)) {
|
|
96
|
+
return tab.clickElement('.rejectAll', frameId);
|
|
97
|
+
}
|
|
98
|
+
if (await tab.waitForElement('#catDetails0', 1000, frameId)) {
|
|
99
|
+
await tab.clickElement("#catDetails0", frameId);
|
|
100
|
+
return tab.clickElement(".submit", frameId);
|
|
101
|
+
}
|
|
102
|
+
if (await tab.elementExists(".required", frameId)) {
|
|
103
|
+
await tab.clickElement(".required", frameId);
|
|
104
|
+
} else {
|
|
105
|
+
await this.navigateToSettings(tab, frameId);
|
|
106
|
+
await tab.clickElements(
|
|
107
|
+
".switch span:nth-child(1):not(.active)",
|
|
108
|
+
frameId
|
|
109
|
+
);
|
|
110
|
+
await tab.clickElement(".submit", frameId);
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
await tab.waitForThenClick("#gwt-debug-close_id", 20000, tab.frame.id);
|
|
114
|
+
} catch (e) {
|
|
115
|
+
// ignore frame disappearing
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async optIn(tab: TabActor) {
|
|
121
|
+
if (!tab.frame) {
|
|
122
|
+
await this.openFrame(tab);
|
|
123
|
+
await waitFor(() => !!tab.frame, 10, 200);
|
|
124
|
+
}
|
|
125
|
+
const frameId = tab.frame!.id;
|
|
126
|
+
await this.navigateToSettings(tab, frameId);
|
|
127
|
+
await tab.clickElements(".switch span:nth-child(2)", frameId);
|
|
128
|
+
await tab.clickElement(".submit", frameId);
|
|
129
|
+
await waitFor(
|
|
130
|
+
() => tab.elementExists("#gwt-debug-close_id", frameId),
|
|
131
|
+
300,
|
|
132
|
+
1000
|
|
133
|
+
);
|
|
134
|
+
await tab.clickElement("#gwt-debug-close_id", frameId);
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async openCmp(tab: TabActor) {
|
|
139
|
+
await tab.eval("truste.eu.clickListener()");
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async test() {
|
|
144
|
+
// TODO: find out how to test TrustArc
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export class ConsentOMaticCMP {
|
|
2
|
+
constructor(name, config) {
|
|
3
|
+
this.name = name;
|
|
4
|
+
this.config = config;
|
|
5
|
+
this.methods = new Map();
|
|
6
|
+
config.methods.forEach(methodConfig => {
|
|
7
|
+
if (methodConfig.action) {
|
|
8
|
+
this.methods.set(methodConfig.name, methodConfig.action);
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
this.hasSelfTest = this.methods.has("TEST_CONSENT");
|
|
12
|
+
}
|
|
13
|
+
async detectCmp(tab) {
|
|
14
|
+
return (await Promise.all(this.config.detectors.map(detectorConfig => tab.matches(detectorConfig.presentMatcher)))).some(matched => matched);
|
|
15
|
+
}
|
|
16
|
+
async detectPopup(tab) {
|
|
17
|
+
return (await Promise.all(this.config.detectors.map(detectorConfig => tab.matches(detectorConfig.showingMatcher)))).some(matched => matched);
|
|
18
|
+
}
|
|
19
|
+
async executeAction(tab, method, param) {
|
|
20
|
+
if (this.methods.has(method)) {
|
|
21
|
+
return tab.executeAction(this.methods.get(method), param);
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
async optOut(tab) {
|
|
26
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
27
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
28
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
29
|
+
await this.executeAction(tab, "DO_CONSENT", []);
|
|
30
|
+
await this.executeAction(tab, "SAVE_CONSENT");
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
async optIn(tab) {
|
|
34
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
35
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
36
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
37
|
+
await this.executeAction(tab, "DO_CONSENT", ['D', 'A', 'B', 'E', 'F', 'X']);
|
|
38
|
+
await this.executeAction(tab, "SAVE_CONSENT");
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
async openCmp(tab) {
|
|
42
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
43
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
test(tab) {
|
|
47
|
+
return this.executeAction(tab, "TEST_CONSENT");
|
|
48
|
+
}
|
|
49
|
+
detectFrame(tab, frame) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { AutoCMP, TabActor } from "../types";
|
|
2
|
+
|
|
3
|
+
export type DetectorConfig = {
|
|
4
|
+
presentMatcher: {};
|
|
5
|
+
showingMatcher: {};
|
|
6
|
+
};
|
|
7
|
+
export type MethodConfig = {
|
|
8
|
+
action?: any;
|
|
9
|
+
name: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type ConsentOMaticConfig = {
|
|
13
|
+
detectors: DetectorConfig[];
|
|
14
|
+
methods: MethodConfig[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class ConsentOMaticCMP implements AutoCMP {
|
|
18
|
+
methods = new Map<string, {}>();
|
|
19
|
+
hasSelfTest: boolean;
|
|
20
|
+
|
|
21
|
+
constructor(public name: string, public config: ConsentOMaticConfig) {
|
|
22
|
+
config.methods.forEach(methodConfig => {
|
|
23
|
+
if (methodConfig.action) {
|
|
24
|
+
this.methods.set(methodConfig.name, methodConfig.action);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
this.hasSelfTest = this.methods.has("TEST_CONSENT");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async detectCmp(tab: TabActor): Promise<boolean> {
|
|
31
|
+
return (
|
|
32
|
+
await Promise.all(
|
|
33
|
+
this.config.detectors.map(detectorConfig =>
|
|
34
|
+
tab.matches(detectorConfig.presentMatcher)
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
).some(matched => matched);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async detectPopup(tab: TabActor): Promise<boolean> {
|
|
41
|
+
return (
|
|
42
|
+
await Promise.all(
|
|
43
|
+
this.config.detectors.map(detectorConfig =>
|
|
44
|
+
tab.matches(detectorConfig.showingMatcher)
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
).some(matched => matched);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async executeAction(tab: TabActor, method: string, param?: any) {
|
|
51
|
+
if (this.methods.has(method)) {
|
|
52
|
+
return tab.executeAction(this.methods.get(method), param);
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async optOut(tab: TabActor): Promise<boolean> {
|
|
58
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
59
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
60
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
61
|
+
await this.executeAction(tab, "DO_CONSENT", []);
|
|
62
|
+
await this.executeAction(tab, "SAVE_CONSENT");
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async optIn(tab: TabActor): Promise<boolean> {
|
|
67
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
68
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
69
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
70
|
+
await this.executeAction(tab, "DO_CONSENT", ['D', 'A', 'B', 'E', 'F', 'X']);
|
|
71
|
+
await this.executeAction(tab, "SAVE_CONSENT");
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
async openCmp(tab: TabActor): Promise<boolean> {
|
|
75
|
+
await this.executeAction(tab, "HIDE_CMP");
|
|
76
|
+
await this.executeAction(tab, "OPEN_OPTIONS");
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
test(tab: TabActor): Promise<boolean> {
|
|
81
|
+
return this.executeAction(tab, "TEST_CONSENT");
|
|
82
|
+
}
|
|
83
|
+
detectFrame(tab: TabActor, frame: { url: string }): boolean {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
package/lib/detector.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default async function detectDialog(tab, retries, rules) {
|
|
2
|
+
let breakEarly = false;
|
|
3
|
+
const found = await new Promise(async (resolve) => {
|
|
4
|
+
let earlyReturn = false;
|
|
5
|
+
await Promise.all(rules.map(async (r, index) => {
|
|
6
|
+
try {
|
|
7
|
+
if (await r.detectCmp(tab)) {
|
|
8
|
+
earlyReturn = true;
|
|
9
|
+
resolve(index);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
catch (e) {
|
|
13
|
+
breakEarly = true;
|
|
14
|
+
}
|
|
15
|
+
}));
|
|
16
|
+
if (!earlyReturn) {
|
|
17
|
+
resolve(-1);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
if (found === -1 && retries > 0 && !breakEarly) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
setTimeout(async () => {
|
|
23
|
+
const result = detectDialog(tab, retries - 1, rules);
|
|
24
|
+
resolve(result);
|
|
25
|
+
}, 500);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return found > -1 ? rules[found] : null;
|
|
29
|
+
}
|
package/lib/detector.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AutoCMP, TabActor } from './types';
|
|
2
|
+
|
|
3
|
+
export default async function detectDialog(tab: TabActor, retries: number, rules: AutoCMP[]): Promise<AutoCMP> {
|
|
4
|
+
let breakEarly = false;
|
|
5
|
+
const found: number = await new Promise(async (resolve) => {
|
|
6
|
+
let earlyReturn = false;
|
|
7
|
+
await Promise.all(rules.map(async (r, index) => {
|
|
8
|
+
try {
|
|
9
|
+
if (await r.detectCmp(tab)) {
|
|
10
|
+
earlyReturn = true;
|
|
11
|
+
resolve(index)
|
|
12
|
+
}
|
|
13
|
+
} catch (e) {
|
|
14
|
+
breakEarly = true;
|
|
15
|
+
}
|
|
16
|
+
}));
|
|
17
|
+
if (!earlyReturn) {
|
|
18
|
+
resolve(-1)
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
if (found === -1 && retries > 0 && !breakEarly) {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
setTimeout(async () => {
|
|
24
|
+
const result = detectDialog(tab, retries - 1, rules);
|
|
25
|
+
resolve(result);
|
|
26
|
+
}, 500);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return found > -1 ? rules[found] : null;
|
|
30
|
+
}
|
package/lib/hider.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// hide rules not specific to a single CMP rule
|
|
2
|
+
const globalHidden = [
|
|
3
|
+
"#didomi-popup,.didomi-popup-container,.didomi-popup-notice,.didomi-consent-popup-preferences,#didomi-notice,.didomi-popup-backdrop,.didomi-screen-medium",
|
|
4
|
+
];
|
|
5
|
+
export default async function prehideElements(tab, rules) {
|
|
6
|
+
const selectors = rules.reduce((selectorList, rule) => {
|
|
7
|
+
if (rule.prehideSelectors) {
|
|
8
|
+
return [...selectorList, ...rule.prehideSelectors];
|
|
9
|
+
}
|
|
10
|
+
return selectorList;
|
|
11
|
+
}, globalHidden);
|
|
12
|
+
await tab.hideElements(selectors);
|
|
13
|
+
}
|
package/lib/hider.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AutoCMP, TabActor } from './types';
|
|
2
|
+
|
|
3
|
+
// hide rules not specific to a single CMP rule
|
|
4
|
+
const globalHidden = [
|
|
5
|
+
"#didomi-popup,.didomi-popup-container,.didomi-popup-notice,.didomi-consent-popup-preferences,#didomi-notice,.didomi-popup-backdrop,.didomi-screen-medium",
|
|
6
|
+
]
|
|
7
|
+
|
|
8
|
+
export default async function prehideElements(tab: TabActor, rules: AutoCMP[]): Promise<void> {
|
|
9
|
+
const selectors = rules.reduce((selectorList, rule) => {
|
|
10
|
+
if (rule.prehideSelectors) {
|
|
11
|
+
return [...selectorList, ...rule.prehideSelectors];
|
|
12
|
+
}
|
|
13
|
+
return selectorList;
|
|
14
|
+
}, globalHidden);
|
|
15
|
+
await tab.hideElements(selectors);
|
|
16
|
+
}
|
package/lib/index.js
ADDED