analyze performance upgrade

This commit is contained in:
DaStra3003
2026-09-23 08:01:49 +02:00
parent aabe35fead
commit 7f7b753350
51 changed files with 5827 additions and 1372 deletions
+106 -7
View File
@@ -1,7 +1,11 @@
"""REST endpoints exposed by IoT PreTester 4.6 Demo."""
import json
import logging
import os
import re
import shutil
import subprocess
from pathlib import Path
from uuid import uuid4
@@ -16,7 +20,7 @@ from rest_framework.permissions import AllowAny, IsAdminUser
from rest_framework.response import Response
from rest_framework.views import APIView
from .analyze.security_analysis import collect_cloud_results
from .analyze.security_analysis import analysis_log_path, collect_cloud_results
from .db_create import (
create_capture,
create_device_type,
@@ -48,16 +52,56 @@ from .user_funcs import (
)
logger = logging.getLogger(__name__)
def _validation_error(exc: ValidationError) -> Response:
messages = getattr(exc, "messages", [str(exc)])
return Response({"error": messages[0]}, status=status.HTTP_400_BAD_REQUEST)
def _tool_version(name: str, args=("-v",)) -> str | None:
"""First line of a tool's version output, or None when it is missing."""
path = shutil.which(name)
if not path:
return None
try:
out = subprocess.run([path, *args], capture_output=True, text=True, timeout=15)
first = (out.stdout or out.stderr or "").strip().splitlines()
return first[0][:120] if first else path
except Exception as exc:
return f"{path} (version check failed: {exc})"
class HealthView(APIView):
"""Service status including the external tools the analysis depends on."""
permission_classes = [AllowAny]
def get(self, request):
return Response({"status": "ok", "service": "IoT PreTester 4.6 Demo"})
from analyzer import __version__ as analyzer_version
tshark = _tool_version(os.environ.get("TSHARK_PATH") or "tshark")
upload_dir = str(settings.CAPTURE_UPLOAD_DIR)
data = {
"status": "ok" if tshark else "degraded",
"service": "IoT PreTester 4.6 Demo",
"analyzer_version": analyzer_version,
"tools": {
"tshark": tshark,
"hashcat": _tool_version("hashcat", ("--version",)),
"nmap": _tool_version("nmap", ("--version",)),
},
"upload_dir": upload_dir,
"upload_dir_writable": os.access(upload_dir, os.W_OK),
"log_dir": str(getattr(settings, "LOG_DIR", "")),
"log_level": getattr(settings, "LOG_LEVEL", "INFO"),
"packet_limit": settings.CAPTURE_PACKET_LIMIT or "unlimited",
}
if not tshark:
data["error"] = "tshark is not installed; capture analysis cannot run."
logger.error("Health check: tshark not found on PATH")
return Response(data)
class LoginView(APIView):
@@ -293,15 +337,30 @@ class DeleteDeviceTypeView(APIView):
return Response({"status": "success"})
# Capture status -> payload shown while no finding report exists yet.
_PENDING_CAPTURE_STATES = {
"analyzing": ("analyzing", "The security analysis is still running."),
"pending": ("analyzing", "The security analysis is queued."),
"analysis_failed": ("failed", "The security analysis failed. The error and the analysis log are shown below."),
}
class FindingsView(APIView):
def get(self, request, file_id):
get_object_or_404(File, id=file_id)
capture = get_object_or_404(File, id=file_id)
report = FindingReport.objects.filter(file_id=file_id).first()
if report is None:
return Response(
state, message = _PENDING_CAPTURE_STATES.get(
capture.status,
("empty", "No security analysis is available for this capture."),
)
response = Response(
{
"status": "empty",
"message": "No security analysis is available for this capture.",
"status": state,
"capture_status": capture.status,
"message": message,
"error": capture.error_message,
"log_available": _log_exists(capture),
"summary": {
"total": 0,
"by_severity": {},
@@ -312,7 +371,47 @@ class FindingsView(APIView):
"findings": [],
}
)
return Response(json.loads(report.result_json))
response["Cache-Control"] = "no-store"
return response
payload = json.loads(report.result_json)
payload["status"] = "ready"
payload["capture_status"] = capture.status
payload["error"] = capture.error_message
payload["log_available"] = _log_exists(capture)
response = Response(payload)
response["Cache-Control"] = "no-store"
return response
def _log_exists(capture: File) -> bool:
path = analysis_log_path(capture.filename)
return bool(path and os.path.exists(path))
class AnalysisLogView(APIView):
"""Tail of the per-capture analysis log for troubleshooting."""
def get(self, request, file_id):
from analyzer.logutil import tail
capture = get_object_or_404(File, id=file_id)
path = analysis_log_path(capture.filename)
try:
lines = max(20, min(int(request.GET.get("lines", 400)), 5000))
except (TypeError, ValueError):
lines = 400
if not path or not os.path.exists(path):
return Response(
{"file_id": capture.id, "status": capture.status, "error": capture.error_message,
"log": "", "available": False,
"message": "No analysis log exists for this capture yet."},
)
response = Response({
"file_id": capture.id, "status": capture.status, "error": capture.error_message,
"available": True, "path": os.path.basename(path), "log": tail(path, lines),
})
response["Cache-Control"] = "no-store"
return response
class CloudResultsView(APIView):