openvibers/openvibe.locker Commits

CSP: allow avatars from openvibe.media in img-src (#40)

OP OpenVibers committed 3 days ago · e9be620282 · 2 files, +6 −1

Changes

ddiff --git a/server/app.js b/server/app.js
iindex 4f7e181..6da092c 100644
---- a/server/app.js
++++ b/server/app.js
@@@ -31,7 +31,7 @@ async function createApp(options = {}) {
app.disable('x-powered-by'); app.set('trust proxy', config.trustProxy);
app.use(helmet({ contentSecurityPolicy: { directives: {
defaultSrc: ["'self'"], scriptSrc: ["'self'", "'unsafe-inline'", config.networkUrl, 'https://static.cloudflareinsights.com'], styleSrc: ["'self'", "'unsafe-inline'", config.networkUrl, 'https://fonts.googleapis.com'],
-- fontSrc: ["'self'", 'data:', 'https://fonts.gstatic.com'], imgSrc: ["'self'", 'data:', 'blob:', config.networkUrl],
++ fontSrc: ["'self'", 'data:', 'https://fonts.gstatic.com'], imgSrc: ["'self'", 'data:', 'blob:', config.networkUrl, 'https://openvibe.media'],
connectSrc: ["'self'", config.networkUrl, 'https://openvibe.chat', 'https://billing.openvibe.network', 'https://openvibe.events', 'https://cloudflareinsights.com', 'https://api.pwnedpasswords.com'],
workerSrc: ["'self'"], frameSrc: [config.networkUrl], frameAncestors: ["'none'"], objectSrc: ["'none'"], baseUri: ["'self'"],
formAction: ["'self'", config.networkUrl], upgradeInsecureRequests: config.production ? [] : null,
ddiff --git a/test/locker.test.js b/test/locker.test.js
iindex 8f4b3b5..0c133c3 100644
---- a/test/locker.test.js
++++ b/test/locker.test.js
@@@ -27,6 +27,11 @@ test('llms.txt and llms-full.txt describe the public pages', async () => {
assert.ok(!text.includes('/passwords'), 'no signed-in page is in the full text');
});
++test('the security policy lets an avatar from openvibe.media show in img-src', async () => {
++ const csp = (await t.request('GET', '/', { user: null })).headers.get('content-security-policy') || '';
++ assert.match(csp, /img-src[^;]*https:\/\/openvibe\.media(?:[ ;]|$)/, csp);
++});
++
test('password login items use people locks and remain opaque in storage', async () => {
const secret = JSON.stringify({ version: 1, site: 'https://example.test', username: 'alice', password: 'secret-password', totp: '', notes: '' });
const encrypted = await locker.seal(secret, { lock: 'people', keys: [{ subject: { type: 'user', id: SUBJECT }, publicKey: t.people.get(SUBJECT).ecdhPublic }] });