Initial curated chimera source from a8ae5b1db07fb49926c94585e2718e5130330974
This commit is contained in:
commit
c737a37f71
531 files changed
+119270
No files matched your search
@@ -0,0 +1,340 @@
|
||||
'use strict';
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const http = require('http');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const { SettingsStore } = require('../../src/persistence/settings-store');
|
||||
const { SecretsStore } = require('../../src/security/secrets-store');
|
||||
const { CommandRegistry } = require('../../src/core/command-registry');
|
||||
const { commandErrorCode, createAppServer } = require('../../src/server/app-server');
|
||||
|
||||
test('command failures expose stable machine-readable availability codes', () => {
|
||||
assert.equal(commandErrorCode(new Error('PS5-profiel ontbreekt.')), 'NOT_CONFIGURED');
|
||||
assert.equal(commandErrorCode(new Error('Configureer eerst het IP-adres van je PS5.')), 'NOT_CONFIGURED');
|
||||
assert.equal(commandErrorCode(Object.assign(new Error('connect failed'), { code: 'ECONNREFUSED' })), 'UNAVAILABLE');
|
||||
assert.equal(commandErrorCode(new Error('Upstream HTTP 429')), 'UPSTREAM_UNAVAILABLE');
|
||||
assert.equal(commandErrorCode(new Error('Ongeldige invoer.')), 'COMMAND_FAILED');
|
||||
});
|
||||
|
||||
test('first-run, login session and CSRF protection work end to end', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'porkfolio-app-'));
|
||||
const settings = new SettingsStore(path.join(root, 'config', 'settings.json'));
|
||||
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.json'), keyFile: path.join(root, 'secrets', 'key') });
|
||||
const registry = new CommandRegistry({ platform: 'server' });
|
||||
let operationsStarted = 0;
|
||||
registry.maintenance = { startOperations: () => { operationsStarted += 1; } };
|
||||
registry.register({ name: 'test:read', classification: 'read-only', handler: () => ({ value: 42 }) });
|
||||
registry.register({ name: 'test:write', classification: 'mutating', handler: input => input });
|
||||
registry.register({ name: 'test:large', classification: 'mutating', maxBodyBytes: 512 * 1024, handler: input => ({ length: input.payload.length }) });
|
||||
const logger = { info() {}, warn() {}, error() {}, audit() {} };
|
||||
process.env.PORKFOLIO_ALLOWED_HOSTS = '127.0.0.1';
|
||||
const app = createAppServer({
|
||||
appRoot: path.resolve(__dirname, '../..'), paths: { root, cache: path.join(root, 'cache') }, settings, secrets, registry, logger,
|
||||
ftp: { disconnect: async () => {} }, capabilities: { features: {} }, version: '1.0.9',
|
||||
});
|
||||
const address = await app.listen(0, '127.0.0.1');
|
||||
const base = `http://127.0.0.1:${address.port}`;
|
||||
const headers = { Host: `127.0.0.1:${address.port}`, Origin: base, 'Content-Type': 'application/json' };
|
||||
try {
|
||||
const live = await fetch(`${base}/health/live`, { headers });
|
||||
assert.equal(live.status, 200);
|
||||
const liveBody = await live.json();
|
||||
assert.equal(liveBody.status, 'live');
|
||||
assert.equal(typeof liveBody.build.id, 'string');
|
||||
assert.equal(typeof liveBody.build.revision, 'string');
|
||||
const initialSetupStatus = await fetch(`${base}/api/setup/status`, { headers }).then(response => response.json());
|
||||
assert.equal(initialSetupStatus.defaultLanguage, 'en');
|
||||
const setup = await fetch(`${base}/api/setup`, { method: 'POST', headers, body: JSON.stringify({ username: 'beheerder', password: ['veilig', 'wachtwoord', '123'].join('-'), allowedRoots: [root], safetyConfirmed: true, language: 'nl' }) });
|
||||
assert.equal(setup.status, 201);
|
||||
assert.equal(operationsStarted, 1);
|
||||
const cookie = setup.headers.get('set-cookie').split(';')[0];
|
||||
const auth = await fetch(`${base}/api/auth/status`, { headers: { ...headers, Cookie: cookie } });
|
||||
const authBody = await auth.json();
|
||||
assert.equal(authBody.authenticated, true);
|
||||
const shell = await fetch(`${base}/`, { headers: { ...headers, Cookie: cookie } });
|
||||
assert.equal(shell.status, 200);
|
||||
assert.match(shell.headers.get('content-security-policy'), /script-src 'self'(?:;|$)/);
|
||||
assert.doesNotMatch(shell.headers.get('content-security-policy'), /script-src[^;]*unsafe-inline/);
|
||||
const sessionList = await fetch(`${base}/api/auth/sessions`, { headers: { ...headers, Cookie: cookie } }).then(response => response.json());
|
||||
assert.equal(sessionList.sessions.length, 1);
|
||||
assert.equal(sessionList.sessions[0].current, true);
|
||||
assert.equal(sessionList.sessions[0].username, 'beheerder');
|
||||
const commandCatalog = await fetch(`${base}/api/commands/catalog`, { headers: { ...headers, Cookie: cookie } }).then(response => response.json());
|
||||
assert.equal(commandCatalog.schema, 1);
|
||||
assert.deepEqual(commandCatalog.commands.map(command => command.name), ['test:large', 'test:read', 'test:write']);
|
||||
assert.equal(commandCatalog.commands.find(command => command.name === 'test:read').classification, 'read-only');
|
||||
assert.equal(commandCatalog.commands.find(command => command.name === 'test:large').maxBodyBytes, 512 * 1024);
|
||||
const rendererScript = await fetch(`${base}/modules/state.js`, { headers: { ...headers, Cookie: cookie } });
|
||||
assert.equal(rendererScript.status, 200);
|
||||
assert.equal(rendererScript.headers.get('cache-control'), 'private, no-cache');
|
||||
assert.ok(rendererScript.headers.get('etag'));
|
||||
const notModified = await fetch(`${base}/modules/state.js`, { headers: { ...headers, Cookie: cookie, 'If-None-Match': rendererScript.headers.get('etag') } });
|
||||
assert.equal(notModified.status, 304);
|
||||
const denied = await fetch(`${base}/api/commands/test%3Awrite`, { method: 'POST', headers: { ...headers, Cookie: cookie }, body: JSON.stringify({ args: [{ ok: true }] }) });
|
||||
assert.equal(denied.status, 403);
|
||||
assert.equal(denied.headers.get('cache-control'), 'no-store');
|
||||
const readOnly = await fetch(`${base}/api/commands/test%3Aread`, { method: 'POST', headers: { ...headers, Cookie: cookie }, body: JSON.stringify({ args: [] }) });
|
||||
assert.equal(readOnly.status, 200);
|
||||
assert.equal(readOnly.headers.get('cache-control'), 'no-store');
|
||||
const allowed = await fetch(`${base}/api/commands/test%3Awrite`, { method: 'POST', headers: { ...headers, Cookie: cookie, 'X-CSRF-Token': authBody.csrfToken }, body: JSON.stringify({ args: [{ ok: true }] }) });
|
||||
assert.equal(allowed.status, 200);
|
||||
assert.equal(allowed.headers.get('cache-control'), 'no-store');
|
||||
const payload = 'x'.repeat(300 * 1024);
|
||||
const defaultLimited = await fetch(`${base}/api/commands/test%3Awrite`, { method: 'POST', headers: { ...headers, Cookie: cookie, 'X-CSRF-Token': authBody.csrfToken }, body: JSON.stringify({ args: [{ payload }] }) });
|
||||
assert.equal(defaultLimited.status, 413);
|
||||
const explicitlyAllowed = await fetch(`${base}/api/commands/test%3Alarge`, { method: 'POST', headers: { ...headers, Cookie: cookie, 'X-CSRF-Token': authBody.csrfToken }, body: JSON.stringify({ args: [{ payload }] }) });
|
||||
assert.equal(explicitlyAllowed.status, 200);
|
||||
assert.equal((await explicitlyAllowed.json()).result.length, payload.length);
|
||||
} finally { await app.close(); }
|
||||
});
|
||||
|
||||
test('metrics require a separate constant-time Bearer token', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-metrics-'));
|
||||
const settings = new SettingsStore(path.join(root, 'config', 'settings.json'));
|
||||
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.json'), keyFile: path.join(root, 'secrets', 'key') });
|
||||
secrets.set('monitoring.token', 'a'.repeat(43));
|
||||
const registry = new CommandRegistry({ platform: 'server' });
|
||||
registry.register({ name: 'monitoring:prometheus', classification: 'read-only', permission: 'public', handler: () => 'chimera_up 1\n' });
|
||||
const logger = { info() {}, warn() {}, error() {}, audit() {} };
|
||||
const previousAllowedHosts = process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
process.env.CHIMERA_ALLOWED_HOSTS = '127.0.0.1';
|
||||
const app = createAppServer({
|
||||
appRoot: path.resolve(__dirname, '../..'), paths: { root, cache: path.join(root, 'cache') }, settings, secrets, registry, logger,
|
||||
ftp: { disconnect: async () => {} }, capabilities: { features: {} }, version: '1.0.9',
|
||||
});
|
||||
const address = await app.listen(0, '127.0.0.1');
|
||||
const base = `http://127.0.0.1:${address.port}`;
|
||||
try {
|
||||
const denied = await fetch(`${base}/metrics`, { headers: { Host: `127.0.0.1:${address.port}`, Authorization: 'Bearer wrong' } });
|
||||
assert.equal(denied.status, 401);
|
||||
const allowed = await fetch(`${base}/metrics`, { headers: { Host: `127.0.0.1:${address.port}`, Authorization: `Bearer ${'a'.repeat(43)}` } });
|
||||
assert.equal(allowed.status, 200);
|
||||
assert.match(allowed.headers.get('content-type'), /version=0\.0\.4/);
|
||||
assert.equal(await allowed.text(), 'chimera_up 1\n');
|
||||
} finally {
|
||||
await app.close();
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
if (previousAllowedHosts === undefined) delete process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
else process.env.CHIMERA_ALLOWED_HOSTS = previousAllowedHosts;
|
||||
}
|
||||
});
|
||||
|
||||
test('authenticated Payload Manager proxy rewrites and isolates the PS5 web UI', { concurrency: false }, async () => {
|
||||
const payloadServer = http.createServer((req, res) => {
|
||||
if (req.url === '/') {
|
||||
res.writeHead(200, { 'Content-Type': 'text/html' });
|
||||
res.end('<!doctype html><html><link rel="icon" href="/favicon.svg"><script>fetch(`/list_payloads`)</script></html>');
|
||||
return;
|
||||
}
|
||||
if (req.url === '/list_payloads') {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ payloads: ['/data/payloads/etaHEN.bin'] }));
|
||||
return;
|
||||
}
|
||||
res.writeHead(404).end();
|
||||
});
|
||||
await new Promise(resolve => payloadServer.listen(0, '127.0.0.1', resolve));
|
||||
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-payload-proxy-'));
|
||||
const settings = new SettingsStore(path.join(root, 'config', 'settings.json'));
|
||||
settings.set('ftp.host', '127.0.0.1');
|
||||
settings.set('payloadManager.port', payloadServer.address().port);
|
||||
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.json'), keyFile: path.join(root, 'secrets', 'key') });
|
||||
const registry = new CommandRegistry({ platform: 'server' });
|
||||
const logger = { info() {}, warn() {}, error() {}, audit() {} };
|
||||
const previousAllowedHosts = process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
process.env.CHIMERA_ALLOWED_HOSTS = '127.0.0.1';
|
||||
const app = createAppServer({
|
||||
appRoot: path.resolve(__dirname, '../..'), paths: { root, cache: path.join(root, 'cache') }, settings, secrets, registry, logger,
|
||||
ftp: { disconnect: async () => {} }, capabilities: { features: {} }, version: '1.0.9',
|
||||
});
|
||||
const address = await app.listen(0, '127.0.0.1');
|
||||
const base = `http://127.0.0.1:${address.port}`;
|
||||
const headers = { Host: `127.0.0.1:${address.port}`, Origin: base, 'Content-Type': 'application/json' };
|
||||
try {
|
||||
const setup = await fetch(`${base}/api/setup`, { method: 'POST', headers, body: JSON.stringify({ username: 'beheerder', password: ['veilig', 'wachtwoord', '123'].join('-'), allowedRoots: [root], safetyConfirmed: true }) });
|
||||
assert.equal(setup.status, 201);
|
||||
const cookie = setup.headers.get('set-cookie').split(';')[0];
|
||||
const entry = await fetch(`${base}/ps5-proxy/payload-manager/`, { redirect: 'manual', headers: { ...headers, Cookie: cookie } });
|
||||
assert.equal(entry.status, 302);
|
||||
const tokenPath = entry.headers.get('location');
|
||||
assert.match(tokenPath, /^\/ps5-proxy\/payload-manager\/t\/[A-Za-z0-9_-]{32,128}\/$/);
|
||||
|
||||
const page = await fetch(`${base}${tokenPath}`, { headers: { Host: `127.0.0.1:${address.port}` } });
|
||||
assert.equal(page.status, 200);
|
||||
assert.equal(page.headers.get('x-frame-options'), 'SAMEORIGIN');
|
||||
assert.match(page.headers.get('content-security-policy'), /frame-ancestors 'self'/);
|
||||
const html = await page.text();
|
||||
assert.match(html, new RegExp(`${tokenPath.replace(/\/$/, '')}/list_payloads`));
|
||||
|
||||
const listing = await fetch(`${base}${tokenPath}list_payloads`, { headers: { Host: `127.0.0.1:${address.port}`, Origin: 'null' } });
|
||||
assert.equal(listing.status, 200);
|
||||
assert.equal(listing.headers.get('access-control-allow-origin'), 'null');
|
||||
assert.deepEqual(await listing.json(), { payloads: ['/data/payloads/etaHEN.bin'] });
|
||||
|
||||
const blocked = await fetch(`${base}${tokenPath}shutdown`, { headers: { Host: `127.0.0.1:${address.port}`, Origin: 'null' } });
|
||||
assert.equal(blocked.status, 404);
|
||||
} finally {
|
||||
await app.close();
|
||||
await new Promise(resolve => payloadServer.close(resolve));
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
if (previousAllowedHosts === undefined) delete process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
else process.env.CHIMERA_ALLOWED_HOSTS = previousAllowedHosts;
|
||||
}
|
||||
});
|
||||
|
||||
test('public Payload Manager repository is CORS-readable without exposing an authenticated command bridge', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-public-payloads-'));
|
||||
const settings = new SettingsStore(path.join(root, 'config', 'settings.json'));
|
||||
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.json'), keyFile: path.join(root, 'secrets', 'key') });
|
||||
const registry = new CommandRegistry({ platform: 'server' });
|
||||
registry.register({ name: 'ecosystem:payload-manager:repository', classification: 'read-only', permission: 'public', handler: () => ({ name: 'Chimera Verified Payloads', payloads: [{ name: 'ELF Loader', filename: 'elfldr.elf', url: 'https://example.test/elfldr.elf', checksum: 'a'.repeat(64) }] }) });
|
||||
const logger = { info() {}, warn() {}, error() {}, audit() {} };
|
||||
const previousAllowedHosts = process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
process.env.CHIMERA_ALLOWED_HOSTS = '127.0.0.1';
|
||||
const app = createAppServer({
|
||||
appRoot: path.resolve(__dirname, '../..'), paths: { root, cache: path.join(root, 'cache') }, settings, secrets, registry, logger,
|
||||
ftp: { disconnect: async () => {} }, capabilities: { features: {} }, version: '1.0.9',
|
||||
});
|
||||
const address = await app.listen(0, '127.0.0.1');
|
||||
const base = `http://127.0.0.1:${address.port}`;
|
||||
try {
|
||||
const response = await fetch(`${base}/payloads.json`, { headers: { Host: `127.0.0.1:${address.port}`, Origin: 'http://ps5.local' } });
|
||||
assert.equal(response.status, 200);
|
||||
assert.equal(response.headers.get('access-control-allow-origin'), '*');
|
||||
assert.equal(response.headers.get('cross-origin-resource-policy'), 'cross-origin');
|
||||
assert.match(response.headers.get('cache-control'), /max-age=300/);
|
||||
const repository = await response.json();
|
||||
assert.equal(repository.payloads[0].checksum, 'a'.repeat(64));
|
||||
|
||||
const command = await fetch(`${base}/api/commands/ecosystem%3Apayload-manager%3Arepository`, { method: 'POST', headers: { Host: `127.0.0.1:${address.port}`, Origin: base, 'Content-Type': 'application/json' }, body: JSON.stringify({ args: [] }) });
|
||||
assert.equal(command.status, 401);
|
||||
} finally {
|
||||
await app.close();
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
if (previousAllowedHosts === undefined) delete process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
else process.env.CHIMERA_ALLOWED_HOSTS = previousAllowedHosts;
|
||||
}
|
||||
});
|
||||
|
||||
test('compiled Chimera Beacon artifact is public, CORS-readable and supports byte ranges', async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-public-beacon-'));
|
||||
const appRoot = path.join(root, 'app');
|
||||
fs.mkdirSync(path.join(appRoot, 'build', 'payloads'), { recursive: true });
|
||||
const payload = Buffer.from([0x7f, 0x45, 0x4c, 0x46, 1, 2, 3, 4]);
|
||||
fs.writeFileSync(path.join(appRoot, 'build', 'payloads', 'chimera-beacon.elf'), payload);
|
||||
const settings = new SettingsStore(path.join(root, 'config', 'settings.json'));
|
||||
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.json'), keyFile: path.join(root, 'secrets', 'key') });
|
||||
const registry = new CommandRegistry({ platform: 'server' });
|
||||
const logger = { info() {}, warn() {}, error() {}, audit() {} };
|
||||
const previousAllowedHosts = process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
process.env.CHIMERA_ALLOWED_HOSTS = '127.0.0.1';
|
||||
const app = createAppServer({ appRoot, paths: { root, cache: path.join(root, 'cache') }, settings, secrets, registry, logger, ftp: { disconnect: async () => {} }, capabilities: { features: {} }, version: '1.0.9' });
|
||||
const address = await app.listen(0, '127.0.0.1');
|
||||
try {
|
||||
const response = await fetch(`http://127.0.0.1:${address.port}/payloads/chimera-beacon.elf`, { headers: { Host: `127.0.0.1:${address.port}`, Range: 'bytes=0-3' } });
|
||||
assert.equal(response.status, 206);
|
||||
assert.equal(response.headers.get('access-control-allow-origin'), '*');
|
||||
assert.equal(response.headers.get('cross-origin-resource-policy'), 'cross-origin');
|
||||
assert.equal(response.headers.get('content-type'), 'application/octet-stream');
|
||||
assert.deepEqual(Buffer.from(await response.arrayBuffer()), payload.subarray(0, 4));
|
||||
} finally {
|
||||
await app.close();
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
if (previousAllowedHosts === undefined) delete process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
else process.env.CHIMERA_ALLOWED_HOSTS = previousAllowedHosts;
|
||||
}
|
||||
});
|
||||
|
||||
test('trusted reverse proxy enforces HTTPS, redacts setup details and serves byte ranges', { concurrency: false }, async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-https-'));
|
||||
const settings = new SettingsStore(path.join(root, 'config', 'settings.json'));
|
||||
settings.set('admin.username', 'beheerder');
|
||||
settings.set('admin.passwordHash', 'configured');
|
||||
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.json'), keyFile: path.join(root, 'secrets', 'key') });
|
||||
const registry = new CommandRegistry({ platform: 'server' });
|
||||
const logger = { info() {}, warn() {}, error() {}, audit() {} };
|
||||
const previous = {
|
||||
allowedHosts: process.env.CHIMERA_ALLOWED_HOSTS,
|
||||
publicOrigin: process.env.CHIMERA_PUBLIC_ORIGIN,
|
||||
trustProxy: process.env.CHIMERA_TRUST_PROXY,
|
||||
cookieSecure: process.env.CHIMERA_COOKIE_SECURE,
|
||||
};
|
||||
process.env.CHIMERA_ALLOWED_HOSTS = '127.0.0.1,chimera';
|
||||
process.env.CHIMERA_PUBLIC_ORIGIN = 'https://chimera.test:18443';
|
||||
process.env.CHIMERA_TRUST_PROXY = '1';
|
||||
process.env.CHIMERA_COOKIE_SECURE = '1';
|
||||
const app = createAppServer({
|
||||
appRoot: path.resolve(__dirname, '../..'), paths: { root, cache: path.join(root, 'cache') }, settings, secrets, registry, logger,
|
||||
ftp: { disconnect: async () => {} }, capabilities: { features: {} }, version: '1.0.9',
|
||||
});
|
||||
const address = await app.listen(0, '127.0.0.1');
|
||||
const base = `http://127.0.0.1:${address.port}`;
|
||||
const proxied = { Host: 'chimera.test:18443', 'X-Forwarded-Proto': 'https', 'X-Forwarded-For': '192.168.1.171' };
|
||||
try {
|
||||
const direct = await fetch(`${base}/server-login.html`, { redirect: 'manual', headers: { Host: `127.0.0.1:${address.port}` } });
|
||||
assert.equal(direct.status, 308);
|
||||
assert.equal(direct.headers.get('location'), 'https://chimera.test:18443/server-login.html');
|
||||
|
||||
const login = await fetch(`${base}/server-login.html`, { headers: proxied });
|
||||
assert.equal(login.status, 200);
|
||||
assert.match(login.headers.get('strict-transport-security'), /max-age=31536000/);
|
||||
assert.equal(login.headers.get('x-frame-options'), 'DENY');
|
||||
|
||||
const status = await fetch(`${base}/api/setup/status`, { headers: proxied }).then(response => response.json());
|
||||
assert.deepEqual(status, { configured: true, defaultLanguage: 'en' });
|
||||
|
||||
const icon = await fetch(`${base}/build/icon.png`, { headers: { ...proxied, Range: 'bytes=0-9' } });
|
||||
assert.equal(icon.status, 206);
|
||||
assert.equal(icon.headers.get('content-length'), '10');
|
||||
assert.match(icon.headers.get('content-range'), /^bytes 0-9\//);
|
||||
assert.equal((await icon.arrayBuffer()).byteLength, 10);
|
||||
} finally {
|
||||
await app.close();
|
||||
for (const [key, value] of Object.entries({ CHIMERA_ALLOWED_HOSTS: previous.allowedHosts, CHIMERA_PUBLIC_ORIGIN: previous.publicOrigin, CHIMERA_TRUST_PROXY: previous.trustProxy, CHIMERA_COOKIE_SECURE: previous.cookieSecure })) {
|
||||
if (value === undefined) delete process.env[key]; else process.env[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('Remote Play worker endpoint bypasses browser sessions only through its dedicated authenticator', { concurrency: false }, async () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'chimera-remote-worker-http-'));
|
||||
const settings = new SettingsStore(path.join(root, 'config', 'settings.json'));
|
||||
const secrets = new SecretsStore({ filePath: path.join(root, 'secrets', 'secrets.json'), keyFile: path.join(root, 'secrets', 'key') });
|
||||
const registry = new CommandRegistry({ platform: 'server' });
|
||||
const calls = [];
|
||||
registry.remotePlay = {
|
||||
prefix: '/api/remote-play-worker/v1',
|
||||
handleWorkerRequest(pathname, body) {
|
||||
calls.push({ pathname, body });
|
||||
if (body.token !== 'signed-fixture') throw Object.assign(new Error('Worker-HMAC is ongeldig.'), { statusCode: 401 });
|
||||
return { ok: true, workerId: 'rpw-fixture' };
|
||||
},
|
||||
};
|
||||
const logger = { info() {}, warn() {}, error() {}, audit() {} };
|
||||
const previousAllowedHosts = process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
process.env.CHIMERA_ALLOWED_HOSTS = '127.0.0.1';
|
||||
const app = createAppServer({ appRoot: path.resolve(__dirname, '../..'), paths: { root, cache: path.join(root, 'cache') }, settings, secrets, registry, logger, ftp: { disconnect: async () => {} }, capabilities: { features: {} }, version: '1.0.9' });
|
||||
const address = await app.listen(0, '127.0.0.1');
|
||||
const base = `http://127.0.0.1:${address.port}`;
|
||||
const headers = { Host: `127.0.0.1:${address.port}`, 'Content-Type': 'application/json' };
|
||||
try {
|
||||
const denied = await fetch(`${base}/api/remote-play-worker/v1/poll`, { method: 'POST', headers, body: JSON.stringify({ token: 'wrong' }) });
|
||||
assert.equal(denied.status, 401);
|
||||
assert.equal(denied.headers.get('cache-control'), 'no-store');
|
||||
const accepted = await fetch(`${base}/api/remote-play-worker/v1/poll`, { method: 'POST', headers, body: JSON.stringify({ token: 'signed-fixture' }) });
|
||||
assert.equal(accepted.status, 200);
|
||||
assert.equal(accepted.headers.get('cache-control'), 'no-store');
|
||||
assert.deepEqual(await accepted.json(), { ok: true, workerId: 'rpw-fixture' });
|
||||
const normalApi = await fetch(`${base}/api/capabilities`, { headers });
|
||||
assert.equal(normalApi.status, 401);
|
||||
assert.equal(calls.length, 2);
|
||||
} finally {
|
||||
await app.close();
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
if (previousAllowedHosts === undefined) delete process.env.CHIMERA_ALLOWED_HOSTS;
|
||||
else process.env.CHIMERA_ALLOWED_HOSTS = previousAllowedHosts;
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user