openvibers/openvibe.inventory Commits
Allow Workshop badge previews under Inventory CSP (#265)
Changes
@@@ -163,7 +163,7 @@ 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:'],++ imgSrc: ["'self'", 'data:', 'blob:', 'https:'],// The navbar's Messages count asks Chat (openvibe-shared 4.130.0).connectSrc: ["'self'", 'https://billing.openvibe.network', 'https://inventory.openvibe.network', 'https://openvibe.chat', 'https://openvibe.network', 'https://cloudflareinsights.com', 'https://openvibe.events'],frameSrc: ["'self'", 'https://openvibe.network'],@@@ -30,7 +30,7 @@ const cookieHeader = (r) => r.headers.getSetCookie().map((c) => c.split(';')[0])assert.deepStrictEqual(links.filter((s) => !/^\/inventory(?:[/?#]|$)/.test(s)), [], path);assert.ok(!r.text.includes('/inventory/inventory'), 'no double prefix');assert.ok(r.text.includes(`rel=\"canonical\" href=\"https://openvibe.my${path.split('?')[0]}\"`), path + ': canonical');-- assert.match(r.headers.get('content-security-policy'), /img-src 'self' data: https:;/);++ assert.match(r.headers.get('content-security-policy'), /img-src 'self' data: blob: https:;/);if (path === '/inventory' && as) assert.match(r.text, /<h1>Your inventory<\/h1>/);}const asset = await t.get('/inventory/css/app.css');@@@ -53,9 +53,11 @@ function multipart(fields, file) {const inv = t.ctx.inv;try {await check('badge form offers the shared picker, its limit and a no-script multipart input', async () => {-- const page = (await t.get('/workshop/new', { as: alice })).text;++ const response = await t.get('/workshop/new', { as: alice });++ const page = response.text;assert.match(page, /ov-upload\.css/);assert.match(page, /ov-upload\.js/);++ assert.match(response.headers.get('content-security-policy'), /img-src[^;]*blob:/, 'badge image previews are allowed');assert.match(page, /data-workshop-picker data-max-bytes="204800"/);assert.match(page, /name="image" accept="image\/png,image\/webp" required/);assert.match(page, /role="alert" data-workshop-error/);
@@ -163,7 +163,7 @@ async function createApp(opts = {}) {
@@ -163,7 +163,7 @@ 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:'],
+ imgSrc: ["'self'", 'data:', 'blob:', 'https:'],
// The navbar's Messages count asks Chat (openvibe-shared 4.130.0).
// The navbar's Messages count asks Chat (openvibe-shared 4.130.0).
connectSrc: ["'self'", 'https://billing.openvibe.network', 'https://inventory.openvibe.network', 'https://openvibe.chat', 'https://openvibe.network', 'https://cloudflareinsights.com', 'https://openvibe.events'],
connectSrc: ["'self'", 'https://billing.openvibe.network', 'https://inventory.openvibe.network', 'https://openvibe.chat', 'https://openvibe.network', 'https://cloudflareinsights.com', 'https://openvibe.events'],
frameSrc: ["'self'", 'https://openvibe.network'],
frameSrc: ["'self'", 'https://openvibe.network'],
@@ -30,7 +30,7 @@ const cookieHeader = (r) => r.headers.getSetCookie().map((c) => c.split(';')[0])
@@ -30,7 +30,7 @@ const cookieHeader = (r) => r.headers.getSetCookie().map((c) => c.split(';')[0])
assert.deepStrictEqual(links.filter((s) => !/^\/inventory(?:[/?#]|$)/.test(s)), [], path);
assert.deepStrictEqual(links.filter((s) => !/^\/inventory(?:[/?#]|$)/.test(s)), [], path);
assert.ok(!r.text.includes('/inventory/inventory'), 'no double prefix');
assert.ok(!r.text.includes('/inventory/inventory'), 'no double prefix');
assert.ok(r.text.includes(`rel=\"canonical\" href=\"https://openvibe.my${path.split('?')[0]}\"`), path + ': canonical');
assert.ok(r.text.includes(`rel=\"canonical\" href=\"https://openvibe.my${path.split('?')[0]}\"`), path + ': canonical');
- assert.match(r.headers.get('content-security-policy'), /img-src 'self' data: https:;/);
+ assert.match(r.headers.get('content-security-policy'), /img-src 'self' data: blob: https:;/);
if (path === '/inventory' && as) assert.match(r.text, /<h1>Your inventory<\/h1>/);
if (path === '/inventory' && as) assert.match(r.text, /<h1>Your inventory<\/h1>/);
}
}
const asset = await t.get('/inventory/css/app.css');
const asset = await t.get('/inventory/css/app.css');
@@ -53,9 +53,11 @@ function multipart(fields, file) {
@@ -53,9 +53,11 @@ function multipart(fields, file) {
const inv = t.ctx.inv;
const inv = t.ctx.inv;
try {
try {
await check('badge form offers the shared picker, its limit and a no-script multipart input', async () => {
await check('badge form offers the shared picker, its limit and a no-script multipart input', async () => {
- const page = (await t.get('/workshop/new', { as: alice })).text;
+ const response = await t.get('/workshop/new', { as: alice });
+ const page = response.text;
assert.match(page, /ov-upload\.css/);
assert.match(page, /ov-upload\.css/);
assert.match(page, /ov-upload\.js/);
assert.match(page, /ov-upload\.js/);
+ assert.match(response.headers.get('content-security-policy'), /img-src[^;]*blob:/, 'badge image previews are allowed');
assert.match(page, /data-workshop-picker data-max-bytes="204800"/);
assert.match(page, /data-workshop-picker data-max-bytes="204800"/);
assert.match(page, /name="image" accept="image\/png,image\/webp" required/);
assert.match(page, /name="image" accept="image\/png,image\/webp" required/);
assert.match(page, /role="alert" data-workshop-error/);
assert.match(page, /role="alert" data-workshop-error/);