fix: audit — json try/except, ZIP-bomb drhider, classify reset only processing
Deploy contracts-flask / validate (push) Successful in 0s
Deploy contracts-flask / validate (push) Successful in 0s
This commit is contained in:
+33
-12
@@ -218,8 +218,7 @@ class Handler(BaseHTTPRequestHandler):
|
||||
def _handle_api_sync(self):
|
||||
"""Удалить ВСЕ документы, НЕ входящие в keep_ids. БД = зеркало таблицы."""
|
||||
from db.connection import execute, query
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
body = json.loads(self.rfile.read(length)) if length > 0 else {}
|
||||
body = self._read_json_body()
|
||||
keep_ids = set(body.get("keep_ids", []))
|
||||
# Prevent DoS: too many IDs
|
||||
if len(keep_ids) > 1000:
|
||||
@@ -283,8 +282,9 @@ class Handler(BaseHTTPRequestHandler):
|
||||
Отдельный процесс — свои коннекты, своя память.
|
||||
HTTP-сервер продолжает отвечать на batch-progress.
|
||||
"""
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
body = json.loads(self.rfile.read(length))
|
||||
body = self._read_json_body()
|
||||
if not body:
|
||||
return
|
||||
batch_id = body.get("batch_id")
|
||||
if not batch_id:
|
||||
self._json({"ok": False, "error": "batch_id required"}, 400)
|
||||
@@ -326,8 +326,9 @@ class Handler(BaseHTTPRequestHandler):
|
||||
# ── POST /apply-groups ───────────────────────────────────────────────
|
||||
|
||||
def _handle_apply_groups(self):
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
body = json.loads(self.rfile.read(length))
|
||||
body = self._read_json_body()
|
||||
if not body:
|
||||
return
|
||||
batch_id = body.get("batch_id")
|
||||
groups = body.get("groups", [])
|
||||
if not batch_id:
|
||||
@@ -392,8 +393,9 @@ class Handler(BaseHTTPRequestHandler):
|
||||
|
||||
def _handle_api_prompts_save(self):
|
||||
from db import prompts as db_p
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
body = json.loads(self.rfile.read(length))
|
||||
body = self._read_json_body()
|
||||
if not body:
|
||||
return
|
||||
role = body.get("role", "")
|
||||
name = body.get("name", "v" + __import__("datetime").datetime.now().isoformat()[:16])
|
||||
prompt_body = body.get("body", "")
|
||||
@@ -407,8 +409,9 @@ class Handler(BaseHTTPRequestHandler):
|
||||
|
||||
def _handle_api_prompts_activate(self):
|
||||
from db import prompts as db_p
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
body = json.loads(self.rfile.read(length))
|
||||
body = self._read_json_body()
|
||||
if not body:
|
||||
return
|
||||
pid = body.get("id", "")
|
||||
if not pid:
|
||||
self._json({"ok": False, "error": "id required"}, 400)
|
||||
@@ -418,8 +421,9 @@ class Handler(BaseHTTPRequestHandler):
|
||||
|
||||
def _handle_api_prompts_delete(self):
|
||||
from db import prompts as db_p
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
body = json.loads(self.rfile.read(length))
|
||||
body = self._read_json_body()
|
||||
if not body:
|
||||
return
|
||||
pid = body.get("id", "")
|
||||
if not pid:
|
||||
self._json({"ok": False, "error": "id required"}, 400)
|
||||
@@ -532,6 +536,23 @@ class Handler(BaseHTTPRequestHandler):
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────
|
||||
|
||||
def _read_json_body(self):
|
||||
"""Безопасное чтение JSON из тела POST-запроса.
|
||||
Возвращает dict или None (если ошибка — уже отправлен 400)."""
|
||||
try:
|
||||
length = int(self.headers.get("Content-Length", 0))
|
||||
except (ValueError, TypeError):
|
||||
self._json({"ok": False, "error": "invalid Content-Length"}, 400)
|
||||
return None
|
||||
if length == 0:
|
||||
return {}
|
||||
try:
|
||||
raw = self.rfile.read(length)
|
||||
return json.loads(raw)
|
||||
except (json.JSONDecodeError, Exception) as e:
|
||||
self._json({"ok": False, "error": f"invalid JSON: {e}"}, 400)
|
||||
return None
|
||||
|
||||
def _json(self, data, status=200):
|
||||
self.send_response(status)
|
||||
self._send_cors()
|
||||
|
||||
Reference in New Issue
Block a user