b363c28539
Split dsi_document_checker.py (466 LOC) into doc_checks/ package (9 files). Two-pass L1→L2 logic: L1 checks "Is it mentioned?", L2 checks "Is it correct?" (e.g. controller has full address, specific Art. 6 lit., concrete time periods). 138 total checks (62 L1 + 76 L2) across 7 doc types: - DSE Art. 13: 31, Impressum §5 TMG: 16, Cookie §25 TDDDG: 15 - Widerruf §355: 15, AGB §305ff: 21, Social Media Art. 26: 20, DSFA Art. 35: 18 Frontend: hierarchical L1→L2 display with dual progress bars (green=completeness, blue=correctness). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
254 lines
10 KiB
Python
254 lines
10 KiB
Python
"""
|
|
Social Media DSE checks — Art. 26 DSGVO Joint Controller.
|
|
|
|
Level 1: Pflichtangabe erwaehnt?
|
|
Level 2: Pflichtangabe korrekt/vollstaendig?
|
|
"""
|
|
|
|
JOINT_CONTROLLER_CHECKLIST = [
|
|
# ── L1: Gemeinsam Verantwortliche ─────────────────────────────────
|
|
{
|
|
"id": "joint_parties",
|
|
"label": "Gemeinsam Verantwortliche benannt (Art. 26(1))",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"gemeinsam.*verantwortlich", r"joint.*controller",
|
|
r"gemeinsame\s+verantwortlichkeit",
|
|
r"art\.\s*26", r"mitverantwortlich",
|
|
r"wir.*(?:und|gemeinsam).*(?:betreiber|facebook|meta|google)",
|
|
r"(?:betreiber|netzwerk).*verantwortlich",
|
|
],
|
|
"severity": "HIGH",
|
|
},
|
|
{
|
|
"id": "facebook_meta_named",
|
|
"label": "Facebook/Meta konkret als Verantwortlicher benannt",
|
|
"level": 2, "parent": "joint_parties",
|
|
"patterns": [
|
|
r"(?:facebook|meta)\s+(?:ireland|platforms|inc)",
|
|
r"meta\s+platforms.*(?:verantwortlich|controller|betreiber)",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
|
|
# ── L1: Vereinbarung Art. 26 ──────────────────────────────────────
|
|
{
|
|
"id": "arrangement",
|
|
"label": "Vereinbarung nach Art. 26 DSGVO",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"vereinbarung.*art\.\s*26", r"art\.\s*26.*vereinbarung",
|
|
r"page\s*controller", r"fanpage", r"insights",
|
|
r"gemeinsame.*verantwortung.*(?:vertrag|vereinbarung)",
|
|
r"addendum|nachtrag|seiten.*insights",
|
|
],
|
|
"severity": "HIGH",
|
|
},
|
|
{
|
|
"id": "insights_referenced",
|
|
"label": "Seiteninsights / Page Insights erwaehnt",
|
|
"level": 2, "parent": "arrangement",
|
|
"patterns": [
|
|
r"(?:seiten[\-\s]?)?insights",
|
|
r"page\s+insights",
|
|
r"(?:statistik|nutzungsstatistik).*(?:facebook|meta|fanpage|seite)",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
{
|
|
"id": "page_controller_addendum",
|
|
"label": "Page Controller Addendum / Seiten-Insights-Ergaenzung",
|
|
"level": 2, "parent": "arrangement",
|
|
"patterns": [
|
|
r"page\s+controller\s+addendum",
|
|
r"seiten[\-\s]?insights[\-\s]?erg(?:ae|ä)nzung",
|
|
r"(?:addendum|nachtrag|erg(?:ae|ä)nzung).*(?:controller|verantwortlich)",
|
|
],
|
|
"severity": "LOW",
|
|
},
|
|
|
|
# ── L1: Anlaufstelle ──────────────────────────────────────────────
|
|
{
|
|
"id": "contact_point",
|
|
"label": "Anlaufstelle fuer Betroffene (Art. 26(1) S.3)",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"anlaufstelle", r"kontaktstelle",
|
|
r"ansprechpartner.*betroffene",
|
|
r"rechte.*(?:gegen(?:ue|ü)ber)\s+(?:uns|beiden)",
|
|
r"rechte.*geltend\s+machen",
|
|
r"wenden\s+sie\s+sich",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
{
|
|
"id": "contact_both_parties",
|
|
"label": "Kontaktdaten beider Verantwortlicher",
|
|
"level": 2, "parent": "contact_point",
|
|
"patterns": [
|
|
r"(?:sowohl|beide).*(?:kontakt|wenden|geltend)",
|
|
r"(?:uns|bei\s+uns).*(?:als\s+auch|oder|und).*(?:facebook|meta|google|plattform)",
|
|
r"(?:facebook|meta|google|plattform).*(?:als\s+auch|oder|und).*(?:uns|bei\s+uns)",
|
|
],
|
|
"severity": "LOW",
|
|
},
|
|
|
|
# ── L1: Verarbeitungsaufteilung ───────────────────────────────────
|
|
{
|
|
"id": "processing_split",
|
|
"label": "Verarbeitungsaufteilung (wer macht was)",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"(?:wir|betreiber).*(?:verarbeiten|erheben|nutzen).*(?:daten|informationen)",
|
|
r"(?:facebook|meta|google|youtube|instagram|linkedin|twitter|x\.com).*(?:verarbeit|erhebt|nutzt|speichert)",
|
|
r"bei\s+besuch\s+(?:unserer|der)\s+(?:seite|fanpage|profil)",
|
|
r"(?:nutzungsstatistik|statistik|insight).*(?:betreiber|netzwerk)",
|
|
],
|
|
"severity": "HIGH",
|
|
},
|
|
|
|
# ── L1: Datenkategorien ───────────────────────────────────────────
|
|
{
|
|
"id": "social_data_types",
|
|
"label": "Kategorien verarbeiteter Daten",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"(?:nutzungsstatistik|insight|reichweite|interaktion|klick|aufruf)",
|
|
r"(?:ip.?adresse|standort|browser|ger(?:ae|ä)t|alter|geschlecht)",
|
|
r"(?:personenbezogen|daten).*(?:social|netzwerk|plattform)",
|
|
r"(?:nutzername|beitr(?:ae|ä)g|profil|like|kommentar)",
|
|
],
|
|
"severity": "HIGH",
|
|
},
|
|
|
|
# ── L1: Plattformen ───────────────────────────────────────────────
|
|
{
|
|
"id": "platforms",
|
|
"label": "Auflistung der genutzten Plattformen",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"(?:facebook|instagram|youtube|twitter|x\.com|linkedin|xing|tiktok)",
|
|
r"(?:kan(?:ae|ä)le|plattform|netzwerk|profil|account|auftritte).*(?:social|medien)",
|
|
r"social\s*media.*(?:angebot|pr(?:ae|ä)senz|auftritte)",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
{
|
|
"id": "platform_dse_links",
|
|
"label": "Links zu Datenschutzerklaerungen der Plattformen",
|
|
"level": 2, "parent": "platforms",
|
|
"patterns": [
|
|
r"(?:datenschutz|privacy).*(?:facebook|meta|google|youtube|instagram|linkedin|twitter)",
|
|
r"(?:facebook|meta|google|youtube|instagram|linkedin|twitter).*(?:datenschutz|privacy)",
|
|
r"(?:privacy\s+policy|datenschutzerkl(?:ae|ä)rung).*(?:finden\s+sie|abrufbar|unter)",
|
|
],
|
|
"severity": "LOW",
|
|
},
|
|
|
|
# ── L1: Drittlandtransfer ─────────────────────────────────────────
|
|
{
|
|
"id": "third_country",
|
|
"label": "Drittlandtransfer (USA bei Social Media)",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"(?:usa|vereinigte\s+staaten|drittland|drittstaaten)",
|
|
r"privacy\s+shield|data\s+privacy\s+framework|angemessenheitsbeschluss",
|
|
r"standardvertragsklausel|standard.*contractual",
|
|
r"(?:(?:ue|ü)bermittlung|(?:ueber|über)mittlung).*(?:usa|drittland|au(?:ss|ß)erhalb)",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
{
|
|
"id": "usa_transfer_scc",
|
|
"label": "Standardvertragsklauseln (SCC) fuer US-Transfer",
|
|
"level": 2, "parent": "third_country",
|
|
"patterns": [
|
|
r"standard\s*vertragsklausel|scc",
|
|
r"standard\s+contractual\s+clause",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
{
|
|
"id": "usa_transfer_dpf",
|
|
"label": "Data Privacy Framework (DPF) fuer US-Transfer",
|
|
"level": 2, "parent": "third_country",
|
|
"patterns": [
|
|
r"data\s+privacy\s+framework|dpf",
|
|
r"angemessenheitsbeschluss.*(?:usa|us|amerika)",
|
|
r"adequacy\s+decision",
|
|
],
|
|
"severity": "LOW",
|
|
},
|
|
|
|
# ── L1: Rechtsgrundlage ───────────────────────────────────────────
|
|
{
|
|
"id": "legal_basis",
|
|
"label": "Rechtsgrundlage (Art. 6 DSGVO)",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"rechtsgrundlage", r"art\.\s*6",
|
|
r"berechtigtes\s+interesse",
|
|
r"einwilligung.*art\.\s*6", r"lit\.\s*[a-f]",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
{
|
|
"id": "legal_basis_specific_lit",
|
|
"label": "Konkretes Art. 6(1) lit. angegeben",
|
|
"level": 2, "parent": "legal_basis",
|
|
"patterns": [
|
|
r"art\.\s*6\s*(?:abs\.\s*)?1\s*(?:s\.\s*1\s*)?(?:lit\.\s*)?[a-f]",
|
|
],
|
|
"severity": "LOW",
|
|
},
|
|
|
|
# ── L1: Betroffenenrechte ─────────────────────────────────────────
|
|
{
|
|
"id": "rights",
|
|
"label": "Betroffenenrechte (Art. 15-21)",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"recht\s+auf\s+auskunft", r"recht\s+auf\s+l(?:oe|ö)schung",
|
|
r"art\.\s*1[5-9]", r"betroffenenrecht",
|
|
r"ihre\s+rechte", r"rechte.*betroffene",
|
|
r"widerspruchsrecht",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
{
|
|
"id": "opt_out_social",
|
|
"label": "Opt-Out-Moeglichkeit fuer Social-Media-Tracking",
|
|
"level": 2, "parent": "rights",
|
|
"patterns": [
|
|
r"(?:opt[\-\s]?out|widerspruch|deaktivieren).*(?:social|facebook|tracking|insight)",
|
|
r"(?:social|facebook|tracking|insight).*(?:opt[\-\s]?out|widerspruch|deaktivieren)",
|
|
r"(?:abmelden|abschalten).*(?:tracking|statistik|insight)",
|
|
],
|
|
"severity": "LOW",
|
|
},
|
|
|
|
# ── L1: Social Bookmarks vs Plugins ───────────────────────────────
|
|
{
|
|
"id": "social_bookmarks",
|
|
"label": "Hinweis auf Social Bookmarks vs. Plugins",
|
|
"level": 1, "parent": None,
|
|
"patterns": [
|
|
r"social\s*(?:bookmark|plugin|button|widget)",
|
|
r"(?:kein|keine).*(?:plugin|widget|button).*(?:gesetzt|eingebunden|geladen)",
|
|
r"(?:link|verweis|weiterleitung).*(?:dienst|anbieter|netzwerk)",
|
|
],
|
|
"severity": "MEDIUM",
|
|
},
|
|
{
|
|
"id": "two_click_solution",
|
|
"label": "2-Klick-Loesung oder vergleichbare Technik",
|
|
"level": 2, "parent": "social_bookmarks",
|
|
"patterns": [
|
|
r"(?:zwei|2)[\-\s]?klick",
|
|
r"(?:shariff|share[\-\s]?buttons?\s+ohne\s+tracking)",
|
|
r"(?:erst|nur)\s+(?:bei|nach|durch)\s+(?:klick|aktivierung).*(?:daten|verbindung)",
|
|
],
|
|
"severity": "LOW",
|
|
},
|
|
]
|