'use strict'; const express = require('express'); const { clients, sessions, audit } = require('../db'); const { uuid } = require('../crypto'); const { requireAuth, requireAdmin, roleForClient } = require('../auth'); const tickets = require('../tickets'); const bridge = require('../vnc/bridge'); const hub = require('../vnc/hub'); const router = express.Router(); router.use(requireAuth); /** Mint a one-time ticket for the VNC WebSocket. This is the connect handshake. */ router.post('/', (req, res) => { const client = clients.get(String((req.body || {}).clientId || '')); if (!client) return res.status(404).json({ error: 'no such client' }); const role = roleForClient(req.user, client.id, req.isAdmin); if (!role) return res.status(403).json({ error: 'you do not have access to this client' }); // A viewer can deliberately drop to view-only, but never upgrade past its grant. const requested = (req.body || {}).viewOnly ? 'viewer' : role; if (client.mode === 'agent' && !hub.isOnline(client.id)) { return res.status(409).json({ error: 'that machine is offline' }); } const sessionId = uuid(); const ticket = tickets.issue({ sessionId, clientId: client.id, username: req.username, role: requested, source: 'web', }); res.json({ ticket: ticket.token, expiresIn: ticket.expiresIn, sessionId, role: requested, clientName: client.name, requireConsent: !!client.require_consent, }); }); router.get('/live', (req, res) => { const all = bridge.listLive(); res.json({ sessions: req.isAdmin ? all : all.filter((s) => s.username === req.username) }); }); router.get('/history', (req, res) => { const limit = Math.min(Number(req.query.limit) || 100, 500); const clientId = req.query.clientId ? String(req.query.clientId) : null; if (!req.isAdmin) { if (!clientId) return res.status(403).json({ error: 'admin only' }); if (!roleForClient(req.user, clientId, false)) { return res.status(403).json({ error: 'you do not have access to this client' }); } } res.json({ sessions: sessions.recent(limit, clientId) }); }); router.post('/:id/kill', requireAdmin, (req, res) => { const ok = bridge.killSession(req.params.id, `disconnected by ${req.username}`); if (!ok) return res.status(404).json({ error: 'no such live session' }); audit(req.username, 'session.kill', req.params.id, null); res.json({ ok: true }); }); router.get('/audit', requireAdmin, (req, res) => { res.json({ audit: audit.recent(Math.min(Number(req.query.limit) || 200, 1000)) }); }); module.exports = { router };