Files

63 lines
2.1 KiB
JavaScript

import express from 'express';
import { enqueueCmd } from '../services/natQueue.js';
import { runRouterCmds } from '../services/sshExec.js';
import { error, info } from '../util/Console.js';
const router = express.Router();
const SAFE_CMD_REGX = /^\s*(show|ping|traceroute|terminal length|show ip|show interfaces|show version|show running-config|show ip nat)\b/i;
function checkAdminToken(req) {
const token = req.headers['x-admin-token'] || req.body.token || req.query.token;
const saved = req.app.get('adminToken');
const expiry = req.app.get('adminTokenExpory') || 0;
if (!token || !saved) return false;
if (Date.now() > expiry) return false;
return token === saved;
}
router.post('/', async (req, res) => {
const cmd = (req.body && req.body.cmd) || '';
if (!cmd) return res.status(400).json({ error: 'no command' });
const isAdmin = checkAdminToken(req);
if (!isAdmin && !SAFE_CMD_REGX.test(cmd)) return res.status(403).json({ error: 'not allowed' });
info(`Exec requested${isAdmin ? ' [admin]' : ''}: ${cmd}`);
try {
enqueueCmd(() => runRouterCmds([cmd]));
res.json({ success: true });
} catch (err) {
error(err);
res.status(500).json({ error: 'exec failed' });
}
});
router.get('/stream', (req, res) => {
const cmd = req.query.cmd || '';
if (!cmd) return res.status(400).send('no command');
const isAdmin = checkAdminToken(req);
if (!isAdmin && !SAFE_CMD_REGX.test(cmd)) return res.status(400).send('not allowed');
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders && res.flushHeaders();
enqueueCmd(() => new Promise(async (resolve) => {
try {
await runRouterCmds([cmd], chunk => {
res.write(`data: ${chunk.replace(/\n/g, '\\n')}\n\n`);
});
res.write('data: [[EOF]]\n\n');
res.end();
resolve()
} catch (err) {
res.write(`data: [ERROR] ${String(err)}\n\n`);
res.end();
resolve();
}
}));
});
export default router;