openvibers/openvibe.events Commits

Events: unknown GET paths get the app's own 404 page and favicon instead of nginx's bare page (#37)

OP OpenVibers committed 10 Oct 2026 · a79f534a61 · 2 files, +16 −2

The release UX check flagged openvibe.events' 404 page: no `<html lang>` (axe `html-has-lang`, serious), and `/favicon.ico` answering 404. The app already serves both: an SVG app icon at `/favicon.ico`, and its own 404 page (with lang and the Frame) for browsers or a problem+json for API clients. The vhost's catch-all `location / { return 404; }` answered first with nginx's bare page.

The catch-all now passes GET and HEAD to the app (`limit_except GET HEAD { deny all; }`). Every other method is still refused at nginx, and `/api/`, `/internal` and `/metrics` keep their own blocks. `test/home.test.js` asserts the new catch-all. nginx-only; installed with ov-vhost-install after the deploy.

Changes

ddiff --git a/deploy/nginx/openvibe.events.conf b/deploy/nginx/openvibe.events.conf
iindex ad4ad96..1f7aecd 100644
---- a/deploy/nginx/openvibe.events.conf
++++ b/deploy/nginx/openvibe.events.conf
@@@ -182,6 +182,15 @@ server {
proxy_set_header CF-Connecting-IP $remote_addr;
}
-- # ── Everything else: no route here ──
-- location / { return 404; }
++ # ── Everything else: the app answers GET/HEAD (its /favicon.ico, and its own 404 page for browsers or a
++ # problem+json for API clients, both with lang and the Frame); other methods are refused here ──
++ location / {
++ limit_except GET HEAD { deny all; }
++ proxy_pass http://127.0.0.1:4300;
++ proxy_set_header Host $host;
++ proxy_set_header X-Real-IP $remote_addr;
++ proxy_set_header X-Forwarded-For $remote_addr;
++ proxy_set_header CF-Connecting-IP $remote_addr;
++ proxy_set_header X-Forwarded-Proto $scheme;
++ }
}
ddiff --git a/test/home.test.js b/test/home.test.js
iindex bcd811b..c15ed8d 100644
---- a/test/home.test.js
++++ b/test/home.test.js
@@@ -161,6 +161,11 @@ t('deploy/nginx/openvibe.events.conf is the API and product origin, with no redi
const refusals = [conf.indexOf('location ~* ^/metrics(/|$) { return 404; }'), conf.indexOf('location ~* ^/internal(/|$) { return 404; }')];
assert.ok(refusals.every((i) => i >= 0), 'metrics and /internal/ are refused');
assert.ok(!conf.includes('events.openvibe.network$request_uri'), 'no catch-all redirect to the old API host');
++ // The catch-all hands GET/HEAD to the app (its /favicon.ico and its own 404 page with lang), never other methods.
++ const catchAll = conf.slice(conf.lastIndexOf(' location / {'));
++ assert.match(catchAll, /limit_except GET HEAD \{ deny all; \}/, 'the catch-all only passes GET and HEAD');
++ assert.match(catchAll, /proxy_pass http:\/\/127\.0\.0\.1:4300;/, 'and lets the app answer (favicon, 404 page)');
++ assert.ok(!/location \/ \{ return 404; \}/.test(conf), 'nginx\'s bare 404 page (no lang) is gone');
const old = fs.readFileSync(path.join(__dirname, '..', 'deploy', 'nginx', 'events.openvibe.network.conf'), 'utf8')
.split('\n').filter((l) => !/^\s*#/.test(l)).join('\n');
assert.ok(!old.includes('proxy_pass'), 'events.openvibe.network serves nothing itself');