@aegis-scan/skills 0.4.0 → 0.5.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.
- package/ATTRIBUTION.md +111 -0
- package/CHANGELOG.md +48 -3
- package/package.json +1 -1
- package/skills/compliance/aegis-native/brutaler-anwalt/CHANGELOG.md +202 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/LICENSE +43 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/README.md +236 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/SKILL.md +339 -5
- package/skills/compliance/aegis-native/brutaler-anwalt/references/aegis-integration.md +3 -4
- package/skills/compliance/aegis-native/brutaler-anwalt/references/audit-patterns.md +842 -5
- package/skills/compliance/aegis-native/brutaler-anwalt/references/bgh-urteile.md +226 -10
- package/skills/compliance/aegis-native/brutaler-anwalt/references/branchenrecht.md +365 -1
- package/skills/compliance/aegis-native/brutaler-anwalt/references/checklisten.md +33 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/dsgvo.md +26 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BDSG/paragraphs.md +62 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BFSG/paragraphs.md +85 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BGB/paragraphs.md +112 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/DDG/paragraphs.md +71 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/DSGVO/articles.md +182 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/articles.md +108 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/articles.md +131 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/HGB-AO/paragraphs.md +61 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/INDEX.md +93 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/TDDDG/paragraphs.md +67 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/UWG/paragraphs.md +117 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/VSBG/paragraphs.md +57 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/it-recht.md +22 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/INDEX.md +122 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/ai/mistral-eu.md +123 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/ai/openai-dpa.md +120 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/auth/nextauth-tom.md +120 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/auth/supabase-auth-tom.md +104 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nextjs/proxy-csp-pattern.md +93 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/payment/stripe-pci-tom.md +121 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/tracking/plausible-pattern.md +107 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/AffiliateDisclaimer.tsx.example +54 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/COMPLIANCE-AUDIT-TRAIL-template.md +95 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/DSE-Section-UGC.md.example +77 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/DSFA-template.md +76 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/LostFoundReportForm-consent.tsx.example +126 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/README.md +33 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/UmamiScript.tsx.example +64 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/VVT-template.md +60 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/data-retention-cron.ts.example +52 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/data-retention-workflow.yml.example +47 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/proxy-strict-dynamic.ts.example +80 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/security.txt.example +26 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/scripts/health-check.sh +120 -0
- package/skills/defensive/aegis-native/rls-defense/SKILL.md +85 -0
- package/skills/foundation/aegis-native/aegis-module-builder/SKILL.md +5 -1
- package/skills/foundation/aegis-native/aegis-orchestrator/SKILL.md +87 -4
- package/skills/foundation/aegis-native/aegis-quality-gates/SKILL.md +69 -9
- package/skills/offensive/matty-fork/cicd-redteam/SKILL.md +531 -0
- package/skills/offensive/matty-fork/cloud-security/SKILL.md +106 -0
- package/skills/offensive/matty-fork/container-escape/SKILL.md +174 -0
- package/skills/offensive/matty-fork/mobile-pentester/SKILL.md +357 -0
- package/skills/offensive/matty-fork/subdomain-takeover/SKILL.md +154 -0
- package/skills/osint/elementalsouls-fork/offensive-osint/README.md +92 -0
- package/skills/osint/elementalsouls-fork/offensive-osint/SKILL.md +4177 -0
- package/skills/osint/elementalsouls-fork/osint-methodology/README.md +66 -0
- package/skills/osint/elementalsouls-fork/osint-methodology/SKILL.md +1695 -0
- package/sbom.cdx.json +0 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
license: MIT (snippet)
|
|
3
|
+
provider: Stripe Inc. (USA)
|
|
4
|
+
provider-AVV-status: Standardvertrag verfügbar (Stripe DPA + SCC)
|
|
5
|
+
last-checked: 2026-05-01
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Stripe — PCI-DSS-konformer Checkout + DSE-Wording
|
|
9
|
+
|
|
10
|
+
## 1. PCI-DSS-Strategie: Stripe-hosted Checkout (Pflicht für KMU)
|
|
11
|
+
|
|
12
|
+
Pflicht-Strategy: **Stripe Elements oder Stripe Checkout** — Karten-Daten passieren **nie** den eigenen Server.
|
|
13
|
+
|
|
14
|
+
- ✅ `stripe-js` mit `<CardElement />`: Karten-Daten gehen direkt vom Browser zu Stripe
|
|
15
|
+
- ✅ `Stripe.redirectToCheckout()`: hosted-Page bei Stripe
|
|
16
|
+
- ❌ NICHT: Karten-Daten über eigenen Server entgegennehmen — würde PCI-DSS-Audit-Pflicht triggern (Self-Audit oder QSA)
|
|
17
|
+
|
|
18
|
+
## 2. Compliance-Risiken
|
|
19
|
+
|
|
20
|
+
| Risiko | Wirkung | Fix |
|
|
21
|
+
|--------|---------|-----|
|
|
22
|
+
| Sub-Processor in USA | Drittland-Transfer | DPA + SCC + DSE-Erwähnung |
|
|
23
|
+
| Risiko-Score-Cookies | TDDDG § 25 | Pre-Consent: kein Stripe-Skript |
|
|
24
|
+
| Webhook-Signatur-Prüfung fehlt | Unauthorized Charge / IDOR | `stripe.webhooks.constructEvent()` Pflicht |
|
|
25
|
+
| `card.number` im Server-Log | PCI-DSS-Verstoss + Datenschutz | Logger sanitisieren |
|
|
26
|
+
|
|
27
|
+
## 3. Code-Pattern (sanitized)
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// File: src/app/api/stripe/webhook/route.ts
|
|
31
|
+
// Webhook-Signatur-Verifikation (CWE-345 Schutz)
|
|
32
|
+
import Stripe from 'stripe';
|
|
33
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
34
|
+
|
|
35
|
+
export const runtime = 'nodejs';
|
|
36
|
+
|
|
37
|
+
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2025-06-30.basil' });
|
|
38
|
+
|
|
39
|
+
export async function POST(req: NextRequest) {
|
|
40
|
+
const sig = req.headers.get('stripe-signature');
|
|
41
|
+
if (!sig) return NextResponse.json({ error: 'missing signature' }, { status: 400 });
|
|
42
|
+
|
|
43
|
+
const buf = await req.text(); // raw body Pflicht für Signatur
|
|
44
|
+
let event: Stripe.Event;
|
|
45
|
+
try {
|
|
46
|
+
event = stripe.webhooks.constructEvent(buf, sig, process.env.STRIPE_WEBHOOK_SECRET!);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return NextResponse.json({ error: `Webhook signature mismatch: ${err}` }, { status: 400 });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Idempotency: bei replay-Webhook keine doppelte Aktion
|
|
52
|
+
// ... handle event types ...
|
|
53
|
+
|
|
54
|
+
return NextResponse.json({ received: true });
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
// File: src/components/checkout/StripeButton.tsx
|
|
60
|
+
// Pre-consent OHNE Stripe-Skript-Load
|
|
61
|
+
'use client';
|
|
62
|
+
import { useEffect, useState } from 'react';
|
|
63
|
+
import { loadStripe } from '@stripe/stripe-js';
|
|
64
|
+
|
|
65
|
+
export function StripeButton({ priceId }: { priceId: string }) {
|
|
66
|
+
const [stripe, setStripe] = useState<any>(null);
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
// Erst nach Consent (oder hier explizit beim Klick erst loadStripe rufen)
|
|
70
|
+
loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!).then(setStripe);
|
|
71
|
+
}, []);
|
|
72
|
+
|
|
73
|
+
async function handleCheckout() {
|
|
74
|
+
if (!stripe) return;
|
|
75
|
+
const res = await fetch('/api/stripe/checkout-session', { method: 'POST', body: JSON.stringify({ priceId }) });
|
|
76
|
+
const { sessionId } = await res.json();
|
|
77
|
+
await stripe.redirectToCheckout({ sessionId });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return <button onClick={handleCheckout}>Zahlungspflichtig bestellen</button>;
|
|
81
|
+
// ^^^ Pflicht-Wording § 312j Abs. 3 BGB
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 4. AVV / DPA
|
|
86
|
+
|
|
87
|
+
- **DPA-Link**: https://stripe.com/legal/dpa
|
|
88
|
+
- **SCC**: Modul 2 + 3 (Stripe als Processor + Sub-Processor-Liste)
|
|
89
|
+
- **Sub-Processors**: https://stripe.com/legal/data-processing-providers
|
|
90
|
+
|
|
91
|
+
## 5. DSE-Wording-Vorlage
|
|
92
|
+
|
|
93
|
+
> **Zahlungsabwicklung (Stripe).** Für Zahlungen nutzen wir den Service von
|
|
94
|
+
> Stripe Payments Europe Limited (1 Grand Canal Street Lower, Grand Canal
|
|
95
|
+
> Dock, Dublin, Irland) sowie Stripe Inc. (354 Oyster Point Boulevard,
|
|
96
|
+
> South San Francisco, CA 94080, USA) als Auftragsverarbeiter im Sinne
|
|
97
|
+
> von Art. 28 DSGVO. Karten-Daten werden direkt von Ihrem Browser an
|
|
98
|
+
> Stripe übermittelt — wir verarbeiten diese nicht selbst. Für die
|
|
99
|
+
> Datenübermittlung in die USA gelten die EU-Standardvertragsklauseln
|
|
100
|
+
> (Modul 2 + 3) sowie das EU-US Data Privacy Framework (Stripe Inc. ist
|
|
101
|
+
> DPF-zertifiziert). Rechtsgrundlage: Art. 6 Abs. 1 lit. b DSGVO
|
|
102
|
+
> (Vertragserfüllung). Datenschutz Stripe: https://stripe.com/de/privacy.
|
|
103
|
+
|
|
104
|
+
## 6. Verify-Commands
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Webhook-Konfiguration
|
|
108
|
+
stripe webhooks list
|
|
109
|
+
|
|
110
|
+
# Test-Webhook lokal
|
|
111
|
+
stripe listen --forward-to https://<your-domain>/api/stripe/webhook
|
|
112
|
+
|
|
113
|
+
# Verify Pflicht-Header an Webhook-Endpoint
|
|
114
|
+
curl -X POST https://<your-domain>/api/stripe/webhook -H "stripe-signature: invalid"
|
|
115
|
+
# erwarte: 400 mit "signature mismatch"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## 7. Az.-Anker
|
|
119
|
+
|
|
120
|
+
- BGH I ZR 161/24 (Kuendigungsbutton, 22.05.2025) — § 312k betrifft Stripe-Subscription-Modelle
|
|
121
|
+
- BGH VIII ZR 70/08 (Widerrufsbelehrung) — Pflicht-Belehrung vor Zahlung
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
license: MIT (snippet)
|
|
3
|
+
provider: Plausible Insights OÜ (Estland) — EU-Anbieter
|
|
4
|
+
provider-AVV-status: Standardvertrag verfügbar (DPA)
|
|
5
|
+
last-checked: 2026-05-01
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Plausible Analytics — Cookieless Tracking + DSE-Wording
|
|
9
|
+
|
|
10
|
+
## 1. Default-Verhalten
|
|
11
|
+
|
|
12
|
+
- **Cookieless** by default — keine Tracking-Cookies, kein LocalStorage
|
|
13
|
+
- **EU-Hosting**: Server in Deutschland (Hetzner Falkenstein)
|
|
14
|
+
- **IP-Anonymisierung**: serverseitig, keine vollständige IP gespeichert
|
|
15
|
+
- **DNT-Respektierung**: Plausible respektiert Do-Not-Track auf Server-Seite
|
|
16
|
+
- **GDPR-konform** by design: keine personenbezogenen Daten gespeichert (anonyme Aggregate)
|
|
17
|
+
|
|
18
|
+
## 2. Compliance-Risiken
|
|
19
|
+
|
|
20
|
+
| Risiko | Wirkung | Fix |
|
|
21
|
+
|--------|---------|-----|
|
|
22
|
+
| Trotz cookieless: Skript-Aufruf von externer Domain | minimaler Drittland-Risk | Selbst-Hosting via Subdomain (siehe Code-Pattern) |
|
|
23
|
+
| Outbound-Link-Tracking | Browser-Telemetrie | per Skript-Variante optional |
|
|
24
|
+
| Custom-Events mit personenbezogenen Daten | Risiko Re-Identifizierung | Events ohne PII (nur Page-Path / Action-Type) |
|
|
25
|
+
|
|
26
|
+
## 3. Code-Pattern: env-driven, self-hostable
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
// File: src/components/analytics/Plausible.tsx
|
|
30
|
+
'use client';
|
|
31
|
+
import Script from 'next/script';
|
|
32
|
+
|
|
33
|
+
export function PlausibleAnalytics() {
|
|
34
|
+
// env-driven: Default = own-subdomain für ZUSÄTZLICHE Hardenings
|
|
35
|
+
const host = (
|
|
36
|
+
process.env.NEXT_PUBLIC_PLAUSIBLE_HOST ?? 'https://plausible.io'
|
|
37
|
+
).replace(/\/+$/, '');
|
|
38
|
+
const domain = process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN;
|
|
39
|
+
|
|
40
|
+
if (!domain) return null; // fail-soft
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Script
|
|
44
|
+
strategy="afterInteractive"
|
|
45
|
+
defer
|
|
46
|
+
data-domain={domain}
|
|
47
|
+
data-api={`${host}/api/event`}
|
|
48
|
+
src={`${host}/js/script.js`}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Custom-Events ohne PII
|
|
56
|
+
const trackPlausibleEvent = (name: string, props?: Record<string, string | number>) => {
|
|
57
|
+
if (typeof window === 'undefined') return;
|
|
58
|
+
const w = window as any;
|
|
59
|
+
if (typeof w.plausible === 'function') {
|
|
60
|
+
w.plausible(name, { props });
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// OK: trackPlausibleEvent('signup_clicked', { plan: 'pro' });
|
|
65
|
+
// NICHT OK: trackPlausibleEvent('user_login', { email: 'a@b.de' }); // PII-Verbot
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 4. AVV / DPA
|
|
69
|
+
|
|
70
|
+
- **DPA-Link**: https://plausible.io/dpa.pdf
|
|
71
|
+
- **GDPR-konform-Statement**: https://plausible.io/data-policy
|
|
72
|
+
- **Sub-Processors**: Hetzner (Hosting, DE), Mailgun EU (E-Mail-Versand für Reports)
|
|
73
|
+
|
|
74
|
+
## 5. DSE-Wording-Vorlage
|
|
75
|
+
|
|
76
|
+
> **Reichweitenmessung mit Plausible Analytics.** Wir nutzen Plausible
|
|
77
|
+
> Analytics (Anbieter: Plausible Insights OÜ, Tallinn, Estland) als
|
|
78
|
+
> Werkzeug zur anonymen Reichweitenmessung. Plausible setzt **keine
|
|
79
|
+
> Cookies** und speichert **keine personenbezogenen Daten** — IP-Adressen
|
|
80
|
+
> werden serverseitig nicht gespeichert, sondern über einen Hash anonym
|
|
81
|
+
> aggregiert. Die Daten verbleiben in der EU (Hetzner-Server in
|
|
82
|
+
> Deutschland). Rechtsgrundlage: Art. 6 Abs. 1 lit. f DSGVO (berechtigtes
|
|
83
|
+
> Interesse an aggregierter Reichweitenmessung). Wegen der vollständigen
|
|
84
|
+
> Anonymisierung ist eine Einwilligung nach § 25 TDDDG **nicht
|
|
85
|
+
> erforderlich** (kein Speichern von Informationen in der Endeinrichtung).
|
|
86
|
+
> Datenschutz Plausible: https://plausible.io/privacy.
|
|
87
|
+
|
|
88
|
+
**Wichtig:** Diese Wording-Variante gilt nur bei Default-Plausible (cookieless + ohne Custom-Events mit PII). Bei Outbound-Link-Tracking + zusätzlichen Skript-Features erweitern.
|
|
89
|
+
|
|
90
|
+
## 6. Verify-Commands
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Cookies-Check (sollte KEINE plausible-Cookies setzen)
|
|
94
|
+
curl -s -c /tmp/cookies.txt https://<your-domain> > /dev/null
|
|
95
|
+
grep -i plausible /tmp/cookies.txt
|
|
96
|
+
# erwarte: kein Treffer
|
|
97
|
+
|
|
98
|
+
# Skript-Source
|
|
99
|
+
curl -s https://<your-domain> | grep -oE 'data-domain="[^"]+"'
|
|
100
|
+
# erwarte: deine Domain
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 7. Az.-Anker (Cookies allgemein, nicht plausible-spezifisch)
|
|
104
|
+
|
|
105
|
+
Keine spezifische Az. zu Plausible (zu jung). Allgemein: § 25 TDDDG-Befreiung gilt für Reichweitenmessung mit echter Anonymisierung — kommt aus EDPB Guidelines 2/2023 zur „Audience Measurement"-Ausnahme.
|
|
106
|
+
|
|
107
|
+
Source: https://www.edpb.europa.eu/our-work-tools/our-documents/guidelines/guidelines-22023-technical-scope-art-53-eprivacy_en
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// MIT-License — anonymized teaching snippet for brutaler-anwalt
|
|
2
|
+
// References: checklisten.md Checkliste 3c (UWG § 5a Abs. 4)
|
|
3
|
+
// Az.-Anker: LG Muenchen I 4 HK O 14302/15 (Influencer-Werbung als "Werbung"/"Anzeige")
|
|
4
|
+
|
|
5
|
+
// File: src/components/shared/AffiliateDisclaimer.tsx
|
|
6
|
+
// Use: import + render at top of any /empfehlungen, /partnerprogramm, /tipp,
|
|
7
|
+
// /best-of route. Pflicht: visible above-the-fold + before product listing.
|
|
8
|
+
|
|
9
|
+
import React from 'react';
|
|
10
|
+
|
|
11
|
+
interface AffiliateDisclaimerProps {
|
|
12
|
+
/** optional override of default copy */
|
|
13
|
+
text?: string;
|
|
14
|
+
/** className override for layout-specific styling */
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const DEFAULT_TEXT =
|
|
19
|
+
'Werbehinweis: Diese Seite enthält Affiliate-Links (mit * markiert). ' +
|
|
20
|
+
'Wenn Sie über einen solchen Link einkaufen, erhalten wir eine kleine ' +
|
|
21
|
+
'Provision. Für Sie entstehen dadurch keine Mehrkosten. Diese Provision ' +
|
|
22
|
+
'finanziert unsere Arbeit und beeinflusst nicht unsere Empfehlung.';
|
|
23
|
+
|
|
24
|
+
export function AffiliateDisclaimer({
|
|
25
|
+
text = DEFAULT_TEXT,
|
|
26
|
+
className = '',
|
|
27
|
+
}: AffiliateDisclaimerProps) {
|
|
28
|
+
return (
|
|
29
|
+
<aside
|
|
30
|
+
role="note"
|
|
31
|
+
aria-label="Werbehinweis"
|
|
32
|
+
className={`affiliate-disclaimer ${className}`.trim()}
|
|
33
|
+
data-testid="affiliate-disclaimer"
|
|
34
|
+
>
|
|
35
|
+
<p>{text}</p>
|
|
36
|
+
</aside>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// USAGE (example layout, e.g., src/app/(dashboard)/empfehlungen/layout.tsx):
|
|
41
|
+
//
|
|
42
|
+
// import { AffiliateDisclaimer } from '@/components/shared/AffiliateDisclaimer';
|
|
43
|
+
// export default function EmpfehlungenLayout({ children }) {
|
|
44
|
+
// return (
|
|
45
|
+
// <>
|
|
46
|
+
// <AffiliateDisclaimer />
|
|
47
|
+
// {children}
|
|
48
|
+
// </>
|
|
49
|
+
// );
|
|
50
|
+
// }
|
|
51
|
+
//
|
|
52
|
+
// VERIFY:
|
|
53
|
+
// curl https://<your-domain>/empfehlungen | grep -ic 'Werbehinweis'
|
|
54
|
+
// # erwarte: >= 1 Treffer
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
license: MIT
|
|
3
|
+
purpose: Audit-Trail-Doku-Vorlage. Wird von brutaler-anwalt-Audit als geshippter Bericht erstellt.
|
|
4
|
+
references: SKILL.md Output-Format
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Compliance-Audit-Trail — `<projekt-name>`
|
|
8
|
+
|
|
9
|
+
**Stand:** `<YYYY-MM-DD>`
|
|
10
|
+
**Auditor:** brutaler-anwalt v`<version>` + `<operator>`
|
|
11
|
+
**Scope:** `<Live-URL / Repo / Doku>`
|
|
12
|
+
**Status:** `<DRAFT / FREIGEGEBEN / IN REMEDIATION>`
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 0. Disclaimer
|
|
17
|
+
|
|
18
|
+
Diese Analyse ist keine Rechtsberatung i.S.d. § 2 RDG (BGH I ZR 113/20 Smartlaw)
|
|
19
|
+
und ersetzt keinen zugelassenen Rechtsanwalt. Output ist technisch-indikativ
|
|
20
|
+
fuer interne Vorpruefung — nicht Beratung Dritter.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. Konsolidierte Risiko-Bewertung
|
|
25
|
+
|
|
26
|
+
`<2-4 Saetze: Wahrscheinlichkeit Abmahnung/Bussgeld binnen 90 Tagen, €-Range,
|
|
27
|
+
kritischste 1-3 Findings, primaerer Hebel.>`
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 2. Findings (verified)
|
|
32
|
+
|
|
33
|
+
| # | Wahrsch. | Kritikalitaet | Bereich | Rechtsgrundlage | €-Range | Status | Fix |
|
|
34
|
+
|---|----------|---------------|---------|-----------------|---------|--------|-----|
|
|
35
|
+
| 1 | `<%>` | `<🔴/🟡/🟢>` | `<Bereich>` | `<§/Art.>` | `<X-Y €>` | verified | `<konkret>` |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 3. Anwalts-Anhang (pro Finding)
|
|
40
|
+
|
|
41
|
+
### Finding #`<n>`: `<Bereich + Kurzbeschreibung>`
|
|
42
|
+
|
|
43
|
+
**HUNTER-Befund:**
|
|
44
|
+
`<Was wurde gefunden, wo, wie. Code/Text-Zitat wenn moeglich.>`
|
|
45
|
+
|
|
46
|
+
**Rechtsgrundlage:**
|
|
47
|
+
- §/Art.: `<konkret>`
|
|
48
|
+
- Az. relevantes Urteil: `<LG/OLG/BGH/EuGH + Datum>` (Source: `<URL>`)
|
|
49
|
+
- Tenor: `<1 Satz>`
|
|
50
|
+
|
|
51
|
+
**CHALLENGER-Test:**
|
|
52
|
+
- Bedingung A: `<erfuellt/nicht erfuellt>`
|
|
53
|
+
- Bedingung B: `<...>`
|
|
54
|
+
- Verdict: `<verified/disputed/false-positive>`
|
|
55
|
+
|
|
56
|
+
**Risiko-Vektor:**
|
|
57
|
+
- Abmahnung Wettbewerber: `<%>`
|
|
58
|
+
- Behoerden-Bussgeld: `<€-Range, Stufe Art. 83 DSGVO>`
|
|
59
|
+
- Schadensersatz Betroffene: `<Art. 82 DSGVO>`
|
|
60
|
+
- Worst-Case-Frist: `<Tage>`
|
|
61
|
+
|
|
62
|
+
**Fix:**
|
|
63
|
+
`<Konkrete technische ODER textuelle Massnahme.>`
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 4. Verifikations-Status (Skill-Self-Test)
|
|
68
|
+
|
|
69
|
+
| Verification-Check | Status |
|
|
70
|
+
|--------------------|--------|
|
|
71
|
+
| References geladen (audit-patterns.md + topic-spezifische) | `<✓/✗>` |
|
|
72
|
+
| Jedes Finding hat §/Art. + Az. + Reference-File-Pfad | `<✓/✗>` |
|
|
73
|
+
| Az.-Provenance verifiziert (Source-URL pro Az.) | `<✓/✗>` |
|
|
74
|
+
| HUNTER-Phase fuer alle Inputs durchlaufen | `<✓/✗>` |
|
|
75
|
+
| CHALLENGER-Phase pro Finding | `<✓/✗>` |
|
|
76
|
+
| SYNTHESIZER-Konsolidierung gemacht | `<✓/✗>` |
|
|
77
|
+
| Risk-Klassifikation pro Fix | `<✓/✗>` |
|
|
78
|
+
| Disclaimer am Output-Ende | `<✓/✗>` |
|
|
79
|
+
| Sanitization-Check (keine internen Brand-Refs im Output) | `<✓/✗>` |
|
|
80
|
+
| DEVIL'S ADVOCATE durchgelaufen | `<✓/✗>` |
|
|
81
|
+
| LIVE-PROBE durchgelaufen (falls verfuegbar) | `<✓/✗>` |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 5. Naechste Schritte
|
|
86
|
+
|
|
87
|
+
| Prio | Aktion | Owner | Frist |
|
|
88
|
+
|------|--------|-------|-------|
|
|
89
|
+
| 🔴 | `<...>` | `<...>` | `<...>` |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
*Diese Analyse ersetzt keine anwaltliche Beratung. Fuer verbindliche
|
|
94
|
+
Rechtsauskunft empfehle ich die Konsultation eines Fachanwalts fuer
|
|
95
|
+
IT-Recht / Datenschutzrecht.*
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
license: MIT
|
|
3
|
+
purpose: DSE-Block-Vorlage fuer UGC-Plattformen (Vermisst, Marketplace, Forum, Profile).
|
|
4
|
+
references: audit-patterns.md Phase 5c UGC-PUBLIC-PII-AUDIT
|
|
5
|
+
sources: Art. 6 Abs. 1 lit. a + lit. f DSGVO + EuGH C-131/12 Google Spain + DSA Art. 16
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# DSE-Section: User-Generated-Content (UGC) — Vorlage
|
|
9
|
+
|
|
10
|
+
> Dieser Block gehoert in deine Datenschutzerklaerung wenn deine Plattform
|
|
11
|
+
> oeffentlich abrufbare User-Posts hat (Vermisst-Inserate, Marketplace-Listings,
|
|
12
|
+
> Forum-Threads, oeffentliche Profile, oeffentliche Kommentare).
|
|
13
|
+
|
|
14
|
+
## `<N>`. Nutzer-veroeffentlichte Inhalte (UGC)
|
|
15
|
+
|
|
16
|
+
### `<N>.1` Welche Daten werden veroeffentlicht?
|
|
17
|
+
|
|
18
|
+
Wenn Sie als Nutzer einen Beitrag in `<unsere-Plattform>` (z.B. ein
|
|
19
|
+
Vermisst-Inserat, eine Marketplace-Anzeige, einen Forum-Beitrag, ein
|
|
20
|
+
oeffentliches Profil) veroeffentlichen, sind folgende Daten oeffentlich
|
|
21
|
+
abrufbar:
|
|
22
|
+
|
|
23
|
+
- `<Auflistung der Felder>`, z.B.: Vorname, Stadt, Telefonnummer, E-Mail,
|
|
24
|
+
Foto, Tier-Daten, freier Text
|
|
25
|
+
|
|
26
|
+
Diese Daten sind nach Veroeffentlichung **fuer alle Internetnutzer
|
|
27
|
+
einsehbar**, koennen von Suchmaschinen indexiert werden und ggf. von
|
|
28
|
+
Drittanbietern (Wayback Machine, Google Cache) gespeichert werden.
|
|
29
|
+
|
|
30
|
+
### `<N>.2` Rechtsgrundlage
|
|
31
|
+
|
|
32
|
+
Art. 6 Abs. 1 lit. a DSGVO — Einwilligung. Die Einwilligung wird beim
|
|
33
|
+
Abschicken des Posting-Formulars durch eine Pflicht-Checkbox eingeholt
|
|
34
|
+
(siehe Posting-Form in der App / auf der Website). Die Checkbox ist nicht
|
|
35
|
+
vorausgewaehlt; ohne aktive Bestaetigung kann kein Post abgeschickt werden.
|
|
36
|
+
|
|
37
|
+
### `<N>.3` Speicherdauer
|
|
38
|
+
|
|
39
|
+
`<konkret, z.B.: "Vermisst-Inserate werden 90 Tage nach dem Status
|
|
40
|
+
\"gefunden\" automatisch geloescht. Marketplace-Anzeigen verfallen 30 Tage
|
|
41
|
+
nach Inaktivitaet. Forum-Beitraege werden bis zur expliziten Loeschung durch
|
|
42
|
+
den Nutzer aufbewahrt.">`
|
|
43
|
+
|
|
44
|
+
Die automatischen Loesch-Cron-Jobs sind dokumentiert (siehe
|
|
45
|
+
`references/templates/data-retention-cron.ts.example` als Pattern).
|
|
46
|
+
|
|
47
|
+
### `<N>.4` Recht auf Loeschung (Art. 17 DSGVO)
|
|
48
|
+
|
|
49
|
+
Sie koennen Ihre Beitraege jederzeit selbst loeschen ueber `<Pfad zum
|
|
50
|
+
Loeschen-UI>`. Wir setzen zusaetzlich `X-Robots-Tag: noindex` Header auf
|
|
51
|
+
allen UGC-Detail-Pages mit personenbezogenen Daten — damit Suchmaschinen
|
|
52
|
+
nicht in den Cache nehmen, was Sie spaeter loeschen wollen
|
|
53
|
+
(Az.-Anker: EuGH C-131/12 Google Spain). Wir leiten Loesch-Anfragen
|
|
54
|
+
auf Wunsch auch an Google / Bing / DuckDuckGo weiter
|
|
55
|
+
(siehe Hilfe-FAQ `<URL>` fuer Anleitung).
|
|
56
|
+
|
|
57
|
+
### `<N>.5` Notice-and-Action gem. DSA (Art. 16)
|
|
58
|
+
|
|
59
|
+
Bei rechtswidrigen UGC-Inhalten haben Sie ein Notice-and-Action-Recht.
|
|
60
|
+
Reichen Sie eine Meldung ein unter `<URL zum Report-Endpoint>` oder per
|
|
61
|
+
E-Mail an `<email>`. Wir reagieren innerhalb von `<X>` Tagen (DSA Art. 16
|
|
62
|
+
verlangt unverzuegliche Bearbeitung; bei Strafverfolgungs-relevanten
|
|
63
|
+
Inhalten unverzuegliche Behoerden-Meldung).
|
|
64
|
+
|
|
65
|
+
### `<N>.6` Empfehlung an Nutzer
|
|
66
|
+
|
|
67
|
+
Wir empfehlen, in oeffentlichen UGC-Posts:
|
|
68
|
+
- nicht die Privatadresse, nur Stadt
|
|
69
|
+
- bevorzugt eine sekundaere E-Mail-Adresse oder Plattform-interne Inbox
|
|
70
|
+
- bei Telefonnummer pruefen ob Kontakt-Formular reicht
|
|
71
|
+
|
|
72
|
+
`<weitere Branchen-spezifische Hinweise>`
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
*Disclaimer: technisch-indikative Vorlage, keine Rechtsberatung i.S.d. § 2 RDG.
|
|
77
|
+
Vor produktivem Einsatz von Fachanwalt fuer Datenschutzrecht pruefen lassen.*
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
license: MIT
|
|
3
|
+
purpose: Generische DSFA-Vorlage (Art. 35 DSGVO). Anonym, brand-agnostic.
|
|
4
|
+
references: dsgvo.md (DSFA-Trigger-Liste)
|
|
5
|
+
sources: BayLDA-Hinweise zur DSFA + DSK-Whitelist 2018
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Datenschutz-Folgenabschaetzung (DSFA) — Vorlage
|
|
9
|
+
|
|
10
|
+
> Diese Vorlage erfuellt Art. 35 DSGVO + DSK-Whitelist 2018 + BayLDA-Hinweise.
|
|
11
|
+
> Kein Ersatz fuer anwaltliche Bewertung. Vor Inbetriebnahme der Verarbeitung
|
|
12
|
+
> intern abnehmen lassen (Datenschutzbeauftragter / interner Compliance-Officer).
|
|
13
|
+
|
|
14
|
+
## 1. Verantwortlicher (Art. 4 Nr. 7 DSGVO)
|
|
15
|
+
|
|
16
|
+
| Feld | Wert |
|
|
17
|
+
|------|------|
|
|
18
|
+
| Verantwortlicher | `<Operator-Firma>` |
|
|
19
|
+
| Anschrift | `<vollstaendige-Anschrift>` |
|
|
20
|
+
| Kontakt DSB | `<email-DSB>` (sofern bestellt) |
|
|
21
|
+
| DSFA-Datum | `<YYYY-MM-DD>` |
|
|
22
|
+
| DSFA-Version | `<vN.N>` |
|
|
23
|
+
|
|
24
|
+
## 2. Beschreibung der Verarbeitung (Art. 35 Abs. 7 lit. a DSGVO)
|
|
25
|
+
|
|
26
|
+
- **Verarbeitungszweck**: `<Zweck>`
|
|
27
|
+
- **Datenkategorien**: `<Kategorien>` (z.B. Stammdaten, Kontaktdaten, Nutzungsdaten, ggf. besondere Kategorien Art. 9)
|
|
28
|
+
- **Betroffene Personen**: `<Personenkreis>`
|
|
29
|
+
- **Empfaenger**: `<intern>` / `<Auftragsverarbeiter>` / `<Drittland>`
|
|
30
|
+
- **Speicherdauer**: `<Frist>` (mit gesetzlichem Anker)
|
|
31
|
+
- **Rechtsgrundlage**: Art. 6 Abs. 1 lit. `<a/b/c/d/e/f>` DSGVO `<+ Art. 9 lit. X falls relevant>`
|
|
32
|
+
|
|
33
|
+
## 3. Notwendigkeit + Verhaeltnismaessigkeit (Art. 35 Abs. 7 lit. b)
|
|
34
|
+
|
|
35
|
+
- **Notwendigkeit**: warum diese Daten?
|
|
36
|
+
- **Datenminimierung**: was wurde weggelassen?
|
|
37
|
+
- **Pseudonymisierung / Anonymisierung**: wo moeglich?
|
|
38
|
+
|
|
39
|
+
## 4. Risiken fuer Betroffene (Art. 35 Abs. 7 lit. c)
|
|
40
|
+
|
|
41
|
+
| Risiko-Kategorie | Bewertung | Begruendung |
|
|
42
|
+
|------------------|-----------|-------------|
|
|
43
|
+
| Identitaetsdiebstahl | `<niedrig/mittel/hoch>` | `<...>` |
|
|
44
|
+
| Diskriminierung | `<...>` | `<...>` |
|
|
45
|
+
| Reputations-/Vermoegensschaden | `<...>` | `<...>` |
|
|
46
|
+
| Profiling | `<...>` | `<...>` |
|
|
47
|
+
| Verlust Kontrolle ueber Daten | `<...>` | `<...>` |
|
|
48
|
+
|
|
49
|
+
## 5. Abhilfemassnahmen (Art. 35 Abs. 7 lit. d)
|
|
50
|
+
|
|
51
|
+
| Massnahme | Implementierungsstatus | Verify-Command |
|
|
52
|
+
|-----------|------------------------|----------------|
|
|
53
|
+
| Verschluesselung at-rest (TLS, DB) | `<umgesetzt>` | `<curl -sI ...>` |
|
|
54
|
+
| Verschluesselung in-transit | `<umgesetzt>` | `<...>` |
|
|
55
|
+
| Zugriffsbeschraenkung (RBAC) | `<...>` | `<...>` |
|
|
56
|
+
| Audit-Logging | `<...>` | `<...>` |
|
|
57
|
+
| Datenminimierung in Logs | `<...>` | `<...>` |
|
|
58
|
+
| Auto-Cleanup nach Frist | `<...>` | `<...>` |
|
|
59
|
+
| TOMs (Art. 32 DSGVO) | `<verweis>` | `<...>` |
|
|
60
|
+
|
|
61
|
+
## 6. Konsultations-Pflicht (Art. 36 DSGVO)
|
|
62
|
+
|
|
63
|
+
- Wenn nach Massnahmen Risiko **weiterhin hoch** → Pflicht, Aufsichtsbehoerde
|
|
64
|
+
zu konsultieren VOR Beginn der Verarbeitung.
|
|
65
|
+
- Frist Aufsichtsbehoerde: 8 Wochen (verlaengerbar 6 Wochen).
|
|
66
|
+
|
|
67
|
+
## 7. Review-Frist
|
|
68
|
+
|
|
69
|
+
DSFA mindestens jaehrlich oder bei wesentlicher Aenderung der Verarbeitung
|
|
70
|
+
ueberpruefen. Naechstes Review: `<YYYY-MM-DD>`.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
*Disclaimer: Diese Vorlage ist eine technisch-indikative Hilfe, keine Rechtsberatung
|
|
75
|
+
i.S.d. § 2 RDG. Vor produktivem Einsatz von einem Fachanwalt fuer Datenschutzrecht
|
|
76
|
+
oder einem zertifizierten Datenschutzbeauftragten pruefen lassen.*
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// MIT-License — anonymized teaching snippet for brutaler-anwalt
|
|
2
|
+
// References: audit-patterns.md Phase 5c UGC-PUBLIC-PII-AUDIT
|
|
3
|
+
// Pattern: Posting-Form mit Pflicht-Checkbox "wird oeffentlich" (Art. 7 DSGVO Einwilligung)
|
|
4
|
+
|
|
5
|
+
// File: src/components/forms/LostFoundReportForm.tsx (Beispiel: Vermisst-Inserat)
|
|
6
|
+
// Generalisierbar fuer: Marketplace-Inserate, Forum-Threads, oeffentliche Profile.
|
|
7
|
+
|
|
8
|
+
'use client';
|
|
9
|
+
|
|
10
|
+
import { useState, FormEvent } from 'react';
|
|
11
|
+
|
|
12
|
+
interface LostFoundFormState {
|
|
13
|
+
petName: string;
|
|
14
|
+
city: string;
|
|
15
|
+
contactPhone: string;
|
|
16
|
+
contactEmail: string;
|
|
17
|
+
description: string;
|
|
18
|
+
photo: File | null;
|
|
19
|
+
// Pflicht-Consent — ohne diesen kein Submit
|
|
20
|
+
publicConsent: boolean;
|
|
21
|
+
// Optional zusaetzlich: Speicherdauer-Consent + DSE-Akzeptanz
|
|
22
|
+
privacyAccepted: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const initialState: LostFoundFormState = {
|
|
26
|
+
petName: '',
|
|
27
|
+
city: '',
|
|
28
|
+
contactPhone: '',
|
|
29
|
+
contactEmail: '',
|
|
30
|
+
description: '',
|
|
31
|
+
photo: null,
|
|
32
|
+
publicConsent: false,
|
|
33
|
+
privacyAccepted: false,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export function LostFoundReportForm() {
|
|
37
|
+
const [form, setForm] = useState<LostFoundFormState>(initialState);
|
|
38
|
+
const [error, setError] = useState<string | null>(null);
|
|
39
|
+
const [submitting, setSubmitting] = useState(false);
|
|
40
|
+
|
|
41
|
+
// Submit-Gate — Pflicht-Checkbox + DSE-Akzeptanz
|
|
42
|
+
const canSubmit =
|
|
43
|
+
form.publicConsent &&
|
|
44
|
+
form.privacyAccepted &&
|
|
45
|
+
form.petName.length > 0 &&
|
|
46
|
+
form.city.length > 0 &&
|
|
47
|
+
(form.contactPhone.length > 0 || form.contactEmail.length > 0);
|
|
48
|
+
|
|
49
|
+
async function handleSubmit(e: FormEvent) {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
setError(null);
|
|
52
|
+
if (!canSubmit) {
|
|
53
|
+
setError('Bitte fuelle alle Pflichtfelder aus und bestaetige beide Hinweise.');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
setSubmitting(true);
|
|
57
|
+
try {
|
|
58
|
+
const fd = new FormData();
|
|
59
|
+
Object.entries(form).forEach(([k, v]) => {
|
|
60
|
+
if (v instanceof File) fd.append(k, v);
|
|
61
|
+
else if (typeof v === 'boolean') fd.append(k, v ? 'true' : 'false');
|
|
62
|
+
else fd.append(k, String(v));
|
|
63
|
+
});
|
|
64
|
+
const res = await fetch('/api/lost-found', { method: 'POST', body: fd });
|
|
65
|
+
if (!res.ok) throw new Error(`Server returned ${res.status}`);
|
|
66
|
+
// erfolgreich — redirect / toast
|
|
67
|
+
} catch (err) {
|
|
68
|
+
setError(String(err));
|
|
69
|
+
} finally {
|
|
70
|
+
setSubmitting(false);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<form onSubmit={handleSubmit} className="lost-found-form">
|
|
76
|
+
{/* ... regular fields ... */}
|
|
77
|
+
|
|
78
|
+
{/* PFLICHT-Consent — sichtbar, NICHT vorausgewaehlt */}
|
|
79
|
+
<fieldset className="consent-block" aria-required="true">
|
|
80
|
+
<legend>Veroeffentlichungs-Hinweise (Pflicht)</legend>
|
|
81
|
+
|
|
82
|
+
<label className="consent-row">
|
|
83
|
+
<input
|
|
84
|
+
type="checkbox"
|
|
85
|
+
checked={form.publicConsent}
|
|
86
|
+
onChange={(e) => setForm({ ...form, publicConsent: e.target.checked })}
|
|
87
|
+
required
|
|
88
|
+
/>
|
|
89
|
+
<span>
|
|
90
|
+
Ich habe verstanden, dass dieser Beitrag <strong>oeffentlich
|
|
91
|
+
abrufbar</strong> ist und in Suchmaschinen erscheinen koennte.
|
|
92
|
+
Telefonnummer/E-Mail werden bewusst veroeffentlicht, damit Finder
|
|
93
|
+
Kontakt aufnehmen koennen.
|
|
94
|
+
</span>
|
|
95
|
+
</label>
|
|
96
|
+
|
|
97
|
+
<label className="consent-row">
|
|
98
|
+
<input
|
|
99
|
+
type="checkbox"
|
|
100
|
+
checked={form.privacyAccepted}
|
|
101
|
+
onChange={(e) => setForm({ ...form, privacyAccepted: e.target.checked })}
|
|
102
|
+
required
|
|
103
|
+
/>
|
|
104
|
+
<span>
|
|
105
|
+
Ich akzeptiere die <a href="/datenschutz" target="_blank">
|
|
106
|
+
Datenschutzerklaerung</a> und stimme der Verarbeitung gem. Art. 6
|
|
107
|
+
Abs. 1 lit. a DSGVO zu. Ich kann den Beitrag jederzeit selbst
|
|
108
|
+
loeschen.
|
|
109
|
+
</span>
|
|
110
|
+
</label>
|
|
111
|
+
</fieldset>
|
|
112
|
+
|
|
113
|
+
{error && <div role="alert" className="form-error">{error}</div>}
|
|
114
|
+
|
|
115
|
+
<button type="submit" disabled={!canSubmit || submitting}>
|
|
116
|
+
{submitting ? 'Wird abgeschickt…' : 'Vermisst-Inserat veroeffentlichen'}
|
|
117
|
+
</button>
|
|
118
|
+
</form>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// VERIFY:
|
|
123
|
+
// - Server-Side: API muss `publicConsent === true` UND `privacyAccepted === true` enforcen
|
|
124
|
+
// (Client-Disable allein reicht nicht — Browser-Devtools koennen den Disable umgehen).
|
|
125
|
+
// - Audit-Log: pro Posting consentId + IP-prefix + Zeitpunkt + Form-Version speichern
|
|
126
|
+
// (Rechenschaftspflicht Art. 5 Abs. 2).
|