@duckduckgo/autoconsent 16.12.0 → 16.13.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.
@@ -564,7 +564,7 @@ var DETECT_PATTERNS = [
564
564
  var REJECT_PATTERNS_ENGLISH = [
565
565
  // e.g. "reject", "reject all", "reject all cookies", "deny all", "refuse cookies", "decline",
566
566
  // "reject non-essential cookies", "reject unnecessary cookies", "reject all but necessary", "reject all and close"
567
- // note that "reject and subscribe" and "reject and pay" are excluded via NEVER_MATCH_PATTERNS
567
+ // note that "reject and subscribe" and "reject and pay" are excluded via BUTTON_NEVER_MATCH_PATTERNS
568
568
  /^\s*(no,?\s*)?(i\s+)?(reject|deny|refuse|decline|disable)\s*(all)?\s*(but|except)?\s*(non[- ]?essential|un(necessary|required)|optional|additional|targeting|analytics|marketing|non[- ]?necessary|extra|tracking|advertising|necessary|essential)?\s*(cookies)?\s*(and\s+close)?\s*$/is,
569
569
  // e.g. "i do not accept", "do not accept cookies"
570
570
  /^\s*(i\s+)?do\s+not\s+accept\s*(cookies)?\s*$/is,
@@ -612,7 +612,7 @@ var REJECT_PATTERNS_DUTCH = [
612
612
  ];
613
613
  var REJECT_PATTERNS_FRENCH = [
614
614
  // refuser / rejeter / interdire / décliner (reject verbs, any position)
615
- // "refuser et s'abonner" / "refuser et payer" are excluded via NEVER_MATCH_PATTERNS
615
+ // "refuser et s'abonner" / "refuser et payer" are excluded via BUTTON_NEVER_MATCH_PATTERNS
616
616
  /(^|\s)(refus|rejet|rejeter|interdire|interdis|déclin|declin)/is,
617
617
  // only necessary / essential / technical / functional
618
618
  /(uniquement|seulement|indispensable|strictement nécessaire|que les cookies\s+(nécessaires|techniques|essentiels|indispensables|fonctionnels))/is,
@@ -667,7 +667,7 @@ var REJECT_PATTERNS_BRAZILIAN_PORTUGUESE = [
667
667
  ];
668
668
  var REJECT_PATTERNS_SPANISH = [
669
669
  // rechazar / denegar / declinar / negar (reject verbs, any position)
670
- // "rechazar y pagar" / "rechazar y suscribirse" are excluded via NEVER_MATCH_PATTERNS
670
+ // "rechazar y pagar" / "rechazar y suscribirse" are excluded via BUTTON_NEVER_MATCH_PATTERNS
671
671
  /(^|\s)(rechaz|recház|deneg|negar|declin)/is,
672
672
  // accept/allow/use (only) necessary / essential / technical / functional / own
673
673
  /^\s*(aceptar?|acepta|permitir|permite|usar|utilizar)?\s*(solo|sólo|només|únicamente)?\s*(las?\s+|los\s+)?(cookies?\s+)?(estrictamente\s+)?(necesari\w*|esencial\w*|técnic\w*|obligatori\w*|funcional\w*|propias)\s*$/is,
@@ -735,7 +735,7 @@ var REJECT_PATTERNS = [
735
735
  ...REJECT_PATTERNS_TURKISH,
736
736
  ...REJECT_PATTERNS_INDONESIAN
737
737
  ];
738
- var NEVER_MATCH_PATTERNS = [
738
+ var BUTTON_NEVER_MATCH_PATTERNS = [
739
739
  /pay|subscribe/is,
740
740
  /abonneer/is,
741
741
  /abonnier/is,
@@ -756,6 +756,20 @@ var NEVER_MATCH_PATTERNS = [
756
756
  // Polish (PL)
757
757
  /subskrybuj/
758
758
  ];
759
+ var DETECT_NEVER_MATCH_PATTERNS = [
760
+ // e.g. "age verification", "age confirmation", "age check", "age gate", "age restriction"
761
+ /age\s+(?:verification|confirmation|check|gate|restriction)/i,
762
+ // e.g. "over 18 years", "at least 21 years", "older than 21", "18+"
763
+ /(?:over|above|at\s*least|minimum|older\s+than)\s*(?:18|21)\s*(?:years|yo|y\.?o\.?|\+)?/i,
764
+ // e.g. "18 years of age", "18+ years old", "21 years or older"
765
+ /(?:18|21)\s*(?:\+|years?)\s*(?:of\s*age|or\s*older|or\s*above)/i,
766
+ // e.g. "I am 18+", "I am over 18", "I'm 21 or older"
767
+ /(?:i'?m|i\s*am)\s*(?:over|above|at\s*least)?\s*(?:18|21)(?:\+|\s*(?:or\s*older|years))?/i,
768
+ // e.g. "you must be 18", "users must be at least 21", "visitors must be over 18"
769
+ /(?:you|users?|visitors?)\s+must\s+be\s+(?:over|above|at\s*least)?\s*(?:18|21)/i,
770
+ // e.g. "adult oriented material", "adult content", "adult-only website"
771
+ /adult[\s-]+(?:oriented|only|content|material|websites?)/i
772
+ ];
759
773
  var SETTINGS_PATTERNS = [
760
774
  // Multilingual "open customization" patterns: a customization verb next to a
761
775
  // cookie/preference/settings/options/details/purposes noun (both word orders).
@@ -1129,6 +1143,9 @@ function getActionablePopups(mode = "reject", timeout = POPUP_SEARCH_MAX_TIME) {
1129
1143
  const result = popups.reduce((acc, popup) => {
1130
1144
  const popupText = popup.text?.trim();
1131
1145
  if (popupText) {
1146
+ if (isExcludedPopup(popupText)) {
1147
+ return acc;
1148
+ }
1132
1149
  const { patterns } = checkHeuristicPatterns(popupText);
1133
1150
  if (patterns.length > 0) {
1134
1151
  classifyButtons(popup.buttons);
@@ -1147,6 +1164,13 @@ function classifyButtons(buttons) {
1147
1164
  button.regexClassification = classifyButtonTextRegex(button.text);
1148
1165
  }
1149
1166
  }
1167
+ function isExcludedPopup(popupText, excludePatterns = DETECT_NEVER_MATCH_PATTERNS) {
1168
+ if (!popupText) {
1169
+ return false;
1170
+ }
1171
+ const truncated = popupText.slice(0, TEXT_LIMIT);
1172
+ return excludePatterns.some((p) => p.test(truncated));
1173
+ }
1150
1174
  function classifyPopup(buttons) {
1151
1175
  const { reject, settings, accept, acknowledge } = buttons.reduce(
1152
1176
  (acc, button) => {
@@ -1191,16 +1215,16 @@ function cleanButtonText(buttonText) {
1191
1215
  return result;
1192
1216
  }
1193
1217
  function classifyButtonTextRegex(buttonText) {
1194
- if (testButtonMatches(buttonText, REJECT_PATTERNS, NEVER_MATCH_PATTERNS)) {
1218
+ if (testButtonMatches(buttonText, REJECT_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1195
1219
  return "reject";
1196
1220
  }
1197
- if (testButtonMatches(buttonText, SETTINGS_PATTERNS, NEVER_MATCH_PATTERNS)) {
1221
+ if (testButtonMatches(buttonText, SETTINGS_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1198
1222
  return "settings";
1199
1223
  }
1200
- if (testButtonMatches(buttonText, ACCEPT_PATTERNS, NEVER_MATCH_PATTERNS)) {
1224
+ if (testButtonMatches(buttonText, ACCEPT_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1201
1225
  return "accept";
1202
1226
  }
1203
- if (testButtonMatches(buttonText, ACKNOWLEDGE_PATTERNS, NEVER_MATCH_PATTERNS)) {
1227
+ if (testButtonMatches(buttonText, ACKNOWLEDGE_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1204
1228
  return "acknowledge";
1205
1229
  }
1206
1230
  return "other";
@@ -534,7 +534,7 @@ var DETECT_PATTERNS = [
534
534
  var REJECT_PATTERNS_ENGLISH = [
535
535
  // e.g. "reject", "reject all", "reject all cookies", "deny all", "refuse cookies", "decline",
536
536
  // "reject non-essential cookies", "reject unnecessary cookies", "reject all but necessary", "reject all and close"
537
- // note that "reject and subscribe" and "reject and pay" are excluded via NEVER_MATCH_PATTERNS
537
+ // note that "reject and subscribe" and "reject and pay" are excluded via BUTTON_NEVER_MATCH_PATTERNS
538
538
  /^\s*(no,?\s*)?(i\s+)?(reject|deny|refuse|decline|disable)\s*(all)?\s*(but|except)?\s*(non[- ]?essential|un(necessary|required)|optional|additional|targeting|analytics|marketing|non[- ]?necessary|extra|tracking|advertising|necessary|essential)?\s*(cookies)?\s*(and\s+close)?\s*$/is,
539
539
  // e.g. "i do not accept", "do not accept cookies"
540
540
  /^\s*(i\s+)?do\s+not\s+accept\s*(cookies)?\s*$/is,
@@ -582,7 +582,7 @@ var REJECT_PATTERNS_DUTCH = [
582
582
  ];
583
583
  var REJECT_PATTERNS_FRENCH = [
584
584
  // refuser / rejeter / interdire / décliner (reject verbs, any position)
585
- // "refuser et s'abonner" / "refuser et payer" are excluded via NEVER_MATCH_PATTERNS
585
+ // "refuser et s'abonner" / "refuser et payer" are excluded via BUTTON_NEVER_MATCH_PATTERNS
586
586
  /(^|\s)(refus|rejet|rejeter|interdire|interdis|déclin|declin)/is,
587
587
  // only necessary / essential / technical / functional
588
588
  /(uniquement|seulement|indispensable|strictement nécessaire|que les cookies\s+(nécessaires|techniques|essentiels|indispensables|fonctionnels))/is,
@@ -637,7 +637,7 @@ var REJECT_PATTERNS_BRAZILIAN_PORTUGUESE = [
637
637
  ];
638
638
  var REJECT_PATTERNS_SPANISH = [
639
639
  // rechazar / denegar / declinar / negar (reject verbs, any position)
640
- // "rechazar y pagar" / "rechazar y suscribirse" are excluded via NEVER_MATCH_PATTERNS
640
+ // "rechazar y pagar" / "rechazar y suscribirse" are excluded via BUTTON_NEVER_MATCH_PATTERNS
641
641
  /(^|\s)(rechaz|recház|deneg|negar|declin)/is,
642
642
  // accept/allow/use (only) necessary / essential / technical / functional / own
643
643
  /^\s*(aceptar?|acepta|permitir|permite|usar|utilizar)?\s*(solo|sólo|només|únicamente)?\s*(las?\s+|los\s+)?(cookies?\s+)?(estrictamente\s+)?(necesari\w*|esencial\w*|técnic\w*|obligatori\w*|funcional\w*|propias)\s*$/is,
@@ -705,7 +705,7 @@ var REJECT_PATTERNS = [
705
705
  ...REJECT_PATTERNS_TURKISH,
706
706
  ...REJECT_PATTERNS_INDONESIAN
707
707
  ];
708
- var NEVER_MATCH_PATTERNS = [
708
+ var BUTTON_NEVER_MATCH_PATTERNS = [
709
709
  /pay|subscribe/is,
710
710
  /abonneer/is,
711
711
  /abonnier/is,
@@ -726,6 +726,20 @@ var NEVER_MATCH_PATTERNS = [
726
726
  // Polish (PL)
727
727
  /subskrybuj/
728
728
  ];
729
+ var DETECT_NEVER_MATCH_PATTERNS = [
730
+ // e.g. "age verification", "age confirmation", "age check", "age gate", "age restriction"
731
+ /age\s+(?:verification|confirmation|check|gate|restriction)/i,
732
+ // e.g. "over 18 years", "at least 21 years", "older than 21", "18+"
733
+ /(?:over|above|at\s*least|minimum|older\s+than)\s*(?:18|21)\s*(?:years|yo|y\.?o\.?|\+)?/i,
734
+ // e.g. "18 years of age", "18+ years old", "21 years or older"
735
+ /(?:18|21)\s*(?:\+|years?)\s*(?:of\s*age|or\s*older|or\s*above)/i,
736
+ // e.g. "I am 18+", "I am over 18", "I'm 21 or older"
737
+ /(?:i'?m|i\s*am)\s*(?:over|above|at\s*least)?\s*(?:18|21)(?:\+|\s*(?:or\s*older|years))?/i,
738
+ // e.g. "you must be 18", "users must be at least 21", "visitors must be over 18"
739
+ /(?:you|users?|visitors?)\s+must\s+be\s+(?:over|above|at\s*least)?\s*(?:18|21)/i,
740
+ // e.g. "adult oriented material", "adult content", "adult-only website"
741
+ /adult[\s-]+(?:oriented|only|content|material|websites?)/i
742
+ ];
729
743
  var SETTINGS_PATTERNS = [
730
744
  // Multilingual "open customization" patterns: a customization verb next to a
731
745
  // cookie/preference/settings/options/details/purposes noun (both word orders).
@@ -1099,6 +1113,9 @@ function getActionablePopups(mode = "reject", timeout = POPUP_SEARCH_MAX_TIME) {
1099
1113
  const result = popups.reduce((acc, popup) => {
1100
1114
  const popupText = popup.text?.trim();
1101
1115
  if (popupText) {
1116
+ if (isExcludedPopup(popupText)) {
1117
+ return acc;
1118
+ }
1102
1119
  const { patterns } = checkHeuristicPatterns(popupText);
1103
1120
  if (patterns.length > 0) {
1104
1121
  classifyButtons(popup.buttons);
@@ -1117,6 +1134,13 @@ function classifyButtons(buttons) {
1117
1134
  button.regexClassification = classifyButtonTextRegex(button.text);
1118
1135
  }
1119
1136
  }
1137
+ function isExcludedPopup(popupText, excludePatterns = DETECT_NEVER_MATCH_PATTERNS) {
1138
+ if (!popupText) {
1139
+ return false;
1140
+ }
1141
+ const truncated = popupText.slice(0, TEXT_LIMIT);
1142
+ return excludePatterns.some((p) => p.test(truncated));
1143
+ }
1120
1144
  function classifyPopup(buttons) {
1121
1145
  const { reject, settings, accept, acknowledge } = buttons.reduce(
1122
1146
  (acc, button) => {
@@ -1161,16 +1185,16 @@ function cleanButtonText(buttonText) {
1161
1185
  return result;
1162
1186
  }
1163
1187
  function classifyButtonTextRegex(buttonText) {
1164
- if (testButtonMatches(buttonText, REJECT_PATTERNS, NEVER_MATCH_PATTERNS)) {
1188
+ if (testButtonMatches(buttonText, REJECT_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1165
1189
  return "reject";
1166
1190
  }
1167
- if (testButtonMatches(buttonText, SETTINGS_PATTERNS, NEVER_MATCH_PATTERNS)) {
1191
+ if (testButtonMatches(buttonText, SETTINGS_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1168
1192
  return "settings";
1169
1193
  }
1170
- if (testButtonMatches(buttonText, ACCEPT_PATTERNS, NEVER_MATCH_PATTERNS)) {
1194
+ if (testButtonMatches(buttonText, ACCEPT_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1171
1195
  return "accept";
1172
1196
  }
1173
- if (testButtonMatches(buttonText, ACKNOWLEDGE_PATTERNS, NEVER_MATCH_PATTERNS)) {
1197
+ if (testButtonMatches(buttonText, ACKNOWLEDGE_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1174
1198
  return "acknowledge";
1175
1199
  }
1176
1200
  return "other";
@@ -536,7 +536,7 @@
536
536
  var REJECT_PATTERNS_ENGLISH = [
537
537
  // e.g. "reject", "reject all", "reject all cookies", "deny all", "refuse cookies", "decline",
538
538
  // "reject non-essential cookies", "reject unnecessary cookies", "reject all but necessary", "reject all and close"
539
- // note that "reject and subscribe" and "reject and pay" are excluded via NEVER_MATCH_PATTERNS
539
+ // note that "reject and subscribe" and "reject and pay" are excluded via BUTTON_NEVER_MATCH_PATTERNS
540
540
  /^\s*(no,?\s*)?(i\s+)?(reject|deny|refuse|decline|disable)\s*(all)?\s*(but|except)?\s*(non[- ]?essential|un(necessary|required)|optional|additional|targeting|analytics|marketing|non[- ]?necessary|extra|tracking|advertising|necessary|essential)?\s*(cookies)?\s*(and\s+close)?\s*$/is,
541
541
  // e.g. "i do not accept", "do not accept cookies"
542
542
  /^\s*(i\s+)?do\s+not\s+accept\s*(cookies)?\s*$/is,
@@ -584,7 +584,7 @@
584
584
  ];
585
585
  var REJECT_PATTERNS_FRENCH = [
586
586
  // refuser / rejeter / interdire / décliner (reject verbs, any position)
587
- // "refuser et s'abonner" / "refuser et payer" are excluded via NEVER_MATCH_PATTERNS
587
+ // "refuser et s'abonner" / "refuser et payer" are excluded via BUTTON_NEVER_MATCH_PATTERNS
588
588
  /(^|\s)(refus|rejet|rejeter|interdire|interdis|déclin|declin)/is,
589
589
  // only necessary / essential / technical / functional
590
590
  /(uniquement|seulement|indispensable|strictement nécessaire|que les cookies\s+(nécessaires|techniques|essentiels|indispensables|fonctionnels))/is,
@@ -639,7 +639,7 @@
639
639
  ];
640
640
  var REJECT_PATTERNS_SPANISH = [
641
641
  // rechazar / denegar / declinar / negar (reject verbs, any position)
642
- // "rechazar y pagar" / "rechazar y suscribirse" are excluded via NEVER_MATCH_PATTERNS
642
+ // "rechazar y pagar" / "rechazar y suscribirse" are excluded via BUTTON_NEVER_MATCH_PATTERNS
643
643
  /(^|\s)(rechaz|recház|deneg|negar|declin)/is,
644
644
  // accept/allow/use (only) necessary / essential / technical / functional / own
645
645
  /^\s*(aceptar?|acepta|permitir|permite|usar|utilizar)?\s*(solo|sólo|només|únicamente)?\s*(las?\s+|los\s+)?(cookies?\s+)?(estrictamente\s+)?(necesari\w*|esencial\w*|técnic\w*|obligatori\w*|funcional\w*|propias)\s*$/is,
@@ -707,7 +707,7 @@
707
707
  ...REJECT_PATTERNS_TURKISH,
708
708
  ...REJECT_PATTERNS_INDONESIAN
709
709
  ];
710
- var NEVER_MATCH_PATTERNS = [
710
+ var BUTTON_NEVER_MATCH_PATTERNS = [
711
711
  /pay|subscribe/is,
712
712
  /abonneer/is,
713
713
  /abonnier/is,
@@ -728,6 +728,20 @@
728
728
  // Polish (PL)
729
729
  /subskrybuj/
730
730
  ];
731
+ var DETECT_NEVER_MATCH_PATTERNS = [
732
+ // e.g. "age verification", "age confirmation", "age check", "age gate", "age restriction"
733
+ /age\s+(?:verification|confirmation|check|gate|restriction)/i,
734
+ // e.g. "over 18 years", "at least 21 years", "older than 21", "18+"
735
+ /(?:over|above|at\s*least|minimum|older\s+than)\s*(?:18|21)\s*(?:years|yo|y\.?o\.?|\+)?/i,
736
+ // e.g. "18 years of age", "18+ years old", "21 years or older"
737
+ /(?:18|21)\s*(?:\+|years?)\s*(?:of\s*age|or\s*older|or\s*above)/i,
738
+ // e.g. "I am 18+", "I am over 18", "I'm 21 or older"
739
+ /(?:i'?m|i\s*am)\s*(?:over|above|at\s*least)?\s*(?:18|21)(?:\+|\s*(?:or\s*older|years))?/i,
740
+ // e.g. "you must be 18", "users must be at least 21", "visitors must be over 18"
741
+ /(?:you|users?|visitors?)\s+must\s+be\s+(?:over|above|at\s*least)?\s*(?:18|21)/i,
742
+ // e.g. "adult oriented material", "adult content", "adult-only website"
743
+ /adult[\s-]+(?:oriented|only|content|material|websites?)/i
744
+ ];
731
745
  var SETTINGS_PATTERNS = [
732
746
  // Multilingual "open customization" patterns: a customization verb next to a
733
747
  // cookie/preference/settings/options/details/purposes noun (both word orders).
@@ -1101,6 +1115,9 @@
1101
1115
  const result = popups.reduce((acc, popup) => {
1102
1116
  const popupText = popup.text?.trim();
1103
1117
  if (popupText) {
1118
+ if (isExcludedPopup(popupText)) {
1119
+ return acc;
1120
+ }
1104
1121
  const { patterns } = checkHeuristicPatterns(popupText);
1105
1122
  if (patterns.length > 0) {
1106
1123
  classifyButtons(popup.buttons);
@@ -1119,6 +1136,13 @@
1119
1136
  button.regexClassification = classifyButtonTextRegex(button.text);
1120
1137
  }
1121
1138
  }
1139
+ function isExcludedPopup(popupText, excludePatterns = DETECT_NEVER_MATCH_PATTERNS) {
1140
+ if (!popupText) {
1141
+ return false;
1142
+ }
1143
+ const truncated = popupText.slice(0, TEXT_LIMIT);
1144
+ return excludePatterns.some((p) => p.test(truncated));
1145
+ }
1122
1146
  function classifyPopup(buttons) {
1123
1147
  const { reject, settings, accept, acknowledge } = buttons.reduce(
1124
1148
  (acc, button) => {
@@ -1163,16 +1187,16 @@
1163
1187
  return result;
1164
1188
  }
1165
1189
  function classifyButtonTextRegex(buttonText) {
1166
- if (testButtonMatches(buttonText, REJECT_PATTERNS, NEVER_MATCH_PATTERNS)) {
1190
+ if (testButtonMatches(buttonText, REJECT_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1167
1191
  return "reject";
1168
1192
  }
1169
- if (testButtonMatches(buttonText, SETTINGS_PATTERNS, NEVER_MATCH_PATTERNS)) {
1193
+ if (testButtonMatches(buttonText, SETTINGS_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1170
1194
  return "settings";
1171
1195
  }
1172
- if (testButtonMatches(buttonText, ACCEPT_PATTERNS, NEVER_MATCH_PATTERNS)) {
1196
+ if (testButtonMatches(buttonText, ACCEPT_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1173
1197
  return "accept";
1174
1198
  }
1175
- if (testButtonMatches(buttonText, ACKNOWLEDGE_PATTERNS, NEVER_MATCH_PATTERNS)) {
1199
+ if (testButtonMatches(buttonText, ACKNOWLEDGE_PATTERNS, BUTTON_NEVER_MATCH_PATTERNS)) {
1176
1200
  return "acknowledge";
1177
1201
  }
1178
1202
  return "other";