""" B1 — Cookie-Consent-UX-001: Mobile Reachability of Consent Settings. DSGVO Art. 7 Abs. 3 requires that withdrawing consent must be as easy as giving it. EDPB Cookie Banner Taskforce Report (2023) and DSK OH Digitale Dienste v1.2 (2024) both demand a permanent, directly reachable way to change cookie preferences — typically a Footer link labelled "Cookie-Einstellungen" that re-opens the CMP in place. Common anti-patterns we want to flag: - Footer points to a Cookie-Policy *page* in a new tab, no CMP - Footer only offers "more info" but no "manage settings" - Only mention is a verbal reference to browser settings inside the privacy-policy text - Mobile footer hides the link in a multi-level accordion This module does the STATIC HTML analysis. The dynamic part (mobile viewport rendering, tap-target measurement, click-behaviour verification) is performed by consent-tester via Playwright and feeds back into `evaluate_combined` in a later phase. Pure module — no DB, no network. Tests live in tests/test_consent_reachability_check.py. """ from __future__ import annotations import logging import re from html.parser import HTMLParser from urllib.parse import urljoin, urlparse logger = logging.getLogger(__name__) # Phrases that suggest "open the consent manager" rather than "show # more info / open a policy page". _REOPEN_PHRASES = ( "cookie-einstellungen", "cookie einstellungen", "cookie-präferenzen", "cookie praeferenzen", "cookie-praferenzen", "cookie-einwilligung", "einwilligung verwalten", "consent manager", "consent settings", "consent-einstellungen", "datenschutz-einstellungen", "datenschutzeinstellungen", "cookies verwalten", "manage cookies", "manage preferences", "privacy settings", "privacy preferences", "tracking-einstellungen", ) # Weaker — these usually point at a policy page, not the CMP itself. _INFO_ONLY_PHRASES = ( "cookie-richtlinie", "cookie richtlinie", "cookie-policy", "cookie policy", "cookies (information)", "datenschutz", "datenschutzerklärung", "privacy policy", "weitere informationen", "more information", ) # Phrases that try to shift the burden to the user's browser — # Bundesländer-Datenschutzbeauftragte explicitly call this insufficient. _BROWSER_DEFLECTION_PHRASES = ( "browser-einstellungen", "browsereinstellungen", "einstellungen ihres browsers", "browser settings", "in ihrem browser", "über ihren browser", ) class _AnchorCollector(HTMLParser): """Collects and