maj cumulative
This commit is contained in:
129
backend/routes/search.py
Normal file
129
backend/routes/search.py
Normal file
@ -0,0 +1,129 @@
|
||||
"""
|
||||
Endpoint de recherche globale rapide — utilisé par la barre Cmd+K
|
||||
"""
|
||||
from fastapi import APIRouter, Query
|
||||
from ..database import db
|
||||
|
||||
router = APIRouter(prefix="/api/search", tags=["search"])
|
||||
|
||||
IP_RE = r"^(\d{1,3}\.){0,3}\d{1,3}$"
|
||||
|
||||
|
||||
@router.get("/quick")
|
||||
async def quick_search(q: str = Query(..., min_length=1, max_length=100)):
|
||||
"""
|
||||
Recherche unifiée sur IPs, JA4, ASN, hosts.
|
||||
Retourne jusqu'à 5 résultats par catégorie.
|
||||
"""
|
||||
q = q.strip()
|
||||
pattern = f"%{q}%"
|
||||
results = []
|
||||
|
||||
# ── IPs ──────────────────────────────────────────────────────────────────
|
||||
ip_rows = db.query(
|
||||
"""
|
||||
SELECT
|
||||
replaceRegexpAll(toString(src_ip), '^::ffff:', '') AS clean_ip,
|
||||
count() AS hits,
|
||||
max(detected_at) AS last_seen,
|
||||
any(threat_level) AS threat_level
|
||||
FROM ml_detected_anomalies
|
||||
WHERE ilike(toString(src_ip), %(p)s)
|
||||
AND detected_at >= now() - INTERVAL 24 HOUR
|
||||
GROUP BY clean_ip
|
||||
ORDER BY hits DESC
|
||||
LIMIT 5
|
||||
""",
|
||||
{"p": pattern},
|
||||
)
|
||||
for r in ip_rows.result_rows:
|
||||
ip = str(r[0])
|
||||
results.append({
|
||||
"type": "ip",
|
||||
"value": ip,
|
||||
"label": ip,
|
||||
"meta": f"{r[1]} détections · {r[3]}",
|
||||
"url": f"/detections/ip/{ip}",
|
||||
"investigation_url": f"/investigation/{ip}",
|
||||
})
|
||||
|
||||
# ── JA4 fingerprints ─────────────────────────────────────────────────────
|
||||
ja4_rows = db.query(
|
||||
"""
|
||||
SELECT
|
||||
ja4,
|
||||
count() AS hits,
|
||||
uniq(src_ip) AS unique_ips
|
||||
FROM ml_detected_anomalies
|
||||
WHERE ilike(ja4, %(p)s)
|
||||
AND ja4 != ''
|
||||
AND detected_at >= now() - INTERVAL 24 HOUR
|
||||
GROUP BY ja4
|
||||
ORDER BY hits DESC
|
||||
LIMIT 5
|
||||
""",
|
||||
{"p": pattern},
|
||||
)
|
||||
for r in ja4_rows.result_rows:
|
||||
results.append({
|
||||
"type": "ja4",
|
||||
"value": str(r[0]),
|
||||
"label": str(r[0]),
|
||||
"meta": f"{r[1]} détections · {r[2]} IPs",
|
||||
"url": f"/investigation/ja4/{r[0]}",
|
||||
})
|
||||
|
||||
# ── Hosts ─────────────────────────────────────────────────────────────────
|
||||
host_rows = db.query(
|
||||
"""
|
||||
SELECT
|
||||
host,
|
||||
count() AS hits,
|
||||
uniq(src_ip) AS unique_ips
|
||||
FROM ml_detected_anomalies
|
||||
WHERE ilike(host, %(p)s)
|
||||
AND host != ''
|
||||
AND detected_at >= now() - INTERVAL 24 HOUR
|
||||
GROUP BY host
|
||||
ORDER BY hits DESC
|
||||
LIMIT 5
|
||||
""",
|
||||
{"p": pattern},
|
||||
)
|
||||
for r in host_rows.result_rows:
|
||||
results.append({
|
||||
"type": "host",
|
||||
"value": str(r[0]),
|
||||
"label": str(r[0]),
|
||||
"meta": f"{r[1]} hits · {r[2]} IPs",
|
||||
"url": f"/detections?search={r[0]}",
|
||||
})
|
||||
|
||||
# ── ASN ───────────────────────────────────────────────────────────────────
|
||||
asn_rows = db.query(
|
||||
"""
|
||||
SELECT
|
||||
asn_org,
|
||||
asn_number,
|
||||
count() AS hits,
|
||||
uniq(src_ip) AS unique_ips
|
||||
FROM ml_detected_anomalies
|
||||
WHERE (ilike(asn_org, %(p)s) OR ilike(asn_number, %(p)s))
|
||||
AND asn_org != '' AND asn_number != ''
|
||||
AND detected_at >= now() - INTERVAL 24 HOUR
|
||||
GROUP BY asn_org, asn_number
|
||||
ORDER BY hits DESC
|
||||
LIMIT 5
|
||||
""",
|
||||
{"p": pattern},
|
||||
)
|
||||
for r in asn_rows.result_rows:
|
||||
results.append({
|
||||
"type": "asn",
|
||||
"value": str(r[1]),
|
||||
"label": f"AS{r[1]} — {r[0]}",
|
||||
"meta": f"{r[2]} hits · {r[3]} IPs",
|
||||
"url": f"/detections?asn={r[1]}",
|
||||
})
|
||||
|
||||
return {"query": q, "results": results}
|
||||
Reference in New Issue
Block a user