@duckduckgo/autoconsent 14.97.0 → 15.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/CHANGELOG.md +18 -0
- package/dist/addon-firefox/background.bundle.js +10 -1
- package/dist/addon-firefox/compact-rules.json +1 -1
- package/dist/addon-firefox/content.bundle.js +142 -33
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/popup.bundle.js +10 -1
- package/dist/addon-firefox/rules.json +1 -1
- package/dist/addon-mv3/background.bundle.js +10 -1
- package/dist/addon-mv3/compact-rules.json +1 -1
- package/dist/addon-mv3/content.bundle.js +142 -33
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/popup.bundle.js +10 -1
- package/dist/addon-mv3/rules.json +1 -1
- package/dist/autoconsent.cjs.js +142 -33
- package/dist/autoconsent.esm.js +142 -33
- package/dist/autoconsent.extra.cjs.js +142 -33
- package/dist/autoconsent.extra.esm.js +142 -33
- package/dist/autoconsent.playwright.js +142 -33
- package/dist/types/cmps/base.d.ts +4 -2
- package/dist/types/heuristic-patterns.d.ts +3 -0
- package/dist/types/heuristics.d.ts +4 -7
- package/dist/types/types.d.ts +18 -2
- package/lib/cmps/base.ts +20 -7
- package/lib/heuristic-patterns.ts +68 -1
- package/lib/heuristics.ts +76 -27
- package/lib/types.ts +20 -2
- package/lib/utils.ts +2 -1
- package/lib/web.ts +3 -1
- package/package.json +1 -1
- package/rules/autoconsent/twitch.json +1 -1
- package/rules/compact-rules.json +1 -1
- package/rules/rules.json +1 -1
- package/tests-wtr/heuristics/get-actionable-popups.html +16 -0
- package/tests-wtr/heuristics/get-actionable-popups.ts +85 -6
- package/tests-wtr/heuristics/heuristic-cmp.html +69 -0
- package/tests-wtr/heuristics/heuristic-cmp.ts +178 -0
- package/tests-wtr/heuristics/heuristics-utils.test.ts +96 -28
- package/tests-wtr/lifecycle/find-cmp.html +14 -0
- package/tests-wtr/lifecycle/find-cmp.ts +44 -2
|
@@ -400,6 +400,14 @@
|
|
|
400
400
|
});
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
+
// lib/types.ts
|
|
404
|
+
var PopupHandlingModes = {
|
|
405
|
+
None: -1,
|
|
406
|
+
Reject: 0,
|
|
407
|
+
Tier1: 1,
|
|
408
|
+
Tier2: 2
|
|
409
|
+
};
|
|
410
|
+
|
|
403
411
|
// lib/random.ts
|
|
404
412
|
function getRandomID() {
|
|
405
413
|
if (crypto && typeof crypto.randomUUID !== "undefined") {
|
|
@@ -709,7 +717,8 @@
|
|
|
709
717
|
waits: false
|
|
710
718
|
},
|
|
711
719
|
performanceLoggingEnabled: false,
|
|
712
|
-
heuristicPopupSearchTimeout: 100
|
|
720
|
+
heuristicPopupSearchTimeout: 100,
|
|
721
|
+
heuristicMode: PopupHandlingModes.Reject
|
|
713
722
|
};
|
|
714
723
|
const updatedConfig = copyObject(defaultConfig);
|
|
715
724
|
for (const key of Object.keys(defaultConfig)) {
|
|
@@ -876,12 +885,17 @@
|
|
|
876
885
|
/^\s*(use|accept|allow|continue\s+with)?\s*only\s*(strictly)?\s*(necessary|essentials?|required)?\s*(cookies)?\s*$/is,
|
|
877
886
|
// e.g. "do not sell or share my personal information", "do not sell my personal information"
|
|
878
887
|
// often used in CCPA
|
|
879
|
-
/^\s*do\s+not\s+sell(\s+or\s+share)?\s*my\s*personal\s*
|
|
888
|
+
/^\s*do\s+not\s+sell(\s+or\s+share)?\s*my\s*personal\s*info(rmation)?\s*$/is,
|
|
880
889
|
"allow selection",
|
|
881
|
-
"disagree and close"
|
|
890
|
+
"disagree and close",
|
|
882
891
|
// These are impactful, but look error-prone
|
|
892
|
+
// // e.g. "disagree"
|
|
893
|
+
/^(i)?\s*disagree\s*(and\s+close)?$/i,
|
|
883
894
|
// // e.g. "i do not agree"
|
|
884
895
|
// /^\s*(i\s+)?do\s+not\s+agree\s*$/i,
|
|
896
|
+
"no",
|
|
897
|
+
/^no,? thanks$/is,
|
|
898
|
+
/^opt[ -]out$/is
|
|
885
899
|
];
|
|
886
900
|
var REJECT_PATTERNS_DUTCH = [
|
|
887
901
|
"weigeren",
|
|
@@ -1457,6 +1471,64 @@
|
|
|
1457
1471
|
/sostienici/is,
|
|
1458
1472
|
/suscribir/is
|
|
1459
1473
|
];
|
|
1474
|
+
var SETTINGS_PATTERNS = [
|
|
1475
|
+
"settings",
|
|
1476
|
+
"preferences",
|
|
1477
|
+
/customi(s|z)e/is,
|
|
1478
|
+
"show details",
|
|
1479
|
+
"more options",
|
|
1480
|
+
/(manage|configure) (my|your) (preferences|choices|cookies)/is,
|
|
1481
|
+
"manage choices",
|
|
1482
|
+
/(cookie )?preference center/is,
|
|
1483
|
+
"change settings",
|
|
1484
|
+
"configure",
|
|
1485
|
+
"change my preferences",
|
|
1486
|
+
"cookie manager",
|
|
1487
|
+
"cookie preference",
|
|
1488
|
+
"let me choose",
|
|
1489
|
+
"cookieconsent preferences",
|
|
1490
|
+
/privacy choices/is,
|
|
1491
|
+
/(privacy|cookie|custom) settings/is,
|
|
1492
|
+
/cookies? (settings|preferences|setting)/is,
|
|
1493
|
+
/(manage|customize|customise|opt-out|edit).*(cookies|preferences|settings|options)/is,
|
|
1494
|
+
"cookie consent options",
|
|
1495
|
+
"privacy controls",
|
|
1496
|
+
"show purposes",
|
|
1497
|
+
// German
|
|
1498
|
+
"einstellungen"
|
|
1499
|
+
];
|
|
1500
|
+
var ACCEPT_PATTERNS = [
|
|
1501
|
+
/^(accept|allow)( all)?( cookies)?$/is,
|
|
1502
|
+
/i (accept|allow)( all)?/is,
|
|
1503
|
+
"yes",
|
|
1504
|
+
/^(i )?agree$/is,
|
|
1505
|
+
"continue with all",
|
|
1506
|
+
"accept and continue",
|
|
1507
|
+
/accept all above/is,
|
|
1508
|
+
/^(accept|agree) and close/is,
|
|
1509
|
+
"accept continue",
|
|
1510
|
+
"agree proceed",
|
|
1511
|
+
"allow and continue",
|
|
1512
|
+
"close and accept",
|
|
1513
|
+
/accept all$/is,
|
|
1514
|
+
"im ok with that",
|
|
1515
|
+
"accept optional cookies",
|
|
1516
|
+
/^alle (cookies )?akzeptieren$/is
|
|
1517
|
+
];
|
|
1518
|
+
var ACKNOWLEDGE_PATTERNS = [
|
|
1519
|
+
"ok",
|
|
1520
|
+
"close",
|
|
1521
|
+
"continue",
|
|
1522
|
+
"x",
|
|
1523
|
+
/^got it!?$/,
|
|
1524
|
+
"i understand",
|
|
1525
|
+
"dismiss",
|
|
1526
|
+
"okay",
|
|
1527
|
+
"acknowledge",
|
|
1528
|
+
/^close (banner|cookie notification)$/is,
|
|
1529
|
+
/understood$/is,
|
|
1530
|
+
"confirm my choices"
|
|
1531
|
+
];
|
|
1460
1532
|
|
|
1461
1533
|
// lib/heuristics.ts
|
|
1462
1534
|
var BUTTON_LIKE_ELEMENT_SELECTOR = 'button, input[type="button"], input[type="submit"], a, [role="button"], [class*="button"]';
|
|
@@ -1475,48 +1547,61 @@
|
|
|
1475
1547
|
}
|
|
1476
1548
|
return { patterns, snippets: snippets2 };
|
|
1477
1549
|
}
|
|
1478
|
-
function getActionablePopups(timeout = POPUP_SEARCH_MAX_TIME) {
|
|
1550
|
+
function getActionablePopups(mode = PopupHandlingModes.Reject, timeout = POPUP_SEARCH_MAX_TIME) {
|
|
1479
1551
|
const popups = getPotentialPopups(timeout);
|
|
1480
1552
|
const result = popups.reduce((acc, popup) => {
|
|
1481
1553
|
const popupText = popup.text?.trim();
|
|
1482
1554
|
if (popupText) {
|
|
1483
1555
|
const { patterns } = checkHeuristicPatterns(popupText);
|
|
1484
1556
|
if (patterns.length > 0) {
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
otherButtons
|
|
1491
|
-
});
|
|
1492
|
-
}
|
|
1557
|
+
classifyButtons(popup.buttons);
|
|
1558
|
+
popup.regexClassification = classifyPopup(popup.buttons);
|
|
1559
|
+
acc.push({
|
|
1560
|
+
...popup
|
|
1561
|
+
});
|
|
1493
1562
|
}
|
|
1494
1563
|
}
|
|
1495
1564
|
return acc;
|
|
1496
1565
|
}, []);
|
|
1497
|
-
return result
|
|
1566
|
+
return result.filter(
|
|
1567
|
+
(popup) => popup.regexClassification !== void 0 && popup.regexClassification !== PopupHandlingModes.None && popup.regexClassification <= mode
|
|
1568
|
+
).sort((a, b) => (a.regexClassification ?? 0) - (b.regexClassification ?? 0));
|
|
1498
1569
|
}
|
|
1499
1570
|
function classifyButtons(buttons) {
|
|
1500
|
-
const rejectButtons = [];
|
|
1501
|
-
const otherButtons = [];
|
|
1502
1571
|
for (const button of buttons) {
|
|
1503
|
-
|
|
1504
|
-
rejectButtons.push(button);
|
|
1505
|
-
} else {
|
|
1506
|
-
otherButtons.push(button);
|
|
1507
|
-
}
|
|
1572
|
+
button.regexClassification = classifyButtonTextRegex(button.text);
|
|
1508
1573
|
}
|
|
1509
|
-
return {
|
|
1510
|
-
rejectButtons,
|
|
1511
|
-
otherButtons
|
|
1512
|
-
};
|
|
1513
1574
|
}
|
|
1514
|
-
function
|
|
1575
|
+
function classifyPopup(buttons) {
|
|
1576
|
+
const { reject, settings, accept, acknowledge } = buttons.reduce(
|
|
1577
|
+
(acc, button) => {
|
|
1578
|
+
if (button.regexClassification && button.regexClassification !== "other") {
|
|
1579
|
+
acc[button.regexClassification]++;
|
|
1580
|
+
}
|
|
1581
|
+
return acc;
|
|
1582
|
+
},
|
|
1583
|
+
{ reject: 0, settings: 0, accept: 0, acknowledge: 0 }
|
|
1584
|
+
);
|
|
1585
|
+
if (reject > 0) {
|
|
1586
|
+
return PopupHandlingModes.Reject;
|
|
1587
|
+
}
|
|
1588
|
+
if (settings > 0) {
|
|
1589
|
+
return PopupHandlingModes.None;
|
|
1590
|
+
}
|
|
1591
|
+
if (acknowledge > 0) {
|
|
1592
|
+
return PopupHandlingModes.Tier1;
|
|
1593
|
+
}
|
|
1594
|
+
if (accept > 0) {
|
|
1595
|
+
return accept === 1 ? PopupHandlingModes.Tier2 : PopupHandlingModes.None;
|
|
1596
|
+
}
|
|
1597
|
+
return PopupHandlingModes.None;
|
|
1598
|
+
}
|
|
1599
|
+
function testButtonMatches(buttonText, matchPatterns, neverMatchPatterns) {
|
|
1515
1600
|
if (!buttonText) {
|
|
1516
1601
|
return false;
|
|
1517
1602
|
}
|
|
1518
1603
|
const cleanedButtonText = cleanButtonText(buttonText);
|
|
1519
|
-
return !neverMatchPatterns.some((p) => p.test(cleanedButtonText)) &&
|
|
1604
|
+
return !neverMatchPatterns.some((p) => p instanceof RegExp && p.test(cleanedButtonText) || p === cleanedButtonText) && matchPatterns.some((p) => p instanceof RegExp && p.test(cleanedButtonText) || p === cleanedButtonText);
|
|
1520
1605
|
}
|
|
1521
1606
|
function cleanButtonText(buttonText) {
|
|
1522
1607
|
let result = buttonText.toLowerCase();
|
|
@@ -1530,6 +1615,21 @@
|
|
|
1530
1615
|
result = result.trim();
|
|
1531
1616
|
return result;
|
|
1532
1617
|
}
|
|
1618
|
+
function classifyButtonTextRegex(buttonText) {
|
|
1619
|
+
if (testButtonMatches(buttonText, REJECT_PATTERNS, NEVER_MATCH_PATTERNS)) {
|
|
1620
|
+
return "reject";
|
|
1621
|
+
}
|
|
1622
|
+
if (testButtonMatches(buttonText, SETTINGS_PATTERNS, NEVER_MATCH_PATTERNS)) {
|
|
1623
|
+
return "settings";
|
|
1624
|
+
}
|
|
1625
|
+
if (testButtonMatches(buttonText, ACCEPT_PATTERNS, NEVER_MATCH_PATTERNS)) {
|
|
1626
|
+
return "accept";
|
|
1627
|
+
}
|
|
1628
|
+
if (testButtonMatches(buttonText, ACKNOWLEDGE_PATTERNS, NEVER_MATCH_PATTERNS)) {
|
|
1629
|
+
return "acknowledge";
|
|
1630
|
+
}
|
|
1631
|
+
return "other";
|
|
1632
|
+
}
|
|
1533
1633
|
function getPotentialPopups(timeout = POPUP_SEARCH_MAX_TIME) {
|
|
1534
1634
|
const isFramed = !isTopFrame();
|
|
1535
1635
|
if (isFramed && window.parent && window.parent !== window.top) {
|
|
@@ -1975,7 +2075,7 @@
|
|
|
1975
2075
|
}
|
|
1976
2076
|
};
|
|
1977
2077
|
var AutoConsentHeuristicCMP = class extends AutoConsentCMPBase {
|
|
1978
|
-
constructor(autoconsentInstance) {
|
|
2078
|
+
constructor(autoconsentInstance, mode = PopupHandlingModes.Reject) {
|
|
1979
2079
|
super(autoconsentInstance);
|
|
1980
2080
|
this.popups = [];
|
|
1981
2081
|
this.name = "HEURISTIC";
|
|
@@ -1984,6 +2084,7 @@
|
|
|
1984
2084
|
frame: false
|
|
1985
2085
|
// do not run in iframes for security reasons
|
|
1986
2086
|
};
|
|
2087
|
+
this.mode = mode;
|
|
1987
2088
|
}
|
|
1988
2089
|
get hasSelfTest() {
|
|
1989
2090
|
return true;
|
|
@@ -1997,25 +2098,33 @@
|
|
|
1997
2098
|
async detectCmp() {
|
|
1998
2099
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1999
2100
|
this.autoconsent.config.performanceLoggingEnabled && performance.mark("heuristicDetectorStart");
|
|
2000
|
-
this.popups = getActionablePopups(this.autoconsent.config.heuristicPopupSearchTimeout);
|
|
2101
|
+
this.popups = getActionablePopups(this.mode, this.autoconsent.config.heuristicPopupSearchTimeout);
|
|
2001
2102
|
this.autoconsent.config.performanceLoggingEnabled && performance.mark("heuristicDetectorEnd");
|
|
2002
2103
|
this.autoconsent.config.performanceLoggingEnabled && performance.measure("heuristicDetector", "heuristicDetectorStart", "heuristicDetectorEnd");
|
|
2003
2104
|
if (this.popups.length > 0) {
|
|
2105
|
+
this.name = `HEURISTIC-TIER${this.popups[0].regexClassification}`;
|
|
2004
2106
|
return Promise.resolve(true);
|
|
2005
2107
|
}
|
|
2006
2108
|
return Promise.resolve(false);
|
|
2007
2109
|
}
|
|
2008
2110
|
async detectPopup() {
|
|
2009
2111
|
if (this.popups.length > 0) {
|
|
2010
|
-
if (this.popups.length > 1
|
|
2011
|
-
this.autoconsent.config.logs.errors && console.warn("Heuristic found multiple
|
|
2112
|
+
if (this.popups.length > 1) {
|
|
2113
|
+
this.autoconsent.config.logs.errors && console.warn("Heuristic found multiple popups");
|
|
2012
2114
|
}
|
|
2013
2115
|
return true;
|
|
2014
2116
|
}
|
|
2015
2117
|
return false;
|
|
2016
2118
|
}
|
|
2119
|
+
getTargetButton() {
|
|
2120
|
+
const popup = this.popups[0];
|
|
2121
|
+
const level = popup.regexClassification;
|
|
2122
|
+
const buttons = popup.buttons;
|
|
2123
|
+
const targetButtonType = level === PopupHandlingModes.Reject ? "reject" : level === PopupHandlingModes.Tier1 ? "acknowledge" : "accept";
|
|
2124
|
+
return buttons.find((button) => button.regexClassification === targetButtonType);
|
|
2125
|
+
}
|
|
2017
2126
|
optOut() {
|
|
2018
|
-
const button = this.
|
|
2127
|
+
const button = this.getTargetButton();
|
|
2019
2128
|
if (button) {
|
|
2020
2129
|
return this.clickElement(button.element);
|
|
2021
2130
|
}
|
|
@@ -2028,7 +2137,7 @@
|
|
|
2028
2137
|
throw new Error("Not Implemented");
|
|
2029
2138
|
}
|
|
2030
2139
|
async test() {
|
|
2031
|
-
const button = this.
|
|
2140
|
+
const button = this.getTargetButton();
|
|
2032
2141
|
if (button) {
|
|
2033
2142
|
await this.wait(500);
|
|
2034
2143
|
return !isElementVisible(button.element);
|
|
@@ -3497,7 +3606,7 @@
|
|
|
3497
3606
|
}
|
|
3498
3607
|
}
|
|
3499
3608
|
});
|
|
3500
|
-
const heuristicRules = isTop && this.config.enableHeuristicAction && this.state.findCmpAttempts % 2 === 0 ? [new AutoConsentHeuristicCMP(this)] : [];
|
|
3609
|
+
const heuristicRules = isTop && this.config.enableHeuristicAction && this.state.findCmpAttempts % 2 === 0 ? [new AutoConsentHeuristicCMP(this, this.config.heuristicMode)] : [];
|
|
3501
3610
|
const rulesPriorityStages = [
|
|
3502
3611
|
["site-specific", siteSpecificRules],
|
|
3503
3612
|
["generic", genericRules],
|
|
@@ -761,6 +761,14 @@
|
|
|
761
761
|
return parseImpl(url, 5, suffixLookup, options, getEmptyResult());
|
|
762
762
|
}
|
|
763
763
|
|
|
764
|
+
// lib/types.ts
|
|
765
|
+
var PopupHandlingModes = {
|
|
766
|
+
None: -1,
|
|
767
|
+
Reject: 0,
|
|
768
|
+
Tier1: 1,
|
|
769
|
+
Tier2: 2
|
|
770
|
+
};
|
|
771
|
+
|
|
764
772
|
// lib/utils.ts
|
|
765
773
|
function copyObject(data) {
|
|
766
774
|
if (globalThis.structuredClone) {
|
|
@@ -795,7 +803,8 @@
|
|
|
795
803
|
waits: false
|
|
796
804
|
},
|
|
797
805
|
performanceLoggingEnabled: false,
|
|
798
|
-
heuristicPopupSearchTimeout: 100
|
|
806
|
+
heuristicPopupSearchTimeout: 100,
|
|
807
|
+
heuristicMode: PopupHandlingModes.Reject
|
|
799
808
|
};
|
|
800
809
|
const updatedConfig = copyObject(defaultConfig);
|
|
801
810
|
for (const key of Object.keys(defaultConfig)) {
|