@duckduckgo/autoconsent 2.1.2 → 2.2.1
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/.vscode/.idea/.vscode.iml +9 -0
- package/.vscode/.idea/modules.xml +8 -0
- package/.vscode/.idea/workspace.xml +28 -0
- package/.vscode/settings.json +7 -0
- package/dist/addon-firefox/background.bundle.js +1 -1
- package/dist/addon-firefox/content.bundle.js +1 -1
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/rules.json +985 -51
- package/dist/addon-mv3/background.bundle.js +1 -1
- package/dist/addon-mv3/content.bundle.js +1 -1
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/rules.json +985 -51
- package/dist/autoconsent.cjs.js +1 -1
- package/dist/autoconsent.esm.js +1 -1
- package/dist/autoconsent.playwright.js +1 -1
- package/lib/cmps/all.ts +7 -0
- package/lib/cmps/base.ts +37 -24
- package/lib/cmps/consentmanager.ts +27 -4
- package/lib/cmps/conversant.ts +60 -0
- package/lib/cmps/klaro.ts +66 -0
- package/lib/cmps/onetrust.ts +3 -3
- package/lib/cmps/sourcepoint-frame.ts +9 -8
- package/lib/cmps/sourcepoint-top.ts +5 -0
- package/lib/cmps/trustarc-frame.ts +3 -0
- package/lib/cmps/uniconsent.ts +71 -0
- package/lib/rules.ts +8 -1
- package/lib/web.ts +48 -25
- package/package.json +1 -1
- package/readme.md +29 -0
- package/rules/autoconsent/adroll.json +11 -0
- package/rules/autoconsent/aws-amazon.json +6 -1
- package/rules/autoconsent/axeptio.json +41 -0
- package/rules/autoconsent/clickio.json +18 -0
- package/rules/autoconsent/complianz-banner.json +13 -0
- package/rules/autoconsent/complianz-categories.json +17 -0
- package/rules/autoconsent/complianz-notice.json +14 -0
- package/rules/autoconsent/complianz-optin.json +20 -0
- package/rules/autoconsent/cookie-notice.json +3 -1
- package/rules/autoconsent/cookieinformation.json +14 -0
- package/rules/autoconsent/dsgvo.json +16 -0
- package/rules/autoconsent/eu-cookie-law.json +20 -0
- package/rules/autoconsent/ezoic.json +19 -0
- package/rules/autoconsent/iubenda.json +23 -0
- package/rules/autoconsent/jquery-cookiebar.json +25 -0
- package/rules/autoconsent/mediavine.json +20 -0
- package/rules/autoconsent/moove.json +28 -0
- package/rules/autoconsent/paypal.json +4 -1
- package/rules/autoconsent/primebox.json +19 -0
- package/rules/autoconsent/privacymanager.json +30 -0
- package/rules/autoconsent/pubtech.json +42 -0
- package/rules/autoconsent/sibbo.json +43 -0
- package/rules/autoconsent/sirdata.json +11 -0
- package/rules/autoconsent/tarteaucitron.json +18 -0
- package/rules/autoconsent/tealium.json +0 -1
- package/rules/autoconsent/termly.json +31 -0
- package/rules/autoconsent/testcmp.json +4 -1
- package/rules/autoconsent/uk-cookie-consent.json +15 -0
- package/rules/autoconsent/{usercentrics-1.json → usercentrics-api.json} +2 -2
- package/rules/autoconsent/usercentrics-button.json +14 -0
- package/rules/autoconsent/vodafone-de.json +5 -5
- package/rules/autoconsent/wp-cookie-notice.json +12 -0
- package/rules/rules.json +985 -51
- package/tests/adroll.spec.ts +15 -0
- package/tests/axeptio.spec.ts +9 -0
- package/tests/clickio.spec.ts +10 -0
- package/tests/complianz-banner.spec.ts +7 -0
- package/tests/complianz-categories.spec.ts +14 -0
- package/tests/{cookieconsent.spec.ts → complianz-notice.spec.ts} +1 -2
- package/tests/complianz-optin.spec.ts +6 -0
- package/tests/consentmanager.spec.ts +2 -1
- package/tests/conversant.spec.ts +10 -0
- package/tests/{cookienotice.spec.ts → cookie-notice.spec.ts} +0 -0
- package/tests/cookieinformation.spec.ts +10 -0
- package/tests/dsgvo.spec.ts +6 -0
- package/tests/eu-cookie-law.spec.ts +6 -0
- package/tests/ezoic.spec.ts +8 -0
- package/tests/iubenda.spec.ts +8 -0
- package/tests/jquery-cookiebar.spec.ts +6 -0
- package/tests/klaro.spec.ts +6 -2
- package/tests/mediavine.spec.ts +8 -0
- package/tests/moove.spec.ts +14 -0
- package/tests/oil.spec.ts +3 -2
- package/tests/primebox.spec.ts +7 -0
- package/tests/privacymanager.spec.ts +8 -0
- package/tests/pubtech.spec.ts +13 -0
- package/tests/sibbo.spec.ts +16 -0
- package/tests/sirdata.spec.ts +8 -0
- package/tests/tarteaucitron.spec.ts +9 -0
- package/tests/tealium.spec.ts +1 -1
- package/tests/termly.spec.ts +12 -0
- package/tests/trustarc.spec.ts +1 -9
- package/tests/uk-cookie-consent.spec.ts +7 -0
- package/tests/uniconsent.spec.ts +12 -0
- package/tests/{usercentrics-1.spec.ts → usercentrics-api.spec.ts} +3 -2
- package/tests/usercentrics-button.spec.ts +8 -0
- package/tests/wp-cookie-notice.spec.ts +8 -0
- package/dist/autoconsent.standalone.js +0 -1
- package/rules/autoconsent/cookieconsent.json +0 -8
- package/rules/autoconsent/destatis-de.json +0 -8
- package/rules/autoconsent/klaro.json +0 -10
- package/tests/destatis.spec.ts +0 -7
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { click, elementExists, elementVisible, waitForElement } from "../rule-executors";
|
|
1
|
+
import { click, doEval, elementExists, elementVisible, wait, waitForElement } from "../rule-executors";
|
|
2
2
|
import AutoConsentCMPBase from "./base";
|
|
3
3
|
|
|
4
4
|
// Note: JS API is also available:
|
|
5
5
|
// https://help.consentmanager.net/books/cmp/page/javascript-api
|
|
6
6
|
export default class ConsentManager extends AutoConsentCMPBase {
|
|
7
7
|
|
|
8
|
-
prehideSelectors = ["#cmpbox,#cmpbox2"]
|
|
8
|
+
prehideSelectors = ["#cmpbox,#cmpbox2"];
|
|
9
|
+
apiAvailable = false;
|
|
9
10
|
|
|
10
11
|
get hasSelfTest(): boolean {
|
|
11
|
-
return
|
|
12
|
+
return this.apiAvailable;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
get isIntermediate(): boolean {
|
|
@@ -20,14 +21,27 @@ export default class ConsentManager extends AutoConsentCMPBase {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
async detectCmp() {
|
|
23
|
-
|
|
24
|
+
this.apiAvailable = await doEval('window.__cmp && typeof __cmp("getCMPData") === "object"');
|
|
25
|
+
if (!this.apiAvailable) {
|
|
26
|
+
return elementExists("#cmpbox");
|
|
27
|
+
} else {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
async detectPopup() {
|
|
33
|
+
if (this.apiAvailable) {
|
|
34
|
+
return await doEval("!__cmp('consentStatus').userChoiceExists");
|
|
35
|
+
}
|
|
27
36
|
return elementVisible("#cmpbox .cmpmore", 'any');
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
async optOut() {
|
|
40
|
+
await wait(500);
|
|
41
|
+
if (this.apiAvailable) {
|
|
42
|
+
return await doEval("__cmp('setConsent', 0)");
|
|
43
|
+
}
|
|
44
|
+
|
|
31
45
|
if (click(".cmpboxbtnno")) {
|
|
32
46
|
return true;
|
|
33
47
|
}
|
|
@@ -46,6 +60,15 @@ export default class ConsentManager extends AutoConsentCMPBase {
|
|
|
46
60
|
}
|
|
47
61
|
|
|
48
62
|
async optIn() {
|
|
63
|
+
if (this.apiAvailable) {
|
|
64
|
+
return await doEval("__cmp('setConsent', 1)");
|
|
65
|
+
}
|
|
49
66
|
return click(".cmpboxbtnyes");
|
|
50
67
|
}
|
|
68
|
+
|
|
69
|
+
async test() {
|
|
70
|
+
if (this.apiAvailable) {
|
|
71
|
+
return await doEval("__cmp('consentStatus').userChoiceExists");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
51
74
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { click, elementExists, elementVisible, waitForElement, waitForThenClick } from "../rule-executors";
|
|
2
|
+
import { waitFor } from "../utils";
|
|
3
|
+
import AutoConsentCMPBase from "./base";
|
|
4
|
+
|
|
5
|
+
export default class Conversant extends AutoConsentCMPBase {
|
|
6
|
+
|
|
7
|
+
prehideSelectors = [".cmp-root"]
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
super("Conversant");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get hasSelfTest(): boolean {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get isIntermediate(): boolean {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async detectCmp() {
|
|
22
|
+
return elementExists(".cmp-root .cmp-receptacle");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async detectPopup() {
|
|
26
|
+
return elementVisible(".cmp-root .cmp-receptacle", 'any');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async optOut() {
|
|
30
|
+
if (!(await waitForThenClick(".cmp-main-button:not(.cmp-main-button--primary)"))) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!(await waitForElement(".cmp-view-tab-tabs"))) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
await waitForThenClick(".cmp-view-tab-tabs > :first-child");
|
|
39
|
+
await waitForThenClick(".cmp-view-tab-tabs > .cmp-view-tab--active:first-child");
|
|
40
|
+
|
|
41
|
+
for (const item of Array.from(document.querySelectorAll('.cmp-accordion-item'))) {
|
|
42
|
+
(<HTMLElement>item.querySelector('.cmp-accordion-item-title')).click();
|
|
43
|
+
await waitFor(() => !!item.querySelector('.cmp-accordion-item-content.cmp-active'), 10, 50);
|
|
44
|
+
const content = item.querySelector('.cmp-accordion-item-content.cmp-active');
|
|
45
|
+
content.querySelectorAll('.cmp-toggle-actions .cmp-toggle-deny:not(.cmp-toggle-deny--active)').forEach((e: HTMLElement) => e.click());
|
|
46
|
+
content.querySelectorAll('.cmp-toggle-actions .cmp-toggle-checkbox:not(.cmp-toggle-checkbox--active)').forEach((e: HTMLElement) => e.click());
|
|
47
|
+
// await waitFor(() => !item.querySelector('.cmp-toggle-deny--active,.cmp-toggle-checkbox--active'), 5, 50); // this may take a long time
|
|
48
|
+
}
|
|
49
|
+
await click(".cmp-main-button:not(.cmp-main-button--primary)");
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async optIn() {
|
|
54
|
+
return waitForThenClick(".cmp-main-button.cmp-main-button--primary");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async test() {
|
|
58
|
+
return document.cookie.includes('cmp-data=0');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { click, doEval, elementExists, elementVisible, waitForElement } from "../rule-executors";
|
|
2
|
+
import AutoConsentCMPBase from "./base";
|
|
3
|
+
|
|
4
|
+
export default class Klaro extends AutoConsentCMPBase {
|
|
5
|
+
|
|
6
|
+
prehideSelectors = [".klaro"]
|
|
7
|
+
settingsOpen = false;
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
super("Klaro");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get hasSelfTest(): boolean {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get isIntermediate(): boolean {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async detectCmp() {
|
|
22
|
+
if (elementExists('.klaro > .cookie-modal')) {
|
|
23
|
+
this.settingsOpen = true;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return elementExists(".klaro > .cookie-notice");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async detectPopup() {
|
|
30
|
+
return elementVisible(".klaro > .cookie-notice,.klaro > .cookie-modal", 'any');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async optOut() {
|
|
34
|
+
if (click('.klaro .cn-decline')) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!this.settingsOpen) {
|
|
39
|
+
click('.klaro .cn-learn-more');
|
|
40
|
+
await waitForElement('.klaro > .cookie-modal', 2000);
|
|
41
|
+
this.settingsOpen = true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (click('.klaro .cn-decline')) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
click('.cm-purpose:not(.cm-toggle-all) > input:not(.half-checked)', true);
|
|
49
|
+
return click('.cm-btn-accept');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async optIn() {
|
|
53
|
+
if (click('.klaro .cm-btn-accept-all')) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (this.settingsOpen) {
|
|
57
|
+
click('.cm-purpose:not(.cm-toggle-all) > input.half-checked', true);
|
|
58
|
+
return click('.cm-btn-accept');
|
|
59
|
+
}
|
|
60
|
+
return click('.klaro .cookie-notice .cm-btn-success');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async test() {
|
|
64
|
+
return await doEval('klaro.getManager().config.services.every(c => c.required || !klaro.getManager().consents[c.name])');
|
|
65
|
+
}
|
|
66
|
+
}
|
package/lib/cmps/onetrust.ts
CHANGED
|
@@ -4,7 +4,7 @@ import AutoConsentCMPBase from "./base";
|
|
|
4
4
|
|
|
5
5
|
export default class Onetrust extends AutoConsentCMPBase {
|
|
6
6
|
|
|
7
|
-
prehideSelectors = ["#onetrust-banner-sdk,#onetrust-consent-sdk,.
|
|
7
|
+
prehideSelectors = ["#onetrust-banner-sdk,#onetrust-consent-sdk,.onetrust-pc-dark-filter,.js-consent-banner"]
|
|
8
8
|
|
|
9
9
|
constructor() {
|
|
10
10
|
super("Onetrust");
|
|
@@ -19,11 +19,11 @@ export default class Onetrust extends AutoConsentCMPBase {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
async detectCmp() {
|
|
22
|
-
return elementExists("#onetrust-banner-sdk
|
|
22
|
+
return elementExists("#onetrust-banner-sdk");
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
async detectPopup() {
|
|
26
|
-
return elementVisible("#onetrust-banner-sdk
|
|
26
|
+
return elementVisible("#onetrust-banner-sdk", 'all');
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
async optOut() {
|
|
@@ -32,7 +32,7 @@ export default class SourcePoint extends AutoConsentCMPBase {
|
|
|
32
32
|
return true;
|
|
33
33
|
}
|
|
34
34
|
return (url.pathname === '/index.html' || url.pathname === '/privacy-manager/index.html')
|
|
35
|
-
&& url.searchParams.has('message_id')
|
|
35
|
+
&& (url.searchParams.has('message_id') || url.searchParams.has('requestUUID') || url.searchParams.has('consentUUID'));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
async detectPopup() {
|
|
@@ -57,16 +57,17 @@ export default class SourcePoint extends AutoConsentCMPBase {
|
|
|
57
57
|
|
|
58
58
|
async optOut() {
|
|
59
59
|
if (!this.isManagerOpen()) {
|
|
60
|
-
const actionable = await waitForElement('
|
|
60
|
+
const actionable = await waitForElement('.sp_choice_type_12,.sp_choice_type_13');
|
|
61
61
|
if (!actionable) {
|
|
62
62
|
return false;
|
|
63
63
|
}
|
|
64
|
-
if (!elementExists("
|
|
64
|
+
if (!elementExists(".sp_choice_type_12")) {
|
|
65
65
|
// do not sell button
|
|
66
|
-
return click("
|
|
66
|
+
return click(".sp_choice_type_13");
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
click("
|
|
69
|
+
click(".sp_choice_type_12");
|
|
70
|
+
// the page may navigate at this point but that's okay
|
|
70
71
|
await waitFor(
|
|
71
72
|
() => location.pathname === "/privacy-manager/index.html",
|
|
72
73
|
200,
|
|
@@ -88,9 +89,8 @@ export default class SourcePoint extends AutoConsentCMPBase {
|
|
|
88
89
|
await wait(1000);
|
|
89
90
|
return click(rejectSelector1);
|
|
90
91
|
} else if (path === 1) {
|
|
91
|
-
|
|
92
|
+
click(rejectSelector2);
|
|
92
93
|
} else if (path === 2) {
|
|
93
|
-
// TODO: check if this is still working
|
|
94
94
|
await waitForElement('.pm-features', 10000);
|
|
95
95
|
click('.checked > span', true);
|
|
96
96
|
|
|
@@ -99,6 +99,7 @@ export default class SourcePoint extends AutoConsentCMPBase {
|
|
|
99
99
|
} catch (e) {
|
|
100
100
|
enableLogs && console.warn(e);
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
click('.sp_choice_type_SAVE_AND_EXIT');
|
|
103
|
+
return true;
|
|
103
104
|
}
|
|
104
105
|
}
|
|
@@ -35,6 +35,11 @@ export default class SourcePoint extends AutoConsentCMPBase {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async optOut() {
|
|
38
|
+
// unblock scrolling
|
|
39
|
+
const container = document.querySelector('.sp-message-open');
|
|
40
|
+
if (container) {
|
|
41
|
+
container.classList.remove('sp-message-open');
|
|
42
|
+
}
|
|
38
43
|
return true;
|
|
39
44
|
}
|
|
40
45
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { elementExists, elementVisible, wait, waitForElement, waitForThenClick } from "../rule-executors";
|
|
2
|
+
import AutoConsentCMPBase from "./base";
|
|
3
|
+
|
|
4
|
+
export default class Uniconsent extends AutoConsentCMPBase {
|
|
5
|
+
constructor() {
|
|
6
|
+
super("Uniconsent");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
get prehideSelectors(): string[] {
|
|
10
|
+
return ['.unic', '.modal:has(.unic)'];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get hasSelfTest(): boolean {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get isIntermediate(): boolean {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async detectCmp() {
|
|
22
|
+
return elementExists(".unic .unic-box,.unic .unic-bar");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async detectPopup() {
|
|
26
|
+
return elementVisible(".unic .unic-box,.unic .unic-bar", 'any');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async optOut() {
|
|
30
|
+
await waitForElement(".unic button", 1000);
|
|
31
|
+
document.querySelectorAll(".unic button").forEach((button: HTMLButtonElement) => {
|
|
32
|
+
const text = button.textContent;
|
|
33
|
+
if (text.includes('Manage Options') || text.includes('Optionen verwalten')) {
|
|
34
|
+
button.click();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (await waitForElement('.unic input[type=checkbox]', 1000)) {
|
|
39
|
+
await waitForElement('.unic button', 1000);
|
|
40
|
+
|
|
41
|
+
document.querySelectorAll('.unic input[type=checkbox]').forEach((c: HTMLInputElement) => {
|
|
42
|
+
if (c.checked) {
|
|
43
|
+
c.click();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
for (const b of <NodeListOf<HTMLButtonElement>>document.querySelectorAll('.unic button')) {
|
|
48
|
+
const text = b.textContent;
|
|
49
|
+
for (const pattern of ['Confirm Choices', 'Save Choices', 'Auswahl speichern']) {
|
|
50
|
+
if (text.includes(pattern)) {
|
|
51
|
+
b.click();
|
|
52
|
+
await wait(500); // give it some time to close the popup
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async optIn() {
|
|
63
|
+
return waitForThenClick(".unic #unic-agree");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async test() {
|
|
67
|
+
await wait(1000);
|
|
68
|
+
const res = elementExists(".unic .unic-box,.unic .unic-bar");
|
|
69
|
+
return !res;
|
|
70
|
+
}
|
|
71
|
+
}
|
package/lib/rules.ts
CHANGED
|
@@ -28,7 +28,8 @@ export type AutoConsentRuleStep = { optional?: boolean } & Partial<
|
|
|
28
28
|
Partial<WaitForThenClickRule> &
|
|
29
29
|
Partial<WaitRule> &
|
|
30
30
|
Partial<UrlRule> &
|
|
31
|
-
Partial<HideRule
|
|
31
|
+
Partial<HideRule> &
|
|
32
|
+
Partial<IfRule>;
|
|
32
33
|
|
|
33
34
|
export type ElementExistsRule = {
|
|
34
35
|
exists: string;
|
|
@@ -80,3 +81,9 @@ export type HideRule = {
|
|
|
80
81
|
hide: string[];
|
|
81
82
|
method?: HideMethod;
|
|
82
83
|
};
|
|
84
|
+
|
|
85
|
+
export type IfRule = {
|
|
86
|
+
if: Partial<ElementExistsRule> & Partial<ElementVisibleRule>;
|
|
87
|
+
then: AutoConsentRuleStep[];
|
|
88
|
+
else?: AutoConsentRuleStep[];
|
|
89
|
+
};
|
package/lib/web.ts
CHANGED
|
@@ -107,16 +107,46 @@ export default class AutoConsent {
|
|
|
107
107
|
|
|
108
108
|
async _start() {
|
|
109
109
|
enableLogs && console.log(`Detecting CMPs on ${window.location.href}`)
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
110
|
+
const cmps = await this.findCmp(this.config.detectRetries);
|
|
111
|
+
if (cmps.length > 0) {
|
|
112
|
+
const popupLookups: Promise<boolean>[] = [];
|
|
113
|
+
for (const cmp of cmps) {
|
|
114
|
+
enableLogs && console.log("detected CMP:", cmp.name, window.location.href);
|
|
115
|
+
this.sendContentMessage({
|
|
116
|
+
type: 'cmpDetected',
|
|
117
|
+
url: location.href,
|
|
118
|
+
cmp: cmp.name,
|
|
119
|
+
}); // notify the browser
|
|
120
|
+
popupLookups.push(this.waitForPopup(cmp).then((isOpen) => {
|
|
121
|
+
if (isOpen) {
|
|
122
|
+
if (!this.foundCmp) {
|
|
123
|
+
this.foundCmp = cmp;
|
|
124
|
+
}
|
|
125
|
+
this.sendContentMessage({
|
|
126
|
+
type: 'popupFound',
|
|
127
|
+
cmp: cmp.name,
|
|
128
|
+
url: location.href,
|
|
129
|
+
}); // notify the browser
|
|
130
|
+
return true;
|
|
131
|
+
} else {
|
|
132
|
+
return Promise.reject(`${cmp.name} popup not found`);
|
|
133
|
+
}
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// could use `somethingOpen = await Promise.any(popupLookups).catch(() => false)`, but Promise.any is often unavailable in polyfilled environments
|
|
138
|
+
let somethingOpen = false;
|
|
139
|
+
for (const popupLookup of popupLookups) {
|
|
140
|
+
try {
|
|
141
|
+
await popupLookup;
|
|
142
|
+
somethingOpen = true;
|
|
143
|
+
break;
|
|
144
|
+
} catch (e) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!somethingOpen) {
|
|
120
150
|
enableLogs && console.log('no popup found');
|
|
121
151
|
if (this.config.enablePrehide) {
|
|
122
152
|
undoPrehide();
|
|
@@ -124,13 +154,6 @@ export default class AutoConsent {
|
|
|
124
154
|
return false;
|
|
125
155
|
}
|
|
126
156
|
|
|
127
|
-
this.foundCmp = cmp;
|
|
128
|
-
this.sendContentMessage({
|
|
129
|
-
type: 'popupFound',
|
|
130
|
-
cmp: cmp.name,
|
|
131
|
-
url: location.href,
|
|
132
|
-
}); // notify the browser
|
|
133
|
-
|
|
134
157
|
if (this.config.autoAction === 'optOut') {
|
|
135
158
|
return await this.doOptOut();
|
|
136
159
|
} else if (this.config.autoAction === 'optIn') {
|
|
@@ -148,8 +171,7 @@ export default class AutoConsent {
|
|
|
148
171
|
}
|
|
149
172
|
}
|
|
150
173
|
|
|
151
|
-
async findCmp(retries: number): Promise<AutoCMP> {
|
|
152
|
-
let foundCmp: AutoCMP = null;
|
|
174
|
+
async findCmp(retries: number): Promise<AutoCMP[]> {
|
|
153
175
|
const allFoundCmps: AutoCMP[] = [];
|
|
154
176
|
|
|
155
177
|
for (const cmp of this.rules) {
|
|
@@ -161,9 +183,6 @@ export default class AutoConsent {
|
|
|
161
183
|
if (result) {
|
|
162
184
|
enableLogs && console.log(`Found CMP: ${cmp.name}`);
|
|
163
185
|
allFoundCmps.push(cmp);
|
|
164
|
-
if (!foundCmp) {
|
|
165
|
-
foundCmp = cmp;
|
|
166
|
-
}
|
|
167
186
|
}
|
|
168
187
|
} catch (e) {
|
|
169
188
|
enableLogs && console.warn(`error detecting ${cmp.name}`, e);
|
|
@@ -182,7 +201,7 @@ export default class AutoConsent {
|
|
|
182
201
|
});
|
|
183
202
|
}
|
|
184
203
|
|
|
185
|
-
if (
|
|
204
|
+
if (allFoundCmps.length === 0 && retries > 0) {
|
|
186
205
|
return new Promise((resolve) => {
|
|
187
206
|
setTimeout(async () => {
|
|
188
207
|
const result = this.findCmp(retries - 1);
|
|
@@ -191,7 +210,7 @@ export default class AutoConsent {
|
|
|
191
210
|
});
|
|
192
211
|
}
|
|
193
212
|
|
|
194
|
-
return
|
|
213
|
+
return allFoundCmps;
|
|
195
214
|
}
|
|
196
215
|
|
|
197
216
|
async doOptOut(): Promise<boolean> {
|
|
@@ -236,6 +255,7 @@ export default class AutoConsent {
|
|
|
236
255
|
} else {
|
|
237
256
|
enableLogs && console.log(`CMP ${this.foundCmp.name}: opt in on ${window.location.href}`);
|
|
238
257
|
optInResult = await this.foundCmp.optIn();
|
|
258
|
+
enableLogs && console.log(`${this.foundCmp.name}: opt in result ${optInResult}`);
|
|
239
259
|
}
|
|
240
260
|
|
|
241
261
|
if (this.config.enablePrehide) {
|
|
@@ -286,7 +306,7 @@ export default class AutoConsent {
|
|
|
286
306
|
if (!isOpen && retries > 0) {
|
|
287
307
|
return new Promise((resolve) => setTimeout(() => resolve(this.waitForPopup(cmp, retries - 1, interval)), interval));
|
|
288
308
|
}
|
|
289
|
-
enableLogs && console.log(`popup is ${isOpen ? 'open' : 'not open'}`);
|
|
309
|
+
enableLogs && console.log(cmp.name, `popup is ${isOpen ? 'open' : 'not open'}`);
|
|
290
310
|
return isOpen;
|
|
291
311
|
}
|
|
292
312
|
|
|
@@ -314,6 +334,9 @@ export default class AutoConsent {
|
|
|
314
334
|
case 'initResp':
|
|
315
335
|
this.initialize(message.config, message.rules);
|
|
316
336
|
break;
|
|
337
|
+
case 'optIn':
|
|
338
|
+
await this.doOptIn();
|
|
339
|
+
break;
|
|
317
340
|
case 'optOut':
|
|
318
341
|
await this.doOptOut();
|
|
319
342
|
break;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -106,6 +106,17 @@ Returns true if elements returned from `document.querySelectorAll(selector)` are
|
|
|
106
106
|
```
|
|
107
107
|
Waits until `selector` exists in the page. After `timeout` ms the step fails.
|
|
108
108
|
|
|
109
|
+
### Wait for visibility
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"waitForVisible": "selector",
|
|
114
|
+
"timeout": 1000,
|
|
115
|
+
"check": "any" | "all" | "none"
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
Waits until element is visible in the page. After `timeout` ms the step fails.
|
|
119
|
+
|
|
109
120
|
### Click an element
|
|
110
121
|
```json
|
|
111
122
|
{
|
|
@@ -152,6 +163,24 @@ Hide the elements matched by the selectors. `method` defines how elements are hi
|
|
|
152
163
|
Evaluates `code` in the context of the page. The rule is considered successful if it *evaluates to a truthy value*.
|
|
153
164
|
Eval rules are not 100% reliable because they can be blocked by a CSP policy on the page. Therefore, they should only be used as a last resort when none of the other rules are sufficient.
|
|
154
165
|
|
|
166
|
+
### Conditionals
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"if": { "exists": "selector" },
|
|
171
|
+
"then": [
|
|
172
|
+
{ "click": ".button1" },
|
|
173
|
+
{ "click": ".button3" }
|
|
174
|
+
],
|
|
175
|
+
"else": [
|
|
176
|
+
{ "click": ".button2" }
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Allows to do conditional branching in JSON rules. The `if` section can contain either a "visible" or "exists" rule. Depending on the result of that rule, `then` or `else` sequences will be executed. `else` section is optional.
|
|
182
|
+
The "if" rule is considered successful as long as all rules inside the chosen branch are successful. The other branch, as well as the result of the condition itself, do not affect the result of the whole rule.
|
|
183
|
+
|
|
155
184
|
### Optional actions
|
|
156
185
|
|
|
157
186
|
Any rule can include the `"optional": true` to ignore failure.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Adroll",
|
|
3
|
+
"prehideSelectors": ["#adroll_consent_container"],
|
|
4
|
+
"detectCmp": [{ "exists": "#adroll_consent_container" }],
|
|
5
|
+
"detectPopup": [{ "visible": "#adroll_consent_container" }],
|
|
6
|
+
"optIn": [ { "waitForThenClick": "#adroll_consent_accept" } ],
|
|
7
|
+
"optOut": [ { "waitForThenClick": "#adroll_consent_reject" } ],
|
|
8
|
+
"test": [
|
|
9
|
+
{ "eval": "!document.cookie.includes('__adroll_fpc')" }
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -9,7 +9,12 @@
|
|
|
9
9
|
"click": "button[data-id=awsccc-cb-btn-customize]"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
|
-
"
|
|
12
|
+
"waitFor": "input[aria-checked]"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"click": "input[aria-checked=true]",
|
|
16
|
+
"all": true,
|
|
17
|
+
"optional": true
|
|
13
18
|
},
|
|
14
19
|
{
|
|
15
20
|
"click": "button[data-id=awsccc-cs-btn-save]"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "axeptio",
|
|
3
|
+
"prehideSelectors": [".axeptio_widget"],
|
|
4
|
+
"detectCmp":
|
|
5
|
+
[
|
|
6
|
+
{
|
|
7
|
+
"exists": ".axeptio_widget"
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
"detectPopup":
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
"visible": ".axeptio_widget"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"optIn":
|
|
17
|
+
[
|
|
18
|
+
{
|
|
19
|
+
"waitFor": ".axeptio-widget--open"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"click": "button#axeptio_btn_acceptAll"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"optOut":
|
|
26
|
+
[
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
"waitFor": ".axeptio-widget--open"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"click": "button#axeptio_btn_dismiss"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"test":
|
|
36
|
+
[
|
|
37
|
+
{
|
|
38
|
+
"eval": "document.cookie.includes('axeptio_authorized_vendors=%2C%2C')"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "click.io",
|
|
3
|
+
"prehideSelectors": ["#cl-consent"],
|
|
4
|
+
"detectCmp": [{ "exists": "#cl-consent" }],
|
|
5
|
+
"detectPopup": [{ "visible": "#cl-consent" }],
|
|
6
|
+
"optIn": [ { "waitForThenClick": "#cl-consent [data-role=\"b_agree\"]" } ],
|
|
7
|
+
"optOut": [
|
|
8
|
+
{ "waitFor": "#cl-consent [data-role=\"b_options\"]" },
|
|
9
|
+
{ "wait": 500 },
|
|
10
|
+
{ "click": "#cl-consent [data-role=\"b_options\"]" },
|
|
11
|
+
{ "waitFor": ".cl-consent-popup.cl-consent-visible [data-role=\"alloff\"]" },
|
|
12
|
+
{ "click": ".cl-consent-popup.cl-consent-visible [data-role=\"alloff\"]", "all": true },
|
|
13
|
+
{ "click": "[data-role=\"b_save\"]" }
|
|
14
|
+
],
|
|
15
|
+
"test": [
|
|
16
|
+
{ "eval": "document.cookie.includes('__lxG__consent__v2_daisybit=')", "comment": "TODO: this only checks if we interacted at all" }
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Complianz banner",
|
|
3
|
+
"prehideSelectors": ["#cmplz-cookiebanner-container"],
|
|
4
|
+
"detectCmp": [{ "exists": "#cmplz-cookiebanner-container .cmplz-cookiebanner" }],
|
|
5
|
+
"detectPopup": [{ "visible": "#cmplz-cookiebanner-container .cmplz-cookiebanner", "check": "any" }],
|
|
6
|
+
"optIn": [
|
|
7
|
+
{ "waitForThenClick": ".cmplz-cookiebanner .cmplz-accept" }
|
|
8
|
+
],
|
|
9
|
+
"optOut": [
|
|
10
|
+
{ "waitForThenClick": ".cmplz-cookiebanner .cmplz-deny" }
|
|
11
|
+
],
|
|
12
|
+
"test": [ { "eval": "document.cookie.includes('cmplz_banner-status=dismissed')" } ]
|
|
13
|
+
}
|