openvibers/openvibe.report Commits
CSP: allow the Live and Community thumbnails Report shows (#101)
Changes
@@@ -119,7 +119,9 @@ async function createApp(opts = {}) {scriptSrc: ["'self'", "'unsafe-inline'", 'https://openvibe.network', 'https://static.cloudflareinsights.com'],styleSrc: ["'self'", "'unsafe-inline'", 'https://openvibe.network', 'https://fonts.googleapis.com', 'https://cdnjs.cloudflare.com'],fontSrc: ["'self'", 'data:', 'https://fonts.gstatic.com', 'https://cdnjs.cloudflare.com'],-- imgSrc: ["'self'", 'data:', 'https://openvibe.network', 'https://openvibe.media'],++ // Cards show the readings' own pictures: a stream's thumbnail comes from Live and a post's screenshot++ // from Community (the sources of the Rundown's takes), so both origins are allowed here and nowhere wider.++ imgSrc: ["'self'", 'data:', 'https://openvibe.network', 'https://openvibe.media', 'https://openvibe.live', 'https://openvibe.community'],connectSrc: ["'self'", 'https://openvibe.network', 'https://cloudflareinsights.com', 'https://openvibe.events'],frameSrc: ["'self'", 'https://openvibe.network'],frameAncestors: ["'none'"],@@@ -32,6 +32,21 @@ const { boot, check, done, defaults } = require('./helpers/boot');});}++ await check('the CSP allows the Live and Community thumbnails on the pages that show them', async () => {++ for (const path of ['/', '/rundown']) {++ const r = await t.get(path);++ const csp = r.headers.get('content-security-policy') || '';++ const imgSrc = csp.split(';').map((directive) => directive.trim()).find((directive) => directive.startsWith('img-src '));++ assert.ok(imgSrc, `${path}: no img-src directive`);++ const origins = imgSrc.split(/\s+/).slice(1);++ for (const origin of ['https://openvibe.live', 'https://openvibe.community']) {++ assert.ok(origins.includes(origin), `${path}: img-src does not allow ${origin}`);++ }++ // The fix names those two origins; it does not open img-src to every https origin.++ assert.ok(!origins.some((origin) => origin === '*' || origin === 'https:'), `${path}: img-src is wider than the two origins`);++ }++ });++await check('the home has WebSite and Organization JSON-LD', async () => {const r = await t.get('/');const ld = [...r.text.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)].map((m) => JSON.parse(m[1])).flatMap((b) => b['@graph'] || [b]);
@@ -119,7 +119,9 @@ async function createApp(opts = {}) {
@@ -119,7 +119,9 @@ async function createApp(opts = {}) {
scriptSrc: ["'self'", "'unsafe-inline'", 'https://openvibe.network', 'https://static.cloudflareinsights.com'],
scriptSrc: ["'self'", "'unsafe-inline'", 'https://openvibe.network', 'https://static.cloudflareinsights.com'],
styleSrc: ["'self'", "'unsafe-inline'", 'https://openvibe.network', 'https://fonts.googleapis.com', 'https://cdnjs.cloudflare.com'],
styleSrc: ["'self'", "'unsafe-inline'", 'https://openvibe.network', 'https://fonts.googleapis.com', 'https://cdnjs.cloudflare.com'],
fontSrc: ["'self'", 'data:', 'https://fonts.gstatic.com', 'https://cdnjs.cloudflare.com'],
fontSrc: ["'self'", 'data:', 'https://fonts.gstatic.com', 'https://cdnjs.cloudflare.com'],
- imgSrc: ["'self'", 'data:', 'https://openvibe.network', 'https://openvibe.media'],
+ // Cards show the readings' own pictures: a stream's thumbnail comes from Live and a post's screenshot
+ // from Community (the sources of the Rundown's takes), so both origins are allowed here and nowhere wider.
+ imgSrc: ["'self'", 'data:', 'https://openvibe.network', 'https://openvibe.media', 'https://openvibe.live', 'https://openvibe.community'],
connectSrc: ["'self'", 'https://openvibe.network', 'https://cloudflareinsights.com', 'https://openvibe.events'],
connectSrc: ["'self'", 'https://openvibe.network', 'https://cloudflareinsights.com', 'https://openvibe.events'],
frameSrc: ["'self'", 'https://openvibe.network'],
frameSrc: ["'self'", 'https://openvibe.network'],
frameAncestors: ["'none'"],
frameAncestors: ["'none'"],
@@ -32,6 +32,21 @@ const { boot, check, done, defaults } = require('./helpers/boot');
@@ -32,6 +32,21 @@ const { boot, check, done, defaults } = require('./helpers/boot');
});
});
}
}
+ await check('the CSP allows the Live and Community thumbnails on the pages that show them', async () => {
+ for (const path of ['/', '/rundown']) {
+ const r = await t.get(path);
+ const csp = r.headers.get('content-security-policy') || '';
+ const imgSrc = csp.split(';').map((directive) => directive.trim()).find((directive) => directive.startsWith('img-src '));
+ assert.ok(imgSrc, `${path}: no img-src directive`);
+ const origins = imgSrc.split(/\s+/).slice(1);
+ for (const origin of ['https://openvibe.live', 'https://openvibe.community']) {
+ assert.ok(origins.includes(origin), `${path}: img-src does not allow ${origin}`);
+ }
+ // The fix names those two origins; it does not open img-src to every https origin.
+ assert.ok(!origins.some((origin) => origin === '*' || origin === 'https:'), `${path}: img-src is wider than the two origins`);
+ }
+ });
+
await check('the home has WebSite and Organization JSON-LD', async () => {
await check('the home has WebSite and Organization JSON-LD', async () => {
const r = await t.get('/');
const r = await t.get('/');
const ld = [...r.text.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)].map((m) => JSON.parse(m[1])).flatMap((b) => b['@graph'] || [b]);
const ld = [...r.text.matchAll(/<script type="application\/ld\+json">([\s\S]*?)<\/script>/g)].map((m) => JSON.parse(m[1])).flatMap((b) => b['@graph'] || [b]);