fix(cctv): admit and bound HLS leases by peer

This commit is contained in:
Said committed 2026-10-20 00:11:31 +01:00
1 parent de2138e84c
commit 167aa947ce
6 files changed
+154 -17

No files matched your search

+19 -4
View File
@@ -17,6 +17,7 @@ import {
CCTV_MAX_SOURCES_CEILING,
} from './cctv/constants.js';
import { sanitizeCctvRangeHeader } from './cctv/range.js';
import { admitSameSite } from './common/same-site.js';
import { createHlsPuller } from './cctv/stream.js';
import { googleServerApiKey } from './places/google-key.js';
export { CCTV_FRAME_FETCH_TIMEOUT_MS, fetchCctvImageFromUpstream };
@@ -135,11 +136,18 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
});
server.middlewares.use('/api/cctv', async (req, res) => {
try {
const url = new URL(req.url || '/', 'http://localhost');
// Refuse before catalog I/O, session creation, renewal or release.
if (url.pathname.startsWith('/media/') && admitSameSite(req, res))
return;
const clientId = String(req.socket?.remoteAddress || 'unknown').replace(
/^::ffff:/,
'',
);
const sources = await getCctvSources();
const sourceById = new Map(
sources.map((source) => [source.id, source]),
);
const url = new URL(req.url || '/', 'http://localhost');
if (url.pathname === '/sources') {
const body = {
@@ -238,7 +246,7 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
return;
}
if (req.method === 'DELETE') {
if (leaseId) puller.release(cameraId, leaseId);
if (leaseId) puller.release(cameraId, leaseId, clientId);
res.writeHead(204);
res.end();
return;
@@ -268,6 +276,7 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
url.searchParams.get('session'),
Number(match[3]),
leaseId,
clientId,
);
res.writeHead(body ? 200 : 404, {
'Content-Type': 'video/mp2t',
@@ -279,10 +288,15 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
const downstream = watchDownstreamClose(res);
let entry;
const cancelPending = () => {
if (entry) puller.release(cameraId, leaseId);
if (entry) puller.release(cameraId, leaseId, clientId);
};
try {
entry = await puller.ensure(cameraId, mediaUrl, leaseId);
entry = await puller.ensure(
cameraId,
mediaUrl,
leaseId,
clientId,
);
if (downstream.closed) {
cancelPending();
return;
@@ -296,6 +310,7 @@ export function cctvProxy({ sourceRoot = process.cwd() } = {}) {
entry,
cameraId,
leaseId,
clientId,
);
if (downstream.closed) return;
if (!playlist) throw new Error('Stream unavailable');