dashboard changes for Session tab
This commit is contained in:
@@ -407,6 +407,107 @@ def build_presence() -> dict:
|
||||
}
|
||||
|
||||
|
||||
SESSION_GAP_SECS = 120 # gap > 2 min between events from same src = new session
|
||||
|
||||
|
||||
def _finalize_session(active: dict) -> dict:
|
||||
reasons = active["reasons"]
|
||||
dominant = max(set(reasons), key=reasons.count) if reasons else 0
|
||||
_, classification = deauth_reason_info(dominant)
|
||||
|
||||
rssi_vals = [r for r in active["rssi_vals"] if r is not None]
|
||||
start_dt = datetime.datetime.fromisoformat(active["start"])
|
||||
end_dt = datetime.datetime.fromisoformat(active["end"])
|
||||
duration = int((end_dt - start_dt).total_seconds())
|
||||
frames = len(active["frames"])
|
||||
|
||||
if classification == "attack" and frames >= 5:
|
||||
severity = "attack"
|
||||
elif frames >= 3 or classification in ("attack", "suspicious"):
|
||||
severity = "suspicious"
|
||||
else:
|
||||
severity = "normal"
|
||||
|
||||
src_vendor, src_rand = oui_lookup(active["src"])
|
||||
return {
|
||||
"src": active["src"],
|
||||
"src_vendor": src_vendor,
|
||||
"src_randomized": src_rand,
|
||||
"start": active["start"],
|
||||
"end": active["end"],
|
||||
"duration_secs": duration,
|
||||
"frame_count": frames,
|
||||
"unique_bssids": list(active["bssids"]),
|
||||
"unique_targets": list(active["targets"]),
|
||||
"node_count": len(active["nodes"]),
|
||||
"nodes": list(active["nodes"]),
|
||||
"peak_rssi": max(rssi_vals) if rssi_vals else None,
|
||||
"avg_rssi": round(sum(rssi_vals) / len(rssi_vals), 1) if rssi_vals else None,
|
||||
"dominant_reason": dominant,
|
||||
"severity": severity,
|
||||
"events": active["frames"][:50],
|
||||
}
|
||||
|
||||
|
||||
def build_sessions() -> list[dict]:
|
||||
cutoff = (datetime.datetime.utcnow() - datetime.timedelta(days=7)).isoformat(timespec="seconds")
|
||||
|
||||
rows = query("""
|
||||
SELECT src, dst, bssid, reason, rssi, received_at, node_id, subtype
|
||||
FROM deauth_events
|
||||
WHERE received_at > ?
|
||||
ORDER BY src, received_at
|
||||
""", (cutoff,))
|
||||
|
||||
if not rows:
|
||||
return []
|
||||
|
||||
sessions: list[dict] = []
|
||||
active: dict | None = None
|
||||
|
||||
for row in rows:
|
||||
src = row["src"]
|
||||
ts = row["received_at"]
|
||||
|
||||
new_session = False
|
||||
if active is None or active["src"] != src:
|
||||
new_session = True
|
||||
else:
|
||||
last_dt = datetime.datetime.fromisoformat(active["end"])
|
||||
curr_dt = datetime.datetime.fromisoformat(ts)
|
||||
if (curr_dt - last_dt).total_seconds() > SESSION_GAP_SECS:
|
||||
new_session = True
|
||||
|
||||
if new_session:
|
||||
if active is not None:
|
||||
sessions.append(_finalize_session(active))
|
||||
active = {
|
||||
"src": src,
|
||||
"start": ts,
|
||||
"end": ts,
|
||||
"bssids": set(),
|
||||
"targets": set(),
|
||||
"nodes": set(),
|
||||
"reasons": [],
|
||||
"rssi_vals": [],
|
||||
"frames": [],
|
||||
}
|
||||
|
||||
active["end"] = ts
|
||||
active["bssids"].add(row["bssid"])
|
||||
active["targets"].add(row["dst"])
|
||||
active["nodes"].add(row["node_id"])
|
||||
active["reasons"].append(row["reason"])
|
||||
active["rssi_vals"].append(row["rssi"])
|
||||
active["frames"].append(row)
|
||||
|
||||
if active is not None:
|
||||
sessions.append(_finalize_session(active))
|
||||
|
||||
sessions.sort(key=lambda s: s["start"], reverse=True)
|
||||
return sessions[:100]
|
||||
|
||||
|
||||
def build_alerts() -> dict:
|
||||
now = datetime.datetime.utcnow()
|
||||
cutoff_5m = (now - datetime.timedelta(minutes=5)).isoformat(timespec="seconds")
|
||||
@@ -881,6 +982,11 @@ async def api_rssi_history(bssid: str, hours: int = 2):
|
||||
return series
|
||||
|
||||
|
||||
@app.get("/api/sessions")
|
||||
async def api_sessions():
|
||||
return build_sessions()
|
||||
|
||||
|
||||
@app.get("/api/search")
|
||||
async def api_search(q: str = ""):
|
||||
return build_search(q)
|
||||
|
||||
Reference in New Issue
Block a user