openvibers/openvibe.live Commits
Require live.agent_sandbox.register from the released Contracts registry (#658)
Changes
@@@ -23,7 +23,7 @@"multer": "^1.4.5-lts.1","node-media-server": "^2.7.1","onnxruntime-node": "^1.20.0",-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.305.0",++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.314.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.93.0","openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.124.0","pg": "^8.23.1",@@@ -2840,9 +2840,9 @@}},"node_modules/openvibe-contracts": {-- "version": "0.305.0",-- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.305.0",-- "integrity": "sha512-jTU1zlnTmHlydwL3/c5HVdUiPpd8r2KucVdHYUYX5MZgJoqy4M7Hg2jy6UKbJQ6s665uIZyTvswbmJjB2uwc5Q==",++ "version": "0.314.0",++ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.314.0",++ "integrity": "sha512-sq5idLBEw+fWc4J63QvmZocf6dxq91qrtsUFzU362uKJ2hpXFQFtos2gGx1oeAyqmKL/5YfEikc/uKNY0v/x5w==","license": "AGPL-3.0-only","dependencies": {"ajv": "^8.17.1",@@@ -42,7 +42,7 @@"multer": "^1.4.5-lts.1","node-media-server": "^2.7.1","onnxruntime-node": "^1.20.0",-- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.305.0",++ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.314.0","openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.93.0","openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.124.0","pg": "^8.23.1",@@@ -24,11 +24,9 @@ const AUDIENCE = 'openvibe.live';// before the registry entry is pinned still works.const CAPABILITIES = ['live.agent_stream.publish', 'live.agent-stream.publish'];const CAPABILITY = CAPABILITIES[0];--// The sandbox worker (S6): the capability that lets OpenVibe's sandbox worker register itself. The--// registry's id carries no hyphen; the design's spelling is accepted too, so a token minted before the--// registry entry is pinned still works.--const SANDBOX_CAPABILITIES = ['live.agent_sandbox.register', 'live.agent-sandbox.register'];--const SANDBOX_CAPABILITY = SANDBOX_CAPABILITIES[0];++// The sandbox worker (S6): the capability that lets OpenVibe's sandbox worker register itself, as the++// pinned Contracts release names it (a capability id carries no hyphen).++const SANDBOX_CAPABILITY = 'live.agent_sandbox.register';const FIRST_PARTY_SUB = /^(svc|node):/;/** The local account linked to a Network subject, or null. */@@@ -109,15 +107,11 @@ async function publisher(req, res, next) {}}--/** The capability on a service token, with the pinned registry's check when it knows the id. */++/** The sandbox registration capability on a service token, checked against the pinned registry. */function holdsSandboxCapability(claims) {const c = claims || {};-- if (!Array.isArray(c.cap)) return false;-- return SANDBOX_CAPABILITIES.some((capability) => {-- if (!c.cap.includes(capability)) return false;-- if (contracts.capabilities.get(capability)) return contracts.capabilities.check(c, capability).allowed;-- return contracts.capabilities.grants(c.cap, capability);-- });++ if (!Array.isArray(c.cap) || !c.cap.includes(SANDBOX_CAPABILITY)) return false;++ return contracts.capabilities.check(c, SANDBOX_CAPABILITY).allowed;}/**@@@ -185,4 +179,4 @@ async function userFromToken(token) {return decoded ? await resolveNetworkUser(decoded) : null;}--module.exports = { publisher, viewer, viewerSubject, userForSubject, userFromToken, holdsCapability, holdsSandboxCapability, sandboxRegistrar, AUDIENCE, CAPABILITY, CAPABILITIES, SANDBOX_CAPABILITY, SANDBOX_CAPABILITIES };++module.exports = { publisher, viewer, viewerSubject, userForSubject, userFromToken, holdsCapability, holdsSandboxCapability, sandboxRegistrar, AUDIENCE, CAPABILITY, CAPABILITIES, SANDBOX_CAPABILITY };@@@ -42,6 +42,12 @@ async function check(name, fn) {VALUES (1, 'ann', 'ann', 'ann@x', 'x', 'streamer', 0) ON CONFLICT (id) DO NOTHING`).run();await raw.prepare("INSERT INTO linked_accounts (user_id, service, service_user_id, subject_id) VALUES (1, 'network', '101', ?) ON CONFLICT DO NOTHING").run(SID.ann);++ // The capability is the one the pinned Contracts release names, and the old hyphen spelling is not a grant.++ const contracts = require('openvibe-contracts');++ const cap = contracts.capabilities.get('live.agent_sandbox.register');++ assert.ok(cap, 'the pinned contracts know live.agent_sandbox.register');++ assert.strictEqual(cap.owner, 'live');++ assert.ok(cap.implementedBy.includes('POST /api/streams/agent/:id/plays/worker'), 'the capability names the registration route');// The Network is not here: a service token is verified by this stand-in. The worker's token holds the// sandbox capability; the other one does not.const sdkAuth = require('openvibe-sdk/auth');@@@ -51,6 +57,9 @@ async function check(name, fn) {if (token === 'tok-person') return { ok: true, claims: { sub: SID.ann, cap: ['live.agent_sandbox.register'] } };return { ok: false, code: 'token.invalid' };};++ const auth = require('../server/agent-streams/auth');++ assert.strictEqual(auth.holdsSandboxCapability({ cap: ['live.agent_sandbox.register'] }), true);++ assert.strictEqual(auth.holdsSandboxCapability({ cap: ['live.agent-sandbox.register'] }), false, 'the design spelling carries no grant');const config = require('../server/config');config.baseUrl = 'https://openvibe.live';
@@ -23,7 +23,7 @@
@@ -23,7 +23,7 @@
"multer": "^1.4.5-lts.1",
"multer": "^1.4.5-lts.1",
"node-media-server": "^2.7.1",
"node-media-server": "^2.7.1",
"onnxruntime-node": "^1.20.0",
"onnxruntime-node": "^1.20.0",
- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.305.0",
+ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.314.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.93.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.93.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.124.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.124.0",
"pg": "^8.23.1",
"pg": "^8.23.1",
@@ -2840,9 +2840,9 @@
@@ -2840,9 +2840,9 @@
}
}
},
},
"node_modules/openvibe-contracts": {
"node_modules/openvibe-contracts": {
- "version": "0.305.0",
- "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.305.0",
- "integrity": "sha512-jTU1zlnTmHlydwL3/c5HVdUiPpd8r2KucVdHYUYX5MZgJoqy4M7Hg2jy6UKbJQ6s665uIZyTvswbmJjB2uwc5Q==",
+ "version": "0.314.0",
+ "resolved": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.314.0",
+ "integrity": "sha512-sq5idLBEw+fWc4J63QvmZocf6dxq91qrtsUFzU362uKJ2hpXFQFtos2gGx1oeAyqmKL/5YfEikc/uKNY0v/x5w==",
"license": "AGPL-3.0-only",
"license": "AGPL-3.0-only",
"dependencies": {
"dependencies": {
"ajv": "^8.17.1",
"ajv": "^8.17.1",
@@ -42,7 +42,7 @@
@@ -42,7 +42,7 @@
"multer": "^1.4.5-lts.1",
"multer": "^1.4.5-lts.1",
"node-media-server": "^2.7.1",
"node-media-server": "^2.7.1",
"onnxruntime-node": "^1.20.0",
"onnxruntime-node": "^1.20.0",
- "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.305.0",
+ "openvibe-contracts": "https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/v0.314.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.93.0",
"openvibe-sdk": "https://codeload.github.com/OpenVibers/OpenVibe.SDK/tar.gz/refs/tags/v0.93.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.124.0",
"openvibe-shared": "https://codeload.github.com/OpenVibers/OpenVibe.Shared/tar.gz/refs/tags/v4.124.0",
"pg": "^8.23.1",
"pg": "^8.23.1",
@@ -24,11 +24,9 @@ const AUDIENCE = 'openvibe.live';
@@ -24,11 +24,9 @@ const AUDIENCE = 'openvibe.live';
// before the registry entry is pinned still works.
// before the registry entry is pinned still works.
const CAPABILITIES = ['live.agent_stream.publish', 'live.agent-stream.publish'];
const CAPABILITIES = ['live.agent_stream.publish', 'live.agent-stream.publish'];
const CAPABILITY = CAPABILITIES[0];
const CAPABILITY = CAPABILITIES[0];
-// The sandbox worker (S6): the capability that lets OpenVibe's sandbox worker register itself. The
-// registry's id carries no hyphen; the design's spelling is accepted too, so a token minted before the
-// registry entry is pinned still works.
-const SANDBOX_CAPABILITIES = ['live.agent_sandbox.register', 'live.agent-sandbox.register'];
-const SANDBOX_CAPABILITY = SANDBOX_CAPABILITIES[0];
+// The sandbox worker (S6): the capability that lets OpenVibe's sandbox worker register itself, as the
+// pinned Contracts release names it (a capability id carries no hyphen).
+const SANDBOX_CAPABILITY = 'live.agent_sandbox.register';
const FIRST_PARTY_SUB = /^(svc|node):/;
const FIRST_PARTY_SUB = /^(svc|node):/;
/** The local account linked to a Network subject, or null. */
/** The local account linked to a Network subject, or null. */
@@ -109,15 +107,11 @@ async function publisher(req, res, next) {
@@ -109,15 +107,11 @@ async function publisher(req, res, next) {
}
}
}
}
-/** The capability on a service token, with the pinned registry's check when it knows the id. */
+/** The sandbox registration capability on a service token, checked against the pinned registry. */
function holdsSandboxCapability(claims) {
function holdsSandboxCapability(claims) {
const c = claims || {};
const c = claims || {};
- if (!Array.isArray(c.cap)) return false;
- return SANDBOX_CAPABILITIES.some((capability) => {
- if (!c.cap.includes(capability)) return false;
- if (contracts.capabilities.get(capability)) return contracts.capabilities.check(c, capability).allowed;
- return contracts.capabilities.grants(c.cap, capability);
- });
+ if (!Array.isArray(c.cap) || !c.cap.includes(SANDBOX_CAPABILITY)) return false;
+ return contracts.capabilities.check(c, SANDBOX_CAPABILITY).allowed;
}
}
/**
/**
@@ -185,4 +179,4 @@ async function userFromToken(token) {
@@ -185,4 +179,4 @@ async function userFromToken(token) {
return decoded ? await resolveNetworkUser(decoded) : null;
return decoded ? await resolveNetworkUser(decoded) : null;
}
}
-module.exports = { publisher, viewer, viewerSubject, userForSubject, userFromToken, holdsCapability, holdsSandboxCapability, sandboxRegistrar, AUDIENCE, CAPABILITY, CAPABILITIES, SANDBOX_CAPABILITY, SANDBOX_CAPABILITIES };
+module.exports = { publisher, viewer, viewerSubject, userForSubject, userFromToken, holdsCapability, holdsSandboxCapability, sandboxRegistrar, AUDIENCE, CAPABILITY, CAPABILITIES, SANDBOX_CAPABILITY };
@@ -42,6 +42,12 @@ async function check(name, fn) {
@@ -42,6 +42,12 @@ async function check(name, fn) {
VALUES (1, 'ann', 'ann', 'ann@x', 'x', 'streamer', 0) ON CONFLICT (id) DO NOTHING`).run();
VALUES (1, 'ann', 'ann', 'ann@x', 'x', 'streamer', 0) ON CONFLICT (id) DO NOTHING`).run();
await raw.prepare("INSERT INTO linked_accounts (user_id, service, service_user_id, subject_id) VALUES (1, 'network', '101', ?) ON CONFLICT DO NOTHING").run(SID.ann);
await raw.prepare("INSERT INTO linked_accounts (user_id, service, service_user_id, subject_id) VALUES (1, 'network', '101', ?) ON CONFLICT DO NOTHING").run(SID.ann);
+ // The capability is the one the pinned Contracts release names, and the old hyphen spelling is not a grant.
+ const contracts = require('openvibe-contracts');
+ const cap = contracts.capabilities.get('live.agent_sandbox.register');
+ assert.ok(cap, 'the pinned contracts know live.agent_sandbox.register');
+ assert.strictEqual(cap.owner, 'live');
+ assert.ok(cap.implementedBy.includes('POST /api/streams/agent/:id/plays/worker'), 'the capability names the registration route');
// The Network is not here: a service token is verified by this stand-in. The worker's token holds the
// The Network is not here: a service token is verified by this stand-in. The worker's token holds the
// sandbox capability; the other one does not.
// sandbox capability; the other one does not.
const sdkAuth = require('openvibe-sdk/auth');
const sdkAuth = require('openvibe-sdk/auth');
@@ -51,6 +57,9 @@ async function check(name, fn) {
@@ -51,6 +57,9 @@ async function check(name, fn) {
if (token === 'tok-person') return { ok: true, claims: { sub: SID.ann, cap: ['live.agent_sandbox.register'] } };
if (token === 'tok-person') return { ok: true, claims: { sub: SID.ann, cap: ['live.agent_sandbox.register'] } };
return { ok: false, code: 'token.invalid' };
return { ok: false, code: 'token.invalid' };
};
};
+ const auth = require('../server/agent-streams/auth');
+ assert.strictEqual(auth.holdsSandboxCapability({ cap: ['live.agent_sandbox.register'] }), true);
+ assert.strictEqual(auth.holdsSandboxCapability({ cap: ['live.agent-sandbox.register'] }), false, 'the design spelling carries no grant');
const config = require('../server/config');
const config = require('../server/config');
config.baseUrl = 'https://openvibe.live';
config.baseUrl = 'https://openvibe.live';