Fortsetzung des Musik-Fundes: PayPal und Google haetten an derselben Stelle still versagt, sobald Dogi seine Zugangsdaten eintraegt -- leerer Bereich statt Bezahlknopf, ohne Fehlermeldung, ohne Protokolleintrag. Vorgehen bewusst gemessen statt geraten: Erst die Angaben der Anbieter (PayPal "Best Practices", Google CSP-Abschnitt der Setup-Anleitung), dann im echten Browser mit PayPals offizieller Testkennung "client-id=test" nachgemessen und die Verstoesse ueber das Ereignis securitypolicyviolation eingesammelt. Die Messung hat zwei Dinge gefunden, die in keiner Anleitung standen: - www.sandbox.paypal.com (frame-src + connect-src). Beim Einrichten testet man mit Sandbox-Zugangsdaten; ohne diesen Eintrag haette die Kasse in genau dieser Phase nicht abgeschlossen werden koennen. - accounts.google.com/gsi/style (style-src). 'unsafe-inline' deckt das NICHT ab -- es erlaubt nur Stile im Dokument, keine nachgeladene Stilvorlage. Der Anmelde-Knopf waere unformatiert erschienen. Bewusst einzelne Adressen statt PayPals vorgeschlagener Platzhalter (*.paypal.com): Was die Messung nicht gebraucht hat, steht nicht drin. Skripte bleiben ohne 'unsafe-inline' -- die Pruefsummen-Loesung fuer die eigenen Inline-Bloecke bleibt unangetastet, und ein zusaetzliches 'unsafe-inline' waere neben Pruefsummen ohnehin wirkungslos. Neuer Test pruef-kasse.mjs (15 Pruefungen): laedt das echte PayPal-SDK, baut die Bezahlknoepfe wirklich auf, rendert den echten Google-Knopf und verlangt NULL Verstoesse. Bestandstest pruef-inhaltsrichtlinie.mjs (22) und pruef-musik.mjs (17) bleiben gruen -- inklusive der Gegenprobe, dass eingeschleuste Skripte weiterhin blockiert werden. Co-Authored-By: Claude Opus 5 <[email protected]>
39 lines
3.0 KiB
JavaScript
39 lines
3.0 KiB
JavaScript
import { chromium } from "playwright";
|
|
import { spawn } from "node:child_process";
|
|
const server = spawn(process.execPath, ["index.js"], { cwd: "server", env: { ...process.env, PORT: "4434" }, stdio: "ignore" });
|
|
const warte = async () => { for (let i=0;i<40;i++){ try { if ((await fetch("http://127.0.0.1:4434/index.html")).ok) return; } catch{} await new Promise(r=>setTimeout(r,250)); } throw new Error("kein Server"); };
|
|
await warte();
|
|
const b = await chromium.launch();
|
|
const s = await b.newPage();
|
|
await s.goto("http://127.0.0.1:4434/abonnieren.html", { waitUntil: "domcontentloaded" });
|
|
await s.evaluate(() => { window.__v = []; document.addEventListener("securitypolicyviolation", (e) => window.__v.push({ dir: e.violatedDirective, blockiert: e.blockedURI })); });
|
|
const paypal = await s.evaluate(async () => {
|
|
const geladen = await new Promise((res) => { const sk = document.createElement("script"); sk.src = "https://www.paypal.com/sdk/js?client-id=test¤cy=EUR"; sk.onload = () => res(true); sk.onerror = () => res(false); document.body.appendChild(sk); setTimeout(() => res(false), 15000); });
|
|
if (!geladen || !window.paypal) return { geladen, buttons: false };
|
|
const ziel = document.createElement("div"); ziel.id = "pp-test"; ziel.style.width = "300px"; document.body.appendChild(ziel);
|
|
try { await window.paypal.Buttons({}).render("#pp-test"); } catch (e) { return { geladen, buttons: false, fehler: String(e).slice(0,150) }; }
|
|
const f = ziel.querySelector("iframe");
|
|
return { geladen, buttons: !!f, rahmenHoehe: f ? Math.round(f.getBoundingClientRect().height) : 0 };
|
|
});
|
|
console.log("PAYPAL:", JSON.stringify(paypal));
|
|
const google = await s.evaluate(async () => {
|
|
const geladen = await new Promise((res) => { const sk = document.createElement("script"); sk.src = "https://accounts.google.com/gsi/client"; sk.onload = () => res(true); sk.onerror = () => res(false); document.head.appendChild(sk); setTimeout(() => res(false), 15000); });
|
|
if (!geladen || !window.google) return { geladen, knopf: false };
|
|
const ziel = document.createElement("div"); ziel.id = "g-test"; document.body.appendChild(ziel);
|
|
try {
|
|
window.google.accounts.id.initialize({ client_id: "000000000000-testtesttesttesttesttest.apps.googleusercontent.com", callback: () => {} });
|
|
window.google.accounts.id.renderButton(ziel, { type: "standard" });
|
|
} catch (e) { return { geladen, knopf: false, fehler: String(e).slice(0,150) }; }
|
|
await new Promise(r => setTimeout(r, 4000));
|
|
return { geladen, knopf: ziel.children.length > 0, inhalt: ziel.innerHTML.slice(0, 60) };
|
|
});
|
|
console.log("GOOGLE:", JSON.stringify(google));
|
|
await s.waitForTimeout(3000);
|
|
const v = await s.evaluate(() => window.__v);
|
|
const zus = {};
|
|
for (const e of v) { const k = e.dir + " <- " + (e.blockiert || "(inline)"); zus[k] = (zus[k]||0)+1; }
|
|
console.log("\nVERSTOESSE:", Object.keys(zus).length === 0 ? "KEINE" : "");
|
|
Object.entries(zus).sort().forEach(([k,n]) => console.log(" " + n + "x " + k));
|
|
console.log("\nRahmen:"); s.frames().forEach(f => console.log(" " + f.url().slice(0,75)));
|
|
await b.close(); server.kill();
|