Skip to content

Commit da7c524

Browse files
committed
feat: add api for dashboard
1 parent 29969bf commit da7c524

1 file changed

Lines changed: 108 additions & 1 deletion

File tree

hashshield_daemon.py

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,111 @@ async def api_event(request):
314314
async def index_handler(request):
315315
return web.FileResponse(os.path.join(DIST_DIR, 'dashboard.html'))
316316

317-
# ------------------------------------------------------------------
317+
async def api_get_intel(request):
318+
# 1. Top Families
319+
top_families = run_query("""
320+
SELECT family as name, COUNT(*) as count
321+
FROM threats GROUP BY family ORDER BY count DESC LIMIT 10
322+
""", fetch=True)
323+
324+
# 2. Engine Breakdown
325+
engine_bd = run_query("""
326+
SELECT engine, COUNT(*) as count
327+
FROM threats GROUP BY engine
328+
""", fetch=True)
329+
330+
# 3. Per Agent Stats
331+
per_agent = run_query("""
332+
SELECT agent, COUNT(*) as count
333+
FROM threats GROUP BY agent ORDER BY count DESC
334+
""", fetch=True)
335+
336+
# 4. Platform Breakdown (Deteksi dari awalan nama malware)
337+
all_threats = run_query("SELECT name FROM threats", fetch=True)
338+
plat_counts = {"Win": 0, "Linux": 0, "Android": 0, "Java": 0, "Html": 0, "Other": 0}
339+
340+
for t in all_threats:
341+
name = t['name'].lower()
342+
if name.startswith('win'): plat_counts['Win'] += 1
343+
elif name.startswith('linux'): plat_counts['Linux'] += 1
344+
elif name.startswith('android'): plat_counts['Android'] += 1
345+
elif name.startswith('java'): plat_counts['Java'] += 1
346+
elif name.startswith('html'): plat_counts['Html'] += 1
347+
else: plat_counts['Other'] += 1
348+
349+
platforms = [{"platform": k, "count": v} for k, v in plat_counts.items() if v > 0]
350+
platforms.sort(key=lambda x: x['count'], reverse=True)
351+
352+
return web.json_response({
353+
"top_families": top_families,
354+
"engine_breakdown": engine_bd,
355+
"platforms": platforms,
356+
"per_agent": per_agent
357+
})
358+
359+
async def api_intel_lookup(request):
360+
# Handler untuk fitur Hash Lookup di halaman Threat Intel
361+
hash_val = request.query.get('hash', '').strip().lower()
362+
if not hash_val:
363+
return web.json_response({"found": False})
364+
365+
rows = run_query("SELECT * FROM threats WHERE hash=? LIMIT 1", (hash_val,), fetch=True)
366+
if rows:
367+
return web.json_response({"found": True, "threat": rows[0]})
368+
return web.json_response({"found": False})
369+
370+
async def api_get_analytics(request):
371+
# 1. Summary
372+
sum_rows = run_query("""
373+
SELECT SUM(total_scanned) as tf, SUM(infected_count) as ti, COUNT(*) as ts
374+
FROM scan_reports
375+
""", fetch=True)
376+
377+
tf = sum_rows[0]['tf'] or 0
378+
ti = sum_rows[0]['ti'] or 0
379+
ts = sum_rows[0]['ts'] or 0
380+
det_rate = round((ti / tf * 100), 2) if tf > 0 else 0
381+
382+
# 2. Daily Chart Activity
383+
chart_rows = run_query("""
384+
SELECT date(scan_date) as date_val, SUM(total_scanned) as total, SUM(infected_count) as infected
385+
FROM scan_reports
386+
WHERE date(scan_date) >= date('now', '-6 days')
387+
GROUP BY date(scan_date) ORDER BY date(scan_date) ASC
388+
""", fetch=True)
389+
390+
labels, clean_data, threat_data = [], [], []
391+
for r in chart_rows:
392+
labels.append(r['date_val'][5:]) # Ambil MM-DD
393+
infected = r['infected'] or 0
394+
total = r['total'] or 0
395+
threat_data.append(infected)
396+
clean_data.append(total - infected)
397+
398+
# 3. Per Agent Performance
399+
agent_stats = run_query("""
400+
SELECT agent, COUNT(*) as total_scans,
401+
SUM(total_scanned) as total_files, SUM(infected_count) as total_infected,
402+
ROUND(AVG(duration), 2) as avg_duration,
403+
ROUND(AVG(CAST(total_scanned AS FLOAT) / CASE WHEN duration = 0 THEN 1 ELSE duration END), 1) as avg_throughput
404+
FROM scan_reports GROUP BY agent
405+
""", fetch=True)
406+
407+
# 4. Scan History
408+
history = run_query("""
409+
SELECT agent, scan_date, total_scanned, infected_count,
410+
ROUND(CAST(total_scanned AS FLOAT) / CASE WHEN duration = 0 THEN 1 ELSE duration END, 1) as throughput
411+
FROM scan_reports ORDER BY id DESC LIMIT 15
412+
""", fetch=True)
413+
414+
return web.json_response({
415+
"summary": {"total_files": tf, "total_infected": ti, "detection_rate": det_rate, "total_sessions": ts},
416+
"daily_chart": {"labels": labels, "threats": threat_data, "clean": clean_data},
417+
"per_agent_stats": agent_stats,
418+
"scan_history": history
419+
})
420+
421+
# ------------------------------------------------------------------
318422
# APP SETUP
319423
# ------------------------------------------------------------------
320424
app = web.Application(middlewares=[auth_middleware])
@@ -326,6 +430,9 @@ async def index_handler(request):
326430
app.router.add_get('/api/threats', api_get_threats)
327431
app.router.add_post('/api/heartbeat', api_heartbeat)
328432
app.router.add_post('/api/event', api_event)
433+
app.router.add_get('/api/intel', api_get_intel)
434+
app.router.add_get('/api/intel/lookup', api_intel_lookup)
435+
app.router.add_get('/api/analytics', api_get_analytics)
329436
app.router.add_get('/', index_handler)
330437
app.router.add_static('/', path=DIST_DIR, name='static')
331438

0 commit comments

Comments
 (0)