diff --git a/Dockerfile b/Dockerfile index 6310d47..a0f5a47 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,7 @@ WORKDIR /app COPY api/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY api/app/ ./app/ +COPY api/static/ ./static/ # <-- Add this line RUN mkdir -p /data EXPOSE 8000 CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/api/app/auth.py b/api/app/auth.py index c8f3109..9ac44b6 100644 --- a/api/app/auth.py +++ b/api/app/auth.py @@ -14,6 +14,8 @@ def get_db(): conn.row_factory = sqlite3.Row return conn +# your-very-long-random-admin-key + def init_db(): conn = get_db() conn.execute(""" diff --git a/api/app/main.py b/api/app/main.py index 4e6dc24..ef83de5 100644 --- a/api/app/main.py +++ b/api/app/main.py @@ -1,23 +1,31 @@ from fastapi import FastAPI, HTTPException, Depends, Header, Query, Request -from fastapi.responses import JSONResponse -from .auth import init_db, verify_api_key, get_db # make sure auth.py exports get_db +from fastapi.responses import JSONResponse, FileResponse +from fastapi.security import HTTPBasic, HTTPBasicCredentials +from .auth import init_db, verify_api_key, get_db from .models import Event, BatchEvents from .enrichment import enrich_event from .influx import write_event, client, INFLUX_ORG, INFLUX_BUCKET import logging import os import secrets -import datetime +import pathlib logging.basicConfig(level=logging.INFO) # Environment variables -ADMIN_API_KEY = os.getenv("ADMIN_API_KEY", "admin-secret-change-me") +ADMIN_USERNAME = os.getenv("ADMIN_USERNAME", "admin") +ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "admin") # change in pod YAML! -# Initialise database (creates table if missing) init_db() - app = FastAPI(title="Signal - Roblox Telemetry") +security = HTTPBasic() + +# ---------- HTTP Basic auth dependency ---------- +def require_admin(credentials: HTTPBasicCredentials = Depends(security)): + if credentials.username != ADMIN_USERNAME or credentials.password != ADMIN_PASSWORD: + raise HTTPException(status_code=401, detail="Invalid credentials", + headers={"WWW-Authenticate": "Basic"}) + return True # ---------- Original endpoints ---------- @app.get("/health") @@ -35,11 +43,12 @@ async def ingest_event(payload: Event | BatchEvents, game: str = Depends(verify_ write_event(enriched) return {"success": True} -# ---------- Admin authentication helper ---------- -def require_admin(x_admin_key: str = Header(None)): - if not x_admin_key or x_admin_key != ADMIN_API_KEY: - raise HTTPException(status_code=403, detail="Forbidden") - return True +# ---------- Serve the admin HTML ---------- +STATIC_DIR = pathlib.Path(__file__).parent.parent / "static" + +@app.get("/admin", include_in_schema=False) +async def admin_page(admin: bool = Depends(require_admin)): + return FileResponse(STATIC_DIR / "index.html") # ---------- Admin: API Keys ---------- @app.get("/admin/keys") diff --git a/api/static/index.html b/api/static/index.html new file mode 100644 index 0000000..5c3a391 --- /dev/null +++ b/api/static/index.html @@ -0,0 +1,142 @@ + + + + + RBXLogger Admin + + + +

RBXLogger Admin

+ + + + +
+ +
+
+
Create new key
+ + +
+ + + +
KeyGameActiveCreatedActions
+
+ + +
+
+ + +
+
+
Delete events
+ + + + +
+ + + +
TimeMeasurementFieldsTags
+
+ + +
+ + + + +
NameID
+
+
+ + + + + \ No newline at end of file