diff --git a/server.py b/server.py index 7605e11..fa35911 100644 --- a/server.py +++ b/server.py @@ -2940,9 +2940,11 @@ def render_page(title: str, content: str, username: Optional[str] = None, active """Render a page with nav bar and content. Used for clean URL pages.""" user_info = "" if username: + # Display as @user@server format + actor_id = f"@{username}@{L2_DOMAIN}" if not username.startswith("@") else username user_info = f'''
- Logged in as {username} + Logged in as {actor_id} Logout
''' @@ -2994,29 +2996,31 @@ def render_ui_html(username: Optional[str] = None, tab: str = "runs") -> str: """Render main UI HTML with optional user context.""" user_info = "" if username: + # Display as @user@server format + actor_id = f"@{username}@{L2_DOMAIN}" if not username.startswith("@") else username user_info = f'''
- Logged in as {username} - Logout + Logged in as {actor_id} + Logout
''' else: user_info = '''
- Login + Login
''' runs_active = "border-b-2 border-blue-500 text-white" if tab == "runs" else "text-gray-400 hover:text-white" recipes_active = "border-b-2 border-blue-500 text-white" if tab == "recipes" else "text-gray-400 hover:text-white" - cache_active = "border-b-2 border-blue-500 text-white" if tab == "cache" else "text-gray-400 hover:text-white" + media_active = "border-b-2 border-blue-500 text-white" if tab == "media" else "text-gray-400 hover:text-white" if tab == "runs": content_url = "/ui/runs" elif tab == "recipes": content_url = "/ui/recipes-list" else: - content_url = "/ui/cache-list" + content_url = "/ui/media-list" return f""" @@ -3031,15 +3035,15 @@ def render_ui_html(username: Optional[str] = None, tab: str = "runs") -> str:

- Art DAG L1 Server + Art DAG L1 Server

{user_info}
@@ -3053,139 +3057,32 @@ def render_ui_html(username: Optional[str] = None, tab: str = "runs") -> str: """ -def get_auth_page_html(page_type: str = "login", error: str = None) -> str: - """Generate login or register page HTML with Tailwind CSS.""" - is_login = page_type == "login" - title = "Login" if is_login else "Register" +# Auth routes - L1 never handles credentials, redirects to L2 +# L2 sets auth_token cookie with domain=.rose-ash.com for shared auth - login_active = "bg-blue-600 text-white" if is_login else "bg-dark-500 text-gray-400 hover:text-white" - register_active = "bg-dark-500 text-gray-400 hover:text-white" if is_login else "bg-blue-600 text-white" - - error_html = f'
{error}
' if error else '' - - form_fields = ''' - - - ''' - - if not is_login: - form_fields += ''' - - ''' - - return f""" - - - - - - {title} | Art DAG L1 Server - {TAILWIND_CONFIG} - - -
-

- Art DAG L1 Server -

- - - - - - Back - - -
-
- Login - Register -
- - {error_html} - -
- {form_fields} - -
-
-
- - -""" +L1_PUBLIC_URL = os.environ.get("L1_PUBLIC_URL", "http://localhost:8100") -UI_LOGIN_HTML = get_auth_page_html("login") -UI_REGISTER_HTML = get_auth_page_html("register") - - -# Clean URL auth routes -@app.get("/login", response_class=HTMLResponse) +@app.get("/login") async def login_page(): - """Login page (clean URL).""" - return UI_LOGIN_HTML + """Redirect to L2 server for login. L1 never handles credentials.""" + # Redirect to L2 with return URL so L2 can redirect back after login + return_url = f"{L1_PUBLIC_URL}/runs" + return RedirectResponse(url=f"{L2_SERVER}/login?return_to={return_url}", status_code=302) -@app.post("/login") -async def login(username: str = Form(...), password: str = Form(...)): - """Process login form (clean URL).""" - try: - resp = http_requests.post( - f"{L2_SERVER}/auth/login", - json={"username": username, "password": password}, - timeout=5 - ) - if resp.status_code == 200: - token = resp.json().get("access_token") - response = RedirectResponse(url="/runs", status_code=303) - response.set_cookie("auth_token", token, httponly=True, max_age=30*24*60*60) - return response - except Exception: - pass - - return HTMLResponse(get_auth_page_html("login", "Invalid username or password")) - - -@app.get("/register", response_class=HTMLResponse) +@app.get("/register") async def register_page(): - """Register page (clean URL).""" - return UI_REGISTER_HTML - - -@app.post("/register") -async def register( - username: str = Form(...), - password: str = Form(...), - email: str = Form(None) -): - """Process registration form (clean URL).""" - try: - resp = http_requests.post( - f"{L2_SERVER}/auth/register", - json={"username": username, "password": password, "email": email}, - timeout=5 - ) - if resp.status_code == 200: - token = resp.json().get("access_token") - response = RedirectResponse(url="/runs", status_code=303) - response.set_cookie("auth_token", token, httponly=True, max_age=30*24*60*60) - return response - elif resp.status_code == 400: - error = resp.json().get("detail", "Registration failed") - return HTMLResponse(get_auth_page_html("register", error)) - except Exception as e: - return HTMLResponse(get_auth_page_html("register", f"Registration failed: {e}")) + """Redirect to L2 server for registration. L1 never handles credentials.""" + return_url = f"{L1_PUBLIC_URL}/runs" + return RedirectResponse(url=f"{L2_SERVER}/register?return_to={return_url}", status_code=302) @app.get("/logout") async def logout(): - """Logout - clear cookie (clean URL).""" - response = RedirectResponse(url="/runs", status_code=303) + """Logout - clear cookie and redirect to L2 logout.""" + # Clear local cookie and redirect to L2 to clear shared cookie + response = RedirectResponse(url=f"{L2_SERVER}/logout?return_to={L1_PUBLIC_URL}/", status_code=302) response.delete_cookie("auth_token") return response @@ -3194,41 +3091,25 @@ async def logout(): async def ui_index(tab: str = "runs"): """Redirect /ui to clean URLs.""" if tab == "cache": - return RedirectResponse(url="/cache", status_code=302) + return RedirectResponse(url="/media", status_code=302) return RedirectResponse(url="/runs", status_code=302) @app.get("/ui/login") async def ui_login_page(): - """Redirect to clean URL.""" + """Redirect to L2 login.""" return RedirectResponse(url="/login", status_code=302) -@app.post("/ui/login") -async def ui_login(username: str = Form(...), password: str = Form(...)): - """Redirect POST to clean URL handler.""" - return await login(username, password) - - @app.get("/ui/register") async def ui_register_page(): - """Redirect to clean URL.""" + """Redirect to L2 register.""" return RedirectResponse(url="/register", status_code=302) -@app.post("/ui/register") -async def ui_register( - username: str = Form(...), - password: str = Form(...), - email: str = Form(None) -): - """Redirect POST to clean URL handler.""" - return await register(username, password, email) - - @app.get("/ui/logout") async def ui_logout(): - """Redirect to clean URL.""" + """Redirect to logout.""" return RedirectResponse(url="/logout", status_code=302) @@ -3392,19 +3273,19 @@ async def ui_runs(request: Request): return '\n'.join(html_parts) -@app.get("/ui/cache-list", response_class=HTMLResponse) -async def ui_cache_list( +@app.get("/ui/media-list", response_class=HTMLResponse) +async def ui_media_list( request: Request, folder: Optional[str] = None, collection: Optional[str] = None, tag: Optional[str] = None ): - """HTMX partial: list of cached items with optional filtering.""" + """HTMX partial: list of media items with optional filtering.""" current_user = get_user_from_cookie(request) - # Require login to see cache + # Require login to see media if not current_user: - return '

Login to see cached content.

' + return '

Login to see media.

' # Get hashes owned by/associated with this user user_hashes = get_user_cache_hashes(current_user)