Harden server: drain connections on stop, validate proxy URL scheme, add fetch timeout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,8 +35,16 @@ function startServer({ port, overlayDir }) {
|
|||||||
app.get('/api/image-proxy', async (req, res) => {
|
app.get('/api/image-proxy', async (req, res) => {
|
||||||
const url = req.query.url;
|
const url = req.query.url;
|
||||||
if (!url) return res.status(400).send('Missing url parameter');
|
if (!url) return res.status(400).send('Missing url parameter');
|
||||||
|
|
||||||
|
let parsed;
|
||||||
|
try { parsed = new URL(url); }
|
||||||
|
catch { return res.status(400).send('Invalid url'); }
|
||||||
|
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
||||||
|
return res.status(400).send('Only http/https URLs are allowed');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url);
|
const response = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
||||||
if (!response.ok) return res.status(response.status).send('Upstream error');
|
if (!response.ok) return res.status(response.status).send('Upstream error');
|
||||||
res.set('Content-Type', response.headers.get('content-type') || 'image/jpeg');
|
res.set('Content-Type', response.headers.get('content-type') || 'image/jpeg');
|
||||||
res.set('Cache-Control', 'public, max-age=3600');
|
res.set('Cache-Control', 'public, max-age=3600');
|
||||||
@@ -52,6 +60,7 @@ function startServer({ port, overlayDir }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wss.on('connection', (ws) => {
|
wss.on('connection', (ws) => {
|
||||||
|
ws.on('error', () => {});
|
||||||
ws.send(JSON.stringify(currentState));
|
ws.send(JSON.stringify(currentState));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,14 +68,17 @@ function startServer({ port, overlayDir }) {
|
|||||||
currentState = mergeState(currentState, update || {});
|
currentState = mergeState(currentState, update || {});
|
||||||
const message = JSON.stringify(currentState);
|
const message = JSON.stringify(currentState);
|
||||||
wss.clients.forEach((client) => {
|
wss.clients.forEach((client) => {
|
||||||
if (client.readyState === 1) client.send(message);
|
if (client.readyState === 1) client.send(message); // 1 === WebSocket.OPEN
|
||||||
});
|
});
|
||||||
return currentState;
|
return currentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stop() {
|
function stop() {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
wss.close(() => server.close(() => resolve()));
|
wss.close(() => {
|
||||||
|
server.closeAllConnections();
|
||||||
|
server.close(() => resolve());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user