Improve system accuracy and router configuration for security monitoring
Fixes type mismatches in API responses, updates router configuration to use correct REST API ports, and refactors statistics calculation for improved accuracy. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 7a657272-55ba-4a79-9a2e-f1ed9bc7a528 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 2601dca2-8641-4d91-9722-c30ebbbf23af Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/449cf7c4-c97a-45ae-8234-e5c5b8d6a84f/7a657272-55ba-4a79-9a2e-f1ed9bc7a528/5aJYCET
This commit is contained in:
parent
a3ec75b86b
commit
4229c54d62
@ -37,10 +37,12 @@ export default function Dashboard() {
|
|||||||
refetchInterval: 10000, // Refresh every 10s
|
refetchInterval: 10000, // Refresh every 10s
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: recentDetections } = useQuery<Detection[]>({
|
const { data: recentDetectionsData } = useQuery<{ detections: Detection[]; total: number }>({
|
||||||
queryKey: ["/api/detections?limit=100"],
|
queryKey: ["/api/detections", { limit: 100 }],
|
||||||
refetchInterval: 5000, // Refresh every 5s
|
queryFn: () => fetch("/api/detections?limit=100").then(r => r.json()),
|
||||||
|
refetchInterval: 5000,
|
||||||
});
|
});
|
||||||
|
const recentDetections = recentDetectionsData?.detections;
|
||||||
|
|
||||||
const { data: routers } = useQuery<Router[]>({
|
const { data: routers } = useQuery<Router[]>({
|
||||||
queryKey: ["/api/routers"],
|
queryKey: ["/api/routers"],
|
||||||
|
|||||||
@ -16,6 +16,7 @@ interface DashboardStats {
|
|||||||
attacksByCountry: Record<string, number>;
|
attacksByCountry: Record<string, number>;
|
||||||
attacksByType: Record<string, number>;
|
attacksByType: Record<string, number>;
|
||||||
recentDetections: Detection[];
|
recentDetections: Detection[];
|
||||||
|
blockedCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DashboardLive() {
|
export default function DashboardLive() {
|
||||||
@ -32,7 +33,7 @@ export default function DashboardLive() {
|
|||||||
const attackPercentage = totalTraffic > 0 ? ((totalAttacks / totalTraffic) * 100).toFixed(2) : "0";
|
const attackPercentage = totalTraffic > 0 ? ((totalAttacks / totalTraffic) * 100).toFixed(2) : "0";
|
||||||
|
|
||||||
const detections = stats?.recentDetections || [];
|
const detections = stats?.recentDetections || [];
|
||||||
const blockedAttacks = detections.filter(d => d.blocked).length;
|
const blockedAttacks = stats?.blockedCount || 0;
|
||||||
|
|
||||||
// Usa dati aggregati già calcolati dal backend
|
// Usa dati aggregati già calcolati dal backend
|
||||||
const attacksByCountry = stats?.attacksByCountry || {};
|
const attacksByCountry = stats?.attacksByCountry || {};
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export default function PublicLists() {
|
|||||||
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
|
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
|
||||||
const [editingList, setEditingList] = useState<any>(null);
|
const [editingList, setEditingList] = useState<any>(null);
|
||||||
|
|
||||||
const { data: lists, isLoading } = useQuery({
|
const { data: lists, isLoading } = useQuery<any[]>({
|
||||||
queryKey: ["/api/public-lists"],
|
queryKey: ["/api/public-lists"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ export default function Routers() {
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: "",
|
name: "",
|
||||||
ipAddress: "",
|
ipAddress: "",
|
||||||
apiPort: 8729,
|
apiPort: 80,
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -167,7 +167,7 @@ export default function Routers() {
|
|||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Aggiungi Router MikroTik</DialogTitle>
|
<DialogTitle>Aggiungi Router MikroTik</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Configura un nuovo router MikroTik per il sistema IDS. Assicurati che l'API RouterOS (porta 8729/8728) sia abilitata.
|
Configura un nuovo router MikroTik per il sistema IDS. Usa la REST API (porta 80 HTTP o 443 HTTPS).
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
@ -216,14 +216,14 @@ export default function Routers() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="8729"
|
placeholder="80"
|
||||||
{...field}
|
{...field}
|
||||||
onChange={(e) => field.onChange(parseInt(e.target.value))}
|
onChange={(e) => field.onChange(parseInt(e.target.value))}
|
||||||
data-testid="input-port"
|
data-testid="input-port"
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
Porta RouterOS API MikroTik (8729 per API-SSL, 8728 per API)
|
Porta REST API MikroTik (80 per HTTP, 443 per HTTPS)
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@ -445,14 +445,14 @@ export default function Routers() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="8729"
|
placeholder="80"
|
||||||
{...field}
|
{...field}
|
||||||
onChange={(e) => field.onChange(parseInt(e.target.value))}
|
onChange={(e) => field.onChange(parseInt(e.target.value))}
|
||||||
data-testid="input-edit-port"
|
data-testid="input-edit-port"
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
Porta RouterOS API MikroTik (8729 per API-SSL, 8728 per API)
|
Porta REST API MikroTik (80 per HTTP, 443 per HTTPS)
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { createServer, type Server } from "http";
|
import { createServer, type Server } from "http";
|
||||||
import { storage } from "./storage";
|
import { storage } from "./storage";
|
||||||
import { insertRouterSchema, insertDetectionSchema, insertWhitelistSchema, insertPublicListSchema, networkAnalytics, routers } from "@shared/schema";
|
import { insertRouterSchema, insertDetectionSchema, insertWhitelistSchema, insertPublicListSchema, networkAnalytics, routers, detections, networkLogs } from "@shared/schema";
|
||||||
import { db } from "./db";
|
import { db } from "./db";
|
||||||
import { desc, eq } from "drizzle-orm";
|
import { desc, eq, gte, sql } from "drizzle-orm";
|
||||||
|
|
||||||
export async function registerRoutes(app: Express): Promise<Server> {
|
export async function registerRoutes(app: Express): Promise<Server> {
|
||||||
// Routers
|
// Routers
|
||||||
@ -310,7 +310,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
|
|
||||||
// Parse IPs based on content type
|
// Parse IPs based on content type
|
||||||
let ips: Array<{ip: string, cidr?: string}> = [];
|
let ips: Array<{ip: string, cidr: string | null}> = [];
|
||||||
|
|
||||||
if (contentType.includes('json') || list.url.endsWith('.json')) {
|
if (contentType.includes('json') || list.url.endsWith('.json')) {
|
||||||
// JSON format (Spamhaus DROP v4 JSON)
|
// JSON format (Spamhaus DROP v4 JSON)
|
||||||
@ -322,7 +322,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
const [ip] = entry.cidr.split('/');
|
const [ip] = entry.cidr.split('/');
|
||||||
ips.push({ ip, cidr: entry.cidr });
|
ips.push({ ip, cidr: entry.cidr });
|
||||||
} else if (entry.ip) {
|
} else if (entry.ip) {
|
||||||
ips.push({ ip: entry.ip, cidr: null as any });
|
ips.push({ ip: entry.ip, cidr: null });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,7 +342,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
if (match) {
|
if (match) {
|
||||||
const ip = match[1];
|
const ip = match[1];
|
||||||
const cidr = match[2] ? `${match[1]}${match[2]}` : null;
|
const cidr = match[2] ? `${match[1]}${match[2]}` : null;
|
||||||
ips.push({ ip, cidr: cidr as any });
|
ips.push({ ip, cidr });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,30 +481,35 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
// Stats
|
// Stats
|
||||||
app.get("/api/stats", async (req, res) => {
|
app.get("/api/stats", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const routers = await storage.getAllRouters();
|
const routersList = await storage.getAllRouters();
|
||||||
const detectionsResult = await storage.getAllDetections({ limit: 1000 });
|
|
||||||
const recentLogs = await storage.getRecentLogs(1000);
|
|
||||||
const whitelistResult = await storage.getAllWhitelist({ limit: 1 });
|
const whitelistResult = await storage.getAllWhitelist({ limit: 1 });
|
||||||
const latestTraining = await storage.getLatestTraining();
|
const latestTraining = await storage.getLatestTraining();
|
||||||
|
|
||||||
const detectionsList = detectionsResult.detections;
|
const detectionStats = await db.select({
|
||||||
const blockedCount = detectionsList.filter(d => d.blocked).length;
|
total: sql<number>`count(*)::int`,
|
||||||
const criticalCount = detectionsList.filter(d => parseFloat(d.riskScore) >= 85).length;
|
blocked: sql<number>`count(*) filter (where blocked = true)::int`,
|
||||||
const highCount = detectionsList.filter(d => parseFloat(d.riskScore) >= 70 && parseFloat(d.riskScore) < 85).length;
|
critical: sql<number>`count(*) filter (where ${detections.riskScore}::numeric >= 85)::int`,
|
||||||
|
high: sql<number>`count(*) filter (where ${detections.riskScore}::numeric >= 70 and ${detections.riskScore}::numeric < 85)::int`,
|
||||||
|
}).from(detections);
|
||||||
|
|
||||||
|
const logStats = await db.select({
|
||||||
|
count: sql<number>`count(*)::int`,
|
||||||
|
}).from(networkLogs)
|
||||||
|
.where(gte(networkLogs.timestamp, new Date(Date.now() - 24 * 60 * 60 * 1000)));
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
routers: {
|
routers: {
|
||||||
total: routers.length,
|
total: routersList.length,
|
||||||
enabled: routers.filter(r => r.enabled).length
|
enabled: routersList.filter(r => r.enabled).length
|
||||||
},
|
},
|
||||||
detections: {
|
detections: {
|
||||||
total: detectionsResult.total,
|
total: detectionStats[0]?.total || 0,
|
||||||
blocked: blockedCount,
|
blocked: detectionStats[0]?.blocked || 0,
|
||||||
critical: criticalCount,
|
critical: detectionStats[0]?.critical || 0,
|
||||||
high: highCount
|
high: detectionStats[0]?.high || 0
|
||||||
},
|
},
|
||||||
logs: {
|
logs: {
|
||||||
recent: recentLogs.length
|
recent: logStats[0]?.count || 0
|
||||||
},
|
},
|
||||||
whitelist: {
|
whitelist: {
|
||||||
total: whitelistResult.total
|
total: whitelistResult.total
|
||||||
|
|||||||
@ -80,13 +80,14 @@ export interface IStorage {
|
|||||||
attacksByCountry: Record<string, number>;
|
attacksByCountry: Record<string, number>;
|
||||||
attacksByType: Record<string, number>;
|
attacksByType: Record<string, number>;
|
||||||
recentDetections: Detection[];
|
recentDetections: Detection[];
|
||||||
|
blockedCount: number;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// Public Lists
|
// Public Lists
|
||||||
getAllPublicLists(): Promise<PublicList[]>;
|
getAllPublicLists(): Promise<PublicList[]>;
|
||||||
getPublicListById(id: string): Promise<PublicList | undefined>;
|
getPublicListById(id: string): Promise<PublicList | undefined>;
|
||||||
createPublicList(list: InsertPublicList): Promise<PublicList>;
|
createPublicList(list: InsertPublicList): Promise<PublicList>;
|
||||||
updatePublicList(id: string, list: Partial<InsertPublicList>): Promise<PublicList | undefined>;
|
updatePublicList(id: string, list: Partial<InsertPublicList> & { lastFetch?: Date | null; lastSuccess?: Date | null }): Promise<PublicList | undefined>;
|
||||||
deletePublicList(id: string): Promise<boolean>;
|
deletePublicList(id: string): Promise<boolean>;
|
||||||
|
|
||||||
// Public Blacklist IPs
|
// Public Blacklist IPs
|
||||||
@ -453,6 +454,11 @@ export class DatabaseStorage implements IStorage {
|
|||||||
.orderBy(desc(detections.detectedAt))
|
.orderBy(desc(detections.detectedAt))
|
||||||
.limit(100);
|
.limit(100);
|
||||||
|
|
||||||
|
const [blockedResult] = await db
|
||||||
|
.select({ count: sql<number>`count(*)::int` })
|
||||||
|
.from(detections)
|
||||||
|
.where(eq(detections.blocked, true));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
totalPackets,
|
totalPackets,
|
||||||
attackPackets,
|
attackPackets,
|
||||||
@ -462,6 +468,7 @@ export class DatabaseStorage implements IStorage {
|
|||||||
attacksByCountry,
|
attacksByCountry,
|
||||||
attacksByType,
|
attacksByType,
|
||||||
recentDetections,
|
recentDetections,
|
||||||
|
blockedCount: blockedResult?.count || 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +487,7 @@ export class DatabaseStorage implements IStorage {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updatePublicList(id: string, updateData: Partial<InsertPublicList>): Promise<PublicList | undefined> {
|
async updatePublicList(id: string, updateData: Partial<InsertPublicList> & { lastFetch?: Date | null; lastSuccess?: Date | null }): Promise<PublicList | undefined> {
|
||||||
const [list] = await db
|
const [list] = await db
|
||||||
.update(publicLists)
|
.update(publicLists)
|
||||||
.set(updateData)
|
.set(updateData)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user