File size: 1,926 Bytes
ecb9f70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"""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")