@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.
Files changed (99) hide show
  1. package/.eslintrc +12 -0
  2. package/Dockerfile +9 -0
  3. package/Jenkinsfile +50 -0
  4. package/LICENSE +373 -0
  5. package/cosmetics/rules.json +110 -0
  6. package/dist/autoconsent.cjs.js +1316 -0
  7. package/dist/autoconsent.esm.js +1308 -0
  8. package/dist/autoconsent.puppet.js +980 -0
  9. package/lib/cmps/all.js +17 -0
  10. package/lib/cmps/all.ts +21 -0
  11. package/lib/cmps/base.js +170 -0
  12. package/lib/cmps/base.ts +199 -0
  13. package/lib/cmps/consentmanager.js +31 -0
  14. package/lib/cmps/consentmanager.ts +39 -0
  15. package/lib/cmps/cookiebot.js +73 -0
  16. package/lib/cmps/cookiebot.ts +81 -0
  17. package/lib/cmps/evidon.js +26 -0
  18. package/lib/cmps/evidon.ts +32 -0
  19. package/lib/cmps/sourcepoint.js +82 -0
  20. package/lib/cmps/sourcepoint.ts +95 -0
  21. package/lib/cmps/trustarc.js +106 -0
  22. package/lib/cmps/trustarc.ts +147 -0
  23. package/lib/consentomatic/index.js +52 -0
  24. package/lib/consentomatic/index.ts +86 -0
  25. package/lib/detector.js +29 -0
  26. package/lib/detector.ts +30 -0
  27. package/lib/hider.js +13 -0
  28. package/lib/hider.ts +16 -0
  29. package/lib/index.js +4 -0
  30. package/lib/index.ts +6 -0
  31. package/lib/messages.d.ts +58 -0
  32. package/lib/node.js +30 -0
  33. package/lib/node.ts +38 -0
  34. package/lib/puppet/tab.js +114 -0
  35. package/lib/puppet/tab.ts +136 -0
  36. package/lib/rules.d.ts +80 -0
  37. package/lib/tabwrapper.js +61 -0
  38. package/lib/tabwrapper.ts +68 -0
  39. package/lib/types.d.ts +61 -0
  40. package/lib/web/consentomatic/index.js +188 -0
  41. package/lib/web/consentomatic/index.ts +249 -0
  42. package/lib/web/consentomatic/tools.js +177 -0
  43. package/lib/web/consentomatic/tools.ts +198 -0
  44. package/lib/web/content.js +91 -0
  45. package/lib/web/content.ts +83 -0
  46. package/lib/web/tab.js +106 -0
  47. package/lib/web/tab.ts +171 -0
  48. package/lib/web.js +90 -0
  49. package/lib/web.ts +109 -0
  50. package/package.json +41 -0
  51. package/playwright.config.ts +31 -0
  52. package/readme.md +151 -0
  53. package/rollup.config.js +54 -0
  54. package/rules/autoconsent/asus.json +7 -0
  55. package/rules/autoconsent/cc-banner.json +9 -0
  56. package/rules/autoconsent/cookie-law-info.json +14 -0
  57. package/rules/autoconsent/cookie-notice.json +9 -0
  58. package/rules/autoconsent/cookieconsent.json +9 -0
  59. package/rules/autoconsent/drupal.json +7 -0
  60. package/rules/autoconsent/eu-cookie-compliance.json +14 -0
  61. package/rules/autoconsent/fundingchoices.json +12 -0
  62. package/rules/autoconsent/hubspot.json +7 -0
  63. package/rules/autoconsent/klaro.json +10 -0
  64. package/rules/autoconsent/notice-cookie.json +9 -0
  65. package/rules/autoconsent/onetrust.json +24 -0
  66. package/rules/autoconsent/osano.json +11 -0
  67. package/rules/autoconsent/quantcast.json +14 -0
  68. package/rules/autoconsent/tealium.json +19 -0
  69. package/rules/autoconsent/testcmp.json +12 -0
  70. package/rules/build.js +63 -0
  71. package/rules/rules.json +3030 -0
  72. package/tests/asus.spec.ts +5 -0
  73. package/tests/ccbanner.spec.ts +11 -0
  74. package/tests/consentmanager.spec.ts +10 -0
  75. package/tests/cookiebot.spec.ts +9 -0
  76. package/tests/cookieconsent.spec.ts +8 -0
  77. package/tests/cookielawinfo.spec.ts +9 -0
  78. package/tests/cookienotice.spec.ts +6 -0
  79. package/tests/didomi.spec.ts +9 -0
  80. package/tests/eu-cookie-compliance-banner.spec.ts +7 -0
  81. package/tests/evidon.spec.ts +6 -0
  82. package/tests/fundingchoices.spec.ts +10 -0
  83. package/tests/hubspot.spec.ts +6 -0
  84. package/tests/klaro.spec.ts +5 -0
  85. package/tests/notice-cookie.spec.ts +7 -0
  86. package/tests/oil.spec.ts +10 -0
  87. package/tests/onetrust.spec.ts +15 -0
  88. package/tests/optanon.spec.ts +10 -0
  89. package/tests/osano.spec.ts +5 -0
  90. package/tests/quantcast.spec.ts +16 -0
  91. package/tests/runner.ts +61 -0
  92. package/tests/sourcepoint.spec.ts +17 -0
  93. package/tests/springer.spec.ts +11 -0
  94. package/tests/tealium.spec.ts +6 -0
  95. package/tests/testcmp.spec.ts +5 -0
  96. package/tests/trustarc.spec.ts +13 -0
  97. package/tests/wordpressgdpr.spec.ts +9 -0
  98. package/tsconfig.json +14 -0
  99. package/update_version.js +8 -0
