| 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=["*"], |
| ) |
|
|
| |
|
|
| 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." |
| } |
|
|
| |
| if os.path.exists("static"): |
| app.mount("/", StaticFiles(directory="static", html=True), name="static") |
|
|
| |
| @app.exception_handler(404) |
| async def spa_fallback_404_handler(request: Request, exc: Exception): |
| |
| 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"}) |
|
|
|
|
|
|