Spaces:
Sleeping
Sleeping
| """Centralized request input-size limits and lightweight content validation. | |
| These guard against memory-exhaustion DoS (huge uploads / frames / text) and | |
| spoofed file types. Values are conservative defaults; tune as needed. | |
| """ | |
| from __future__ import annotations | |
| from fastapi import HTTPException | |
| # ββ Size limits βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| MIN_AUDIO_BYTES = 1_000 | |
| MAX_AUDIO_BYTES = 25 * 1024 * 1024 # 25 MB | |
| MAX_RESUME_BYTES = 10 * 1024 * 1024 # 10 MB | |
| MAX_DOCUMENT_BYTES = 10 * 1024 * 1024 # 10 MB | |
| MAX_EDITOR_CHARS = 50_000 # ~50 KB of code/text | |
| MAX_WS_FRAME_CHARS = 4 * 1024 * 1024 # ~4 MB base64 webcam frame | |
| MAX_QUERY_CHARS = 1_000 | |
| MAX_JD_CHARS = 20_000 # job-description text for ATS matching | |
| def enforce_max_bytes(data: bytes, limit: int, label: str = "File") -> None: | |
| """Raise 413 if `data` exceeds `limit` bytes.""" | |
| if len(data) > limit: | |
| mb = limit / (1024 * 1024) | |
| raise HTTPException(413, f"{label} too large (max {mb:.0f} MB)") | |
| # ββ Magic-byte sniffing βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def looks_like_pdf(data: bytes) -> bool: | |
| return data[:5] == b"%PDF-" | |
| def looks_like_docx(data: bytes) -> bool: | |
| # DOCX (and any OOXML) is a ZIP archive: "PK\x03\x04" / "PK\x05\x06" (empty). | |
| return data[:2] == b"PK" | |
| def validate_resume_bytes(data: bytes) -> None: | |
| """Validate an uploaded resume actually looks like a PDF or DOCX, not just a | |
| spoofed extension/content-type.""" | |
| if not (looks_like_pdf(data) or looks_like_docx(data)): | |
| raise HTTPException(400, "File content does not match a PDF or DOCX") | |