analyze performance upgrade
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user