Compare commits
No commits in common. "0269dc929e392206384d4aa36d297f77c4c2131e" and "a3ec75b86bb84614ed5d00c90f5d4f27271d9490" have entirely different histories.
0269dc929e
...
a3ec75b86b
@ -37,12 +37,10 @@ export default function Dashboard() {
|
|||||||
refetchInterval: 10000, // Refresh every 10s
|
refetchInterval: 10000, // Refresh every 10s
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: recentDetectionsData } = useQuery<{ detections: Detection[]; total: number }>({
|
const { data: recentDetections } = useQuery<Detection[]>({
|
||||||
queryKey: ["/api/detections", { limit: 100 }],
|
queryKey: ["/api/detections?limit=100"],
|
||||||
queryFn: () => fetch("/api/detections?limit=100").then(r => r.json()),
|
refetchInterval: 5000, // Refresh every 5s
|
||||||
refetchInterval: 5000,
|
|
||||||
});
|
});
|
||||||
const recentDetections = recentDetectionsData?.detections;
|
|
||||||
|
|
||||||
const { data: routers } = useQuery<Router[]>({
|
const { data: routers } = useQuery<Router[]>({
|
||||||
queryKey: ["/api/routers"],
|
queryKey: ["/api/routers"],
|
||||||
|
|||||||
@ -16,7 +16,6 @@ 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() {
|
||||||
@ -33,7 +32,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 = stats?.blockedCount || 0;
|
const blockedAttacks = detections.filter(d => d.blocked).length;
|
||||||
|
|
||||||
// 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<any[]>({
|
const { data: lists, isLoading } = useQuery({
|
||||||
queryKey: ["/api/public-lists"],
|
queryKey: ["/api/public-lists"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ export default function Routers() {
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: "",
|
name: "",
|
||||||
ipAddress: "",
|
ipAddress: "",
|
||||||
apiPort: 80,
|
apiPort: 8729,
|
||||||
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. Usa la REST API (porta 80 HTTP o 443 HTTPS).
|
Configura un nuovo router MikroTik per il sistema IDS. Assicurati che l'API RouterOS (porta 8729/8728) sia abilitata.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
@ -216,14 +216,14 @@ export default function Routers() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="80"
|
placeholder="8729"
|
||||||
{...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 REST API MikroTik (80 per HTTP, 443 per HTTPS)
|
Porta RouterOS API MikroTik (8729 per API-SSL, 8728 per API)
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@ -445,14 +445,14 @@ export default function Routers() {
|
|||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="80"
|
placeholder="8729"
|
||||||
{...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 REST API MikroTik (80 per HTTP, 443 per HTTPS)
|
Porta RouterOS API MikroTik (8729 per API-SSL, 8728 per API)
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
-- PostgreSQL database dump
|
-- PostgreSQL database dump
|
||||||
--
|
--
|
||||||
|
|
||||||
\restrict dD9aoEfsbejhZrnq39dZalwHgFaXuIKh3obps9QwB0cunaM36PvpYWXEbzkuxIC
|
\restrict m8BX2OAI4IqpPQYg9LDdkx9gw71E8mW7NhAoc6tFhxIWe7hPFxv4gky0SVxio2N
|
||||||
|
|
||||||
-- Dumped from database version 16.11 (df20cf9)
|
-- Dumped from database version 16.11 (df20cf9)
|
||||||
-- Dumped by pg_dump version 16.10
|
-- Dumped by pg_dump version 16.10
|
||||||
@ -387,5 +387,5 @@ ALTER TABLE ONLY public.public_blacklist_ips
|
|||||||
-- PostgreSQL database dump complete
|
-- PostgreSQL database dump complete
|
||||||
--
|
--
|
||||||
|
|
||||||
\unrestrict dD9aoEfsbejhZrnq39dZalwHgFaXuIKh3obps9QwB0cunaM36PvpYWXEbzkuxIC
|
\unrestrict m8BX2OAI4IqpPQYg9LDdkx9gw71E8mW7NhAoc6tFhxIWe7hPFxv4gky0SVxio2N
|
||||||
|
|
||||||
|
|||||||
@ -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, detections, networkLogs } from "@shared/schema";
|
import { insertRouterSchema, insertDetectionSchema, insertWhitelistSchema, insertPublicListSchema, networkAnalytics, routers } from "@shared/schema";
|
||||||
import { db } from "./db";
|
import { db } from "./db";
|
||||||
import { desc, eq, gte, sql } from "drizzle-orm";
|
import { desc, eq } 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 | null}> = [];
|
let ips: Array<{ip: string, cidr?: string}> = [];
|
||||||
|
|
||||||
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 });
|
ips.push({ ip: entry.ip, cidr: null as any });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 });
|
ips.push({ ip, cidr: cidr as any });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,35 +481,30 @@ 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 routersList = await storage.getAllRouters();
|
const routers = 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 detectionStats = await db.select({
|
const detectionsList = detectionsResult.detections;
|
||||||
total: sql<number>`count(*)::int`,
|
const blockedCount = detectionsList.filter(d => d.blocked).length;
|
||||||
blocked: sql<number>`count(*) filter (where blocked = true)::int`,
|
const criticalCount = detectionsList.filter(d => parseFloat(d.riskScore) >= 85).length;
|
||||||
critical: sql<number>`count(*) filter (where ${detections.riskScore}::numeric >= 85)::int`,
|
const highCount = detectionsList.filter(d => parseFloat(d.riskScore) >= 70 && parseFloat(d.riskScore) < 85).length;
|
||||||
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: routersList.length,
|
total: routers.length,
|
||||||
enabled: routersList.filter(r => r.enabled).length
|
enabled: routers.filter(r => r.enabled).length
|
||||||
},
|
},
|
||||||
detections: {
|
detections: {
|
||||||
total: detectionStats[0]?.total || 0,
|
total: detectionsResult.total,
|
||||||
blocked: detectionStats[0]?.blocked || 0,
|
blocked: blockedCount,
|
||||||
critical: detectionStats[0]?.critical || 0,
|
critical: criticalCount,
|
||||||
high: detectionStats[0]?.high || 0
|
high: highCount
|
||||||
},
|
},
|
||||||
logs: {
|
logs: {
|
||||||
recent: logStats[0]?.count || 0
|
recent: recentLogs.length
|
||||||
},
|
},
|
||||||
whitelist: {
|
whitelist: {
|
||||||
total: whitelistResult.total
|
total: whitelistResult.total
|
||||||
|
|||||||
@ -80,14 +80,13 @@ 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> & { lastFetch?: Date | null; lastSuccess?: Date | null }): Promise<PublicList | undefined>;
|
updatePublicList(id: string, list: Partial<InsertPublicList>): Promise<PublicList | undefined>;
|
||||||
deletePublicList(id: string): Promise<boolean>;
|
deletePublicList(id: string): Promise<boolean>;
|
||||||
|
|
||||||
// Public Blacklist IPs
|
// Public Blacklist IPs
|
||||||
@ -454,11 +453,6 @@ 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,
|
||||||
@ -468,7 +462,6 @@ export class DatabaseStorage implements IStorage {
|
|||||||
attacksByCountry,
|
attacksByCountry,
|
||||||
attacksByType,
|
attacksByType,
|
||||||
recentDetections,
|
recentDetections,
|
||||||
blockedCount: blockedResult?.count || 0,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,7 +480,7 @@ export class DatabaseStorage implements IStorage {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updatePublicList(id: string, updateData: Partial<InsertPublicList> & { lastFetch?: Date | null; lastSuccess?: Date | null }): Promise<PublicList | undefined> {
|
async updatePublicList(id: string, updateData: Partial<InsertPublicList>): Promise<PublicList | undefined> {
|
||||||
const [list] = await db
|
const [list] = await db
|
||||||
.update(publicLists)
|
.update(publicLists)
|
||||||
.set(updateData)
|
.set(updateData)
|
||||||
|
|||||||
16
version.json
16
version.json
@ -1,13 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0.110",
|
"version": "1.0.109",
|
||||||
"lastUpdate": "2026-02-16T10:36:31.538Z",
|
"lastUpdate": "2026-02-16T07:50:06.148Z",
|
||||||
"changelog": [
|
"changelog": [
|
||||||
{
|
|
||||||
"version": "1.0.110",
|
|
||||||
"date": "2026-02-16",
|
|
||||||
"type": "patch",
|
|
||||||
"description": "Deployment automatico v1.0.110"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"version": "1.0.109",
|
"version": "1.0.109",
|
||||||
"date": "2026-02-16",
|
"date": "2026-02-16",
|
||||||
@ -301,6 +295,12 @@
|
|||||||
"date": "2025-11-24",
|
"date": "2025-11-24",
|
||||||
"type": "patch",
|
"type": "patch",
|
||||||
"description": "Deployment automatico v1.0.61"
|
"description": "Deployment automatico v1.0.61"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "1.0.60",
|
||||||
|
"date": "2025-11-24",
|
||||||
|
"type": "patch",
|
||||||
|
"description": "Deployment automatico v1.0.60"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user