import type { Express } from "express"; import { createServer, type Server } from "http"; import { storage } from "./storage"; import { insertRouterSchema, insertDetectionSchema, insertWhitelistSchema } from "@shared/schema"; export async function registerRoutes(app: Express): Promise { // Routers app.get("/api/routers", async (req, res) => { try { const routers = await storage.getAllRouters(); res.json(routers); } catch (error) { res.status(500).json({ error: "Failed to fetch routers" }); } }); app.post("/api/routers", async (req, res) => { try { const validatedData = insertRouterSchema.parse(req.body); const router = await storage.createRouter(validatedData); res.json(router); } catch (error) { res.status(400).json({ error: "Invalid router data" }); } }); app.delete("/api/routers/:id", async (req, res) => { try { const success = await storage.deleteRouter(req.params.id); if (!success) { return res.status(404).json({ error: "Router not found" }); } res.json({ success: true }); } catch (error) { res.status(500).json({ error: "Failed to delete router" }); } }); // Network Logs app.get("/api/logs", async (req, res) => { try { const limit = parseInt(req.query.limit as string) || 100; const logs = await storage.getRecentLogs(limit); res.json(logs); } catch (error) { res.status(500).json({ error: "Failed to fetch logs" }); } }); app.get("/api/logs/ip/:ip", async (req, res) => { try { const limit = parseInt(req.query.limit as string) || 50; const logs = await storage.getLogsByIp(req.params.ip, limit); res.json(logs); } catch (error) { res.status(500).json({ error: "Failed to fetch logs for IP" }); } }); // Detections app.get("/api/detections", async (req, res) => { try { const limit = parseInt(req.query.limit as string) || 100; const detections = await storage.getAllDetections(limit); res.json(detections); } catch (error) { res.status(500).json({ error: "Failed to fetch detections" }); } }); app.get("/api/detections/unblocked", async (req, res) => { try { const detections = await storage.getUnblockedDetections(); res.json(detections); } catch (error) { res.status(500).json({ error: "Failed to fetch unblocked detections" }); } }); // Whitelist app.get("/api/whitelist", async (req, res) => { try { const whitelist = await storage.getAllWhitelist(); res.json(whitelist); } catch (error) { res.status(500).json({ error: "Failed to fetch whitelist" }); } }); app.post("/api/whitelist", async (req, res) => { try { const validatedData = insertWhitelistSchema.parse(req.body); const item = await storage.createWhitelist(validatedData); res.json(item); } catch (error) { res.status(400).json({ error: "Invalid whitelist data" }); } }); app.delete("/api/whitelist/:id", async (req, res) => { try { const success = await storage.deleteWhitelist(req.params.id); if (!success) { return res.status(404).json({ error: "Whitelist entry not found" }); } res.json({ success: true }); } catch (error) { res.status(500).json({ error: "Failed to delete whitelist entry" }); } }); // Training History app.get("/api/training-history", async (req, res) => { try { const limit = parseInt(req.query.limit as string) || 10; const history = await storage.getTrainingHistory(limit); res.json(history); } catch (error) { res.status(500).json({ error: "Failed to fetch training history" }); } }); app.get("/api/training-history/latest", async (req, res) => { try { const latest = await storage.getLatestTraining(); res.json(latest || null); } catch (error) { res.status(500).json({ error: "Failed to fetch latest training" }); } }); // Stats app.get("/api/stats", async (req, res) => { try { const routers = await storage.getAllRouters(); const detections = await storage.getAllDetections(1000); const recentLogs = await storage.getRecentLogs(1000); const whitelist = await storage.getAllWhitelist(); const latestTraining = await storage.getLatestTraining(); const blockedCount = detections.filter(d => d.blocked).length; const criticalCount = detections.filter(d => parseFloat(d.riskScore) >= 85).length; const highCount = detections.filter(d => parseFloat(d.riskScore) >= 70 && parseFloat(d.riskScore) < 85).length; res.json({ routers: { total: routers.length, enabled: routers.filter(r => r.enabled).length }, detections: { total: detections.length, blocked: blockedCount, critical: criticalCount, high: highCount }, logs: { recent: recentLogs.length }, whitelist: { total: whitelist.length }, latestTraining: latestTraining }); } catch (error) { res.status(500).json({ error: "Failed to fetch stats" }); } }); // ML Actions - Trigger training/detection on Python backend const ML_BACKEND_URL = process.env.ML_BACKEND_URL || "http://localhost:8000"; const ML_TIMEOUT = 120000; // 2 minutes timeout app.post("/api/ml/train", async (req, res) => { try { const { max_records = 100000, hours_back = 24 } = req.body; // Validate input if (typeof max_records !== 'number' || max_records <= 0 || max_records > 1000000) { return res.status(400).json({ error: "max_records must be between 1 and 1000000" }); } if (typeof hours_back !== 'number' || hours_back <= 0 || hours_back > 720) { return res.status(400).json({ error: "hours_back must be between 1 and 720" }); } const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), ML_TIMEOUT); const response = await fetch(`${ML_BACKEND_URL}/train`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ max_records, hours_back }), signal: controller.signal, }); clearTimeout(timeout); if (!response.ok) { const errorData = await response.json().catch(() => ({})); return res.status(response.status).json({ error: errorData.detail || "Training failed", status: response.status, }); } const data = await response.json(); res.json(data); } catch (error: any) { if (error.name === 'AbortError') { return res.status(504).json({ error: "Training timeout - operation took too long" }); } if (error.code === 'ECONNREFUSED') { return res.status(503).json({ error: "ML backend not available - is Python server running?" }); } res.status(500).json({ error: error.message || "Failed to trigger training" }); } }); app.post("/api/ml/detect", async (req, res) => { try { const { max_records = 50000, hours_back = 1, risk_threshold = 75, auto_block = false } = req.body; // Validate input if (typeof max_records !== 'number' || max_records <= 0 || max_records > 1000000) { return res.status(400).json({ error: "max_records must be between 1 and 1000000" }); } if (typeof hours_back !== 'number' || hours_back <= 0 || hours_back > 720) { return res.status(400).json({ error: "hours_back must be between 1 and 720" }); } if (typeof risk_threshold !== 'number' || risk_threshold < 0 || risk_threshold > 100) { return res.status(400).json({ error: "risk_threshold must be between 0 and 100" }); } const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), ML_TIMEOUT); const response = await fetch(`${ML_BACKEND_URL}/detect`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ max_records, hours_back, risk_threshold, auto_block }), signal: controller.signal, }); clearTimeout(timeout); if (!response.ok) { const errorData = await response.json().catch(() => ({})); return res.status(response.status).json({ error: errorData.detail || "Detection failed", status: response.status, }); } const data = await response.json(); res.json(data); } catch (error: any) { if (error.name === 'AbortError') { return res.status(504).json({ error: "Detection timeout - operation took too long" }); } if (error.code === 'ECONNREFUSED') { return res.status(503).json({ error: "ML backend not available - is Python server running?" }); } res.status(500).json({ error: error.message || "Failed to trigger detection" }); } }); app.get("/api/ml/stats", async (req, res) => { try { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 10000); // 10s timeout for stats const response = await fetch(`${ML_BACKEND_URL}/stats`, { signal: controller.signal, }); clearTimeout(timeout); if (!response.ok) { const errorData = await response.json().catch(() => ({})); return res.status(response.status).json({ error: errorData.detail || "Failed to fetch ML stats", status: response.status, }); } const data = await response.json(); res.json(data); } catch (error: any) { if (error.name === 'AbortError') { return res.status(504).json({ error: "Stats timeout" }); } if (error.code === 'ECONNREFUSED') { return res.status(503).json({ error: "ML backend not available" }); } res.status(500).json({ error: error.message || "Failed to fetch ML stats" }); } }); const httpServer = createServer(app); return httpServer; }