Preview (and version-history Preview) renders the page in an <iframe sandbox srcdoc> without allow-same-origin, i.e. an opaque origin. Every site-builder asset response carries Cross-Origin-Resource-Policy: same-site (whp libs/SiteBuilderAssetServe.php), so each upload requested from that frame is cross-site and blocked (ERR_BLOCKED_BY_RESPONSE.NotSameSite, naturalWidth 0). The canvas was fine; Preview images were broken for everyone. CORP and the sandbox stay as they are. Before the HTML is handed to the sandboxed frame, the editor (panel origin, same-origin to the proxy) fetches this site's proxy assets and swaps each URL for a data: URL in the HTML text (utils/preview-assets.ts): img src/srcset, poster, video src, <link> icon, inline-style and <style> url(), "/& forms, both proxy URL forms. <a href>, <meta content>, other sites, other origins are left alone. Per-asset (8 MiB), total (40 MiB), count (200) and timeout (15 s) caps; any per-asset failure keeps the original URL. Save/Publish/export are untouched. blob: was measured and rejected: in Chromium and Firefox a blob: URL made by the editor window or by the Preview tab does not load inside the null-origin frame; data: does. Tests: vitest for the collector/rewriter; new real-browser suite test:browser:preview-assets (real HTTP stub with the backend's CORP header, Preview opened by a click through the real openers) reproduces the block with the old opener and passes with the new one in Chromium and Firefox, measures blob vs data, and checks the real backend publish holds only assets/<file>. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0185ukXgk6UunFCKyXqLe2Cq
59 lines
2.3 KiB
JSON
59 lines
2.3 KiB
JSON
{
|
|
"name": "whp-site-builder",
|
|
"private": true,
|
|
"version": "2.0.0",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "tsc && vite build",
|
|
"preview": "vite preview",
|
|
"test": "playwright test tests/site-builder.spec.ts --reporter=list",
|
|
"test:headed": "playwright test tests/site-builder.spec.ts --reporter=list --headed",
|
|
"test:e2e:sitesmith": "playwright test tests/sitesmith.spec.ts --reporter=list",
|
|
"test:unit": "vitest run",
|
|
"test:browser:bg": "node scripts/e2e-background.mjs",
|
|
"test:browser:canvas": "node scripts/e2e-canvas-parity.mjs",
|
|
"test:browser:mobile": "node scripts/e2e-mobile-parity.mjs",
|
|
"test:browser:mobile-guard": "node scripts/e2e-mobile-guard.mjs",
|
|
"test:browser:legacy-grid": "node scripts/e2e-legacy-grid.mjs",
|
|
"test:browser:colorpick": "node scripts/e2e-color-pick.mjs",
|
|
"test:browser:colors": "node scripts/e2e-color-system.mjs",
|
|
"test:browser:capture-fidelity": "node scripts/e2e-capture-fidelity.mjs",
|
|
"test:browser:capture-security": "node scripts/e2e-capture-security.mjs",
|
|
"test:browser:sitesmith": "node scripts/e2e-sitesmith.mjs",
|
|
"test:browser:sitesmith-editor-assets": "node scripts/e2e-sitesmith-editor-assets.mjs",
|
|
"test:browser:sitesmith-cleaned": "node scripts/e2e-sitesmith-cleaned.mjs",
|
|
"test:browser:preview-assets": "node scripts/e2e-preview-assets.mjs",
|
|
"test:unit:watch": "vitest"
|
|
},
|
|
"dependencies": {
|
|
"@codemirror/autocomplete": "^6.20.3",
|
|
"@codemirror/commands": "^6.10.4",
|
|
"@codemirror/lang-css": "^6.3.1",
|
|
"@codemirror/lang-html": "^6.4.11",
|
|
"@codemirror/lang-javascript": "^6.2.5",
|
|
"@codemirror/language": "^6.12.4",
|
|
"@codemirror/state": "^6.7.1",
|
|
"@codemirror/theme-one-dark": "^6.1.3",
|
|
"@codemirror/view": "^6.43.6",
|
|
"@craftjs/core": "^0.2.10",
|
|
"@craftjs/layers": "^0.2.7",
|
|
"dompurify": "^3.4.5",
|
|
"html-to-image": "1.11.13",
|
|
"react": "^18.3.1",
|
|
"react-dom": "^18.3.1"
|
|
},
|
|
"devDependencies": {
|
|
"@playwright/test": "^1.59.1",
|
|
"@types/dompurify": "^3.0.5",
|
|
"@types/react": "^18.3.12",
|
|
"@types/react-dom": "^18.3.1",
|
|
"@vitejs/plugin-react": "^4.3.4",
|
|
"@vitest/ui": "^4.1.7",
|
|
"jsdom": "^29.1.1",
|
|
"typescript": "^5.6.3",
|
|
"vite": "^6.0.5",
|
|
"vitest": "^4.1.7"
|
|
}
|
|
}
|