openvibers/openvibe.network Commits

/internal/events/stream-live accepts a service token with network.notifications.push

OP OpenVibers committed 23 Sept 2026 · 65b2b9065b · 2 files, +8 −2


Changes

ddiff --git a/server/internal/routes.js b/server/internal/routes.js
iindex 64c7e7e8..f84ed7b3 100644
---- a/server/internal/routes.js
++++ b/server/internal/routes.js
@@@ -30,7 +30,7 @@ function requireInternalKey(req, res, next) {
return res.status(403).json({ error: 'Invalid or missing internal key' });
}
const principals = require('../identity/principals');
--const TOKEN_ROUTES = new Set(['GET /identity/resolve', 'POST /identity/resolve-batch', 'POST /coins/credit', 'POST /coins/debit', 'POST /coins/transfer', 'POST /notifications/push', 'POST /notifications/push-bulk']);
++const TOKEN_ROUTES = new Set(['GET /identity/resolve', 'POST /identity/resolve-batch', 'POST /coins/credit', 'POST /coins/debit', 'POST /coins/transfer', 'POST /notifications/push', 'POST /notifications/push-bulk', 'POST /events/stream-live']);
const TOKEN_ROUTE_PATTERNS = [/^(GET|PUT) \/modules\/[a-z0-9_.]+\/[A-Za-z0-9_]+$/];
const forApp = (req) => (req.body && req.body.app_id !== undefined ? String(req.body.app_id) : undefined);
const forService = (req) => (req.body && req.body.service !== undefined ? String(req.body.service) : undefined);
@@@ -306,7 +306,7 @@ router.post('/coins/transfer', principals.guard('network.coins.transfer', { ownA
// followers + "all streamer" subscribers.
// ═══════════════════════════════════════════════════════════════
--router.post('/events/stream-live', async (req, res) => {
++router.post('/events/stream-live', principals.guard('network.notifications.push'), async (req, res) => {
const { streamer, stream, follower_network_ids } = req.body;
if (!streamer?.username || !stream?.id) {
return res.status(400).json({ error: 'streamer and stream objects required' });
ddiff --git a/test/principals.test.js b/test/principals.test.js
iindex 12a4fbc6..dc3ed849 100644
---- a/test/principals.test.js
++++ b/test/principals.test.js
@@@ -113,6 +113,12 @@ const server = http.createServer(app);
const cm = await token({ client_id: 'live', client_secret: 'live-secret', audience: 'openvibe.community' });
assert.deepStrictEqual(cm.body.scope.split(' '), ['community.comment.moderate', 'community.comment.write', 'community.paste.create', 'community.paste.moderate', 'community.paste.write', 'community.pulse.write']);
++ // Go-live fan-out accepts Live's token (network.notifications.push); a narrower token is refused.
++ r = await post('/internal/events/stream-live', {}, { authorization: `Bearer ${full}` });
++ assert.strictEqual(r.status, 400, 'guard passed, handler validated the body');
++ r = await post('/internal/events/stream-live', {}, { authorization: `Bearer ${creditOnly}` });
++ assert.strictEqual(r.status, 403);
++
// ── Legacy key keeps working ──
r = await post('/internal/coins/credit', credit(), { 'x-internal-key': 'legacy-key' });
assert.strictEqual(r.status, 200);