Remove login links from L1 - L1 doesn't know where L2 is

L1 can't redirect users to login because it doesn't know which L2
server they use. Users must log in directly at their L2 server,
and the shared cookie will authenticate them on L1.

- Replace "Log in" links with "Not logged in" text
- Remove /login and /register routes
- Keep /logout to just clear cookie and redirect home
- Remove unused DEFAULT_L2_SERVER config

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-09 16:52:32 +00:00
parent 780c223714
commit 304f3ad56f

View File

@@ -66,9 +66,6 @@ def compute_run_id(input_hashes: list[str], recipe: str, recipe_hash: str = None
json_str = json.dumps(data, sort_keys=True, separators=(",", ":"))
return hashlib.sha3_256(json_str.encode()).hexdigest()
# Default L2 for login redirect when not logged in (user can login to any L2)
DEFAULT_L2_SERVER = os.environ.get("DEFAULT_L2_SERVER", "http://localhost:8200")
# IPFS gateway URL for public access to IPFS content
IPFS_GATEWAY_URL = os.environ.get("IPFS_GATEWAY_URL", "")
@@ -526,7 +523,7 @@ def render_home_html(actor_id: Optional[str] = None) -> str:
Logged in as <a href="{l2_user_url}" class="text-blue-400 hover:text-blue-300">{actor_id}</a>
</div>'''
else:
user_section = '''<a href="/login" class="ml-auto px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-md text-white font-medium transition-colors">Login via L2</a>'''
user_section = '''<span class="ml-auto text-sm text-gray-400">Not logged in</span>'''
return f"""
<!DOCTYPE html>
@@ -967,7 +964,7 @@ async def run_detail(run_id: str, request: Request):
if wants_html(request):
ctx = await get_user_context_from_cookie(request)
if not ctx:
content = '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to view run details.</p>'
content = '<p class="text-gray-400 py-8 text-center">Not logged in.</p>'
return HTMLResponse(render_page("Login Required", content, None, active_tab="runs"), status_code=401)
# Check user owns this run
@@ -1219,7 +1216,7 @@ async def list_runs(request: Request, page: int = 1, limit: int = 20):
if wants_html(request):
if not ctx:
content = '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see your runs.</p>'
content = '<p class="text-gray-400 py-8 text-center">Not logged in.</p>'
return HTMLResponse(render_page("Runs", content, None, active_tab="runs"))
if not runs_page:
@@ -1402,7 +1399,7 @@ async def list_recipes_api(request: Request, page: int = 1, limit: int = 20):
if not ctx:
return HTMLResponse(render_page(
"Recipes",
'<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see recipes.</p>',
'<p class="text-gray-400 py-8 text-center">Not logged in.</p>',
None,
active_tab="recipes"
))
@@ -1895,7 +1892,7 @@ async def ui_recipes_list(request: Request):
ctx = await get_user_context_from_cookie(request)
if not ctx:
return '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see recipes.</p>'
return '<p class="text-gray-400 py-8 text-center">Not logged in.</p>'
all_recipes = list_all_recipes()
@@ -2019,7 +2016,7 @@ async def get_cached(content_hash: str, request: Request):
# Raw data is only served from /cache/{hash}/raw endpoint
if True: # Always show HTML page, raw data via /raw endpoint
if not ctx:
content = '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to view cached content.</p>'
content = '<p class="text-gray-400 py-8 text-center">Not logged in.</p>'
return HTMLResponse(render_page("Login Required", content, None, active_tab="media"), status_code=401)
# Check user has access
@@ -2661,7 +2658,7 @@ async def list_media(
if wants_html(request):
# Require login for HTML media view
if not ctx:
content = '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see media.</p>'
content = '<p class="text-gray-400 py-8 text-center">Not logged in.</p>'
return HTMLResponse(render_page("Media", content, None, active_tab="media"))
# Get hashes owned by/associated with this user
@@ -3727,8 +3724,8 @@ def render_page(title: str, content: str, actor_id: Optional[str] = None, active
'''
else:
user_info = '''
<div class="text-sm">
<a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a>
<div class="text-sm text-gray-400">
Not logged in
</div>
'''
@@ -3789,8 +3786,8 @@ def render_ui_html(actor_id: Optional[str] = None, tab: str = "runs") -> str:
'''
else:
user_info = '''
<div class="text-sm">
<a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a>
<div class="text-sm text-gray-400">
Not logged in
</div>
'''
@@ -3841,32 +3838,13 @@ def render_ui_html(actor_id: Optional[str] = None, tab: str = "runs") -> str:
"""
# Auth routes - L1 never handles credentials, redirects to L2
# L2 sets auth_token cookie with domain=.rose-ash.com for shared auth
L1_PUBLIC_URL = os.environ.get("L1_PUBLIC_URL", "http://localhost:8100")
@app.get("/login")
async def login_page():
"""Redirect to L2 server for login. L1 never handles credentials."""
# Redirect to default L2 with return URL so L2 can redirect back after login
return_url = f"{L1_PUBLIC_URL}/runs"
return RedirectResponse(url=f"{DEFAULT_L2_SERVER}/login?return_to={return_url}", status_code=302)
@app.get("/register")
async def register_page():
"""Redirect to L2 server for registration. L1 never handles credentials."""
return_url = f"{L1_PUBLIC_URL}/runs"
return RedirectResponse(url=f"{DEFAULT_L2_SERVER}/register?return_to={return_url}", status_code=302)
# Auth - L1 doesn't handle login (user logs in at their L2 server)
# Shared cookie authenticates across L1 and L2
@app.get("/logout")
async def logout():
"""Logout - clear cookie and redirect to L2 logout."""
# Clear local cookie and redirect to L2 to clear shared cookie
response = RedirectResponse(url=f"{DEFAULT_L2_SERVER}/logout?return_to={L1_PUBLIC_URL}/", status_code=302)
"""Logout - clear local cookie and redirect to home."""
response = RedirectResponse(url="/", status_code=302)
response.delete_cookie("auth_token")
return response
@@ -3965,7 +3943,7 @@ async def ui_runs(request: Request):
# Require login to see runs
if not ctx:
return '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see your runs.</p>'
return '<p class="text-gray-400 py-8 text-center">Not logged in.</p>'
# Filter runs by user - match both plain username and ActivityPub format (@user@domain)
runs = [r for r in runs if r.username in (ctx.username, ctx.actor_id)]
@@ -4064,7 +4042,7 @@ async def ui_media_list(
# Require login to see media
if not ctx:
return '<p class="text-gray-400 py-8 text-center"><a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a> to see media.</p>'
return '<p class="text-gray-400 py-8 text-center">Not logged in.</p>'
# Get hashes owned by/associated with this user
user_hashes = await get_user_cache_hashes(ctx.username, ctx.actor_id)