switched rover <-> server streams to rtsptcp, and moved mediamtx to be a server owned and configured child process!

This commit is contained in:
legop3
2026-08-04 01:47:03 -04:00
parent 28fcbad902
commit c7c52eb39c
26 changed files with 641 additions and 186 deletions
@@ -33,6 +33,7 @@ function registerVideoAuthRoute(deps) {
}
const isSrtLikeProtocol = protocol === 'srt' || protocol === 'srtconn' || protocol.startsWith('srt');
const isRtspProtocol = protocol === 'rtsp' || protocol.startsWith('rtsp');
const isForwardAudioRead = action === 'read' && streamInfo?.id?.endsWith('-fwd');
if ((action === 'read' && isSrtLikeProtocol) || isForwardAudioRead) {
return res.status(200).end();
@@ -40,6 +41,15 @@ function registerVideoAuthRoute(deps) {
if (action === 'publish' && isSrtLikeProtocol) {
return res.status(200).end();
}
/*
Rover and server publishers reach MediaMTX only on the local network and intentionally
do not carry browser session credentials. MediaMTX still invokes its global HTTP auth
callback for RTSP, so explicitly admit that publish protocol while leaving WHEP reads
under the existing session and role checks below.
*/
if (action === 'publish' && isRtspProtocol) {
return res.status(200).end();
}
if (!sessionId || !streamInfo?.id) {
logger.warn('auth missing session or stream (session=%s path=%s)', sessionId, path);
@@ -0,0 +1,48 @@
// Video Auth HTTP Route Tests
// Purpose: Verifies credential-free LAN RTSP publishing without weakening browser read authorization.
// Scope: Invokes the registered route with lightweight request/response doubles.
const test = require('node:test');
const assert = require('node:assert/strict');
const { registerVideoAuthRoute } = require('./httpRoute');
function createHarness() {
let handler;
const app = { post: (_path, fn) => { handler = fn; } };
registerVideoAuthRoute({
app,
io: { sockets: { sockets: new Map() } },
logger: { info() {}, warn() {} },
videoSessions: { getSession: () => null, revokeSession() {} },
getRequestIp: () => '127.0.0.1',
logAdminEvent() {},
extractStreamInfoFromBody: (body) => ({ type: 'rover', id: body.path, baseId: body.path }),
canAccessStream: () => false,
});
function request(body) {
const result = { statusCode: null };
const response = {
status(code) {
result.statusCode = code;
return response;
},
end() {
return response;
},
};
handler({ body }, response);
return result.statusCode;
}
return { request };
}
test('allows an RTSP rover publisher without a browser session', () => {
const { request } = createHarness();
assert.equal(request({ protocol: 'rtsp', action: 'publish', path: 'rover-one' }), 200);
});
test('continues rejecting an unauthenticated WebRTC read', () => {
const { request } = createHarness();
assert.equal(request({ protocol: 'webrtc', action: 'read', path: 'rover-one' }), 401);
});