Initial scaffold: FastAPI server, responsive UI shell
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"""Hermes Command Center - FastAPI backend."""
|
||||
|
||||
import os
|
||||
import base64
|
||||
import secrets
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, Request, Response
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
|
||||
# ── Auth ──────────────────────────────────────────────────────────────
|
||||
DASHBOARD_USER = os.environ.get("DASHBOARD_USER", "shawn")
|
||||
DASHBOARD_PASS = os.environ.get("DASHBOARD_PASS", "Brett85!@")
|
||||
|
||||
|
||||
def _check_auth(auth_header: str | None) -> bool:
|
||||
if not auth_header:
|
||||
return False
|
||||
try:
|
||||
decoded = base64.b64decode(auth_header.removeprefix("Basic ")).decode()
|
||||
user, _, passwd = decoded.partition(":")
|
||||
return secrets.compare_digest(user, DASHBOARD_USER) and secrets.compare_digest(passwd, DASHBOARD_PASS)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
_unauthorized = Response(
|
||||
content="<html><body><h1>401 Unauthorized</h1></body></html>",
|
||||
status_code=401,
|
||||
headers={"WWW-Authenticate": 'Basic realm="Command Center"'},
|
||||
)
|
||||
|
||||
app = FastAPI(title="Hermes Command Center")
|
||||
|
||||
STATIC_DIR = Path(__file__).parent / "static"
|
||||
|
||||
|
||||
@app.middleware("http")
|
||||
async def auth_middleware(request: Request, call_next):
|
||||
if request.url.path in ("/health", "/api/health"):
|
||||
return await call_next(request)
|
||||
if not _check_auth(request.headers.get("Authorization")):
|
||||
return _unauthorized
|
||||
return await call_next(request)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
return {"status": "ok", "service": "hermes-command-center"}
|
||||
|
||||
|
||||
# ── Serve frontend ────────────────────────────────────────────────────
|
||||
if STATIC_DIR.exists():
|
||||
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
|
||||
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def index():
|
||||
index_path = STATIC_DIR / "index.html"
|
||||
if index_path.exists():
|
||||
return HTMLResponse(content=index_path.read_text())
|
||||
return HTMLResponse(content="<h1>Command Center - Loading...</h1>")
|
||||
Reference in New Issue
Block a user