Commit Graph

20 Commits

Author SHA1 Message Date
s4luorth
494518e98e fix: kein s.w.org-emoji-request + kein weissraum unter dem blocker (v1.4.3)
1) Das Warn-Emoji "⚠" im platzhalter-text loeste WordPress' wp-emoji aus, das
   die grafik von s.w.org nachlud (drittanbieter-request). Emoji aus den texten
   entfernt; das warn-dreieck wird jetzt rein per CSS gezeichnet (kein netzwerk).
   Hinweis: s.w.org ist der WP-emoji-CDN, NICHT Google.
2) Der platzhalter reservierte die hoehe des eingebetteten elements -> bei
   kuerzerem inhalt entstand weissraum darunter. Hoehen-reservierung entfernt
   (PHP min-height-style, JS minHeight, CSS min-height:180px) - der content
   blocker ist jetzt exakt so hoch wie sein eigener inhalt. Die original-masse
   bleiben als data-attribute fuer das iframe nach einwilligung erhalten.
3) Redundante, partielle de_DE-.po/.mo (mit altem emoji) entfernt - deutsche
   locales nutzen direkt die deutschen quell-strings.

+ version 1.4.3 (assets cache-busting).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:23:34 +02:00
s4luorth
176ded0228 fix: Elementor e-youtube-base widget erkennen (v1.4.2)
Das YouTube-video auf der startseite ist kein .elementor-widget-video, sondern
Elementors neueres element <div class="e-youtube-base" data-e-type="e-youtube"
data-settings='{"source":"https://www.youtube.com/watch?v=..."}'>. Daher griff
weder server-autodetect (kein iframe) noch mein client-handler -> leere box.

- selektor erweitert um .e-youtube-base/.e-vimeo-base und
  [data-e-type^="e-youtube"|"e-vimeo"].
- URL-extraktion liest jetzt auch den key "source" (und "url").
An der echten data-settings der live-seite verifiziert.

+ version 1.4.2 (assets cache-busting).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 13:15:53 +02:00
s4luorth
1ce9f8121b fix: leerer elementor-video-platzhalter wenn URL nicht auslesbar (v1.4.1)
Wenn ein Elementor-video per JS gebaut wird und im DOM weder URL noch
Thumbnail steht (nur {"video_type":"youtube"}), konnte mein handler keinen
platzhalter bauen -> Elementor baut nichts (API blockiert) -> leere box.

Fallback: dienst ueber den video_type erkennen und trotzdem einen
einwilligungs-platzhalter zeigen. Da keine embed-URL bekannt ist, gibt dessen
button die einwilligung und laedt die seite neu - danach rendert Elementor das
video normal (scripts sind dann freigegeben). "Einmal laden" entfaellt dort.

+ version 1.4.1 (assets cache-busting fuer die JS-aenderung).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:58:28 +02:00
s4luorth
2361228c14 chore: CB_VERSION auf 1.4.0 (assets cache-busting) - war noch 1.3.0
Header stand bereits auf 1.4.0, CB_VERSION aber auf 1.3.0. Dadurch wurden
geaenderte frontend.js/admin.js mit unveraendertem ?ver=1.3.0 ausgeliefert
und vom browser/cache als alte version geladen. Jetzt konsistent 1.4.0, damit
die JS-fixes (script-guard, elementor-youtube-erkennung) tatsaechlich greifen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:52:56 +02:00
s4luorth
1b7d3434bf fix: elementor-youtube-widget (per JS gebaut) zuverlaessig erkennen
Nach dem script-blocking blieb ein per YouTube-iframe_api gebautes
Elementor-video leer: die API wird blockiert, also baut Elementor kein
iframe -> mein iframe-basierter platzhalter griff nicht, und das
data-settings enthielt nur {"video_type":"youtube"} (keine URL).

