Compare commits

..

1 Commits

16 changed files with 587 additions and 611 deletions

View File

@ -10,7 +10,7 @@
# Cookie Dialog Monster
Cookie Dialog Monster is a browser extension that hides cookie consent dialogs without changing user preferences. By default, we do NOT accept cookies (except in [a few cases](https://git.wanhose.dev/wanhose/cookie-dialog-monster/src/branch/main/database.json) where the pages do not function without accepting them). You can report broken sites with a single click, which will create an issue in this repository to be fixed promptly.
Cookie Dialog Monster is a browser extension that hides cookie consent dialogs without changing user preferences. By default, we do NOT accept cookies (except in [a few cases](https://git.wanhose.dev/wanhose/cookie-dialog-monster/src/branch/main/database.json#L248) where the pages do not function without accepting them). You can report broken sites with a single click, which will create an issue in this repository to be fixed promptly.
## Contributing

View File

@ -1,257 +1,547 @@
{
"actions": [
"commonWords": [
"ablehnen",
"accept",
"accepta",
"accepter",
"accettare",
"accordo",
"aceitar",
"aceptar",
"acuerdo",
"advertising",
"agree",
"akzeptieren",
"analitica",
"analítica",
"analitice",
"analityka",
"analyse",
"analytics",
"analytique",
"baner",
"banner",
"bannière",
"cc",
"cerrar",
"chiudere",
"close",
"cmp",
"compliance",
"concordar",
"confidențialitate",
"confidentialité",
"configuraciones",
"configurações",
"conformidade",
"conformità",
"conformitate",
"conformité",
"consenso",
"consent",
"consentement",
"consentimento",
"consentimiento",
"consimțământ",
"cookie",
"cumplimiento",
"d'accord",
"dados",
"dane",
"data",
"date",
"daten",
"datenschutz",
"dati",
"datos",
"de acord",
"declinar",
"declinare",
"decline",
"décliner",
"déni",
"descargo de responsabilidad",
"desempenho",
"dialog",
"dialogo",
"diálogo",
"dialogue",
"disclaimer",
"disconoscimento",
"données",
"dritte",
"einstellungen",
"einwilligung",
"fechar",
"fermer",
"fonctionnel",
"funcional",
"functional",
"funcțional",
"funkcjonalny",
"funktional",
"funzionale",
"gdpr",
"gerenciar",
"gérer",
"gesetz",
"gestiona",
"gestionar",
"gestire",
"guardar",
"haftungsausschluss",
"impostazioni",
"închide",
"informação",
"información",
"informacja",
"informații",
"information",
"informazione",
"isenção de responsabilidade",
"konformität",
"konieczny",
"law",
"lege",
"legge",
"lei",
"leistung",
"ley",
"loi",
"manage",
"necesar",
"necesario",
"nécessaire",
"necessario",
"necessário",
"necessary",
"notwendig",
"nutzung",
"odmówić",
"odrzucić",
"opcional",
"opcjonalny",
"optional",
"opțional",
"optionnel",
"opzionale",
"paramètres",
"performance",
"performanță",
"personalisierung",
"personalização",
"personalización",
"personalizacja",
"personalizare",
"personalization",
"personalizzazione",
"personnalisation",
"policy",
"politica",
"politică",
"política",
"politik",
"politique",
"polityka",
"popup",
"präferenzen",
"prawo",
"preferences",
"préférences",
"preferencias",
"preferências",
"preferencje",
"preferenze",
"preferințe",
"prestazioni",
"privacidad",
"privacidade",
"privacy",
"prywatność",
"pubblicità",
"publicidad",
"publicidade",
"publicitate",
"publicité",
"rastreamento",
"rechazar",
"refuza",
"reject",
"rejeitar",
"rejeter",
"reklama",
"rendimiento",
"respinge",
"rifiutare",
"salva",
"salvar",
"salvare",
"sauvegarder",
"save",
"schließen",
"seguimiento",
"setări",
"settings",
"śledzenie",
"speichern",
"strona trzecia",
"suivi",
"terceiro",
"tercero",
"terță parte",
"terza parte",
"third-party",
"tiers",
"tracciamento",
"tracking",
"urmărire",
"usage",
"uso",
"ustawienia",
"utilisation",
"utilizare",
"użycie",
"verfolgung",
"verwalten",
"werbung",
"wydajność",
"zaakceptować",
"zamknij",
"zapisz",
"zarządzać",
"zgoda",
"zgodność",
"zgodzić się",
"zrzeczenie się",
"zustimmen",
"аналитика",
"баннер",
"всплывающее окно",
"данные",
"диалог",
"закон",
"закрыть",
"информация",
"использование",
"конфиденциальность",
"настройки",
"необходимо",
"опционально",
"отказ",
"отказаться",
"отклонить",
"отслеживание",
"персонализация",
"политика",
"предпочтения",
"принять",
"производительность",
"реклама",
"согласен",
"согласие",
"соответствие",
"сохранить",
"третья сторона",
"управлять",
"функциональный"
],
"fixes": [
{
"action": "click",
"domain": "action.com",
"name": "click",
"selector": "#CybotCookiebotDialogBodyLevelButtonLevelOptinDeclineAll"
},
{
"action": "resetAll",
"domain": "automobielmanagement.nl",
"name": "resetAll",
"property": "filter",
"selector": "body > *"
},
{
"action": "click",
"domain": "bilbaomuseoa.eus",
"name": "click",
"selector": ".alert_message .btn-confirm"
},
{
"action": "resetAll",
"domain": "breitbart.com",
"name": "resetAll",
"property": "display",
"selector": ".twitter-tweet"
},
{
"action": "resetAll",
"domain": "breitbart.com",
"name": "resetAll",
"property": "visibility",
"selector": ".twitter-tweet"
},
{
"action": "click",
"domain": "buscotelefonosgratis.es",
"name": "click",
"selector": "#cookie_action_close_header_reject"
},
{
"action": "click",
"domain": "chollometro.com",
"name": "click",
"selector": "[data-t=\"continueWithoutAccepting\"]"
},
{
"action": "click",
"domain": "classicube.net",
"name": "click",
"selector": "#acceptcookies"
},
{
"action": "click",
"domain": "compact-online.de",
"name": "click",
"selector": "[id*=\"bnnr-body-rightSide-\"] div + div > span"
},
{
"action": "click",
"domain": "consent.google",
"name": "click",
"selector": "[aria-label=\"Alle ablehnen\"], [aria-label=\"Odrzuć wszystko\"], [aria-label=\"Rechazar todo\"], [aria-label=\"Recusar tudo\"], [aria-label=\"Reject all\"], [aria-label=\"Rejeitar tudo\"], [aria-label=\"Respinge tot\"], [aria-label=\"Rifiuta tutto\"], [aria-label=\"Tout refuser\"], [aria-label=\"Отклонить все\"]"
},
{
"action": "click",
"domain": "consent.yahoo",
"name": "click",
"selector": ".reject-all"
},
{
"action": "click",
"domain": "consent.youtube",
"name": "click",
"selector": "[aria-label=\"Alle ablehnen\"], [aria-label=\"Odrzuć wszystko\"], [aria-label=\"Rechazar todo\"], [aria-label=\"Recusar tudo\"], [aria-label=\"Reject all\"], [aria-label=\"Rejeitar tudo\"], [aria-label=\"Respinge tot\"], [aria-label=\"Rifiuta tutto\"], [aria-label=\"Tout refuser\"], [aria-label=\"Отклонить все\"]"
},
{
"action": "click",
"domain": "dailymotion.com",
"name": "click",
"selector": "[aria-label=\"Continue without accepting\"]"
},
{
"action": "click",
"domain": "dealabs.com",
"name": "click",
"selector": "[data-t=\"continueWithoutAccepting\"]"
},
{
"action": "click",
"domain": "derstandard",
"name": "click",
"selector": "[aria-label=\"Einverstanden\"]"
},
{
"action": "click",
"domain": "fiberplane.dev",
"name": "click",
"selector": "button[aria-label=\"Close Banner\"]"
},
{
"action": "click",
"domain": "foto-erhardt.de",
"name": "click",
"selector": "[class=\"modal show\"]"
},
{
"action": "reset",
"domain": "gamestar.de",
"name": "reset",
"property": "filter",
"selector": "#content"
},
{
"action": "click",
"domain": "gettr.com",
"name": "click",
"selector": "button.bold"
},
{
"action": "click",
"domain": "gib-uns-deinen-gebrauchten.de",
"name": "click",
"selector": "#cookie-banner-accept-selected-button"
},
{
"action": "click",
"domain": "gmx.com",
"name": "click",
"selector": "#onetrust-accept-btn-handler"
},
{
"action": "click",
"domain": "gmx.net",
"name": "click",
"selector": "[data-id=\"save-all-pur\"]"
},
{
"action": "click",
"domain": "golem.de",
"name": "click",
"selector": "[title=\"Zustimmen und weiter\"]"
},
{
"action": "click",
"domain": "google",
"name": "click",
"selector": "[aria-modal=\"true\"][role=\"dialog\"]:has([href*=\"policies.google.com/technologies/cookies\"]) button:not([aria-label]):not([role=\"link\"])"
},
{
"action": "click",
"domain": "hagglezon.com",
"name": "click",
"selector": "[data-test=\"cookie-submit\"]"
},
{
"action": "click",
"domain": "instagram.com",
"name": "click",
"selector": "[role=\"dialog\"] > [style=\"display: flex; flex-direction: column; height: 100%; max-width: 100%;\"] > button"
},
{
"action": "click",
"domain": "motorolasound.com",
"name": "click",
"selector": "#cookie-btn-denied"
},
{
"action": "click",
"domain": "mydealz.de",
"name": "click",
"selector": "[data-t=\"continueWithoutAccepting\"]"
},
{
"domain": "myprivacy.dpgmedia",
"name": "reload"
"action": "reload",
"domain": "myprivacy.dpgmedia"
},
{
"action": "click",
"domain": "off-campers.com",
"name": "click",
"selector": "[form=\"cookie-consent-form\"][value=\"deny\"]"
},
{
"action": "reset",
"domain": "orcd.co",
"name": "reset",
"property": "opacity",
"selector": ".player-container.box-shadow"
},
{
"action": "resetAll",
"domain": ".pl",
"name": "resetAll",
"property": "filter",
"selector": "body:has(.advertisement.contentAds.ads.adsbygoogle.top-banners.adbanner.bannerAd.ad-google.AdSense:first-child) > *"
},
{
"action": "reset",
"domain": "play.google",
"name": "reset",
"property": "z-index",
"selector": "body > div"
},
{
"action": "click",
"domain": "popeyes.es",
"name": "click",
"selector": ".cookie-buttons > .cookie-buttons-column > div:last-child"
},
{
"action": "click",
"domain": "producthunt.com",
"name": "click",
"selector": "[data-test=\"dismiss-CookiePopup\"] button"
},
{
"action": "click",
"domain": "reddit.com",
"name": "click",
"selector": "#SHORTCUT_FOCUSABLE_DIV [style*=\"--Toaster\"] section:last-child section:last-child button"
},
{
"action": "reset",
"domain": "resonanz-labor.de",
"name": "reset",
"property": "overflow",
"selector": "#wrapwrap"
},
{
"action": "click",
"domain": "staylibere.com",
"name": "click",
"selector": "[class*=\"LayoutCookieBanner_buttons\"] > button:last-child"
},
{
"action": "reset",
"domain": "thetvdb.com",
"name": "reset",
"property": "overflow",
"selector": "body"
},
{
"action": "click",
"domain": "twitch.tv",
"name": "click",
"selector": "[data-a-target=\"consent-banner-accept\"]"
},
{
"action": "click",
"domain": "usnews.com",
"name": "click",
"selector": "#gdpr-modal-agree"
},
{
"action": "click",
"domain": "web.de",
"name": "click",
"selector": "#reminder"
},
{
"action": "click",
"domain": "web.dev",
"name": "click",
"selector": "a[href*=\"cookies\"] + button"
},
{
"action": "click",
"domain": "youtube.com",
"name": "click",
"selector": "[aria-label*=\"ablehnen\"], [aria-label*=\"Reject\"], [aria-label*=\"Rechazar\"], [aria-label*=\"refuser\"], [aria-label*=\"Rifiuta\"], [aria-label*=\"Nie wyrażaj zgody\"], [aria-label*=\"Rejeitar\"], [aria-label*=\"Recusar\"], [aria-label*=\"Resping\"], [aria-label*=\"Запретить\"]"
},
{
"action": "click",
"domain": "zdf.de",
"name": "click",
"selector": "#aria-dialog-cmp-error-dialog > .dialog-close"
},
{
"action": "click",
"domain": "zeit.de",
"name": "click",
"selector": "[title=\"ACCEPT AND CONTINUE\"]"
}
],
"exclusions": {
"rules": [
"||app.usercentrics.eu^",
"||b2brouter.net/de/wp-content/plugins/cookies-and-content-security-policy^",
"||benno-gymnasium.de/plugins/system/gdpr^",
"||c.evidon.com^",
"||cdn-cookieyes.com^",
"||cdn.consentmanager.net^",
"||cdn.cookielaw.org^",
"||cdn.optable.co^",
"||cdn.trustcommander.net/privacy^",
"||cdntranscend.eventbrite.com^",
"||chollometro.com/assets/js/CookiesMessage*.js^",
"||city-bahn.de/wp-content/plugins/borlabs-cookie^",
"||cmp.huffingtonpost.fr^",
"||cmp.inmobi.com^",
"||cmp.prisa.com^",
"||cmp.uniconsent.com^",
"||cms.static-bahn.de/cms/consent-layer^",
"||consent.cookiebot.com^",
"||consent.cookiefirst.com^",
"||consent.pdf24.org^",
"||consent.trustarc.com^",
"||consent.up.welt.de^",
"||consentbar.interencheres.com^",
"||consentcdn.cookiebot.com^",
"||cookiehub.net^",
"||cp.as.com^",
"||cp.inside-digital.de^",
"||download.amd.com/OneTrust^",
"||driftingchef.com/static/*/Sticky2,ConsentManager",
"||emp.bbci.co.uk^",
"||eu.fastcmp.com^",
"||forum.vorondesign.com/js/xf/notice.min.js^",
"||gdpr-tcfv2.sp-prod.net^",
"||get.optad360.io/sf/*/plugin.min.js",
"||ilims.de/typo3conf/ext/nb_cookie_banner^",
"||itkadmin.de/_javascripts/cookiesolution/es_cookie_solution_sources_v2.js^",
"||js.vxcdn.com/usercentrics-sdk^",
"||lensois.com/wp-admin/admin-ajax.php",
"||media.bzcompany.cz/scookies^",
"||myprivacy-static.dpgmedia.net/consent.js^",
"||myprivacy.dpgmedia.*/consent^",
"||optanon.blob.core.windows.net^",
"||privacy.wetransfer.com/fides.js^",
"||prod.widgets.burgerprofiel.vlaanderen.be/*/js.cookie.js^",
"||redditstatic.com/onetrust.*.js",
"||s.nitropay.com/gpp-*.min.js",
"||s.p7s1.io/cmp^",
"||sdk.privacy-center.org^",
"||static.fastcmp.com^",
"||transcend-cdn.com^",
"||wcpstatic.microsoft.com^",
"||webtools.europa.eu/js/webtools.cck.js^",
"||widgets.marketcat.net^"
],
"skips": {
"domains": [
"*.bauhaus.cz",
"*.codesandbox.io",
"*.cookie-dialog-monster.com",
"*.facebook.com",
"*.googleapis.com",
"*.olympics.com",
"translate.google.*",
"www.youtube-nocookie.com",
"www.youtube.com"
],
"overflows": [
"app.diagrams.net",
"blog.sapegin.me",
"buyagift.co.uk",
@ -674,307 +964,6 @@
"YTD-YOODLE-RENDERER"
]
},
"keywords": [
"ablehnen",
"accept",
"accepta",
"accepter",
"accettare",
"accordo",
"aceitar",
"aceptar",
"acuerdo",
"advertising",
"agree",
"akzeptieren",
"analitica",
"analítica",
"analitice",
"analityka",
"analyse",
"analytics",
"analytique",
"baner",
"banner",
"bannière",
"cc",
"cerrar",
"chiudere",
"close",
"cmp",
"compliance",
"concordar",
"confidențialitate",
"confidentialité",
"configuraciones",
"configurações",
"conformidade",
"conformità",
"conformitate",
"conformité",
"consenso",
"consent",
"consentement",
"consentimento",
"consentimiento",
"consimțământ",
"cookie",
"cumplimiento",
"d'accord",
"dados",
"dane",
"data",
"date",
"daten",
"datenschutz",
"dati",
"datos",
"de acord",
"declinar",
"declinare",
"decline",
"décliner",
"déni",
"descargo de responsabilidad",
"desempenho",
"dialog",
"dialogo",
"diálogo",
"dialogue",
"disclaimer",
"disconoscimento",
"données",
"dritte",
"einstellungen",
"einwilligung",
"fechar",
"fermer",
"fonctionnel",
"funcional",
"functional",
"funcțional",
"funkcjonalny",
"funktional",
"funzionale",
"gdpr",
"gerenciar",
"gérer",
"gesetz",
"gestiona",
"gestionar",
"gestire",
"guardar",
"haftungsausschluss",
"impostazioni",
"închide",
"informação",
"información",
"informacja",
"informații",
"information",
"informazione",
"isenção de responsabilidade",
"konformität",
"konieczny",
"law",
"lege",
"legge",
"lei",
"leistung",
"ley",
"loi",
"manage",
"necesar",
"necesario",
"nécessaire",
"necessario",
"necessário",
"necessary",
"notwendig",
"nutzung",
"odmówić",
"odrzucić",
"opcional",
"opcjonalny",
"optional",
"opțional",
"optionnel",
"opzionale",
"paramètres",
"performance",
"performanță",
"personalisierung",
"personalização",
"personalización",
"personalizacja",
"personalizare",
"personalization",
"personalizzazione",
"personnalisation",
"policy",
"politica",
"politică",
"política",
"politik",
"politique",
"polityka",
"popup",
"präferenzen",
"prawo",
"preferences",
"préférences",
"preferencias",
"preferências",
"preferencje",
"preferenze",
"preferințe",
"prestazioni",
"privacidad",
"privacidade",
"privacy",
"prywatność",
"pubblicità",
"publicidad",
"publicidade",
"publicitate",
"publicité",
"rastreamento",
"rechazar",
"refuza",
"reject",
"rejeitar",
"rejeter",
"reklama",
"rendimiento",
"respinge",
"rifiutare",
"salva",
"salvar",
"salvare",
"sauvegarder",
"save",
"schließen",
"seguimiento",
"setări",
"settings",
"śledzenie",
"speichern",
"strona trzecia",
"suivi",
"terceiro",
"tercero",
"terță parte",
"terza parte",
"third-party",
"tiers",
"tracciamento",
"tracking",
"urmărire",
"usage",
"uso",
"ustawienia",
"utilisation",
"utilizare",
"użycie",
"verfolgung",
"verwalten",
"werbung",
"wydajność",
"zaakceptować",
"zamknij",
"zapisz",
"zarządzać",
"zgoda",
"zgodność",
"zgodzić się",
"zrzeczenie się",
"zustimmen",
"аналитика",
"баннер",
"всплывающее окно",
"данные",
"диалог",
"закон",
"закрыть",
"информация",
"использование",
"конфиденциальность",
"настройки",
"необходимо",
"опционально",
"отказ",
"отказаться",
"отклонить",
"отслеживание",
"персонализация",
"политика",
"предпочтения",
"принять",
"производительность",
"реклама",
"согласен",
"согласие",
"соответствие",
"сохранить",
"третья сторона",
"управлять",
"функциональный"
],
"rules": [
"||app.usercentrics.eu^",
"||b2brouter.net/de/wp-content/plugins/cookies-and-content-security-policy^",
"||benno-gymnasium.de/plugins/system/gdpr^",
"||c.evidon.com^",
"||cdn-cookieyes.com^",
"||cdn.consentmanager.net^",
"||cdn.cookielaw.org^",
"||cdn.optable.co^",
"||cdn.trustcommander.net/privacy^",
"||cdntranscend.eventbrite.com^",
"||chollometro.com/assets/js/CookiesMessage*.js^",
"||city-bahn.de/wp-content/plugins/borlabs-cookie^",
"||cmp.huffingtonpost.fr^",
"||cmp.inmobi.com^",
"||cmp.prisa.com^",
"||cmp.uniconsent.com^",
"||cms.static-bahn.de/cms/consent-layer^",
"||consent.cookiebot.com^",
"||consent.cookiefirst.com^",
"||consent.pdf24.org^",
"||consent.trustarc.com^",
"||consent.up.welt.de^",
"||consentbar.interencheres.com^",
"||consentcdn.cookiebot.com^",
"||cookiehub.net^",
"||cp.as.com^",
"||cp.inside-digital.de^",
"||download.amd.com/OneTrust^",
"||driftingchef.com/static/*/Sticky2,ConsentManager",
"||emp.bbci.co.uk^",
"||eu.fastcmp.com^",
"||forum.vorondesign.com/js/xf/notice.min.js^",
"||gdpr-tcfv2.sp-prod.net^",
"||get.optad360.io/sf/*/plugin.min.js",
"||ilims.de/typo3conf/ext/nb_cookie_banner^",
"||itkadmin.de/_javascripts/cookiesolution/es_cookie_solution_sources_v2.js^",
"||js.vxcdn.com/usercentrics-sdk^",
"||lensois.com/wp-admin/admin-ajax.php",
"||media.bzcompany.cz/scookies^",
"||myprivacy-static.dpgmedia.net/consent.js^",
"||myprivacy.dpgmedia.*/consent^",
"||optanon.blob.core.windows.net^",
"||privacy.wetransfer.com/fides.js^",
"||prod.widgets.burgerprofiel.vlaanderen.be/*/js.cookie.js^",
"||redditstatic.com/onetrust.*.js",
"||s.nitropay.com/gpp-*.min.js",
"||s.p7s1.io/cmp^",
"||sdk.privacy-center.org^",
"||static.fastcmp.com^",
"||transcend-cdn.com^",
"||wcpstatic.microsoft.com^",
"||webtools.europa.eu/js/webtools.cck.js^",
"||widgets.marketcat.net^"
],
"tokens": {
"backdrops": [
".cc-policy-overlay",
@ -14008,5 +13997,5 @@
"ytm-consent-bump-v2-renderer"
]
},
"version": "1729252494919"
"version": "1728300083309"
}

View File

@ -12,9 +12,6 @@ import v4ReportRoutes from 'routes/v4/report';
import v5DataRoutes from 'routes/v5/data';
import v5IssuesRoutes from 'routes/v5/issues';
import v5ReportRoutes from 'routes/v5/report';
import v6DataRoutes from 'routes/v6/data';
import v6IssuesRoutes from 'routes/v6/issues';
import v6ReportRoutes from 'routes/v6/report';
import environment from 'services/environment';
const server = fastify({ logger: true });
@ -42,9 +39,6 @@ server.register(v4ReportRoutes, { prefix: '/rest/v4' });
server.register(v5DataRoutes, { prefix: '/rest/v5' });
server.register(v5IssuesRoutes, { prefix: '/rest/v5' });
server.register(v5ReportRoutes, { prefix: '/rest/v5' });
server.register(v6DataRoutes, { prefix: '/rest/v6' });
server.register(v6IssuesRoutes, { prefix: '/rest/v6' });
server.register(v6ReportRoutes, { prefix: '/rest/v6' });
server.listen({ host: '0.0.0.0', port: environment.port }, (error, address) => {
if (error) {

View File

@ -1,6 +1,6 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch';
import { parseAction } from 'services/compatibility';
import { parseNewFix } from 'services/compatibility';
import environment from 'services/environment';
import { RATE_LIMIT_10_PER_MIN } from 'services/rateLimit';
@ -14,18 +14,17 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
},
async (_request, reply) => {
try {
const database = `${environment.gitea.raw}/database.json`;
const response = await fetch(database);
const { actions, exclusions, keywords, tokens } = await response.json();
const url = `${environment.gitea.raw}/database.json`;
const result = await (await fetch(url)).json();
reply.send({
data: {
classes: tokens.classes,
commonWords: keywords,
elements: tokens.selectors,
fixes: actions.map(parseAction),
skips: exclusions.overflows,
tags: exclusions.tags,
classes: result.tokens.classes,
commonWords: result.commonWords,
elements: result.tokens.selectors,
fixes: result.fixes.map(parseNewFix),
skips: result.skips.domains,
tags: result.skips.tags,
},
success: true,
});

View File

@ -1,6 +1,6 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch';
import { parseAction } from 'services/compatibility';
import { parseNewFix } from 'services/compatibility';
import environment from 'services/environment';
import { RATE_LIMIT_3_PER_MIN } from 'services/rateLimit';
@ -14,16 +14,13 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
},
async (_request, reply) => {
try {
const database = `${environment.gitea.raw}/database.json`;
const response = await fetch(database);
const { actions, exclusions, keywords, ...rest } = await response.json();
const url = `${environment.gitea.raw}/database.json`;
const result = await (await fetch(url)).json();
reply.send({
data: {
...rest,
commonWords: keywords,
fixes: actions.map(parseAction),
skips: { domains: exclusions.overflows, tags: exclusions.tags },
...result,
fixes: result.fixes.map(parseNewFix),
},
success: true,
});

View File

@ -1,6 +1,5 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch';
import { parseActionName, toDeclarativeNetRequestRule } from 'services/compatibility';
import environment from 'services/environment';
import { RATE_LIMIT_3_PER_MIN } from 'services/rateLimit';
@ -14,18 +13,14 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
},
async (_request, reply) => {
try {
const database = `${environment.gitea.raw}/database.json`;
const options = { headers: { 'Cache-Control': 'no-cache' } };
const response = await fetch(database, options);
const { actions, exclusions, keywords, rules, ...rest } = await response.json();
const url = `${environment.gitea.raw}/database.json`;
const { rules, ...result } = await (await fetch(url, options)).json();
reply.send({
data: {
...rest,
actions: actions.map(parseActionName),
commonWords: keywords,
...result,
rules: rules.map(toDeclarativeNetRequestRule),
skips: { domains: exclusions.overflows, tags: exclusions.tags },
},
success: true,
});
@ -40,3 +35,17 @@ export default (server: FastifyInstance, _options: RouteShorthandOptions, done:
done();
};
function toDeclarativeNetRequestRule(urlFilter: string, index: number) {
return {
action: {
type: 'block',
},
condition: {
resourceTypes: ['font', 'image', 'media', 'object', 'script', 'stylesheet', 'xmlhttprequest'],
urlFilter,
},
id: index + 1,
priority: 1,
};
}

View File

@ -1,39 +0,0 @@
import { FastifyInstance, RouteShorthandOptions } from 'fastify';
import fetch from 'node-fetch';
import { toDeclarativeNetRequestRule } from 'services/compatibility';
import environment from 'services/environment';
import { RATE_LIMIT_3_PER_MIN } from 'services/rateLimit';
export default (server: FastifyInstance, _options: RouteShorthandOptions, done: () => void) => {
server.get(
'/data/',
{
config: {
rateLimit: RATE_LIMIT_3_PER_MIN,
},
},
async (_request, reply) => {
try {
const database = `${environment.gitea.raw}/database.json`;
const options = { headers: { 'Cache-Control': 'no-cache' } };
const response = await fetch(database, options);
const { rules, ...rest } = await response.json();
reply.send({
data: {
...rest,
rules: rules.map(toDeclarativeNetRequestRule),
},
success: true,
});
} catch (error) {
reply.send({
errors: [error.message],
success: false,
});
}
}
);
done();
};

View File

@ -1 +0,0 @@
export { default as default } from '../v5/issues';

View File

@ -1 +0,0 @@
export { default as default } from '../v5/report';

View File

@ -1,32 +1,13 @@
export function parseAction(action: Action): string {
return `${action.domain}##${action.selector}##${action.name}${action.property ? `##${action.property}` : ''}`;
/**
* Parse the new fix object into the old string format used by older versions of the extension
*/
export function parseNewFix(fix: Fix): string {
return `${fix.domain}##${fix.selector}##${fix.action}${fix.property ? `##${fix.property}` : ''}`;
}
export function parseActionName(
action: Action
): Omit<Action, 'name'> & { readonly action: string } {
const { name, ...rest } = action;
return { action: name, ...rest };
}
export function toDeclarativeNetRequestRule(urlFilter: string, index: number) {
return {
action: {
type: 'block',
},
condition: {
resourceTypes: ['font', 'image', 'media', 'object', 'script', 'stylesheet', 'xmlhttprequest'],
urlFilter,
},
id: index + 1,
priority: 1,
};
}
export interface Action {
export interface Fix {
readonly action: string;
readonly domain: string;
readonly name: string;
readonly property?: string;
readonly selector: string;
}

View File

@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "Cookie Dialog Monster Mobile",
"version": "8.0.2",
"version": "8.0.1",
"default_locale": "en",
"description": "__MSG_appDesc__",
"icons": {
@ -28,6 +28,28 @@
"content_scripts": [
{
"all_frames": true,
"exclude_matches": [
"*://*.bauhaus.cz/*",
"*://*.codesandbox.io/*",
"*://*.facebook.com/*",
"*://*.googleapis.com/embed/*",
"*://*.olympics.com/*",
"*://*.youtube-nocookie.com/embed/*",
"*://*.youtube.com/embed/*",
"*://www.youtube.com/*",
"*://translate.google.ca/*",
"*://translate.google.co.in/*",
"*://translate.google.co.jp/*",
"*://translate.google.co.uk/*",
"*://translate.google.com.au/*",
"*://translate.google.com.br/*",
"*://translate.google.com/*",
"*://translate.google.de/*",
"*://translate.google.es/*",
"*://translate.google.fr/*",
"*://translate.google.it/*",
"*://www.cookie-dialog-monster.com/*"
],
"js": ["scripts/content.js"],
"matches": ["http://*/*", "https://*/*"],
"run_at": "document_start"

View File

@ -49,7 +49,7 @@ class RequestManager {
* @description API URL
* @type {string}
*/
const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v6';
const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v5';
/**
* @description Request manager instance
@ -144,6 +144,34 @@ async function getState(hostname) {
return { ...stateByDefault, ...state, updateAvailable };
}
/**
* @description Format number to avoid errors
* @param {number} [value]
* @returns {string | null}
*/
function formatNumber(value) {
if (value) {
if (value >= 1e6) {
return `${Math.floor(value / 1e6)}M`;
} else if (value >= 1e3) {
return `${Math.floor(value / 1e3)}K`;
} else {
return value.toString();
}
}
return null;
}
/**
* @description Convert match string to pattern string
* @param {string} match
* @returns {string}
*/
function matchToPattern(match) {
return `^${match.replaceAll('*.', '*(.)?').replaceAll('*', '.*')}$`;
}
/**
* @async
* @description Refresh data
@ -287,10 +315,11 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
case 'REPORT':
report(message).then(callback);
return true;
case 'UPDATE_BADGE':
if (isPage && tabId !== undefined) {
browser.action.setBadgeBackgroundColor({ color: '#6b7280' });
browser.action.setBadgeText({ tabId, text: message.value ? `${message.value}` : null });
browser.action.setBadgeText({ tabId, text: formatNumber(message.value) });
}
break;
case 'UPDATE_STORE':
@ -306,7 +335,6 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
*/
browser.runtime.onInstalled.addListener((details) => {
if (details.reason === 'update') {
refreshData();
storage.remove('updateAvailable');
}
});
@ -334,24 +362,27 @@ browser.webRequest.onBeforeRequest.addListener(
const { tabId, type, url } = details;
if (tabId > -1 && type === 'main_frame') {
const { exclusions, rules } = await getData();
const manifest = browser.runtime.getManifest();
const excludeMatches = manifest.content_scripts[0].exclude_matches;
const excludePatterns = excludeMatches.map(matchToPattern);
if (exclusions.domains.some((x) => location.hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
if (excludePatterns.some((pattern) => new RegExp(pattern).test(url))) {
return;
}
const data = await getData();
const hostname = getHostname(url);
const state = await getState(hostname);
if (rules?.length) {
const rulesWithTabId = rules.map((rule) => ({
if (data?.rules?.length) {
const rules = data.rules.map((rule) => ({
...rule,
condition: { ...rule.condition, tabIds: [tabId] },
}));
await browser.declarativeNetRequest.updateSessionRules({
addRules: state.on ? rulesWithTabId : undefined,
removeRuleIds: rules.map((rule) => rule.id),
addRules: state.on ? rules : undefined,
removeRuleIds: data.rules.map((rule) => rule.id),
});
}
}
@ -364,10 +395,15 @@ browser.webRequest.onBeforeRequest.addListener(
*/
browser.webRequest.onErrorOccurred.addListener(
async (details) => {
const { error, tabId } = details;
const { error, tabId, url } = details;
if (error === 'net::ERR_BLOCKED_BY_CLIENT' && tabId > -1) {
await browser.tabs.sendMessage(tabId, { type: 'INCREASE_ACTIONS_COUNT', value: error });
const hostname = getHostname(url);
const state = await getState(hostname);
if (state.on) {
await browser.tabs.sendMessage(tabId, { type: 'INCREASE_ACTIONS_COUNT' });
}
}
},
{ urls: ['<all_urls>'] }

View File

@ -1,9 +1,9 @@
/**
* @typedef {Object} Action
* @property {string} domain
* @property {string} name
* @property {string} [property]
* @property {string} selector
* @typedef {Object} ExtensionData
* @property {string[]} commonWords
* @property {Fix[]} fixes
* @property {{ domains: string[], tags: string[] }} skips
* @property {{ backdrops: string[], classes: string[], containers: string[], selectors: string[] }} tokens
*/
/**
@ -12,24 +12,11 @@
*/
/**
* @typedef {Object} ExclusionMap
* @property {string[]} domains
* @property {string[]} overflows
* @property {string[]} tags
*/
/**
* @typedef {Object} ExtensionData
* @property {Action[]} actions
* @property {ExclusionMap} exclusions
* @property {string[]} keywords
* @property {TokenMap} tokens
*/
/**
* @typedef {Object} GetElementsParams
* @property {boolean} [filterEarly]
* @property {HTMLElement} [from]
* @typedef {Object} Fix
* @property {string} action
* @property {string} domain
* @property {string} [property]
* @property {string} selector
*/
/**
@ -40,11 +27,9 @@
*/
/**
* @typedef {Object} TokenMap
* @property {string[]} backdrops
* @property {string[]} classes
* @property {string[]} containers
* @property {string[]} selectors
* @typedef {Object} GetElementsParams
* @property {boolean} [filterEarly]
* @property {HTMLElement} [from]
*/
/**
@ -57,31 +42,22 @@ if (typeof browser === 'undefined') {
}
/**
* @description Class for request batching
* @description Actions done by the extension
* @type {Set<string>}
*/
class NotifiableSet extends Set {
constructor(...args) {
super(...args);
}
add(value) {
super.add(value);
browser.runtime.sendMessage({ type: 'UPDATE_BADGE', value: super.size });
}
}
const actions = new Set();
/**
* @description Data object with all the necessary information
* @type {ExtensionData}
*/
let { actions, exclusions, keywords, tokens } = {
actions: [],
exclusions: {
let { commonWords, fixes, skips, tokens } = {
commonWords: [],
fixes: [],
skips: {
domains: [],
overflows: [],
tags: [],
},
keywords: [],
tokens: {
backdrops: [],
classes: [],
@ -104,13 +80,7 @@ const hostname = getHostname();
* @description Initial visibility state
* @type {boolean}
*/
let initiallyVisible = false;
/**
* @description Log of those steps done by the extension
* @type {NotifiableSet<string>}
*/
const log = new NotifiableSet();
let initiallyVisible = document.visibilityState === 'visible';
/**
* @description Options provided to observer
@ -126,9 +96,9 @@ const seen = new Set();
/**
* @description Extension state
* @type {ContentState | undefined}
* @type {ContentState}
*/
let state = undefined;
let state = { on: true };
/**
* @description Clean DOM
@ -150,7 +120,8 @@ function clean(elements, skipMatch) {
if (element instanceof HTMLDialogElement) element.close();
hide(element);
log.add(`${Date.now()}`);
actions.add(`${Date.now()}`);
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
}
seen.add(element);
@ -165,11 +136,11 @@ function clean(elements, skipMatch) {
}
/**
* @description Check if element contains a keyword
* @description Check if element contains a common word
* @param {HTMLElement} element
*/
function hasKeyword(element) {
return !!keywords?.length && !!element.outerHTML.match(new RegExp(keywords.join('|')));
function containsCommonWord(element) {
return !!commonWords.length && !!element.outerHTML.match(new RegExp(commonWords.join('|')));
}
/**
@ -232,21 +203,6 @@ function getHostname() {
return hostname.split('.').slice(-3).join('.').replace('www.', '');
}
/**
* @async
* @description Run if the page wasn't visited yet
* @param {Object} message
* @returns {Promise<void>}
*/
function handleRuntimeMessage(message) {
switch (message.type) {
case 'INCREASE_ACTIONS_COUNT': {
log.add(message.value);
break;
}
}
}
/**
* @description Check if an element is visible in the viewport
* @param {HTMLElement} element
@ -273,7 +229,7 @@ function isInViewport(element) {
* @returns {boolean}
*/
function match(element, skipMatch) {
if (!exclusions.tags.length || !tokens.selectors.length) {
if (!tokens.selectors.length || !skips.tags.length) {
return false;
}
@ -287,7 +243,7 @@ function match(element, skipMatch) {
const tagName = element.tagName.toUpperCase();
if (exclusions.tags.includes(tagName)) {
if (skips.tags.includes(tagName)) {
return false;
}
@ -327,7 +283,7 @@ function filterNodeEarly(node, stopRecursion) {
return [];
}
if (hasKeyword(node) && !stopRecursion) {
if (commonWords && containsCommonWord(node) && !stopRecursion) {
return [node, ...[...node.children].flatMap((node) => filterNodeEarly(node, true))];
}
@ -335,27 +291,46 @@ function filterNodeEarly(node, stopRecursion) {
}
/**
* @description Fix specific cases
* @description Fix data, middle consent page and scroll issues
* @returns {void}
*/
function fix() {
for (const action of actions) {
const { domain, name, property, selector } = action;
const backdrops = getElements(tokens.backdrops);
const domains = skips.domains.map((x) => (x.split('.').length < 3 ? `*${x}` : x));
if (hostname.match(domain.replaceAll(/\*/g, '[^ ]*'))) {
switch (name) {
for (const backdrop of backdrops) {
if (backdrop.children.length === 0 && !seen.has(backdrop)) {
actions.add(`${Date.now()}`);
seen.add(backdrop);
hide(backdrop);
}
}
if (domains.every((x) => !hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
for (const element of [document.body, document.documentElement]) {
element?.classList.remove(...(tokens.classes ?? []));
element?.style.setProperty('position', 'initial', 'important');
element?.style.setProperty('overflow-y', 'initial', 'important');
}
}
for (const fix of fixes) {
const { action, domain, property, selector } = fix;
if (hostname.includes(domain)) {
switch (action) {
case 'click': {
const element = document.querySelector(selector);
actions.add('click');
element?.click();
log.add(name);
break;
}
case 'remove': {
const element = document.querySelector(selector);
actions.add('remove');
element?.style?.removeProperty(property);
log.add(name);
break;
}
case 'reload': {
@ -365,56 +340,38 @@ function fix() {
case 'reset': {
const element = document.querySelector(selector);
actions.add('reset');
element?.style?.setProperty(property, 'initial', 'important');
log.add(name);
break;
}
case 'resetAll': {
const elements = getElements(selector);
actions.add('resetAll');
elements.forEach((e) => e?.style?.setProperty(property, 'initial', 'important'));
log.add(name);
break;
}
}
}
}
const backdrops = getElements(tokens.backdrops);
for (const backdrop of backdrops) {
if (backdrop.children.length === 0 && !seen.has(backdrop)) {
log.add(`${Date.now()}`);
seen.add(backdrop);
hide(backdrop);
}
}
const skips = exclusions.overflows.map((x) => (x.split('.').length < 3 ? `*${x}` : x));
if (!skips.some((x) => hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
for (const element of [document.body, document.documentElement]) {
element?.classList.remove(...(tokens.classes ?? []));
element?.style.setProperty('position', 'initial', 'important');
element?.style.setProperty('overflow-y', 'initial', 'important');
}
}
const ionRouterOutlet = document.getElementsByTagName('ion-router-outlet')[0];
if (ionRouterOutlet) {
actions.add('ion-router-outlet');
// 2024-08-02: fix #644 temporarily
ionRouterOutlet.removeAttribute('inert');
log.add('ion-router-outlet');
}
const t4Wrapper = document.getElementsByClassName('t4-wrapper')[0];
if (t4Wrapper) {
log.add('t4-wrapper');
actions.add('t4-wrapper');
// 2024-09-12: fix #945 temporarily
t4Wrapper.removeAttribute('inert');
}
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
}
/**
@ -455,48 +412,41 @@ function run(params = {}) {
* @async
* @description Set up the extension
* @param {SetUpParams} [params]
* @returns {Promise<void>}
*/
async function setUp(params = {}) {
const data = await dispatch({ hostname, type: 'GET_DATA' });
exclusions = data?.exclusions ?? exclusions;
if (exclusions.domains.some((x) => location.hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
dispatch({ type: 'DISABLE_ICON' });
observer.disconnect();
return;
}
state = await dispatch({ hostname, type: 'GET_STATE' });
dispatch({ type: 'ENABLE_POPUP' });
dispatch({ type: 'ENABLE_REPORT' });
if (state.on) {
browser.runtime.onMessage.addListener(handleRuntimeMessage);
dispatch({ hostname, type: 'ENABLE_ICON' });
const data = await dispatch({ hostname, type: 'GET_DATA' });
actions = data?.actions ?? actions;
keywords = data?.keywords ?? keywords;
commonWords = data?.commonWords ?? commonWords;
fixes = data?.fixes ?? fixes;
skips = data?.skips ?? skips;
tokens = data?.tokens ?? tokens;
dispatch({ type: 'ENABLE_REPORT' });
dispatch({ hostname, type: 'ENABLE_ICON' });
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
observer.observe(document.body ?? document.documentElement, options);
if (!params.skipRunFn) run({ containers: tokens.containers });
} else {
dispatch({ type: 'DISABLE_REPORT' });
dispatch({ type: 'DISABLE_ICON' });
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
observer.disconnect();
}
}
/**
* @description Wait for the body to exist
* @returns {Promise<void>}
* @param {void} callback
* @returns {void}
*/
async function setUpAfterWaitForBody() {
if (document.visibilityState === 'visible' && !initiallyVisible) {
if (document.body) {
initiallyVisible = true;
await setUp();
return;
}
if (document.body) {
await setUp();
} else {
setTimeout(setUpAfterWaitForBody, 50);
}
}
@ -516,6 +466,50 @@ const observer = new MutationObserver((mutations) => {
run({ elements });
});
document.addEventListener('visibilitychange', setUpAfterWaitForBody);
window.addEventListener('pageshow', setUpAfterWaitForBody);
setUpAfterWaitForBody();
/**
* @description Listen to messages from any other scripts
* @listens browser.runtime#onMessage
*/
browser.runtime.onMessage.addListener(async (message) => {
switch (message.type) {
case 'INCREASE_ACTIONS_COUNT': {
actions.add(`${Date.now()}`);
break;
}
}
});
/**
* @description Fix bfcache issues
* @listens window#pageshow
* @returns {void}
*/
window.addEventListener('pageshow', async (event) => {
if (document.visibilityState === 'visible' && event.persisted) {
await setUp();
}
});
/**
* @async
* @description Run if the page wasn't visited yet
* @listens window#visibilitychange
* @returns {void}
*/
window.addEventListener('visibilitychange', async () => {
if (document.visibilityState === 'visible') {
if (!initiallyVisible) {
initiallyVisible = true;
await setUp();
}
dispatch({ type: state.on ? 'ENABLE_REPORT' : 'DISABLE_REPORT' });
}
});
/**
* @description Run as soon as possible, if the user is in front of the page
*/
if (document.visibilityState === 'visible') {
setUpAfterWaitForBody();
}

View File

@ -25,10 +25,6 @@
{
"version": "7.3.2",
"update_link": "https://www.cookie-dialog-monster.com/releases/7.3.2-mozilla-mobile.xpi"
},
{
"version": "8.0.1",
"update_link": "https://www.cookie-dialog-monster.com/releases/8.0.1-mozilla-mobile.xpi"
}
]
}