@duckduckgo/autoconsent 14.97.0 → 15.1.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 +30 -0
- package/build.sh +3 -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 +157 -40
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/popup.bundle.js +190 -14
- package/dist/addon-firefox/popup.html +93 -8
- package/dist/addon-firefox/rule-index.json +1 -0
- 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 +157 -40
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/popup.bundle.js +190 -14
- package/dist/addon-mv3/popup.html +93 -8
- package/dist/addon-mv3/rule-index.json +1 -0
- package/dist/addon-mv3/rules.json +1 -1
- package/dist/autoconsent.cjs.js +157 -40
- package/dist/autoconsent.esm.js +157 -40
- package/dist/autoconsent.extra.cjs.js +157 -40
- package/dist/autoconsent.extra.esm.js +157 -40
- package/dist/autoconsent.playwright.js +157 -40
- package/dist/autoconsent.standalone.js +4138 -0
- package/dist/types/cmps/base.d.ts +4 -2
- package/dist/types/cmps/trustarc-top.d.ts +1 -1
- package/dist/types/eval-handler.d.ts +3 -3
- 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/cmps/conversant.ts +7 -4
- package/lib/cmps/trustarc-top.ts +1 -1
- package/lib/cmps/uniconsent.ts +4 -4
- package/lib/eval-handler.ts +6 -3
- package/lib/heuristic-patterns.ts +68 -1
- package/lib/heuristics.ts +76 -27
- package/lib/types.ts +20 -2
- package/lib/utils.ts +13 -6
- package/lib/web.ts +3 -1
- package/package.json +1 -1
- package/rules/autoconsent/twitch.json +1 -1
- package/rules/build.ts +4 -0
- package/rules/compact-rules.json +1 -1
- package/rules/rule-index-builder.ts +63 -0
- package/rules/rule-index.json +1 -0
- package/rules/rules.json +1 -1
- package/standalone/content.ts +103 -0
- 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") {
|
|
@@ -426,6 +434,9 @@
|
|
|
426
434
|
sendContentMessage: null
|
|
427
435
|
};
|
|
428
436
|
function requestEval(code, snippetId) {
|
|
437
|
+
if (!evalState.sendContentMessage) {
|
|
438
|
+
return Promise.reject(new Error("AutoConsent is not initialized yet"));
|
|
439
|
+
}
|
|
429
440
|
const id = getRandomID();
|
|
430
441
|
evalState.sendContentMessage({
|
|
431
442
|
type: "eval",
|
|
@@ -709,7 +720,8 @@
|
|
|
709
720
|
waits: false
|
|
710
721
|
},
|
|
711
722
|
performanceLoggingEnabled: false,
|
|
712
|
-
heuristicPopupSearchTimeout: 100
|
|
723
|
+
heuristicPopupSearchTimeout: 100,
|
|
724
|
+
heuristicMode: PopupHandlingModes.Reject
|
|
713
725
|
};
|
|
714
726
|
const updatedConfig = copyObject(defaultConfig);
|
|
715
727
|
for (const key of Object.keys(defaultConfig)) {
|
|
@@ -727,12 +739,13 @@
|
|
|
727
739
|
}
|
|
728
740
|
}
|
|
729
741
|
function highlightNode(node) {
|
|
742
|
+
const highlightedNode = node;
|
|
730
743
|
if (!node.style) return;
|
|
731
|
-
if (
|
|
744
|
+
if (highlightedNode.__oldStyles !== void 0) {
|
|
732
745
|
return;
|
|
733
746
|
}
|
|
734
747
|
if (node.hasAttribute("style")) {
|
|
735
|
-
|
|
748
|
+
highlightedNode.__oldStyles = node.style.cssText;
|
|
736
749
|
}
|
|
737
750
|
node.style.animation = "pulsate .5s infinite";
|
|
738
751
|
node.style.outline = "solid red";
|
|
@@ -760,10 +773,11 @@
|
|
|
760
773
|
document.head.appendChild(styleTag);
|
|
761
774
|
}
|
|
762
775
|
function unhighlightNode(node) {
|
|
776
|
+
const highlightedNode = node;
|
|
763
777
|
if (!node.style || !node.hasAttribute("style")) return;
|
|
764
|
-
if (
|
|
765
|
-
node.style.cssText =
|
|
766
|
-
delete
|
|
778
|
+
if (highlightedNode.__oldStyles !== void 0) {
|
|
779
|
+
node.style.cssText = highlightedNode.__oldStyles;
|
|
780
|
+
delete highlightedNode.__oldStyles;
|
|
767
781
|
} else {
|
|
768
782
|
node.removeAttribute("style");
|
|
769
783
|
}
|
|
@@ -876,12 +890,17 @@
|
|
|
876
890
|
/^\s*(use|accept|allow|continue\s+with)?\s*only\s*(strictly)?\s*(necessary|essentials?|required)?\s*(cookies)?\s*$/is,
|
|
877
891
|
// e.g. "do not sell or share my personal information", "do not sell my personal information"
|
|
878
892
|
// often used in CCPA
|
|
879
|
-
/^\s*do\s+not\s+sell(\s+or\s+share)?\s*my\s*personal\s*
|
|
893
|
+
/^\s*do\s+not\s+sell(\s+or\s+share)?\s*my\s*personal\s*info(rmation)?\s*$/is,
|
|
880
894
|
"allow selection",
|
|
881
|
-
"disagree and close"
|
|
895
|
+
"disagree and close",
|
|
882
896
|
// These are impactful, but look error-prone
|
|
897
|
+
// // e.g. "disagree"
|
|
898
|
+
/^(i)?\s*disagree\s*(and\s+close)?$/i,
|
|
883
899
|
// // e.g. "i do not agree"
|
|
884
900
|
// /^\s*(i\s+)?do\s+not\s+agree\s*$/i,
|
|
901
|
+
"no",
|
|
902
|
+
/^no,? thanks$/is,
|
|
903
|
+
/^opt[ -]out$/is
|
|
885
904
|
];
|
|
886
905
|
var REJECT_PATTERNS_DUTCH = [
|
|
887
906
|
"weigeren",
|
|
@@ -1457,6 +1476,64 @@
|
|
|
1457
1476
|
/sostienici/is,
|
|
1458
1477
|
/suscribir/is
|
|
1459
1478
|
];
|
|
1479
|
+
var SETTINGS_PATTERNS = [
|
|
1480
|
+
"settings",
|
|
1481
|
+
"preferences",
|
|
1482
|
+
/customi(s|z)e/is,
|
|
1483
|
+
"show details",
|
|
1484
|
+
"more options",
|
|
1485
|
+
/(manage|configure) (my|your) (preferences|choices|cookies)/is,
|
|
1486
|
+
"manage choices",
|
|
1487
|
+
/(cookie )?preference center/is,
|
|
1488
|
+
"change settings",
|
|
1489
|
+
"configure",
|
|
1490
|
+
"change my preferences",
|
|
1491
|
+
"cookie manager",
|
|
1492
|
+
"cookie preference",
|
|
1493
|
+
"let me choose",
|
|
1494
|
+
"cookieconsent preferences",
|
|
1495
|
+
/privacy choices/is,
|
|
1496
|
+
/(privacy|cookie|custom) settings/is,
|
|
1497
|
+
/cookies? (settings|preferences|setting)/is,
|
|
1498
|
+
/(manage|customize|customise|opt-out|edit).*(cookies|preferences|settings|options)/is,
|
|
1499
|
+
"cookie consent options",
|
|
1500
|
+
"privacy controls",
|
|
1501
|
+
"show purposes",
|
|
1502
|
+
// German
|
|
1503
|
+
"einstellungen"
|
|
1504
|
+
];
|
|
1505
|
+
var ACCEPT_PATTERNS = [
|
|
1506
|
+
/^(accept|allow)( all)?( cookies)?$/is,
|
|
1507
|
+
/i (accept|allow)( all)?/is,
|
|
1508
|
+
"yes",
|
|
1509
|
+
/^(i )?agree$/is,
|
|
1510
|
+
"continue with all",
|
|
1511
|
+
"accept and continue",
|
|
1512
|
+
/accept all above/is,
|
|
1513
|
+
/^(accept|agree) and close/is,
|
|
1514
|
+
"accept continue",
|
|
1515
|
+
"agree proceed",
|
|
1516
|
+
"allow and continue",
|
|
1517
|
+
"close and accept",
|
|
1518
|
+
/accept all$/is,
|
|
1519
|
+
"im ok with that",
|
|
1520
|
+
"accept optional cookies",
|
|
1521
|
+
/^alle (cookies )?akzeptieren$/is
|
|
1522
|
+
];
|
|
1523
|
+
var ACKNOWLEDGE_PATTERNS = [
|
|
1524
|
+
"ok",
|
|
1525
|
+
"close",
|
|
1526
|
+
"continue",
|
|
1527
|
+
"x",
|
|
1528
|
+
/^got it!?$/,
|
|
1529
|
+
"i understand",
|
|
1530
|
+
"dismiss",
|
|
1531
|
+
"okay",
|
|
1532
|
+
"acknowledge",
|
|
1533
|
+
/^close (banner|cookie notification)$/is,
|
|
1534
|
+
/understood$/is,
|
|
1535
|
+
"confirm my choices"
|
|
1536
|
+
];
|
|
1460
1537
|
|
|
1461
1538
|
// lib/heuristics.ts
|
|
1462
1539
|
var BUTTON_LIKE_ELEMENT_SELECTOR = 'button, input[type="button"], input[type="submit"], a, [role="button"], [class*="button"]';
|
|
@@ -1475,48 +1552,61 @@
|
|
|
1475
1552
|
}
|
|
1476
1553
|
return { patterns, snippets: snippets2 };
|
|
1477
1554
|
}
|
|
1478
|
-
function getActionablePopups(timeout = POPUP_SEARCH_MAX_TIME) {
|
|
1555
|
+
function getActionablePopups(mode = PopupHandlingModes.Reject, timeout = POPUP_SEARCH_MAX_TIME) {
|
|
1479
1556
|
const popups = getPotentialPopups(timeout);
|
|
1480
1557
|
const result = popups.reduce((acc, popup) => {
|
|
1481
1558
|
const popupText = popup.text?.trim();
|
|
1482
1559
|
if (popupText) {
|
|
1483
1560
|
const { patterns } = checkHeuristicPatterns(popupText);
|
|
1484
1561
|
if (patterns.length > 0) {
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
otherButtons
|
|
1491
|
-
});
|
|
1492
|
-
}
|
|
1562
|
+
classifyButtons(popup.buttons);
|
|
1563
|
+
popup.regexClassification = classifyPopup(popup.buttons);
|
|
1564
|
+
acc.push({
|
|
1565
|
+
...popup
|
|
1566
|
+
});
|
|
1493
1567
|
}
|
|
1494
1568
|
}
|
|
1495
1569
|
return acc;
|
|
1496
1570
|
}, []);
|
|
1497
|
-
return result
|
|
1571
|
+
return result.filter(
|
|
1572
|
+
(popup) => popup.regexClassification !== void 0 && popup.regexClassification !== PopupHandlingModes.None && popup.regexClassification <= mode
|
|
1573
|
+
).sort((a, b) => (a.regexClassification ?? 0) - (b.regexClassification ?? 0));
|
|
1498
1574
|
}
|
|
1499
1575
|
function classifyButtons(buttons) {
|
|
1500
|
-
const rejectButtons = [];
|
|
1501
|
-
const otherButtons = [];
|
|
1502
1576
|
for (const button of buttons) {
|
|
1503
|
-
|
|
1504
|
-
rejectButtons.push(button);
|
|
1505
|
-
} else {
|
|
1506
|
-
otherButtons.push(button);
|
|
1507
|
-
}
|
|
1577
|
+
button.regexClassification = classifyButtonTextRegex(button.text);
|
|
1508
1578
|
}
|
|
1509
|
-
return {
|
|
1510
|
-
rejectButtons,
|
|
1511
|
-
otherButtons
|
|
1512
|
-
};
|
|
1513
1579
|
}
|
|
1514
|
-
function
|
|
1580
|
+
function classifyPopup(buttons) {
|
|
1581
|
+
const { reject, settings, accept, acknowledge } = buttons.reduce(
|
|
1582
|
+
(acc, button) => {
|
|
1583
|
+
if (button.regexClassification && button.regexClassification !== "other") {
|
|
1584
|
+
acc[button.regexClassification]++;
|
|
1585
|
+
}
|
|
1586
|
+
return acc;
|
|
1587
|
+
},
|
|
1588
|
+
{ reject: 0, settings: 0, accept: 0, acknowledge: 0 }
|
|
1589
|
+
);
|
|
1590
|
+
if (reject > 0) {
|
|
1591
|
+
return PopupHandlingModes.Reject;
|
|
1592
|
+
}
|
|
1593
|
+
if (settings > 0) {
|
|
1594
|
+
return PopupHandlingModes.None;
|
|
1595
|
+
}
|
|
1596
|
+
if (acknowledge > 0) {
|
|
1597
|
+
return PopupHandlingModes.Tier1;
|
|
1598
|
+
}
|
|
1599
|
+
if (accept > 0) {
|
|
1600
|
+
return accept === 1 ? PopupHandlingModes.Tier2 : PopupHandlingModes.None;
|
|
1601
|
+
}
|
|
1602
|
+
return PopupHandlingModes.None;
|
|
1603
|
+
}
|
|
1604
|
+
function testButtonMatches(buttonText, matchPatterns, neverMatchPatterns) {
|
|
1515
1605
|
if (!buttonText) {
|
|
1516
1606
|
return false;
|
|
1517
1607
|
}
|
|
1518
1608
|
const cleanedButtonText = cleanButtonText(buttonText);
|
|
1519
|
-
return !neverMatchPatterns.some((p) => p.test(cleanedButtonText)) &&
|
|
1609
|
+
return !neverMatchPatterns.some((p) => p instanceof RegExp && p.test(cleanedButtonText) || p === cleanedButtonText) && matchPatterns.some((p) => p instanceof RegExp && p.test(cleanedButtonText) || p === cleanedButtonText);
|
|
1520
1610
|
}
|
|
1521
1611
|
function cleanButtonText(buttonText) {
|
|
1522
1612
|
let result = buttonText.toLowerCase();
|
|
@@ -1530,6 +1620,21 @@
|
|
|
1530
1620
|
result = result.trim();
|
|
1531
1621
|
return result;
|
|
1532
1622
|
}
|
|
1623
|
+
function classifyButtonTextRegex(buttonText) {
|
|
1624
|
+
if (testButtonMatches(buttonText, REJECT_PATTERNS, NEVER_MATCH_PATTERNS)) {
|
|
1625
|
+
return "reject";
|
|
1626
|
+
}
|
|
1627
|
+
if (testButtonMatches(buttonText, SETTINGS_PATTERNS, NEVER_MATCH_PATTERNS)) {
|
|
1628
|
+
return "settings";
|
|
1629
|
+
}
|
|
1630
|
+
if (testButtonMatches(buttonText, ACCEPT_PATTERNS, NEVER_MATCH_PATTERNS)) {
|
|
1631
|
+
return "accept";
|
|
1632
|
+
}
|
|
1633
|
+
if (testButtonMatches(buttonText, ACKNOWLEDGE_PATTERNS, NEVER_MATCH_PATTERNS)) {
|
|
1634
|
+
return "acknowledge";
|
|
1635
|
+
}
|
|
1636
|
+
return "other";
|
|
1637
|
+
}
|
|
1533
1638
|
function getPotentialPopups(timeout = POPUP_SEARCH_MAX_TIME) {
|
|
1534
1639
|
const isFramed = !isTopFrame();
|
|
1535
1640
|
if (isFramed && window.parent && window.parent !== window.top) {
|
|
@@ -1975,7 +2080,7 @@
|
|
|
1975
2080
|
}
|
|
1976
2081
|
};
|
|
1977
2082
|
var AutoConsentHeuristicCMP = class extends AutoConsentCMPBase {
|
|
1978
|
-
constructor(autoconsentInstance) {
|
|
2083
|
+
constructor(autoconsentInstance, mode = PopupHandlingModes.Reject) {
|
|
1979
2084
|
super(autoconsentInstance);
|
|
1980
2085
|
this.popups = [];
|
|
1981
2086
|
this.name = "HEURISTIC";
|
|
@@ -1984,6 +2089,7 @@
|
|
|
1984
2089
|
frame: false
|
|
1985
2090
|
// do not run in iframes for security reasons
|
|
1986
2091
|
};
|
|
2092
|
+
this.mode = mode;
|
|
1987
2093
|
}
|
|
1988
2094
|
get hasSelfTest() {
|
|
1989
2095
|
return true;
|
|
@@ -1997,25 +2103,33 @@
|
|
|
1997
2103
|
async detectCmp() {
|
|
1998
2104
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1999
2105
|
this.autoconsent.config.performanceLoggingEnabled && performance.mark("heuristicDetectorStart");
|
|
2000
|
-
this.popups = getActionablePopups(this.autoconsent.config.heuristicPopupSearchTimeout);
|
|
2106
|
+
this.popups = getActionablePopups(this.mode, this.autoconsent.config.heuristicPopupSearchTimeout);
|
|
2001
2107
|
this.autoconsent.config.performanceLoggingEnabled && performance.mark("heuristicDetectorEnd");
|
|
2002
2108
|
this.autoconsent.config.performanceLoggingEnabled && performance.measure("heuristicDetector", "heuristicDetectorStart", "heuristicDetectorEnd");
|
|
2003
2109
|
if (this.popups.length > 0) {
|
|
2110
|
+
this.name = `HEURISTIC-TIER${this.popups[0].regexClassification}`;
|
|
2004
2111
|
return Promise.resolve(true);
|
|
2005
2112
|
}
|
|
2006
2113
|
return Promise.resolve(false);
|
|
2007
2114
|
}
|
|
2008
2115
|
async detectPopup() {
|
|
2009
2116
|
if (this.popups.length > 0) {
|
|
2010
|
-
if (this.popups.length > 1
|
|
2011
|
-
this.autoconsent.config.logs.errors && console.warn("Heuristic found multiple
|
|
2117
|
+
if (this.popups.length > 1) {
|
|
2118
|
+
this.autoconsent.config.logs.errors && console.warn("Heuristic found multiple popups");
|
|
2012
2119
|
}
|
|
2013
2120
|
return true;
|
|
2014
2121
|
}
|
|
2015
2122
|
return false;
|
|
2016
2123
|
}
|
|
2124
|
+
getTargetButton() {
|
|
2125
|
+
const popup = this.popups[0];
|
|
2126
|
+
const level = popup.regexClassification;
|
|
2127
|
+
const buttons = popup.buttons;
|
|
2128
|
+
const targetButtonType = level === PopupHandlingModes.Reject ? "reject" : level === PopupHandlingModes.Tier1 ? "acknowledge" : "accept";
|
|
2129
|
+
return buttons.find((button) => button.regexClassification === targetButtonType);
|
|
2130
|
+
}
|
|
2017
2131
|
optOut() {
|
|
2018
|
-
const button = this.
|
|
2132
|
+
const button = this.getTargetButton();
|
|
2019
2133
|
if (button) {
|
|
2020
2134
|
return this.clickElement(button.element);
|
|
2021
2135
|
}
|
|
@@ -2028,7 +2142,7 @@
|
|
|
2028
2142
|
throw new Error("Not Implemented");
|
|
2029
2143
|
}
|
|
2030
2144
|
async test() {
|
|
2031
|
-
const button = this.
|
|
2145
|
+
const button = this.getTargetButton();
|
|
2032
2146
|
if (button) {
|
|
2033
2147
|
await this.wait(500);
|
|
2034
2148
|
return !isElementVisible(button.element);
|
|
@@ -2709,7 +2823,7 @@
|
|
|
2709
2823
|
async optOut() {
|
|
2710
2824
|
await this.waitForElement(".unic button", 1e3);
|
|
2711
2825
|
document.querySelectorAll(".unic button").forEach((button) => {
|
|
2712
|
-
const text = button.textContent;
|
|
2826
|
+
const text = button.textContent || "";
|
|
2713
2827
|
if (text.includes("Manage Options") || text.includes("Optionen verwalten")) {
|
|
2714
2828
|
button.click();
|
|
2715
2829
|
}
|
|
@@ -2722,7 +2836,7 @@
|
|
|
2722
2836
|
}
|
|
2723
2837
|
});
|
|
2724
2838
|
for (const b of document.querySelectorAll(".unic button")) {
|
|
2725
|
-
const text = b.textContent;
|
|
2839
|
+
const text = b.textContent || "";
|
|
2726
2840
|
for (const pattern of ["Confirm Choices", "Save Choices", "Auswahl speichern"]) {
|
|
2727
2841
|
if (text.includes(pattern)) {
|
|
2728
2842
|
b.click();
|
|
@@ -2779,6 +2893,9 @@
|
|
|
2779
2893
|
item.querySelector(".cmp-accordion-item-title").click();
|
|
2780
2894
|
await waitFor(() => !!item.querySelector(".cmp-accordion-item-content.cmp-active"), 10, 50);
|
|
2781
2895
|
const content = item.querySelector(".cmp-accordion-item-content.cmp-active");
|
|
2896
|
+
if (!content) {
|
|
2897
|
+
return false;
|
|
2898
|
+
}
|
|
2782
2899
|
content.querySelectorAll(".cmp-toggle-actions .cmp-toggle-deny:not(.cmp-toggle-deny--active)").forEach((e) => e.click());
|
|
2783
2900
|
content.querySelectorAll(".cmp-toggle-actions .cmp-toggle-checkbox:not(.cmp-toggle-checkbox--active)").forEach((e) => e.click());
|
|
2784
2901
|
}
|
|
@@ -3497,7 +3614,7 @@
|
|
|
3497
3614
|
}
|
|
3498
3615
|
}
|
|
3499
3616
|
});
|
|
3500
|
-
const heuristicRules = isTop && this.config.enableHeuristicAction && this.state.findCmpAttempts % 2 === 0 ? [new AutoConsentHeuristicCMP(this)] : [];
|
|
3617
|
+
const heuristicRules = isTop && this.config.enableHeuristicAction && this.state.findCmpAttempts % 2 === 0 ? [new AutoConsentHeuristicCMP(this, this.config.heuristicMode)] : [];
|
|
3501
3618
|
const rulesPriorityStages = [
|
|
3502
3619
|
["site-specific", siteSpecificRules],
|
|
3503
3620
|
["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)) {
|
|
@@ -904,6 +913,7 @@
|
|
|
904
913
|
}
|
|
905
914
|
|
|
906
915
|
// addon/popup.ts
|
|
916
|
+
var maxRenderedRules = 100;
|
|
907
917
|
async function init() {
|
|
908
918
|
const autoconsentConfig = await storageGet("config");
|
|
909
919
|
const enabledCheckbox = document.querySelector("input#enabled");
|
|
@@ -917,8 +927,7 @@
|
|
|
917
927
|
const cosmeticOffRadio = document.querySelector("input#cosmetic-off");
|
|
918
928
|
const generatedOnRadio = document.querySelector("input#generated-on");
|
|
919
929
|
const generatedOffRadio = document.querySelector("input#generated-off");
|
|
920
|
-
const
|
|
921
|
-
const heuristicActionOffRadio = document.querySelector("input#heuristic-action-off");
|
|
930
|
+
const heuristicActionCheckbox = document.querySelector("input#heuristic-action");
|
|
922
931
|
const visualTestOnRadio = document.querySelector("input#visual-test-on");
|
|
923
932
|
const visualTestOffRadio = document.querySelector("input#visual-test-off");
|
|
924
933
|
const popupMutationOnRadio = document.querySelector("input#popup-mutation-on");
|
|
@@ -933,6 +942,47 @@
|
|
|
933
942
|
const logsMessagesCheckbox = document.querySelector("input#logs-messages");
|
|
934
943
|
const ruleReloadButton = document.querySelector("#reload");
|
|
935
944
|
const resetButton = document.querySelector("#reset");
|
|
945
|
+
const ruleSectionControls = {
|
|
946
|
+
generated: {
|
|
947
|
+
details: document.querySelector("#generated-rules-section"),
|
|
948
|
+
count: document.querySelector("#generated-rules-count"),
|
|
949
|
+
search: document.querySelector("#generated-rules-search"),
|
|
950
|
+
enableAll: document.querySelector("#generated-rules-enable-all"),
|
|
951
|
+
disableAll: document.querySelector("#generated-rules-disable-all"),
|
|
952
|
+
status: document.querySelector("#generated-rules-status"),
|
|
953
|
+
list: document.querySelector("#generated-rules-list")
|
|
954
|
+
},
|
|
955
|
+
generic: {
|
|
956
|
+
details: document.querySelector("#generic-rules-section"),
|
|
957
|
+
count: document.querySelector("#generic-rules-count"),
|
|
958
|
+
search: document.querySelector("#generic-rules-search"),
|
|
959
|
+
enableAll: document.querySelector("#generic-rules-enable-all"),
|
|
960
|
+
disableAll: document.querySelector("#generic-rules-disable-all"),
|
|
961
|
+
status: document.querySelector("#generic-rules-status"),
|
|
962
|
+
list: document.querySelector("#generic-rules-list")
|
|
963
|
+
},
|
|
964
|
+
code: {
|
|
965
|
+
details: document.querySelector("#code-rules-section"),
|
|
966
|
+
count: document.querySelector("#code-rules-count"),
|
|
967
|
+
search: document.querySelector("#code-rules-search"),
|
|
968
|
+
enableAll: document.querySelector("#code-rules-enable-all"),
|
|
969
|
+
disableAll: document.querySelector("#code-rules-disable-all"),
|
|
970
|
+
status: document.querySelector("#code-rules-status"),
|
|
971
|
+
list: document.querySelector("#code-rules-list")
|
|
972
|
+
},
|
|
973
|
+
consentomatic: {
|
|
974
|
+
details: document.querySelector("#consentomatic-rules-section"),
|
|
975
|
+
count: document.querySelector("#consentomatic-rules-count"),
|
|
976
|
+
search: document.querySelector("#consentomatic-rules-search"),
|
|
977
|
+
enableAll: document.querySelector("#consentomatic-rules-enable-all"),
|
|
978
|
+
disableAll: document.querySelector("#consentomatic-rules-disable-all"),
|
|
979
|
+
status: document.querySelector("#consentomatic-rules-status"),
|
|
980
|
+
list: document.querySelector("#consentomatic-rules-list")
|
|
981
|
+
}
|
|
982
|
+
};
|
|
983
|
+
let ruleIndexPromise = null;
|
|
984
|
+
let ruleIndex = null;
|
|
985
|
+
autoconsentConfig.disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
936
986
|
const [currentTab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true });
|
|
937
987
|
if (!currentTab.url || !currentTab.id) {
|
|
938
988
|
console.error("Current tab is not valid");
|
|
@@ -998,11 +1048,7 @@
|
|
|
998
1048
|
} else {
|
|
999
1049
|
generatedOffRadio.checked = true;
|
|
1000
1050
|
}
|
|
1001
|
-
|
|
1002
|
-
heuristicActionOnRadio.checked = true;
|
|
1003
|
-
} else {
|
|
1004
|
-
heuristicActionOffRadio.checked = true;
|
|
1005
|
-
}
|
|
1051
|
+
heuristicActionCheckbox.checked = autoconsentConfig.enableHeuristicAction;
|
|
1006
1052
|
if (autoconsentConfig.visualTest) {
|
|
1007
1053
|
visualTestOnRadio.checked = true;
|
|
1008
1054
|
} else {
|
|
@@ -1052,11 +1098,10 @@
|
|
|
1052
1098
|
generatedOnRadio.addEventListener("change", generatedChange);
|
|
1053
1099
|
generatedOffRadio.addEventListener("change", generatedChange);
|
|
1054
1100
|
function heuristicActionChange() {
|
|
1055
|
-
autoconsentConfig.enableHeuristicAction =
|
|
1101
|
+
autoconsentConfig.enableHeuristicAction = heuristicActionCheckbox.checked;
|
|
1056
1102
|
storageSet({ config: autoconsentConfig });
|
|
1057
1103
|
}
|
|
1058
|
-
|
|
1059
|
-
heuristicActionOffRadio.addEventListener("change", heuristicActionChange);
|
|
1104
|
+
heuristicActionCheckbox.addEventListener("change", heuristicActionChange);
|
|
1060
1105
|
function visualTestChange() {
|
|
1061
1106
|
autoconsentConfig.visualTest = visualTestOnRadio.checked;
|
|
1062
1107
|
storageSet({ config: autoconsentConfig });
|
|
@@ -1102,10 +1147,141 @@
|
|
|
1102
1147
|
logsMessagesCheckbox.addEventListener("change", () => {
|
|
1103
1148
|
updateLogsConfig();
|
|
1104
1149
|
});
|
|
1150
|
+
async function loadRuleIndex() {
|
|
1151
|
+
if (!ruleIndexPromise) {
|
|
1152
|
+
ruleIndexPromise = fetch("./rule-index.json").then(async (res) => await res.json());
|
|
1153
|
+
}
|
|
1154
|
+
ruleIndex = await ruleIndexPromise;
|
|
1155
|
+
updateRuleCounts();
|
|
1156
|
+
return ruleIndex;
|
|
1157
|
+
}
|
|
1158
|
+
function updateRuleCounts() {
|
|
1159
|
+
if (!ruleIndex) {
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
const disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
1163
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1164
|
+
const sectionRules = ruleIndex?.filter((rule) => rule.section === section) || [];
|
|
1165
|
+
const disabledInSection = sectionRules.filter((rule) => disabledCmps.includes(rule.name)).length;
|
|
1166
|
+
const count = ruleSectionControls[section].count;
|
|
1167
|
+
count.textContent = `(${disabledInSection}/${sectionRules.length} disabled)`;
|
|
1168
|
+
count.classList.toggle("rule-count-disabled", disabledInSection > 0);
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
function setRuleEnabled(ruleName, enabled) {
|
|
1172
|
+
const disabledCmps = new Set(autoconsentConfig.disabledCmps || []);
|
|
1173
|
+
if (enabled) {
|
|
1174
|
+
disabledCmps.delete(ruleName);
|
|
1175
|
+
} else {
|
|
1176
|
+
disabledCmps.add(ruleName);
|
|
1177
|
+
}
|
|
1178
|
+
autoconsentConfig.disabledCmps = Array.from(disabledCmps).sort();
|
|
1179
|
+
storageSet({ config: autoconsentConfig });
|
|
1180
|
+
updateRuleCounts();
|
|
1181
|
+
}
|
|
1182
|
+
function renderOpenRuleSections() {
|
|
1183
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1184
|
+
if (ruleSectionControls[section].details.open) {
|
|
1185
|
+
renderRuleSection(section);
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
function setRuleSectionEnabled(section, enabled) {
|
|
1190
|
+
if (!ruleIndex) {
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
const disabledCmps = new Set(autoconsentConfig.disabledCmps || []);
|
|
1194
|
+
ruleIndex.filter((rule) => rule.section === section).forEach((rule) => {
|
|
1195
|
+
if (enabled) {
|
|
1196
|
+
disabledCmps.delete(rule.name);
|
|
1197
|
+
} else {
|
|
1198
|
+
disabledCmps.add(rule.name);
|
|
1199
|
+
}
|
|
1200
|
+
});
|
|
1201
|
+
autoconsentConfig.disabledCmps = Array.from(disabledCmps).sort();
|
|
1202
|
+
storageSet({ config: autoconsentConfig });
|
|
1203
|
+
updateRuleCounts();
|
|
1204
|
+
renderOpenRuleSections();
|
|
1205
|
+
}
|
|
1206
|
+
function renderRuleSection(section) {
|
|
1207
|
+
const controls = ruleSectionControls[section];
|
|
1208
|
+
if (!ruleIndex) {
|
|
1209
|
+
controls.status.textContent = "Rules are not loaded yet.";
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
const disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
1213
|
+
const searchQuery = controls.search.value.trim().toLowerCase();
|
|
1214
|
+
const sectionRules = ruleIndex.filter((rule) => rule.section === section);
|
|
1215
|
+
const matchingRules = sectionRules.filter((rule) => {
|
|
1216
|
+
if (!searchQuery) {
|
|
1217
|
+
return disabledCmps.includes(rule.name);
|
|
1218
|
+
}
|
|
1219
|
+
return rule.name.toLowerCase().includes(searchQuery) || !!rule.urlPattern?.toLowerCase().includes(searchQuery);
|
|
1220
|
+
});
|
|
1221
|
+
const renderedRules = matchingRules.slice(0, maxRenderedRules);
|
|
1222
|
+
const disabledInSection = sectionRules.filter((rule) => disabledCmps.includes(rule.name)).length;
|
|
1223
|
+
controls.status.textContent = searchQuery ? `Showing ${renderedRules.length} of ${matchingRules.length} matches. ${disabledInSection} disabled.` : `Showing ${renderedRules.length} of ${disabledInSection} disabled rules. Search to find enabled rules.`;
|
|
1224
|
+
controls.list.replaceChildren(
|
|
1225
|
+
...renderedRules.map((rule) => {
|
|
1226
|
+
const checkbox = document.createElement("input");
|
|
1227
|
+
checkbox.type = "checkbox";
|
|
1228
|
+
checkbox.checked = !disabledCmps.includes(rule.name);
|
|
1229
|
+
checkbox.addEventListener("change", () => {
|
|
1230
|
+
setRuleEnabled(rule.name, checkbox.checked);
|
|
1231
|
+
renderRuleSection(section);
|
|
1232
|
+
});
|
|
1233
|
+
const label = document.createElement("label");
|
|
1234
|
+
label.className = "rule-row";
|
|
1235
|
+
label.title = rule.urlPattern ? `${rule.name}
|
|
1236
|
+
${rule.urlPattern}` : rule.name;
|
|
1237
|
+
label.append(checkbox, document.createTextNode(` ${rule.name}${rule.cosmetic ? " (cosmetic)" : ""}`));
|
|
1238
|
+
return label;
|
|
1239
|
+
})
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
async function loadAndRenderRuleSection(section) {
|
|
1243
|
+
ruleSectionControls[section].status.textContent = "Loading rules...";
|
|
1244
|
+
try {
|
|
1245
|
+
await loadRuleIndex();
|
|
1246
|
+
renderRuleSection(section);
|
|
1247
|
+
} catch (e) {
|
|
1248
|
+
console.error("Failed to load rule index", e);
|
|
1249
|
+
ruleSectionControls[section].status.textContent = "Failed to load rules.";
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1253
|
+
const controls = ruleSectionControls[section];
|
|
1254
|
+
controls.details.addEventListener("toggle", () => {
|
|
1255
|
+
if (controls.details.open) {
|
|
1256
|
+
loadAndRenderRuleSection(section);
|
|
1257
|
+
}
|
|
1258
|
+
});
|
|
1259
|
+
controls.search.addEventListener("input", () => renderRuleSection(section));
|
|
1260
|
+
controls.enableAll.addEventListener("click", async () => {
|
|
1261
|
+
await loadRuleIndex();
|
|
1262
|
+
setRuleSectionEnabled(section, true);
|
|
1263
|
+
});
|
|
1264
|
+
controls.disableAll.addEventListener("click", async () => {
|
|
1265
|
+
await loadRuleIndex();
|
|
1266
|
+
setRuleSectionEnabled(section, false);
|
|
1267
|
+
});
|
|
1268
|
+
});
|
|
1269
|
+
loadRuleIndex().catch((e) => {
|
|
1270
|
+
console.error("Failed to load rule index", e);
|
|
1271
|
+
});
|
|
1105
1272
|
ruleReloadButton.addEventListener("click", async () => {
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1273
|
+
const [compactRulesRes, fullRulesRes] = await Promise.all([fetch("./compact-rules.json"), fetch("./rules.json")]);
|
|
1274
|
+
const fullRules = await fullRulesRes.json();
|
|
1275
|
+
await storageSet({
|
|
1276
|
+
rules: await compactRulesRes.json(),
|
|
1277
|
+
fullRules: fullRules.autoconsent
|
|
1278
|
+
});
|
|
1279
|
+
ruleIndexPromise = null;
|
|
1280
|
+
ruleIndex = null;
|
|
1281
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1282
|
+
if (ruleSectionControls[section].details.open) {
|
|
1283
|
+
loadAndRenderRuleSection(section);
|
|
1284
|
+
}
|
|
1109
1285
|
});
|
|
1110
1286
|
});
|
|
1111
1287
|
resetButton.addEventListener("click", async () => {
|