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 websockets.typing import Subprotocol
from fastapi import FastAPI, HTTPException, WebSocket from fastapi import FastAPI, HTTPException, WebSocket
from fastapi.responses import HTMLResponse, JSONResponse as FastJSONResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel from pydantic import BaseModel
@@ -465,6 +466,34 @@ async def terminal_ws_proxy(websocket: WebSocket) -> None:
pass 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) # 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) response = c.get("/health", follow_redirects=False)
# Should be redirected to /login or get 307/401 # Should be redirected to /login or get 307/401
assert response.status_code in (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")