Security Improvements (P0.0-P0.4): - P0.0: Migrate to Gemini-only AI stack (simplified, single billing) - P0.1: Fix CORS to restrict allowed origins from env (was *) - P0.2: Remove hardcoded dev password, require env var - P0.3: Add rate limiting (slowapi) - 3-10 req/min on sensitive endpoints - P0.4: Add request size limits (100MB default via middleware) New Features: - Unified LLM service with Google Gemini priority - OXML geometry extractor for layout parsing - TSX validator for generated React components - Client ID support in presentation requests with access control - Configurable LLM/image timeouts via env vars Modern Design System (P0.9 - partial): - Enhanced CSS design tokens (primary, semantic colors, shadows) - Typography scale (h1-h4, body variants, caption) - Modern animations (fadeIn, slideIn, scaleIn) - Updated Button component with better variants and hover effects - Created unified Card and StatusBadge components - Applied design system to Dashboard and Settings pages Backend Improvements: - Master deck parser simplification - Slide-to-HTML endpoint cleanup (325 lines removed) - Better error handling in prompts endpoint Frontend Improvements: - Settings UI simplified to show only Google/Gemini - Dashboard uses CSS variables instead of hardcoded colors - Improved button transitions and hover states Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
38 lines
1.4 KiB
Python
38 lines
1.4 KiB
Python
"""
|
|
Request size limit middleware.
|
|
|
|
Rejects requests with Content-Length exceeding the configured maximum size.
|
|
Prevents memory exhaustion from uploading huge files.
|
|
"""
|
|
|
|
from fastapi import Request
|
|
from fastapi.responses import JSONResponse
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
|
|
|
|
class RequestSizeLimitMiddleware(BaseHTTPMiddleware):
|
|
"""Middleware to limit request body size."""
|
|
|
|
def __init__(self, app, max_size: int = 100 * 1024 * 1024): # 100MB default
|
|
super().__init__(app)
|
|
self.max_size = max_size
|
|
|
|
async def dispatch(self, request: Request, call_next):
|
|
"""Check Content-Length header and reject if too large."""
|
|
if request.method in ["POST", "PUT", "PATCH"]:
|
|
content_length = request.headers.get("content-length")
|
|
if content_length:
|
|
try:
|
|
size = int(content_length)
|
|
if size > self.max_size:
|
|
return JSONResponse(
|
|
status_code=413,
|
|
content={
|
|
"detail": f"Request body too large. Maximum size: {self.max_size / (1024 * 1024):.0f}MB"
|
|
},
|
|
)
|
|
except ValueError:
|
|
# Invalid Content-Length header, let the request proceed
|
|
pass
|
|
|
|
return await call_next(request)
|