completeness pass 2: agent-token auth on /api/agent/*, token-injected agent.py downloads, export-all zip endpoint, node detail drawer (metrics/loot/tags/ping), screenshot watch mode, honest Linux-only binary note, token-aware binary command, watch-state render persistence

This commit is contained in:
Hermes
2026-09-30 01:19:43 +00:00
parent 8c31da986f
commit 67b27bb1a2
5 changed files with 285 additions and 10 deletions

View File

@@ -31,9 +31,19 @@ const AUTH_TOKEN = process.env.NEXUS_AUTH_TOKEN || null;
if (!AUTH_TOKEN) {
console.log('!!! AUTH DISABLED — set NEXUS_AUTH_TOKEN in .env to protect the dashboard !!!');
}
const AUTH_EXEMPT_PREFIXES = ['/api/agent/', '/install', '/agent.py', '/bin/'];
const AGENT_TOKEN = process.env.NEXUS_AGENT_TOKEN || '';
const AUTH_EXEMPT_PREFIXES = ['/install', '/agent.py', '/bin/'];
function agentAuthOk(req) {
if (!AGENT_TOKEN) return true; // agent auth disabled when no token configured
const t = req.headers['x-agent-token'] || req.query.agenttoken || '';
return t === AGENT_TOKEN;
}
function authMiddleware(req, res, next) {
if (!AUTH_TOKEN) return next();
if (req.path.startsWith('/api/agent/')) {
if (agentAuthOk(req)) return next();
return res.status(401).json({ error: 'agent token required' });
}
if (AUTH_EXEMPT_PREFIXES.some(p => req.path.startsWith(p))) return next();
const h = req.headers.authorization || '';
if (h === 'Bearer ' + AUTH_TOKEN) return next();
@@ -953,7 +963,30 @@ echo "[*] Agent deployment initiated — it will register within 10 seconds"
});
app.get('/agent.py', (req, res) => {
res.sendFile(path.join(__dirname, 'agents', 'agent.py'));
try {
const src = fs.readFileSync(path.join(__dirname, 'agents', 'agent.py'), 'utf8');
res.setHeader('Content-Type', 'text/plain');
res.send(AGENT_TOKEN ? src.split('__AGENT_TOKEN__').join(AGENT_TOKEN) : src);
} catch (e) {
res.status(500).send('agent unavailable');
}
});
// ── Completeness additions 2026-09-29 ──
app.get('/api/agenttoken', (req, res) => {
res.json({ token: AGENT_TOKEN || '' });
});
app.get('/api/export/all', (req, res) => {
try {
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
const out = `/tmp/nexusops-export-${stamp}.tar.gz`;
require('child_process').execSync(`tar czf ${out} -C ${DATA_DIR} .`);
res.download(out, `nexusops-full-export-${stamp}.tar.gz`, () => {
try { fs.unlinkSync(out); } catch (e) {}
});
} catch (e) {
res.status(500).json({ error: 'export failed: ' + e.message });
}
});
server.listen(PORT, '0.0.0.0', () => {