openvibers/openvibe.network Commits
Brand assets (/assets/*: logo, app icons, OG images) are readable cross-origin and cached for a day: helmet's Cross-Origin-Resource-Policy same-origin blocked the logo on every placeholder site
Changes
@@@ -6,7 +6,7 @@"scripts": {"start": "node server/index.js","dev": "NODE_ENV=development node server/index.js",-- "test": "node test/registry-bootstrap.test.js && node test/nginx-generator-live.test.js && node test/admin-refresh.test.js && node test/history-sso.test.js && node test/sso-check.test.js && node test/fedcm.test.js && node test/domains.test.js && node test/frame.test.js && node test/avatar.test.js && node test/roadmap-baseline.test.js && node test/identity-subjects.test.js && node test/principals.test.js && node test/modules.test.js && node test/module-events.test.js && node test/registry-ecosystem.test.js && node test/registry-exposure.test.js && node test/registry-topics.test.js && node test/service-principal.test.js && node test/oauth-pkce.test.js && node test/developer-projects.test.js && node test/developer-defaults.test.js && node test/public-cors.test.js && node test/observability.test.js && node test/status.test.js && node test/events-consumer.test.js && node test/security-session.test.js && node test/security-redirects.test.js && node test/analytics-privacy.test.js && node test/data-ownership.test.js && node test/unknown-paths.test.js && node test/oidc-discovery.test.js && node test/refresh-tokens.test.js && node test/provider-secrets.test.js && node test/first-party-origins.test.js && node test/updates.test.js",++ "test": "node test/registry-bootstrap.test.js && node test/nginx-generator-live.test.js && node test/admin-refresh.test.js && node test/history-sso.test.js && node test/sso-check.test.js && node test/fedcm.test.js && node test/domains.test.js && node test/frame.test.js && node test/avatar.test.js && node test/roadmap-baseline.test.js && node test/identity-subjects.test.js && node test/principals.test.js && node test/modules.test.js && node test/module-events.test.js && node test/registry-ecosystem.test.js && node test/registry-exposure.test.js && node test/registry-topics.test.js && node test/service-principal.test.js && node test/oauth-pkce.test.js && node test/developer-projects.test.js && node test/developer-defaults.test.js && node test/public-cors.test.js && node test/observability.test.js && node test/status.test.js && node test/events-consumer.test.js && node test/security-session.test.js && node test/security-redirects.test.js && node test/analytics-privacy.test.js && node test/data-ownership.test.js && node test/unknown-paths.test.js && node test/oidc-discovery.test.js && node test/refresh-tokens.test.js && node test/provider-secrets.test.js && node test/first-party-origins.test.js && node test/updates.test.js && node test/static-headers.test.js","reset-db": "node server/reset-db.js","grant-admin": "node server/grant-admin.js"},@@@ -654,13 +654,7 @@ app.get(['/sso/fanout', '/sso/fanout.html'], (req, res) => {res.sendFile(path.join(__dirname, '..', 'public', 'sso-fanout.html'));});--app.use(express.static(path.join(__dirname, '..', 'public'), {-- setHeaders(res, filePath) {-- if (filePath.endsWith('.js') || filePath.endsWith('.css')) {-- res.setHeader('Cache-Control', 'no-cache');-- }-- },--}));++app.use(express.static(path.join(__dirname, '..', 'public'), { setHeaders: require('./static-headers').publicStaticHeaders }));// openvibe-shared: the OpenVibe.Shared release package.json pins, from node_modules.const sharedFiles = require('openvibe-shared/files');nnew file mode 100644@@@ -0,0 +1,21 @@++'use strict';++/**++ * Headers for Network's public/ files. /assets/* are the network's brand assets (logo, app icons,++ * OG images) that every OpenVibe site and placeholder shows from openvibe.network, so they are++ * readable cross-origin (helmet's default Cross-Origin-Resource-Policy: same-origin broke the logo++ * on every placeholder) and cached for a day. Scripts and stylesheets revalidate every time.++ */++const path = require('path');++++function publicStaticHeaders(res, filePath) {++ const p = String(filePath).split(path.sep).join('/');++ if (/\/public\/assets\//.test(p)) {++ res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');++ res.setHeader('Access-Control-Allow-Origin', '*');++ res.setHeader('Cache-Control', 'public, max-age=86400');++ return;++ }++ if (p.endsWith('.js') || p.endsWith('.css')) res.setHeader('Cache-Control', 'no-cache');++}++++module.exports = { publicStaticHeaders };nnew file mode 100644@@@ -0,0 +1,14 @@++'use strict';++// Brand assets are readable from every OpenVibe site (the placeholders' logo was blocked by CORP).++const assert = require('assert');++const { publicStaticHeaders } = require('../server/static-headers');++const res = () => { const h = {}; return { h, setHeader: (k, v) => { h[k] = v; } }; };++let r = res(); publicStaticHeaders(r, '/opt/openvibe.network/public/assets/logo.svg');++assert.strictEqual(r.h['Cross-Origin-Resource-Policy'], 'cross-origin');++assert.strictEqual(r.h['Cache-Control'], 'public, max-age=86400');++r = res(); publicStaticHeaders(r, '/opt/openvibe.network/public/js/app.js');++assert.strictEqual(r.h['Cache-Control'], 'no-cache');++assert.strictEqual(r.h['Cross-Origin-Resource-Policy'], undefined, 'only brand assets are cross-origin');++r = res(); publicStaticHeaders(r, '/opt/openvibe.network/public/index.html');++assert.deepStrictEqual(r.h, {});++console.log('static headers: all checks passed');
@@ -6,7 +6,7 @@
@@ -6,7 +6,7 @@
"scripts": {
"scripts": {
"start": "node server/index.js",
"start": "node server/index.js",
"dev": "NODE_ENV=development node server/index.js",
"dev": "NODE_ENV=development node server/index.js",
- "test": "node test/registry-bootstrap.test.js && node test/nginx-generator-live.test.js && node test/admin-refresh.test.js && node test/history-sso.test.js && node test/sso-check.test.js && node test/fedcm.test.js && node test/domains.test.js && node test/frame.test.js && node test/avatar.test.js && node test/roadmap-baseline.test.js && node test/identity-subjects.test.js && node test/principals.test.js && node test/modules.test.js && node test/module-events.test.js && node test/registry-ecosystem.test.js && node test/registry-exposure.test.js && node test/registry-topics.test.js && node test/service-principal.test.js && node test/oauth-pkce.test.js && node test/developer-projects.test.js && node test/developer-defaults.test.js && node test/public-cors.test.js && node test/observability.test.js && node test/status.test.js && node test/events-consumer.test.js && node test/security-session.test.js && node test/security-redirects.test.js && node test/analytics-privacy.test.js && node test/data-ownership.test.js && node test/unknown-paths.test.js && node test/oidc-discovery.test.js && node test/refresh-tokens.test.js && node test/provider-secrets.test.js && node test/first-party-origins.test.js && node test/updates.test.js",
+ "test": "node test/registry-bootstrap.test.js && node test/nginx-generator-live.test.js && node test/admin-refresh.test.js && node test/history-sso.test.js && node test/sso-check.test.js && node test/fedcm.test.js && node test/domains.test.js && node test/frame.test.js && node test/avatar.test.js && node test/roadmap-baseline.test.js && node test/identity-subjects.test.js && node test/principals.test.js && node test/modules.test.js && node test/module-events.test.js && node test/registry-ecosystem.test.js && node test/registry-exposure.test.js && node test/registry-topics.test.js && node test/service-principal.test.js && node test/oauth-pkce.test.js && node test/developer-projects.test.js && node test/developer-defaults.test.js && node test/public-cors.test.js && node test/observability.test.js && node test/status.test.js && node test/events-consumer.test.js && node test/security-session.test.js && node test/security-redirects.test.js && node test/analytics-privacy.test.js && node test/data-ownership.test.js && node test/unknown-paths.test.js && node test/oidc-discovery.test.js && node test/refresh-tokens.test.js && node test/provider-secrets.test.js && node test/first-party-origins.test.js && node test/updates.test.js && node test/static-headers.test.js",
"reset-db": "node server/reset-db.js",
"reset-db": "node server/reset-db.js",
"grant-admin": "node server/grant-admin.js"
"grant-admin": "node server/grant-admin.js"
},
},
@@ -654,13 +654,7 @@ app.get(['/sso/fanout', '/sso/fanout.html'], (req, res) => {
@@ -654,13 +654,7 @@ app.get(['/sso/fanout', '/sso/fanout.html'], (req, res) => {
res.sendFile(path.join(__dirname, '..', 'public', 'sso-fanout.html'));
res.sendFile(path.join(__dirname, '..', 'public', 'sso-fanout.html'));
});
});
-app.use(express.static(path.join(__dirname, '..', 'public'), {
- setHeaders(res, filePath) {
- if (filePath.endsWith('.js') || filePath.endsWith('.css')) {
- res.setHeader('Cache-Control', 'no-cache');
- }
- },
-}));
+app.use(express.static(path.join(__dirname, '..', 'public'), { setHeaders: require('./static-headers').publicStaticHeaders }));
// openvibe-shared: the OpenVibe.Shared release package.json pins, from node_modules.
// openvibe-shared: the OpenVibe.Shared release package.json pins, from node_modules.
const sharedFiles = require('openvibe-shared/files');
const sharedFiles = require('openvibe-shared/files');
new file mode 100644
new file mode 100644
@@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
+'use strict';
+/**
+ * Headers for Network's public/ files. /assets/* are the network's brand assets (logo, app icons,
+ * OG images) that every OpenVibe site and placeholder shows from openvibe.network, so they are
+ * readable cross-origin (helmet's default Cross-Origin-Resource-Policy: same-origin broke the logo
+ * on every placeholder) and cached for a day. Scripts and stylesheets revalidate every time.
+ */
+const path = require('path');
+
+function publicStaticHeaders(res, filePath) {
+ const p = String(filePath).split(path.sep).join('/');
+ if (/\/public\/assets\//.test(p)) {
+ res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
+ res.setHeader('Access-Control-Allow-Origin', '*');
+ res.setHeader('Cache-Control', 'public, max-age=86400');
+ return;
+ }
+ if (p.endsWith('.js') || p.endsWith('.css')) res.setHeader('Cache-Control', 'no-cache');
+}
+
+module.exports = { publicStaticHeaders };
new file mode 100644
new file mode 100644
@@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
+'use strict';
+// Brand assets are readable from every OpenVibe site (the placeholders' logo was blocked by CORP).
+const assert = require('assert');
+const { publicStaticHeaders } = require('../server/static-headers');
+const res = () => { const h = {}; return { h, setHeader: (k, v) => { h[k] = v; } }; };
+let r = res(); publicStaticHeaders(r, '/opt/openvibe.network/public/assets/logo.svg');
+assert.strictEqual(r.h['Cross-Origin-Resource-Policy'], 'cross-origin');
+assert.strictEqual(r.h['Cache-Control'], 'public, max-age=86400');
+r = res(); publicStaticHeaders(r, '/opt/openvibe.network/public/js/app.js');
+assert.strictEqual(r.h['Cache-Control'], 'no-cache');
+assert.strictEqual(r.h['Cross-Origin-Resource-Policy'], undefined, 'only brand assets are cross-origin');
+r = res(); publicStaticHeaders(r, '/opt/openvibe.network/public/index.html');
+assert.deepStrictEqual(r.h, {});
+console.log('static headers: all checks passed');