videoUrlForWidget() findet die video-URL jetzt aus mehreren quellen:
- explizite keys (youtube_url/vimeo_url/...) im data-settings
- beliebige youtube/vimeo-URL im data-settings (regex, escaped slashes)
- bereits server-gerendertes iframe im widget
- YouTube-thumbnail (i.ytimg.com/vi/ID/) bei lazyload/overlay-modus
Greift auch fuer .elementor-widget[data-widget_type^="video"] und ueberspringt
widgets, die der server-autodetect schon zum platzhalter gemacht hat.

Extraktions-logik isoliert getestet (thumbnail, escaped-json, vimeo).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 11:36:31 +02:00
s4luorth
ca945d2d80 feat: third-party-scripts blockieren (server + client-guard)
Loest die YouTube/Vimeo-API-Luecke: viele dienste laden ueber <script>
(z. B. youtube.com/iframe_api, www-widgetapi.js, analytics) statt iframes -
oft per JavaScript nachgeladen, daher fuer den scanner unsichtbar.

- Pro dienst aktivierbar ueber das (umbenannte) feld "Zugehoerige Skripte
  blockieren (z. B. YouTube-/Vimeo-API)" = das vorhandene loads_script-flag.
  Presets (YouTube, Vimeo, Maps) haben es bereits an.
- Server-seitig: passende <script src> werden zu type="text/plain"
  (src -> data-cb-src) neutralisiert, laden also nicht.
- Client-seitig: winziger guard ganz frueh im <head> patcht
  appendChild/insertBefore/replaceChild und neutralisiert dynamisch
  injizierte scripts VOR dem einfuegen -> kein request. Faengt damit auch
  die per JS nachgeladene iframe_api ab.
- Einwilligung (per-dienst-consent, z. B. ueber den video-platzhalter)
  schaltet die scripts via cbActivateScripts frei und laedt sie nach.
- Neuer shortcode [content_blocker_consent id="…"] als einwilligungs-button
  fuer reine skript-dienste ohne sichtbaren platzhalter.
- guard-logik mit DOM-mock getestet (block + reinject), server-regex
  isoliert geprueft. i18n DE/EN ergaenzt (127 strings).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 08:24:33 +02:00
s4luorth
b6df4c64af revert: lokales Google-Fonts-Hosting entfernt + scan zeigt nur hinweis
- Feature "Schriften lokal hosten" komplett zurueckgebaut (class-fonts.php,
  tab, ajax-endpunkte, output-buffer, admin-js-handler, optionen).
- Scan: wird fonts.googleapis.com / fonts.gstatic.com erkannt, steht in der
  Aktion-spalte jetzt der nicht-klickbare hinweis "Schriftart fuer
  DSGVO-konformen Betrieb lokal hosten." statt eines buttons.
- i18n entsprechend bereinigt (123 strings).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:39:34 +02:00
s4luorth
94043baf7c feat: alle lizenzen auflisten - GET /api/v1/licenses (+ ?email= filter)
- Neuer admin-endpunkt GET /api/v1/licenses listet alle lizenzen inkl. email,
  status, max_activations, activations_used, produkt, daten.
