Files
stl-repo/app/main.py
Consultoria AS 7a66cc1d6e fix: CSP permisivo para evitar bloqueos en navegador
- Relajado Content-Security-Policy para permitir CDN e iframes
- Eliminado X-Frame-Options que podia bloquear extensiones
- Verificado: no hay iframes en el frontend
2026-04-28 04:51:29 +00:00

73 lines
2.4 KiB
Python

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from app.database import engine, Base
from app.routers import models
from app.migrate import run_migrations
import os
# Create tables and run migrations
Base.metadata.create_all(bind=engine)
run_migrations()
app = FastAPI(title="PrintForge", version="2.2.0")
# CORS — allow production domain and local development
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://3d.consultoria-as.com",
"http://localhost:8000",
"http://127.0.0.1:8000",
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Security headers middleware
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
# Permissive CSP: allow same-origin, CDN scripts, inline styles, images from anywhere
response.headers["Content-Security-Policy"] = (
"default-src * 'self' data: blob: 'unsafe-inline' 'unsafe-eval'; "
"script-src * 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.tailwindcss.com https://cdnjs.cloudflare.com https://cdn.jsdelivr.net; "
"style-src * 'self' 'unsafe-inline'; "
"img-src * 'self' data: blob:; "
"font-src * 'self' data:; "
"connect-src * 'self';"
)
return response
app.add_middleware(SecurityHeadersMiddleware)
app.include_router(models.router)
# Serve static files
app.mount("/static", StaticFiles(directory="static"), name="static")
# Serve uploads, thumbnails and images directly
app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads")
app.mount("/thumbnails", StaticFiles(directory="thumbnails"), name="thumbnails")
app.mount("/images", StaticFiles(directory="images"), name="images")
@app.get("/")
def root():
return FileResponse("static/index.html")
@app.get("/upload")
def upload_page():
return FileResponse("static/upload.html")
@app.get("/model/{model_id}")
def detail_page(model_id: int):
return FileResponse("static/detail.html")