import os, socket, threading, webbrowser, time import gradio as gr from fastapi import FastAPI, Request from fastapi.responses import RedirectResponse, PlainTextResponse import uvicorn from dotenv import load_dotenv from slowapi import Limiter, _rate_limit_exceeded_handler from slowapi.util import get_remote_address from slowapi.errors import RateLimitExceeded from showcase_ui import build_showcase_app from admin_ui import build_admin_app load_dotenv() HOST = "0.0.0.0" PORT = int(os.getenv("PORT", 7860)) ADMIN_USER = os.getenv("ADMIN_USER", "admin") ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "admin") # ── RATE LIMITER ────────────────────────────────────────────────────── limiter = Limiter(key_func=get_remote_address, default_limits=["60/minute"]) # ── ДОДАТКИ ─────────────────────────────────────────────────────────── app_showcase = build_showcase_app() app_admin = build_admin_app() # ── FASTAPI ─────────────────────────────────────────────────────────── app = FastAPI() app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) BLOCKED_PATHS = ( "/config.json", "/.env", "/utils.py", "/main.py", "/admin_ui.py", "/showcase_ui.py", "/queue/", "/upload", "/.git", "/static/../", ) @app.middleware("http") async def security_middleware(request: Request, call_next): path = request.url.path.lower() for blocked in BLOCKED_PATHS: if path.startswith(blocked): return PlainTextResponse("404 Not Found", status_code=404) if ".." in path or "%2e" in path or "%2f" in path: return PlainTextResponse("400 Bad Request", status_code=400) ua = request.headers.get("user-agent", "").lower() bad_agents = ("sqlmap", "nikto", "nmap", "masscan", "zgrab") if any(b in ua for b in bad_agents): return PlainTextResponse("403 Forbidden", status_code=403) response = await call_next(request) response.headers["X-Content-Type-Options"] = "nosniff" response.headers["X-Frame-Options"] = "SAMEORIGIN" response.headers["X-XSS-Protection"] = "1; mode=block" response.headers["Referrer-Policy"] = "no-referrer" return response @app.get("/figvam") def redirect_admin(): return RedirectResponse(url="/figvam/") app = gr.mount_gradio_app(app, app_admin, path="/figvam", auth=(ADMIN_USER, ADMIN_PASSWORD), auth_message="Unstop Admin") app = gr.mount_gradio_app(app, app_showcase, path="/") # ── ЛОКАЛЬНИЙ ЗАПУСК ────────────────────────────────────────────────── def wait_and_open(): for _ in range(40): try: with socket.create_connection(("localhost", PORT), timeout=1): webbrowser.open(f"http://localhost:{PORT}") return except OSError: time.sleep(0.5) if __name__ == "__main__": threading.Thread(target=wait_and_open, daemon=True).start() uvicorn.run(app, host=HOST, port=PORT, log_level="warning")