@@ -0,0 +1,58 @@
1
+ export type ContentScriptMessage =
2
+ | ClickMessage
3
+ | ElemExistsMessage
4
+ | ElemVisibleMessage
5
+ | GetAttributeMessage
6
+ | EvalMessage
7
+ | HideMessage
8
+ | UndoHideMessage
9
+ | MatchesMessage
10
+ | ActionMessage;
11
+
12
+ type ClickMessage = {
13
+ type: "click";
14
+ selector: string;
15
+ all?: boolean;
16
+ };
17
+
18
+ type ElemExistsMessage = {
19
+ type: "elemExists";
20
+ selector: string;
21
+ };
22
+
23
+ type ElemVisibleMessage = {
24
+ type: "elemVisible";
25
+ selector: string;
26
+ check?: "any" | "none" | "all";
27
+ };
28
+
29
+ type GetAttributeMessage = {
30
+ type: "getAttribute";
31
+ selector: string;
32
+ attribute: string;
33
+ };
34
+
35
+ type EvalMessage = {
36
+ type: "eval";
37
+ script: string;
38
+ };
39
+
40
+ type HideMessage = {
41
+ type: "hide";
42
+ selectors: string[];
43
+ };
44
+
45
+ type UndoHideMessage = {
46
+ type: "undohide"
47
+ };
48
+
49
+ type MatchesMessage = {
50
+ type: "matches";
51
+ config: any;
52
+ };
53
+
54
+ type ActionMessage = {
55
+ type: "executeAction";
56
+ config: any;
57
+ param: any;
58
+ };
package/lib/node.js ADDED
@@ -0,0 +1,30 @@
1
+ import Tab from './puppet/tab';
2
+ import detectDialog from './detector';
3
+ import TabConsent from './tabwrapper';
4
+ export * from './index';
5
+ export { ConsentOMaticCMP } from './consentomatic/index';
6
+ export { Tab, detectDialog, TabConsent, };
7
+ export function attachToPage(page, url, rules, retries = 1) {
8
+ const frames = {};
9
+ const tab = new Tab(page, url, frames);
10
+ frames[0] = page.mainFrame();
11
+ async function onFrame(frame) {
12
+ const allFrames = await page.frames();
13
+ allFrames.forEach((frame, frameId) => {
14
+ const frameMatch = rules.findIndex(r => r.detectFrame(tab, {
15
+ url: frame.url(),
16
+ }));
17
+ if (frameMatch > -1) {
18
+ tab.frame = {
19
+ type: rules[frameMatch].name,
20
+ url: frame.url(),
21
+ id: frameId,
22
+ };
23
+ frames[frameId] = frame;
24
+ }
25
+ });
26
+ }
27
+ page.on('framenavigated', onFrame);
28
+ page.frames().forEach(onFrame);
29
+ return new TabConsent(tab, detectDialog(tab, retries, rules));
30
+ }
package/lib/node.ts ADDED
@@ -0,0 +1,38 @@
1
+ import Tab from './puppet/tab';
2
+ import detectDialog from './detector';
3
+ import TabConsent from './tabwrapper';
4
+ import { AutoCMP } from './types';
5
+
6
+ export * from './index';
7
+ export { ConsentOMaticCMP } from './consentomatic/index';
8
+ export {
9
+ Tab,
10
+ detectDialog,
11
+ TabConsent,
12
+ }
13
+
14
+ export function attachToPage(page: any, url: string, rules: AutoCMP[], retries = 1) {
15
+ const frames: { [id: number]: any } = {};
16
+ const tab = new Tab(page, url, frames);
17
+ frames[0] = page.mainFrame();
18
+
19
+ async function onFrame(frame: any) {
20
+ const allFrames: any[] = await page.frames();
21
+ allFrames.forEach((frame, frameId) => {
22
+ const frameMatch = rules.findIndex(r => r.detectFrame(tab, {
23
+ url: frame.url(),
24
+ }));
25
+ if (frameMatch > -1) {
26
+ tab.frame = {
27
+ type: rules[frameMatch].name,
28
+ url: frame.url(),
29
+ id: frameId,
30
+ };
31
+ frames[frameId] = frame;
32
+ }
33
+ })
34
+ }
35
+ page.on('framenavigated', onFrame);
36
+ page.frames().forEach(onFrame);
37
+ return new TabConsent(tab, detectDialog(tab, retries, rules))
38
+ }
@@ -0,0 +1,114 @@
1
+ import { waitFor } from '../cmps/base';
2
+ import Tools from '../web/consentomatic/tools';
3
+ import { matches } from '../web/consentomatic/index';
4
+ const DEBUG = false;
5
+ export default class Tab {
6
+ constructor(page, url, frames) {
7
+ // puppeteer doesn't have tab IDs
8
+ this.id = 1;
9
+ this.page = page;
10
+ this.url = url;
11
+ this.frames = frames;
12
+ }
13
+ async elementExists(selector, frameId = 0) {
14
+ const elements = await this.frames[frameId].$$(selector);
15
+ DEBUG && console.log('[exists]', selector, elements.length > 0);
16
+ return elements.length > 0;
17
+ }
18
+ async clickElement(selector, frameId = 0) {
19
+ if (await this.elementExists(selector, frameId)) {
20
+ try {
21
+ const result = await this.frames[frameId].evaluate((s) => {
22
+ try {
23
+ document.querySelector(s).click();
24
+ return true;
25
+ }
26
+ catch (e) {
27
+ return e.toString();
28
+ }
29
+ }, selector);
30
+ DEBUG && console.log('[click]', selector, result);
31
+ return result;
32
+ }
33
+ catch (e) {
34
+ return false;
35
+ }
36
+ }
37
+ return false;
38
+ }
39
+ async clickElements(selector, frameId = 0) {
40
+ const elements = await this.frames[frameId].$$(selector);
41
+ DEBUG && console.log('[click all]', selector);
42
+ await this.frames[frameId].evaluate((s) => {
43
+ const elem = document.querySelectorAll(s);
44
+ elem.forEach(e => e.click());
45
+ }, selector);
46
+ return true;
47
+ }
48
+ async elementsAreVisible(selector, check, frameId = 0) {
49
+ if (!await this.elementExists(selector, frameId)) {
50
+ return false;
51
+ }
52
+ const visible = await this.frames[frameId].$$eval(selector, (nodes) => nodes.map((n) => n.offsetParent !== null || window.getComputedStyle(n).display !== "none"));
53
+ DEBUG && console.log('[visible]', selector, check, visible);
54
+ if (visible.length === 0) {
55
+ return false;
56
+ }
57
+ else if (check === 'any') {
58
+ return visible.some(r => r);
59
+ }
60
+ else if (check === 'none') {
61
+ return visible.every(r => !r);
62
+ }
63
+ return visible.every(r => r);
64
+ }
65
+ async getAttribute(selector, attribute, frameId = 0) {
66
+ const elem = await this.frames[frameId].$(selector);
67
+ if (elem) {
68
+ return (await elem.getProperty(attribute)).jsonValue();
69
+ }
70
+ }
71
+ async eval(script, frameId = 0) {
72
+ const result = await this.frames[frameId].evaluate(script);
73
+ DEBUG && console.log('[eval]', script, result);
74
+ return result;
75
+ }
76
+ async waitForElement(selector, timeout, frameId = 0) {
77
+ const interval = 200;
78
+ const times = Math.ceil(timeout / interval);
79
+ return waitFor(() => this.elementExists(selector, frameId), times, interval);
80
+ }
81
+ async waitForThenClick(selector, timeout, frameId = 0) {
82
+ if (await this.waitForElement(selector, timeout, frameId)) {
83
+ return await this.clickElement(selector, frameId);
84
+ }
85
+ return false;
86
+ }
87
+ async hideElements(selectors, frameId = 0) {
88
+ // TODO implement this
89
+ return Promise.resolve(true);
90
+ }
91
+ undoHideElements(frameId) {
92
+ return Promise.resolve(true);
93
+ }
94
+ async goto(url) {
95
+ return this.page.goto(url);
96
+ }
97
+ wait(ms) {
98
+ return new Promise((resolve) => {
99
+ setTimeout(() => resolve(true), ms);
100
+ });
101
+ }
102
+ matches(options) {
103
+ const script = `(() => {
104
+ const Tools = ${Tools.toString()};
105
+ const matches = ${matches.toString()};
106
+ return matches(${JSON.stringify(options)})
107
+ })();
108
+ `;
109
+ return this.frames[0].evaluate(script);
110
+ }
111
+ executeAction(config, param) {
112
+ throw new Error("Method not implemented.");
113
+ }
114
+ }
@@ -0,0 +1,136 @@
1
+ import { waitFor } from '../cmps/base';
2
+ import { TabActor } from '../types';
3
+ import Tools from '../web/consentomatic/tools';
4
+ import { matches } from '../web/consentomatic/index';
5
+
6
+ const DEBUG = false;
7
+
8
+ export default class Tab implements TabActor {
9
+ // puppeteer doesn't have tab IDs
10
+ id = 1
11
+ page: any
12
+ url: any
13
+ frames: { [id: number]: any }
14
+ frame: {
15
+ type: string
16
+ id: number
17
+ url: string
18
+ }
19
+
20
+ constructor(page: any, url: string, frames: { [id: number]: any }) {
21
+ this.page = page;
22
+ this.url = url;
23
+ this.frames = frames;
24
+ }
25
+
26
+ async elementExists(selector: string, frameId = 0) {
27
+ const elements = await this.frames[frameId].$$(selector)
28
+ DEBUG && console.log('[exists]', selector, elements.length > 0);
29
+ return elements.length > 0;
30
+ }
31
+
32
+ async clickElement(selector: string, frameId = 0) {
33
+ if (await this.elementExists(selector, frameId)) {
34
+ try {
35
+ const result = await this.frames[frameId].evaluate((s: string) => {
36
+ try {
37
+ (document.querySelector(s) as HTMLElement).click();
38
+ return true;
39
+ } catch (e) {
40
+ return e.toString();
41
+ }
42
+ }, selector);
43
+ DEBUG && console.log('[click]', selector, result);
44
+ return result;
45
+ } catch (e) {
46
+ return false;
47
+ }
48
+ }
49
+ return false;
50
+ }
51
+
52
+ async clickElements(selector: string, frameId = 0) {
53
+ const elements = await this.frames[frameId].$$(selector);
54
+ DEBUG && console.log('[click all]', selector);
55
+ await this.frames[frameId].evaluate((s: string) => {
56
+ const elem = document.querySelectorAll<HTMLElement>(s);
57
+ elem.forEach(e => e.click());
58
+ }, selector)
59
+ return true;
60
+ }
61
+
62
+ async elementsAreVisible(selector: string, check: 'all' | 'any' | 'none', frameId = 0) {
63
+ if (!await this.elementExists(selector, frameId)) {
64
+ return false;
65
+ }
66
+ const visible: boolean[] = await this.frames[frameId].$$eval(selector, (nodes: any) => nodes.map((n: any) => n.offsetParent !== null || window.getComputedStyle(n).display !== "none"));
67
+ DEBUG && console.log('[visible]', selector, check, visible);
68
+ if (visible.length === 0) {
69
+ return false;
70
+ } else if (check === 'any') {
71
+ return visible.some(r => r);
72
+ } else if (check === 'none') {
73
+ return visible.every(r => !r);
74
+ }
75
+ return visible.every(r => r);
76
+ }
77
+
78
+ async getAttribute(selector: string, attribute: string, frameId = 0) {
79
+ const elem = await this.frames[frameId].$(selector);
80
+ if (elem) {
81
+ return (await elem.getProperty(attribute)).jsonValue();
82
+ }
83
+ }
84
+
85
+ async eval(script: string, frameId = 0) {
86
+ const result = await this.frames[frameId].evaluate(script);
87
+ DEBUG && console.log('[eval]', script, result);
88
+ return result
89
+ }
90
+
91
+ async waitForElement(selector: string, timeout: number, frameId = 0) {
92
+ const interval = 200;
93
+ const times = Math.ceil(timeout / interval);
94
+ return waitFor(() => this.elementExists(selector, frameId), times, interval);
95
+ }
96
+
97
+ async waitForThenClick(selector: string, timeout: number, frameId = 0) {
98
+ if (await this.waitForElement(selector, timeout, frameId)) {
99
+ return await this.clickElement(selector, frameId);
100
+ }
101
+ return false;
102
+ }
103
+
104
+ async hideElements(selectors: string[], frameId = 0) {
105
+ // TODO implement this
106
+ return Promise.resolve(true)
107
+ }
108
+
109
+ undoHideElements(frameId?: number): Promise<boolean> {
110
+ return Promise.resolve(true)
111
+ }
112
+
113
+ async goto(url: string) {
114
+ return this.page.goto(url);
115
+ }
116
+
117
+ wait(ms: number): Promise<true> {
118
+ return new Promise((resolve) => {
119
+ setTimeout(() => resolve(true), ms);
120
+ });
121
+ }
122
+
123
+ matches(options: any): Promise<boolean> {
124
+ const script = `(() => {
125
+ const Tools = ${Tools.toString()};
126
+ const matches = ${matches.toString()};
127
+ return matches(${JSON.stringify(options)})
128
+ })();
129
+ `
130
+ return this.frames[0].evaluate(script)
131
+ }
132
+
133
+ executeAction(config: any, param?: any): Promise<boolean> {
134
+ throw new Error("Method not implemented.");
135
+ }
136
+ }
package/lib/rules.d.ts ADDED
@@ -0,0 +1,80 @@
1
+
2
+ export type AutoConsentCMPRule = {
3
+ name: string
4
+ prehideSelectors?: string[]
5
+ isHidingRule?: boolean
6
+ detectCmp: AutoConsentRuleStep[]
7
+ detectPopup: AutoConsentRuleStep[]
8
+ frame?: string
9
+ optOut: AutoConsentRuleStep[]
10
+ optIn: AutoConsentRuleStep[]
11
+ openCmp?: AutoConsentRuleStep[]
12
+ test?: AutoConsentRuleStep[]
13
+ }
14
+
15
+ export type AutoConsentRuleStep = { frame?: boolean; optional?: boolean } & Partial<
16
+ ElementExistsRule
17
+ > &
18
+ Partial<ElementVisibleRule> &
19
+ Partial<EvalRule> &
20
+ Partial<WaitForRule> &
21
+ Partial<ClickRule> &
22
+ Partial<WaitForThenClickRule> &
23
+ Partial<WaitRule> &
24
+ Partial<UrlRule> &
25
+ Partial<GotoUrlRule> &
26
+ Partial<HideRule> &
27
+ Partial<UndoHideRule> &
28
+ Partial<WaitForFrameRule>;
29
+
30
+ type ElementExistsRule = {
31
+ exists: string;
32
+ };
33
+
34
+ type ElementVisibleRule = {
35
+ visible: string;
36
+ check?: "any" | "all" | "none";
37
+ };
38
+
39
+ type EvalRule = {
40
+ eval: string;
41
+ };
42
+
43
+ type WaitForRule = {
44
+ waitFor: string;
45
+ timeout?: number;
46
+ };
47
+
48
+ type ClickRule = {
49
+ click: string;
50
+ all?: boolean;
51
+ };
52
+
53
+ type WaitForThenClickRule = {
54
+ waitForThenClick: string;
55
+ timeout?: number;
56
+ };
57
+
58
+ type WaitRule = {
59
+ wait: number;
60
+ };
61
+
62
+ type UrlRule = {
63
+ url: string;
64
+ };
65
+
66
+ type GotoUrlRule = {
67
+ goto: string;
68
+ };
69
+
70
+ type HideRule = {
71
+ hide: string[];
72
+ };
73
+
74
+ type UndoHideRule = {
75
+ undoHide: boolean;
76
+ }
77
+
78
+ type WaitForFrameRule = {
79
+ waitForFrame: true
80
+ };
@@ -0,0 +1,61 @@
1
+ export default class TabConsent {
2
+ constructor(tab, ruleCheckPromise) {
3
+ this.tab = tab;
4
+ this.optOutStatus = null;
5
+ this.checked = ruleCheckPromise;
6
+ ruleCheckPromise.then(rule => this.rule = rule);
7
+ }
8
+ getCMPName() {
9
+ if (this.rule) {
10
+ return this.rule.name;
11
+ }
12
+ return null;
13
+ }
14
+ async isPopupOpen(retries = 1, interval = 1000) {
15
+ const isOpen = await this.rule.detectPopup(this.tab);
16
+ if (!isOpen && retries > 0) {
17
+ return new Promise((resolve) => setTimeout(() => resolve(this.isPopupOpen(retries - 1, interval)), interval));
18
+ }
19
+ return isOpen;
20
+ }
21
+ async doOptOut() {
22
+ try {
23
+ this.optOutStatus = await this.rule.optOut(this.tab);
24
+ return this.optOutStatus;
25
+ }
26
+ catch (e) {
27
+ this.optOutStatus = e;
28
+ throw e;
29
+ }
30
+ finally {
31
+ if (!this.rule.isHidingRule) {
32
+ if (this.getCMPName().startsWith('com_')) {
33
+ this.tab.wait(5000).then(() => this.tab.undoHideElements());
34
+ }
35
+ else {
36
+ await this.tab.undoHideElements();
37
+ }
38
+ }
39
+ }
40
+ }
41
+ async doOptIn() {
42
+ try {
43
+ return this.rule.optIn(this.tab);
44
+ }
45
+ finally {
46
+ if (!this.rule.isHidingRule) {
47
+ await this.tab.undoHideElements();
48
+ }
49
+ }
50
+ }
51
+ hasTest() {
52
+ return !!this.rule.hasSelfTest;
53
+ }
54
+ async testOptOutWorked() {
55
+ return this.rule.test(this.tab);
56
+ }
57
+ async applyCosmetics(selectors) {
58
+ const hidden = await this.tab.hideElements(selectors);
59
+ return hidden;
60
+ }
61
+ }
@@ -0,0 +1,68 @@
1
+ import { AutoCMP, TabActor } from './types';
2
+
3
+ export default class TabConsent {
4
+ checked: Promise<AutoCMP>
5
+ rule: AutoCMP
6
+ optOutStatus: boolean | Error = null
7
+
8
+ constructor(public tab: TabActor, ruleCheckPromise: Promise<AutoCMP>) {
9
+ this.checked = ruleCheckPromise;
10
+ ruleCheckPromise.then(rule => this.rule = rule);
11
+ }
12
+
13
+ getCMPName() {
14
+ if (this.rule) {
15
+ return this.rule.name;
16
+ }
17
+ return null;
18
+ }
19
+
20
+ async isPopupOpen(retries = 1, interval = 1000): Promise<boolean> {
21
+ const isOpen = await this.rule.detectPopup(this.tab);
22
+ if (!isOpen && retries > 0) {
23
+ return new Promise((resolve) => setTimeout(() => resolve(this.isPopupOpen(retries - 1, interval)), interval));
24
+ }
25
+ return isOpen;
26
+ }
27
+
28
+ async doOptOut() {
29
+ try {
30
+ this.optOutStatus = await this.rule.optOut(this.tab);
31
+ return this.optOutStatus;
32
+ } catch (e) {
33
+ this.optOutStatus = e;
34
+ throw e;
35
+ } finally {
36
+ if (!this.rule.isHidingRule) {
37
+ if (this.getCMPName().startsWith('com_')) {
38
+ this.tab.wait(5000).then(() => this.tab.undoHideElements())
39
+ } else {
40
+ await this.tab.undoHideElements();
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ async doOptIn() {
47
+ try {
48
+ return this.rule.optIn(this.tab);
49
+ } finally {
50
+ if (!this.rule.isHidingRule) {
51
+ await this.tab.undoHideElements();
52
+ }
53
+ }
54
+ }
55
+
56
+ hasTest() {
57
+ return !!this.rule.hasSelfTest
58
+ }
59
+
60
+ async testOptOutWorked() {
61
+ return this.rule.test(this.tab);
62
+ }
63
+
64
+ async applyCosmetics(selectors: string[]) {
65
+ const hidden = await this.tab.hideElements(selectors);
66
+ return hidden;
67
+ }
68
+ }
package/lib/types.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { ContentScriptMessage } from "./messages";
2
+
3
+ type Tab = {
4
+ url: string
5
+ }
6
+
7
+ type BrowserTabs = {
8
+ get(tabId: number): Promise<Tab>
9
+ update(tabId: number, options: any): Promise<void>
10
+ }
11
+
12
+ export type Browser = {
13
+ tabs: BrowserTabs,
14
+ }
15
+
16
+ export interface TabActor {
17
+ frame?: {
18
+ id: number
19
+ url: string
20
+ }
21
+ id: number
22
+ elementExists(selector: string, frameId?: number): Promise<boolean>
23
+ clickElement(selector: string, frameId?: number): Promise<boolean>
24
+ clickElements(selector: string, frameId?: number): Promise<boolean>
25
+ elementsAreVisible(selector: string, check?: 'all' | 'any' | 'none', frameId?: number): Promise<boolean>
26
+ getAttribute(selector: string, attribute: string, frameId?: number): Promise<string>
27
+ eval(script: string, frameId?: number): Promise<boolean>
28
+ waitForElement(selector: string, timeout: number, frameId?: number): Promise<boolean>
29
+ waitForThenClick(selector: string, timeout?: number, frameId?: number): Promise<boolean>
30
+ hideElements(selectors: string[], frameId?: number): Promise<boolean>
31
+ undoHideElements(frameId?: number): Promise<boolean>
32
+ goto(url: string): Promise<void>
33
+ wait(ms: number): Promise<true>
34
+
35
+ // Consent-O-Matic methods
36
+ matches(matcherConfig: any): Promise<boolean>
37
+ executeAction(actionConfig: any, param?: any): Promise<boolean>
38
+ }
39
+
40
+ export type MessageSender<ResultType = any> = (tabId: number, message: ContentScriptMessage, options?: { frameId: number }) => Promise<ResultType>;
41
+
42
+ export interface AutoCMP {
43
+ name: string
44
+ hasSelfTest: boolean
45
+ prehideSelectors?: string[]
46
+ isHidingRule?: boolean
47
+ detectCmp(tab: TabActor): Promise<boolean>
48
+ detectPopup(tab: TabActor): Promise<boolean>
49
+ optOut(tab:TabActor): Promise<boolean>
50
+ optIn(tab: TabActor): Promise<boolean>
51
+ openCmp(tab: TabActor): Promise<boolean>
52
+ test(tab: TabActor): Promise<boolean>
53
+ detectFrame(tab: TabActor, frame: { url: string }): boolean
54
+ }
55
+
56
+ type FindResult = {
57
+ parent?: any
58
+ target?: {
59
+ checked: boolean
60
+ }
61
+ }