Compare commits

..

8 Commits

16 changed files with 611 additions and 587 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#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.
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.
## Contributing

View File

@ -1,547 +1,257 @@
{
"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": [
"actions": [
{
"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\"]"
},
{
"action": "reload",
"domain": "myprivacy.dpgmedia"
"domain": "myprivacy.dpgmedia",
"name": "reload"
},
{
"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\"]"
}
],
"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": {
"exclusions": {
"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",
@ -964,6 +674,307 @@
"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",
@ -13997,5 +14008,5 @@
"ytm-consent-bump-v2-renderer"
]
},
"version": "1728300083309"
"version": "1729252494919"
}

View File

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

View File

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

View File

@ -1,5 +1,6 @@
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';
@ -13,14 +14,18 @@ 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 url = `${environment.gitea.raw}/database.json`;
const { rules, ...result } = await (await fetch(url, options)).json();
const response = await fetch(database, options);
const { actions, exclusions, keywords, rules, ...rest } = await response.json();
reply.send({
data: {
...result,
...rest,
actions: actions.map(parseActionName),
commonWords: keywords,
rules: rules.map(toDeclarativeNetRequestRule),
skips: { domains: exclusions.overflows, tags: exclusions.tags },
},
success: true,
});
@ -35,17 +40,3 @@ 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

@ -0,0 +1,39 @@
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

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

View File

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

View File

@ -1,13 +1,32 @@
/**
* 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 parseAction(action: Action): string {
return `${action.domain}##${action.selector}##${action.name}${action.property ? `##${action.property}` : ''}`;
}
export interface Fix {
readonly action: string;
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 {
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.1",
"version": "8.0.2",
"default_locale": "en",
"description": "__MSG_appDesc__",
"icons": {
@ -28,28 +28,6 @@
"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/v5';
const apiUrl = 'https://api.cookie-dialog-monster.com/rest/v6';
/**
* @description Request manager instance
@ -144,34 +144,6 @@ 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
@ -315,11 +287,10 @@ 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: formatNumber(message.value) });
browser.action.setBadgeText({ tabId, text: message.value ? `${message.value}` : null });
}
break;
case 'UPDATE_STORE':
@ -335,6 +306,7 @@ browser.runtime.onMessage.addListener((message, sender, callback) => {
*/
browser.runtime.onInstalled.addListener((details) => {
if (details.reason === 'update') {
refreshData();
storage.remove('updateAvailable');
}
});
@ -362,27 +334,24 @@ browser.webRequest.onBeforeRequest.addListener(
const { tabId, type, url } = details;
if (tabId > -1 && type === 'main_frame') {
const manifest = browser.runtime.getManifest();
const excludeMatches = manifest.content_scripts[0].exclude_matches;
const excludePatterns = excludeMatches.map(matchToPattern);
const { exclusions, rules } = await getData();
if (excludePatterns.some((pattern) => new RegExp(pattern).test(url))) {
if (exclusions.domains.some((x) => location.hostname.match(x.replaceAll(/\*/g, '[^ ]*')))) {
return;
}
const data = await getData();
const hostname = getHostname(url);
const state = await getState(hostname);
if (data?.rules?.length) {
const rules = data.rules.map((rule) => ({
if (rules?.length) {
const rulesWithTabId = rules.map((rule) => ({
...rule,
condition: { ...rule.condition, tabIds: [tabId] },
}));
await browser.declarativeNetRequest.updateSessionRules({
addRules: state.on ? rules : undefined,
removeRuleIds: data.rules.map((rule) => rule.id),
addRules: state.on ? rulesWithTabId : undefined,
removeRuleIds: rules.map((rule) => rule.id),
});
}
}
@ -395,15 +364,10 @@ browser.webRequest.onBeforeRequest.addListener(
*/
browser.webRequest.onErrorOccurred.addListener(
async (details) => {
const { error, tabId, url } = details;
const { error, tabId } = details;
if (error === 'net::ERR_BLOCKED_BY_CLIENT' && tabId > -1) {
const hostname = getHostname(url);
const state = await getState(hostname);
if (state.on) {
await browser.tabs.sendMessage(tabId, { type: 'INCREASE_ACTIONS_COUNT' });
}
await browser.tabs.sendMessage(tabId, { type: 'INCREASE_ACTIONS_COUNT', value: error });
}
},
{ urls: ['<all_urls>'] }

View File

@ -1,9 +1,9 @@
/**
* @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
* @typedef {Object} Action
* @property {string} domain
* @property {string} name
* @property {string} [property]
* @property {string} selector
*/
/**
@ -12,11 +12,24 @@
*/
/**
* @typedef {Object} Fix
* @property {string} action
* @property {string} domain
* @property {string} [property]
* @property {string} selector
* @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]
*/
/**
@ -27,9 +40,11 @@
*/
/**
* @typedef {Object} GetElementsParams
* @property {boolean} [filterEarly]
* @property {HTMLElement} [from]
* @typedef {Object} TokenMap
* @property {string[]} backdrops
* @property {string[]} classes
* @property {string[]} containers
* @property {string[]} selectors
*/
/**
@ -42,22 +57,31 @@ if (typeof browser === 'undefined') {
}
/**
* @description Actions done by the extension
* @type {Set<string>}
* @description Class for request batching
*/
const actions = new Set();
class NotifiableSet extends Set {
constructor(...args) {
super(...args);
}
add(value) {
super.add(value);
browser.runtime.sendMessage({ type: 'UPDATE_BADGE', value: super.size });
}
}
/**
* @description Data object with all the necessary information
* @type {ExtensionData}
*/
let { commonWords, fixes, skips, tokens } = {
commonWords: [],
fixes: [],
skips: {
let { actions, exclusions, keywords, tokens } = {
actions: [],
exclusions: {
domains: [],
overflows: [],
tags: [],
},
keywords: [],
tokens: {
backdrops: [],
classes: [],
@ -80,7 +104,13 @@ const hostname = getHostname();
* @description Initial visibility state
* @type {boolean}
*/
let initiallyVisible = document.visibilityState === 'visible';
let initiallyVisible = false;
/**
* @description Log of those steps done by the extension
* @type {NotifiableSet<string>}
*/
const log = new NotifiableSet();
/**
* @description Options provided to observer
@ -96,9 +126,9 @@ const seen = new Set();
/**
* @description Extension state
* @type {ContentState}
* @type {ContentState | undefined}
*/
let state = { on: true };
let state = undefined;
/**
* @description Clean DOM
@ -120,8 +150,7 @@ function clean(elements, skipMatch) {
if (element instanceof HTMLDialogElement) element.close();
hide(element);
actions.add(`${Date.now()}`);
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
log.add(`${Date.now()}`);
}
seen.add(element);
@ -136,11 +165,11 @@ function clean(elements, skipMatch) {
}
/**
* @description Check if element contains a common word
* @description Check if element contains a keyword
* @param {HTMLElement} element
*/
function containsCommonWord(element) {
return !!commonWords.length && !!element.outerHTML.match(new RegExp(commonWords.join('|')));
function hasKeyword(element) {
return !!keywords?.length && !!element.outerHTML.match(new RegExp(keywords.join('|')));
}
/**
@ -203,6 +232,21 @@ 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
@ -229,7 +273,7 @@ function isInViewport(element) {
* @returns {boolean}
*/
function match(element, skipMatch) {
if (!tokens.selectors.length || !skips.tags.length) {
if (!exclusions.tags.length || !tokens.selectors.length) {
return false;
}
@ -243,7 +287,7 @@ function match(element, skipMatch) {
const tagName = element.tagName.toUpperCase();
if (skips.tags.includes(tagName)) {
if (exclusions.tags.includes(tagName)) {
return false;
}
@ -283,7 +327,7 @@ function filterNodeEarly(node, stopRecursion) {
return [];
}
if (commonWords && containsCommonWord(node) && !stopRecursion) {
if (hasKeyword(node) && !stopRecursion) {
return [node, ...[...node.children].flatMap((node) => filterNodeEarly(node, true))];
}
@ -291,46 +335,27 @@ function filterNodeEarly(node, stopRecursion) {
}
/**
* @description Fix data, middle consent page and scroll issues
* @description Fix specific cases
* @returns {void}
*/
function fix() {
const backdrops = getElements(tokens.backdrops);
const domains = skips.domains.map((x) => (x.split('.').length < 3 ? `*${x}` : x));
for (const action of actions) {
const { domain, name, property, selector } = action;
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) {
if (hostname.match(domain.replaceAll(/\*/g, '[^ ]*'))) {
switch (name) {
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': {
@ -340,38 +365,56 @@ 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) {
actions.add('t4-wrapper');
log.add('t4-wrapper');
// 2024-09-12: fix #945 temporarily
t4Wrapper.removeAttribute('inert');
}
dispatch({ type: 'UPDATE_BADGE', value: actions.size });
}
/**
@ -412,41 +455,48 @@ function run(params = {}) {
* @async
* @description Set up the extension
* @param {SetUpParams} [params]
* @returns {Promise<void>}
*/
async function setUp(params = {}) {
state = await dispatch({ hostname, type: 'GET_STATE' });
dispatch({ type: 'ENABLE_POPUP' });
if (state.on) {
const data = await dispatch({ hostname, type: 'GET_DATA' });
commonWords = data?.commonWords ?? commonWords;
fixes = data?.fixes ?? fixes;
skips = data?.skips ?? skips;
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' });
actions = data?.actions ?? actions;
keywords = data?.keywords ?? keywords;
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
* @param {void} callback
* @returns {void}
* @returns {Promise<void>}
*/
async function setUpAfterWaitForBody() {
if (document.visibilityState === 'visible' && !initiallyVisible) {
if (document.body) {
initiallyVisible = true;
await setUp();
} else {
return;
}
setTimeout(setUpAfterWaitForBody, 50);
}
}
@ -466,50 +516,6 @@ const observer = new MutationObserver((mutations) => {
run({ elements });
});
/**
* @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') {
document.addEventListener('visibilitychange', setUpAfterWaitForBody);
window.addEventListener('pageshow', setUpAfterWaitForBody);
setUpAfterWaitForBody();
}

View File

@ -25,6 +25,10 @@
{
"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"
}
]
}

Binary file not shown.