refactor: UI improvements and code cleanup

Frontend:
- DetectionsList: Simplify columns, improve truncation and display for IPs, hosts, bot info
- IncidentsView: Replace metric cards with compact stat cards (unique IPs, known bots, ML anomalies, threat levels)
- InvestigationView: Add section navigation anchors, reorganize layout with proper IDs
- ThreatIntelView: Add navigation links to investigation pages, add comment column, improve table layout

Backend:
- Various route and model adjustments
- Configuration updates

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
SOC Analyst
2026-03-20 09:56:49 +01:00
parent dbb9bb3f94
commit bd33fbad01
17 changed files with 444 additions and 510 deletions

View File

@ -1,9 +1,9 @@
"""
Endpoints pour l'analyse de corrélations et la classification SOC
"""
from collections import defaultdict
from fastapi import APIRouter, HTTPException, Query
from typing import Optional, List
from datetime import datetime
import ipaddress
import json
@ -17,6 +17,14 @@ from ..models import (
router = APIRouter(prefix="/api/analysis", tags=["analysis"])
# Mapping code ISO → nom lisible (utilisé par analyze_ip_country et analyze_country)
_COUNTRY_NAMES: dict[str, str] = {
"CN": "China", "US": "United States", "DE": "Germany",
"FR": "France", "RU": "Russia", "GB": "United Kingdom",
"NL": "Netherlands", "IN": "India", "BR": "Brazil",
"JP": "Japan", "KR": "South Korea", "IT": "Italy",
"ES": "Spain", "CA": "Canada", "AU": "Australia"
}
# =============================================================================
# ANALYSE SUBNET / ASN
@ -122,15 +130,6 @@ async def analyze_ip_country(ip: str):
ip_country_code = ip_result.result_rows[0][0]
asn_number = ip_result.result_rows[0][1]
# Noms des pays
country_names = {
"CN": "China", "US": "United States", "DE": "Germany",
"FR": "France", "RU": "Russia", "GB": "United Kingdom",
"NL": "Netherlands", "IN": "India", "BR": "Brazil",
"JP": "Japan", "KR": "South Korea", "IT": "Italy",
"ES": "Spain", "CA": "Canada", "AU": "Australia"
}
# Répartition des autres pays du même ASN
asn_countries_query = """
SELECT
@ -150,7 +149,7 @@ async def analyze_ip_country(ip: str):
asn_countries = [
{
"code": row[0],
"name": country_names.get(row[0], row[0]),
"name": _COUNTRY_NAMES.get(row[0], row[0]),
"count": row[1],
"percentage": round((row[1] / total * 100), 2) if total > 0 else 0.0
}
@ -160,7 +159,7 @@ async def analyze_ip_country(ip: str):
return {
"ip_country": {
"code": ip_country_code,
"name": country_names.get(ip_country_code, ip_country_code)
"name": _COUNTRY_NAMES.get(ip_country_code, ip_country_code)
},
"asn_countries": asn_countries
}
@ -196,19 +195,10 @@ async def analyze_country(days: int = Query(1, ge=1, le=30)):
# Calculer le total pour le pourcentage
total = sum(row[1] for row in top_result.result_rows)
# Noms des pays (mapping simple)
country_names = {
"CN": "China", "US": "United States", "DE": "Germany",
"FR": "France", "RU": "Russia", "GB": "United Kingdom",
"NL": "Netherlands", "IN": "India", "BR": "Brazil",
"JP": "Japan", "KR": "South Korea", "IT": "Italy",
"ES": "Spain", "CA": "Canada", "AU": "Australia"
}
top_countries = [
CountryData(
code=row[0],
name=country_names.get(row[0], row[0]),
name=_COUNTRY_NAMES.get(row[0], row[0]),
count=row[1],
percentage=round((row[1] / total * 100), 2) if total > 0 else 0.0
)
@ -311,7 +301,6 @@ async def analyze_ja4(ip: str):
subnets_result = db.query(subnets_query, {"ja4": ja4})
# Grouper par subnet /24
from collections import defaultdict
subnet_counts = defaultdict(int)
for row in subnets_result.result_rows:
ip_addr = str(row[0])
@ -439,24 +428,24 @@ async def get_classification_recommendation(ip: str):
# Récupérer les analyses
try:
subnet_analysis = await analyze_subnet(ip)
except:
except Exception:
subnet_analysis = None
try:
country_analysis = await analyze_country(1)
except:
except Exception:
country_analysis = None
try:
ja4_analysis = await analyze_ja4(ip)
except:
except Exception:
ja4_analysis = None
try:
ua_analysis = await analyze_user_agents(ip)
except:
except Exception:
ua_analysis = None
# Indicateurs par défaut
indicators = CorrelationIndicators(
subnet_ips_count=subnet_analysis.total_in_subnet if subnet_analysis else 0,