Harden room discovery and health metrics

This commit is contained in:
Koala
2026-06-03 10:48:49 +02:00
parent bf0fb5741f
commit 81c50eff16
16 changed files with 379 additions and 46 deletions
+64
View File
@@ -0,0 +1,64 @@
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const contentPath = path.join(__dirname, '..', 'extension', 'content.js');
const source = fs.readFileSync(contentPath, 'utf8');
function extractFunction(name, text) {
const start = text.indexOf(`function ${name}`);
assert.notStrictEqual(start, -1, `${name} not found`);
const bodyStart = text.indexOf('{', start);
let depth = 0;
for (let i = bodyStart; i < text.length; i++) {
if (text[i] === '{') depth++;
if (text[i] === '}') depth--;
if (depth === 0) return text.slice(start, i + 1);
}
throw new Error(`${name} body did not terminate`);
}
function makeVideo(name, width, height, options = {}) {
return {
name,
tagName: 'VIDEO',
videoWidth: width,
videoHeight: height,
offsetWidth: width,
offsetHeight: height,
muted: options.muted ?? true,
duration: options.duration ?? 0
};
}
const lightPreview = makeVideo('light-preview', 160, 90, { muted: false, duration: 30 });
const shadowPlayer = makeVideo('shadow-player', 1920, 1080, { muted: false, duration: 3600 });
const shadowRoot = {
querySelectorAll(selector) {
if (selector === 'video') return [shadowPlayer];
return [];
}
};
const shadowHost = { shadowRoot };
const fakeDocument = {
querySelectorAll(selector) {
if (selector === 'video') return [lightPreview];
return [shadowHost];
}
};
const fnSource = extractFunction('findVideo', source);
const findVideo = Function('document', `${fnSource}; return findVideo;`)(fakeDocument);
const selected = findVideo(fakeDocument);
assert.strictEqual(
selected,
shadowPlayer,
'findVideo should score Shadow DOM videos together with light DOM videos'
);
console.log('content video finder tests passed');
+27
View File
@@ -0,0 +1,27 @@
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import { cwd } from 'node:process';
const popupPath = path.join(cwd(), 'extension', 'popup.js');
const source = fs.readFileSync(popupPath, 'utf8');
assert.match(
source,
/const ROOM_LIST_REFRESH_COOLDOWN_MS\s*=\s*11000;/,
'popup should define an 11 second room-list refresh cooldown'
);
assert.match(
source,
/elements\.refreshRooms\.disabled\s*=\s*true;/,
'refresh button should be disabled while cooldown is active'
);
assert.match(
source,
/setTimeout\(\(\)\s*=>\s*{\s*elements\.refreshRooms\.disabled\s*=\s*false;/s,
'refresh button should be re-enabled after the cooldown'
);
console.log('popup refresh cooldown tests passed');
+66
View File
@@ -0,0 +1,66 @@
import assert from 'node:assert/strict';
import {
buildHealthPayload,
checkCooldown,
isAdminMetricsAuthorized
} from '../server/ops.js';
const missingAuth = isAdminMetricsAuthorized(undefined, 'secret-token');
assert.equal(missingAuth, false, 'missing Authorization header must not authorize metrics');
const wrongAuth = isAdminMetricsAuthorized('Bearer wrong-token', 'secret-token');
assert.equal(wrongAuth, false, 'wrong bearer token must not authorize metrics');
const correctAuth = isAdminMetricsAuthorized('Bearer secret-token', 'secret-token');
assert.equal(correctAuth, true, 'correct bearer token should authorize metrics');
const disabledAuth = isAdminMetricsAuthorized('Bearer secret-token', '');
assert.equal(disabledAuth, false, 'empty admin token disables admin metrics');
const cooldowns = new Map();
assert.equal(checkCooldown(cooldowns, 'socket-1', 10_000, 100_000), true, 'first cooldown check passes');
assert.equal(checkCooldown(cooldowns, 'socket-1', 10_000, 105_000), false, 'second cooldown check inside window fails');
assert.equal(checkCooldown(cooldowns, 'socket-1', 10_000, 110_000), true, 'cooldown check after window passes');
const roomA = { peers: new Set(['a', 'b']), activeLobby: null };
const roomB = { peers: new Set(['c', 'd', 'e']), activeLobby: { expectedTitle: 'Episode 2' } };
const rooms = new Map([['room-a', roomA], ['room-b', roomB]]);
const basicHealth = buildHealthPayload({
rooms,
connections: 5,
includeMetrics: false,
now: 1234,
uptime: 99,
memoryUsage: () => ({ rss: 10, heapUsed: 5, heapTotal: 8 }),
rateLimitSizes: { connections: 1, events: 2, health: 3, authFailures: 4, roomList: 5 }
});
assert.deepEqual(
Object.keys(basicHealth).sort(),
['connections', 'rooms', 'status', 'timestamp', 'uptime'].sort(),
'basic health should not expose extended metrics'
);
const adminHealth = buildHealthPayload({
rooms,
connections: 5,
includeMetrics: true,
now: 1234,
uptime: 99,
memoryUsage: () => ({ rss: 10, heapUsed: 5, heapTotal: 8 }),
rateLimitSizes: { connections: 1, events: 2, health: 3, authFailures: 4, roomList: 5 }
});
assert.equal(adminHealth.peers, 5, 'admin metrics should include aggregate peer count');
assert.equal(adminHealth.roomsWithLobby, 1, 'admin metrics should count active lobbies');
assert.equal(adminHealth.avgPeersPerRoom, 2.5, 'admin metrics should include average room size');
assert.equal(adminHealth.maxPeersInRoom, 3, 'admin metrics should include max room size');
assert.deepEqual(adminHealth.memory, { rss: 10, heapUsed: 5, heapTotal: 8 }, 'admin metrics should expose process memory');
assert.deepEqual(
adminHealth.rateLimitEntries,
{ connections: 1, events: 2, health: 3, authFailures: 4, roomList: 5 },
'admin metrics should expose aggregate rate-limit map sizes'
);
console.log('server ops tests passed');