64 lines
2.2 KiB
Python
64 lines
2.2 KiB
Python
"""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>")
|