- Optionaler ?email=<adresse> filter (case-insensitive) fuer eine kundenmail.
- Integrationstest-abdeckung ergaenzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:29:44 +02:00
s4luorth
377c64f8d0 feat: lokales Google-Fonts-Hosting + "Lizenz upgraden"-button (v1.3.0)
- Lizenz-Tab: bei vollen Plaetzen erscheint ein "Lizenz upgraden"-Button
  (https://lucas-orth.de/wp-plugins/gdpr-content-blocker/) zusaetzlich zur
  domain-freigabe.
- Neues Feature "Schriften": Google Fonts lokal hosten (button-modell).
  Admin klickt "Jetzt herunterladen & einbinden" -> plugin scannt die seiten,
  laedt googleapis-CSS + gstatic-schriftdateien einmalig in den uploads-ordner,
  schreibt die pfade lokal um und tauscht sie per output-buffer im quelltext.
  Abgedeckt: <link>, inline-@import/url() UND @import/url() in gleicher-origin
  externen CSS-dateien (mit absolutierung der restlichen relativen pfade).
  preconnect/dns-prefetch zu google-font-hosts werden entfernt (kein IP-leak).
  Toggle zum aus/einschalten + "Lokale Schriften loeschen".
- i18n-pipeline robuster: build-en-mo.py nutzt jetzt translations-en.json
  (lookup per quell-string, reihenfolge-unabhaengig) und bricht mit liste ab,
  falls eine uebersetzung fehlt. Alle neuen strings DE/EN ergaenzt (139).
- version 1.3.0 (header + CB_VERSION).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:16:19 +02:00
s4luorth
ca0f2f2c32 fix: SSRF-haertung (IP-pinning) + blank-page-schutz aus security-review
- scan & releases/from-url: verbindung wird an die bereits validierte IP
  gepinnt (node:http/https lookup-option), statt fetch erneut aufloesen zu
  lassen. Schliesst DNS-rebinding/TOCTOU, mit dem ein lizenzierter Kunde
  ueber die DNS seiner eigenen Domain interne Dienste/Cloud-Metadaten
  erreichen koennte.
- releases/from-url folgt redirects jetzt manuell und validiert jeden hop
  (protokoll + private-IP-guard); gitea-token nur an den ausgangs-host.
- pinnedRequest: settle-guard + body-cap loesen das promise auch bei
  ueberlangen antworten (kein haengen).
- autodetect process(): kein blank-page mehr bei PCRE-fehler (fallback auf
  original-HTML statt (string) null = "").
- cleanup: ungenutztes extract_iframe_src() entfernt; redundantes
  &amp;-replace in get_src() entfernt (DOMDocument dekodiert bereits).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 06:52:22 +02:00
s4luorth
40f4207024 feat: kein interner-name-feld mehr - ID automatisch aus anbietername
- Dienst-Zeile zeigt/erfordert nur noch den Anbietername.
- Interne ID wird beim Speichern aus dem Namen abgeleitet (sanitize_title),
  bestehende IDs bleiben via Hidden-Field stabil; Eindeutigkeit erzwungen.
- Shortcode-Hilfe erklaert: ID = Anbietername in Kleinbuchstaben mit Bindestrichen.
- EN-Uebersetzung (120) aktualisiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 17:03:26 +02:00
s4luorth
de4f16fefa fix: scanner ignoriert metadaten-links (gmpg.org rel=profile); version 1.2.0
- Nur ladende <link rel=...> (stylesheet/preload/icon/...) werden gezaehlt;
  rel=profile/canonical/pingback etc. (z.B. gmpg.org) sind keine Requests mehr.
- Plugin-Version + Header auf 1.2.0 (passend zu readme), Changelog-Eintrag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 16:57:09 +02:00
s4luorth
b03f18a794 feat: lizenz aendern - PATCH /api/v1/licenses/:key
- Aendert max_activations (z.B. -1 unbegrenzt), email, note, expires_at, status.
- Partielles Update, validiert; nur erlaubte Felder. Tests + README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:53:31 +02:00
s4luorth
e691b675cd feat: release per URL registrieren (gitea-asset) - /api/v1/releases/from-url
- Admin-Endpoint laedt die ZIP einmal von einer URL (z.B. Gitea-Release-Asset),
  speichert sie lokal; Kunden-Download bleibt token-/lizenzgeschuetzt.
- Guards: Produkt/Version/URL-Pruefung, GITEA_BASE_URL-Restriktion, DNS-SSRF-Schutz,
  optional GITEA_TOKEN fuer private Repos, ZIP-Signatur + 50MB-Limit.
- env-Beispiele + README + Tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:51:19 +02:00
s4luorth
576ad1f74a fix: pfeil groesser, tab ohne fokus-kasten, version 1.1.0 (cache-bust)
- Aufklapp-Pfeil deutlich groesser (26px).
- Tabs: kein Fokus-Kasten mehr, nur untere Linie markiert den aktiven Tab.
- CB_VERSION + Header auf 1.1.0 -> bricht gecachte alte admin.js/frontend.js
  (Ursache, dass ein Dienst auf einer Seite nicht aufklappbar war).
- Aufklappen via Event-Delegation (robust gegen Load-Order/dynamische Zeilen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:31:28 +02:00
s4luorth
a0972b4bbf feat: belegte domains als liste mit papierkorb + status-live-refresh
- Bei voller Lizenz werden alle belegten Domains untereinander gelistet, je
  mit Papierkorb-Button + Bestaetigungsdialog (statt Dropdown).
- Trash gibt die Domain frei (deaktiviert serverseitig) und aktiviert diese Seite.
- Lizenz-Tab re-validiert den Status live (max alle 5 Min), damit eine an anderer
  Stelle freigegebene Domain hier sofort als ungueltig erscheint statt stale aktiv.
- EN-Uebersetzung (122) aktualisiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:27:34 +02:00
s4luorth
4f0f8ea170 feat: pfeile statt +/-, shortcodes-tab, funktionen aus darstellung entfernt
- Ein-/Ausklappen wieder mit schwarzem Pfeil (>/v) ohne Box.
- Neuer Tab Shortcodes; Darstellung listet keine Funktionen mehr.
- CSS-Klassen-Referenz in den Darstellung-Tab (unter Custom CSS) verschoben.
- EN-Uebersetzung (121 Strings) neu gebaut.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:22:20 +02:00
s4luorth
a738841d60 feat: client-seitige erkennung fuer elementor-videos und JS-iframes
- frontend.js erkennt JS-nachgeladene iframes (Slider etc.) per initialem Scan
  + MutationObserver und ersetzt sie durch den Platzhalter.
- Elementor-Video-Widgets: data-settings (youtube_url/vimeo_url) wird gelesen,
  zu Embed-URL konvertiert, Widget neutralisiert und durch Platzhalter ersetzt.
- Service-Daten + i18n werden dafuer ans Frontend lokalisiert (cbConfig).
- readme: Erkennung + Grenzen (Elementor-Vorschaubild) dokumentiert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:11:48 +02:00
s4luorth
3c37bf63cc feat: UI-feinschliff, scan-vorlagenerkennung, einmal-laden, DE/EN-sprachen
UI:
- Ein-/Ausklappen jetzt mit grossem +/- Icon statt kleinem Pfeil.
- "Entfernen" ist ein Papierkorb-Symbol (dashicon).
- Aktiver Tab klar gekennzeichnet (Akzent-Unterstrich + Farbe).
- 20px Abstand zwischen Tabs und Inhalt.

Funktionen:
- Scan erkennt Anbieter, fuer die es eine Vorlage gibt ("Vorlage verfuegbar"),
  und "Vorlage uebernehmen" fuellt die komplette Vorlage statt nur Host/Pattern.
- Platzhalter: Checkbox "Diesen Dienst kuenftig immer laden" (Standard AN).
  Abgewaehlt -> Inhalt wird nur einmal geladen, keine dauerhafte Einwilligung.

i18n:
- Sprachumschaltung: Deutsch fuer alle de_* Locales, Englisch fuer alle anderen
  (plugin_locale-Filter). Vollstaendige englische Uebersetzung (126 Strings,
  inkl. Vorlagentexte/Empfaenger) als gdpr-content-blocker-en_US.po/.mo.
- Helper-Skripte (extract/build) in hilfsdaten/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:06:16 +02:00
s4luorth
ecb5e1bd22 chore: monorepo - plugin, backend und hilfsdaten in einem repo
- Eltern-Ordner ist jetzt EIN Git-Repo (statt getrennter Repos).
- root .gitignore haelt Secrets (.env), node_modules, DB und Build-Artefakte raus.
- release.ps1: manueller Release (ZIP bauen + ans Backend laden).
- root README mit Struktur und Release-Ablauf.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 14:41:38 +02:00