Changeset 07de464 in Klonkt
- Timestamp:
- 06/27/2026 09:37:05 AM (2 months ago)
- Branches:
- main
- Children:
- f3551ec
- Parents:
- 5421ce1
- Location:
- src
- Files:
-
- 2 edited
-
middleware/render.js (modified) (2 diffs)
-
server.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/middleware/render.js
r5421ce1 r07de464 52 52 return new Date(iso).toLocaleString('nl-NL', { timeZone: siteTimezone(), dateStyle: 'medium', timeStyle: 'short' }); 53 53 }; 54 55 // Cross-site Klonkt audio embeds (a followed/boosted site's /embed player) need their56 // origins in the DOCUMENT CSP frame-src — the per-/news injection is ignored once you57 // navigate there via htmx (the document's CSP governs, not the partial's). Collect the58 // distinct origins from the site's timeline (followed + boosted). Cached 60s.59 const _embedOriginsCache = new Map(); // slug -> { origins, exp }60 function embedOriginsFor(slug) {61 const now = Date.now();62 const c = _embedOriginsCache.get(slug);63 if (c && c.exp > now) return c.origins;64 let origins = [];65 try {66 const rows = db.prepare('SELECT DISTINCT url FROM ap_timeline WHERE slug = ? AND url IS NOT NULL').all(slug);67 const set = new Set();68 for (const r of rows) { try { set.add(new URL(r.url).origin); } catch { /* skip bad url */ } }69 origins = [...set];70 } catch { origins = []; }71 _embedOriginsCache.set(slug, { origins, exp: now + 60000 });72 return origins;73 }74 54 75 55 export async function renderPage(req, res, viewName, data = {}) { … … 114 94 const _isViewer = isViewer(_u); 115 95 116 // Per-domain CSP: let a logged-in site manager frame the Klonkt players of the sites in 117 // their timeline (followed + boosted) on the DOCUMENT, so cross-site embeds also work 118 // after an htmx/PWA navigation. NEVER on authorize_interaction — that page shows 119 // untrusted remote content next to the interact buttons, so no embeds / no frame-src 120 // loosening there (clickjacking risk). 121 try { 122 if (_site && _site.slug && viewName !== 'pages/authorize-interaction' && _u && PermissionsService.canAdminSite(_u, _site)) { 123 const origins = embedOriginsFor(_site.slug); 124 if (origins.length) { 125 const csp = res.getHeader('Content-Security-Policy'); 126 if (csp) res.setHeader('Content-Security-Policy', String(csp).replace(/frame-src ([^;]*)/i, (m, g) => `frame-src ${g} ${origins.join(' ')}`)); 127 } 128 } 129 } catch { /* CSP extension is best-effort */ } 96 // Embeds are framed broadly (frame-src https: globally), EXCEPT on authorize_interaction: 97 // that page renders untrusted remote content next to the interact buttons, so lock its 98 // frame-src down to 'self' (no embeds → no clickjacking/overlay over the buttons). 99 if (viewName === 'pages/authorize-interaction') { 100 try { 101 const csp = res.getHeader('Content-Security-Policy'); 102 if (csp) res.setHeader('Content-Security-Policy', String(csp).replace(/frame-src [^;]*/i, "frame-src 'self'")); 103 } catch { /* best-effort */ } 104 } 130 105 131 106 // Who sees the "Admin" link? god/admin, a site owner (artist self-manage), -
src/server.js
r5421ce1 r07de464 125 125 mediaSrc: ["'self'", "https:", "blob:"], 126 126 fontSrc: ["'self'"], 127 frameSrc: [ 128 "'self'", 129 "https://open.spotify.com", 130 "https://w.soundcloud.com", 131 "https://bandcamp.com", 132 "https://embed.music.apple.com", 133 "https://www.youtube-nocookie.com", 134 "https://www.youtube.com", // YouTube IFrame API sometimes creates a www.youtube.com iframe 135 "https://player.vimeo.com", 136 ], 127 // Embeds (platform players + cross-site Klonkt audio players) are framed broadly: 128 // ANY https origin, so embeds work in any context (feed, htmx/PWA nav, public pages). 129 // The sensitive /authorize_interaction page tightens frame-src back to 'self' in 130 // renderPage — it shows untrusted remote content next to the interact buttons. 131 frameSrc: ["'self'", "https:"], 137 132 }, 138 133 },
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)