Release v1.7.15: security hardening, async auth, CSP tightening, model validation, SSRF guard, rate limiting improvements, frontend extraction, Docker compose security
Release / build-and-push (push) Successful in 3m12s

This commit is contained in:
2026-05-28 14:57:09 +02:00
parent fe95dfcfce
commit f7fca05210
18 changed files with 943 additions and 873 deletions
+20 -9
View File
@@ -7,10 +7,18 @@ import structlog
from auth import require_auth
from database import saved_searches_collection
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field
router = APIRouter(dependencies=[Depends(require_auth)])
logger = structlog.get_logger("aoc.saved_searches")
MAX_SAVED_SEARCHES_PER_USER = 50
class SavedSearchCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=200)
filters: dict = Field(default_factory=dict)
def _user_sub(user: dict) -> str:
return user.get("sub", "anonymous")
@@ -29,22 +37,25 @@ async def list_saved_searches(user: dict = Depends(require_auth)):
@router.post("/saved-searches")
async def create_saved_search(body: dict, user: dict = Depends(require_auth)):
async def create_saved_search(body: SavedSearchCreate, user: dict = Depends(require_auth)):
"""Save the current filter set."""
name = (body.get("name") or "").strip()
if not name:
raise HTTPException(status_code=400, detail="Name is required")
sub = _user_sub(user)
existing = saved_searches_collection.count_documents({"created_by": sub})
if existing >= MAX_SAVED_SEARCHES_PER_USER:
raise HTTPException(
status_code=400,
detail=f"Maximum of {MAX_SAVED_SEARCHES_PER_USER} saved searches per user reached.",
)
filters = body.get("filters") or {}
doc = {
"_id": str(uuid.uuid4()),
"name": name,
"filters": filters,
"name": body.name,
"filters": body.filters,
"created_at": datetime.now(UTC).isoformat().replace("+00:00", "Z"),
"created_by": _user_sub(user),
"created_by": sub,
}
saved_searches_collection.insert_one(doc)
logger.info("Saved search created", name=name, user=doc["created_by"])
logger.info("Saved search created", name=body.name, user=sub)
doc["id"] = doc.pop("_id")
return doc