openvibers/openvibe.billing Commits

nginx vhost: the public policy (/policy, /policy.json, /robots.txt) is served without the host-wide X-Robots-Tag noindex, as robots.txt and the app intend (the browser check found production's /policy noindex); that location repeats nosniff and HSTS because a location's add_header replaces the server's. test/nginx-vhost.test.js. Takes effect when the vhost is next installed (not deployed here)

OP OpenVibers committed 26 Sept 2026 · 5fa55460de · 2 files, +31 −0


Changes

ddiff --git a/deploy/nginx/billing.openvibe.network.conf b/deploy/nginx/billing.openvibe.network.conf
iindex f98f4f1..e2d5eb5 100644
---- a/deploy/nginx/billing.openvibe.network.conf
++++ b/deploy/nginx/billing.openvibe.network.conf
@@@ -66,6 +66,15 @@ server {
location ^~ /api/v1 { deny all; }
location ^~ /api/ { return 404; }
++ # The public billing policy is meant to be indexed (robots.txt allows /policy): no X-Robots-Tag here. An
++ # add_header in a location replaces the server's, so the two security headers are repeated.
++ location ~ ^/(policy|policy\.json|robots\.txt)$ {
++ add_header X-Content-Type-Options nosniff always;
++ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
++ limit_req zone=ovbilling_console burst=30 nodelay;
++ proxy_pass http://127.0.0.1:4600;
++ }
++
# Staff console (the app sets CSP, X-Frame-Options, no-store and noindex on every page).
location / {
limit_req zone=ovbilling_console burst=30 nodelay;
ddiff --git a/test/nginx-vhost.test.js b/test/nginx-vhost.test.js
nnew file mode 100644
iindex 0000000..6626948
---- /dev/null
++++ b/test/nginx-vhost.test.js
@@@ -0,0 +1,22 @@
++'use strict';
++// deploy/nginx/billing.openvibe.network.conf: everything is noindex except the public policy (/policy,
++// /policy.json, /robots.txt), which robots.txt allows and the app calls indexable. The server-wide
++// X-Robots-Tag used to cover it too (found by the browser check, OpenVibe.Host scripts/browser-check.js).
++// An add_header inside a location replaces the server's, so that location repeats the security headers.
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++
++const conf = fs.readFileSync(path.join(__dirname, '..', 'deploy', 'nginx', 'billing.openvibe.network.conf'), 'utf8');
++const tls = conf.slice(conf.indexOf('listen 443'));
++const serverLevel = tls.slice(0, tls.indexOf('location'));
++assert.match(serverLevel, /add_header X-Robots-Tag "noindex, nofollow" always;/, 'the host is noindex by default');
++const m = tls.match(/location ~ \^\/\(policy\|policy\\\.json\|robots\\\.txt\)\$ \{([^}]*)\}/);
++assert.ok(m, 'a location for the public policy');
++const block = m[1];
++assert.ok(!/X-Robots-Tag/.test(block), 'the policy is indexable');
++assert.match(block, /add_header X-Content-Type-Options nosniff always;/);
++assert.match(block, /add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;/);
++assert.match(block, /proxy_pass http:\/\/127\.0\.0\.1:4600;/);
++assert.ok(tls.indexOf(m[0]) < tls.indexOf('location / {'), 'before the console catch-all');
++console.log('nginx vhost: the policy is indexable, the rest noindex');