"""Module entrypoint for SupraDashboard.""" from __future__ import annotations import os # gradio launch() self-checks reachability with `networking.url_ok(self.local_url)`, # where local_url is http://0.0.0.0:7860/ because we bind server_name="0.0.0.0" (required # so HF's router can reach the container). httpx.head() to 0.0.0.0 is not connectable from # inside the container, so url_ok returns False and launch() raises "When localhost is not # accessible…", crashing startup. The server itself binds and serves fine — only this # non-essential pre-flight fails — so we neutralize it (and exempt loopback from the proxy). for _k in ("NO_PROXY", "no_proxy"): _cur = os.environ.get(_k, "") _need = "localhost,127.0.0.1,0.0.0.0" os.environ[_k] = f"{_cur},{_need}" if _cur else _need import gradio.networking # noqa: E402 gradio.networking.url_ok = lambda url: True # HF binds 0.0.0.0; the self-check is moot here from ui.app import _auth, build_ui # noqa: E402 — after the launch self-check patch # Gradio's built-in login page is served BEFORE our app theme/CSS load, so it falls back to # the browser's dark mode (black card, invisible username/password text). `auth_message` is # injected as raw HTML on that page — use it to force a light color-scheme and readable inputs # matching the bone-white app theme. _LOGIN_MESSAGE = """
SupraDashboard · Host-Guest Review
""" def _build_app(): """Mount the Gradio app on a FastAPI app fronted by a brute-force guard: a per-IP failed-login lockout on the /login endpoint (Gradio's built-in auth has no rate limiting, so a public Space is otherwise brute-forceable).""" import time from collections import defaultdict import gradio as gr from fastapi import FastAPI, Request from starlette.responses import PlainTextResponse # Tunable via Space variables; defaults: 5 fails / 5 min window -> 15 min lock. max_fails = int(os.environ.get("LOGIN_MAX_FAILS", "5")) window = int(os.environ.get("LOGIN_FAIL_WINDOW", "300")) lockout = int(os.environ.get("LOGIN_LOCKOUT", "900")) fails: dict[str, list[float]] = defaultdict(list) locked: dict[str, float] = {} def client_ip(request: Request) -> str: # HF's router proxies the container, so the real client IP is the first # entry of X-Forwarded-For; fall back to the socket peer locally. xff = request.headers.get("x-forwarded-for") if xff: return xff.split(",")[0].strip() return request.client.host if request.client else "unknown" app = FastAPI() @app.middleware("http") async def login_guard(request: Request, call_next): is_login = request.method == "POST" and request.url.path.rstrip("/").endswith("/login") if not is_login: return await call_next(request) ip = client_ip(request) now = time.time() until = locked.get(ip, 0.0) if until > now: return PlainTextResponse( f"Too many failed login attempts. Try again in {int(until - now)}s.", status_code=429, ) resp = await call_next(request) if resp.status_code >= 400: # Gradio returns 400 on bad credentials recent = [t for t in fails[ip] if now - t < window] recent.append(now) fails[ip] = recent if len(recent) >= max_fails: locked[ip] = now + lockout fails[ip] = [] else: # successful login clears the IP's record fails.pop(ip, None) locked.pop(ip, None) return resp demo = build_ui().queue(default_concurrency_limit=1, api_open=False) return gr.mount_gradio_app( app, demo, path="/", auth=_auth(), auth_message=_LOGIN_MESSAGE, ) if __name__ == "__main__": import uvicorn uvicorn.run(_build_app(), host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))