openvibers/openvibe.codes Commits

Open Codes messages in Dock Chats (#330)

OP OpenVibers committed 4 days ago · a6f09443de · 4 files, +24 −0

Changes

ddiff --git a/deploy/nginx/openvibe.codes.conf b/deploy/nginx/openvibe.codes.conf
iindex 6e5a1cc..12dbd67 100644
---- a/deploy/nginx/openvibe.codes.conf
++++ b/deploy/nginx/openvibe.codes.conf
@@@ -89,6 +89,13 @@ server {
proxy_pass http://127.0.0.1:4900;
}
++ # The Dock token is fetched on signed-in page views; give it the session probe's budget.
++ location = /auth/navbar-token {
++ limit_req zone=ovcodes_api burst=30 nodelay;
++ limit_req_status 429;
++ proxy_pass http://127.0.0.1:4900;
++ }
++
location /auth/ {
limit_req zone=ovcodes_auth burst=10 nodelay;
limit_req_status 429;
ddiff --git a/server/auth/sso.js b/server/auth/sso.js
iindex d6acdd7..1e96c65 100644
---- a/server/auth/sso.js
++++ b/server/auth/sso.js
@@@ -213,6 +213,16 @@ function createSso({ config, keys, fetchImpl = globalThis.fetch, now = () => Dat
return res.json({ user: meOf(claims) });
});
++ // The navbar needs a Network access token for the Dock. Keep /auth/me's
++ // profile response token-free; this same-origin answer is never cached.
++ r.get('/navbar-token', async (req, res) => {
++ res.set('Cache-Control', 'private, no-store');
++ const token = sso.extractToken(req);
++ const claims = await sso.verify(token);
++ if (!claims) return res.status(401).json({ error: 'Not signed in' });
++ return res.json({ token, expires_at: claims.exp ? claims.exp * 1000 : null });
++ });
++
// Sign-out stays a same-site action: another site cannot sign a person out.
const sameOriginRequest = (req) => {
const site = String(req.get('sec-fetch-site') || '');
ddiff --git a/server/render/layout.js b/server/render/layout.js
iindex c4b986f..e20f168 100644
---- a/server/render/layout.js
++++ b/server/render/layout.js
@@@ -101,6 +101,7 @@ function renderPage(o) {
history: { type: 'page', title: o.title || SITE_NAME },
silentLogin: `${o.config.baseUrl}/auth/login?silent=1&next={url}`,
sessionUrl: '/auth/me',
++ tokenUrl: '/auth/navbar-token',
loginUrl: '/auth/login?next={path}', // filled from the current page (boost moves between pages)
logoutUrl: '/auth/logout?next={path}', // Sign out in the shared navbar ends this site's session too
notificationsRealtime: true, // the bell hears new notifications over OpenVibe.Events (Shared 1.22.0)
ddiff --git a/test/security-session.test.js b/test/security-session.test.js
iindex 096e3cc..2aebd8c 100644
---- a/test/security-session.test.js
++++ b/test/security-session.test.js
@@@ -49,6 +49,12 @@ const { signJwt } = require('./helpers/mocks');
const me = await s.get('/auth/me', { as: staff });
assert.strictEqual(me.status, 200, me.text.slice(0, 200));
assert.strictEqual(JSON.parse(me.text).user.username, staff.username);
++ const token = s.network.userToken(staff);
++ const nav = await s.get('/auth/navbar-token', { cookie: `ov_token=${token}` });
++ assert.strictEqual(nav.status, 200);
++ assert.strictEqual(JSON.parse(nav.text).token, token, 'the Dock receives the verified Network token');
++ assert.strictEqual(nav.headers.get('cache-control'), 'private, no-store');
++ assert.strictEqual((await s.get('/auth/navbar-token')).status, 401, 'a guest receives no token');
});
await check('another site cannot sign a person out; this site can', async () => {