System15 / backend /main.py
yamilogic's picture
Fix SMTP port timeout for Hugging Face Spaces
bc81b4c
Raw
History Blame Contribute Delete
3.49 kB
import time
import os
from datetime import datetime
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, HTMLResponse
from fastapi.staticfiles import StaticFiles
from database import engine, Base
from routes import auth_routes, user_routes
Base.metadata.create_all(bind=engine)
app = FastAPI(
title="SMTP-Enabled Authentication System",
description="A beginner-friendly secure authentication system with modular routes and email verification.",
version="1.0.0"
)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173", "http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ─── SIMPLE RATE LIMITING & REQUEST LOGGING ───
RATE_LIMIT_WINDOW = 60
RATE_LIMIT_MAX = 60
client_requests = {}
@app.middleware("http")
async def rate_limiting_and_logging_middleware(request: Request, call_next):
client_ip = request.client.host if request.client else "unknown"
now = time.time()
if client_ip not in client_requests:
client_requests[client_ip] = []
client_requests[client_ip] = [t for t in client_requests[client_ip] if now - t < RATE_LIMIT_WINDOW]
if len(client_requests[client_ip]) >= RATE_LIMIT_MAX:
return JSONResponse(
status_code=429,
content={"detail": "Too many requests. Please slow down and try again in a minute."}
)
client_requests[client_ip].append(now)
start_time = time.time()
try:
response = await call_next(request)
except Exception as exc:
log_line = f"{datetime.utcnow().isoformat()} - {client_ip} - {request.method} {request.url.path} - ERROR: {str(exc)}\n"
with open("requests.log", "a") as log_file:
log_file.write(log_line)
return JSONResponse(
status_code=500,
content={"detail": "An internal server error occurred. Please contact the administrator."}
)
duration = time.time() - start_time
log_line = (
f"{datetime.utcnow().isoformat()} - IP: {client_ip} - "
f"{request.method} {request.url.path} - Status: {response.status_code} - "
f"Took: {duration:.4f}s\n"
)
with open("requests.log", "a") as log_file:
log_file.write(log_line)
return response
app.include_router(auth_routes.router)
app.include_router(user_routes.router)
@app.get("/api")
def home():
return {
"status": "online",
"message": "Welcome to the SMTP Auth API! Go to /docs to test all endpoints."
}
# ─── SERVE FRONTEND STATIC FILES (HF Spaces & Production) ───
if os.path.exists("static"):
app.mount("/", StaticFiles(directory="static", html=True), name="static")
# ─── SPA FALLBACK HANDLER (Serves React Router paths on direct visits/refreshes) ───
@app.exception_handler(404)
async def spa_fallback_404_handler(request: Request, exc: Exception):
# If the request is not an API call, serve the frontend index.html
path = request.url.path
if not path.startswith("/auth") and not path.startswith("/admin") and path != "/api":
if os.path.exists("static/index.html"):
with open("static/index.html", "r") as f:
return HTMLResponse(content=f.read(), status_code=200)
return JSONResponse(status_code=404, content={"detail": "Not Found"})