feat: add /login stub and /auth/mode endpoint

This commit is contained in:
Brian Krabach
2026-03-28 21:53:00 -07:00
parent 88b21832f7
commit ba7101292c
2 changed files with 51 additions and 0 deletions
+29
View File
@@ -22,6 +22,7 @@ import websockets.exceptions
from websockets.typing import Subprotocol
from fastapi import FastAPI, HTTPException, WebSocket
from fastapi.responses import HTMLResponse, JSONResponse as FastJSONResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
@@ -465,6 +466,34 @@ async def terminal_ws_proxy(websocket: WebSocket) -> None:
pass
# ---------------------------------------------------------------------------
# Auth routes
# ---------------------------------------------------------------------------
@app.get("/login", response_class=HTMLResponse)
async def login_page():
"""Stub login page — replaced in Phase 2 with branded login.html."""
return HTMLResponse(
"<html><body>"
"<h1>muxplex login</h1>"
"<form method='POST' action='/login'>"
"<input name='password' type='password' placeholder='Password' autocomplete='current-password'>"
"<button type='submit'>Login</button>"
"</form>"
"</body></html>"
)
@app.get("/auth/mode")
async def auth_mode_endpoint():
"""Return the current auth mode and running username."""
username = ""
if _auth_mode == "pam":
username = pwd.getpwuid(os.getuid()).pw_name
return {"mode": _auth_mode, "user": username}
# ---------------------------------------------------------------------------
# Static file serving — MUST come after all API routes (first-match-wins)
# ---------------------------------------------------------------------------
+22
View File
@@ -683,3 +683,25 @@ def test_non_localhost_without_auth_gets_redirected(monkeypatch):
response = c.get("/health", follow_redirects=False)
# Should be redirected to /login or get 307/401
assert response.status_code in (307, 401)
# ---------------------------------------------------------------------------
# Login stub and auth mode endpoint
# ---------------------------------------------------------------------------
def test_get_login_returns_200_html(client):
"""GET /login returns 200 with HTML content."""
response = client.get("/login")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
assert "<form" in response.text
def test_get_auth_mode_returns_json(client):
"""GET /auth/mode returns JSON with mode field."""
response = client.get("/auth/mode")
assert response.status_code == 200
data = response.json()
assert "mode" in data
assert data["mode"] in ("pam", "password")