v1.0.176: spec_current cascade fix + keep_ids DoS limit
This commit is contained in:
@@ -163,7 +163,11 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
doc_id = parsed.path.split("/")[-1]
|
doc_id = parsed.path.split("/")[-1]
|
||||||
supps = query("SELECT id, contract_id FROM supplements WHERE document_id = %s", (doc_id,))
|
supps = query("SELECT id, contract_id FROM supplements WHERE document_id = %s", (doc_id,))
|
||||||
for s in (supps or []):
|
for s in (supps or []):
|
||||||
execute("DELETE FROM spec_current WHERE contract_id = %s", (s["contract_id"],))
|
execute(
|
||||||
|
"""DELETE FROM spec_current WHERE contract_id = %s
|
||||||
|
AND last_event_id IN (SELECT id FROM spec_events WHERE supplement_id = %s)""",
|
||||||
|
(s["contract_id"], s["id"]),
|
||||||
|
)
|
||||||
execute("DELETE FROM spec_events WHERE supplement_id = %s", (s["id"],))
|
execute("DELETE FROM spec_events WHERE supplement_id = %s", (s["id"],))
|
||||||
execute("DELETE FROM supplements WHERE id = %s", (s["id"],))
|
execute("DELETE FROM supplements WHERE id = %s", (s["id"],))
|
||||||
execute("DELETE FROM documents WHERE id = %s", (doc_id,))
|
execute("DELETE FROM documents WHERE id = %s", (doc_id,))
|
||||||
@@ -177,6 +181,10 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
length = int(self.headers.get("Content-Length", 0))
|
length = int(self.headers.get("Content-Length", 0))
|
||||||
body = json.loads(self.rfile.read(length)) if length > 0 else {}
|
body = json.loads(self.rfile.read(length)) if length > 0 else {}
|
||||||
keep_ids = set(body.get("keep_ids", []))
|
keep_ids = set(body.get("keep_ids", []))
|
||||||
|
# Prevent DoS: too many IDs
|
||||||
|
if len(keep_ids) > 1000:
|
||||||
|
self._json({"ok": False, "error": "too many keep_ids (max 1000)"}, 400)
|
||||||
|
return
|
||||||
docs = query("SELECT id FROM documents", ())
|
docs = query("SELECT id FROM documents", ())
|
||||||
deleted = 0
|
deleted = 0
|
||||||
for d in (docs or []):
|
for d in (docs or []):
|
||||||
@@ -184,7 +192,11 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
continue
|
continue
|
||||||
supps = query("SELECT id, contract_id FROM supplements WHERE document_id = %s", (d["id"],))
|
supps = query("SELECT id, contract_id FROM supplements WHERE document_id = %s", (d["id"],))
|
||||||
for s in (supps or []):
|
for s in (supps or []):
|
||||||
execute("DELETE FROM spec_current WHERE contract_id = %s", (s["contract_id"],))
|
execute(
|
||||||
|
"""DELETE FROM spec_current WHERE contract_id = %s
|
||||||
|
AND last_event_id IN (SELECT id FROM spec_events WHERE supplement_id = %s)""",
|
||||||
|
(s["contract_id"], s["id"]),
|
||||||
|
)
|
||||||
execute("DELETE FROM spec_events WHERE supplement_id = %s", (s["id"],))
|
execute("DELETE FROM spec_events WHERE supplement_id = %s", (s["id"],))
|
||||||
execute("DELETE FROM supplements WHERE id = %s", (s["id"],))
|
execute("DELETE FROM supplements WHERE id = %s", (s["id"],))
|
||||||
execute("DELETE FROM documents WHERE id = %s", (d["id"],))
|
execute("DELETE FROM documents WHERE id = %s", (d["id"],))
|
||||||
|
|||||||
@@ -28,17 +28,24 @@ def get(supp_id):
|
|||||||
|
|
||||||
|
|
||||||
def delete_by_document(contract_id, filename):
|
def delete_by_document(contract_id, filename):
|
||||||
"""Delete supplement+document by contract+filename (cascade: spec_events first)."""
|
"""Delete ALL supplements+documents by contract+filename (cascade: spec_events first).
|
||||||
row = query(
|
Handles duplicates from previously failed uploads."""
|
||||||
|
rows = query(
|
||||||
"""SELECT s.id as sid, s.document_id FROM supplements s
|
"""SELECT s.id as sid, s.document_id FROM supplements s
|
||||||
JOIN documents d ON d.id = s.document_id
|
JOIN documents d ON d.id = s.document_id
|
||||||
WHERE s.contract_id = %s AND d.filename = %s""",
|
WHERE s.contract_id = %s AND d.filename = %s""",
|
||||||
(contract_id, filename),
|
(contract_id, filename),
|
||||||
)
|
)
|
||||||
if row:
|
if not rows:
|
||||||
r = row[0]
|
return False
|
||||||
# 1. Delete spec_current for this contract (FK to spec_events)
|
|
||||||
execute("DELETE FROM spec_current WHERE contract_id = %s", (contract_id,))
|
for r in rows:
|
||||||
|
# 1. Delete spec_current rows referencing this supplement's events
|
||||||
|
execute(
|
||||||
|
"""DELETE FROM spec_current WHERE contract_id = %s
|
||||||
|
AND last_event_id IN (SELECT id FROM spec_events WHERE supplement_id = %s)""",
|
||||||
|
(contract_id, r["sid"]),
|
||||||
|
)
|
||||||
# 2. Delete spec_events referencing this supplement
|
# 2. Delete spec_events referencing this supplement
|
||||||
execute("DELETE FROM spec_events WHERE supplement_id = %s", (r["sid"],))
|
execute("DELETE FROM spec_events WHERE supplement_id = %s", (r["sid"],))
|
||||||
# 3. Delete supplement
|
# 3. Delete supplement
|
||||||
@@ -46,7 +53,6 @@ def delete_by_document(contract_id, filename):
|
|||||||
# 4. Delete document
|
# 4. Delete document
|
||||||
execute("DELETE FROM documents WHERE id = %s", (r["document_id"],))
|
execute("DELETE FROM documents WHERE id = %s", (r["document_id"],))
|
||||||
return True
|
return True
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def delete(supp_id):
|
def delete(supp_id):
|
||||||
|
|||||||
Reference in New Issue
Block a user