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:
56
server.py
56
server.py
@@ -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=(",", ":"))
|
json_str = json.dumps(data, sort_keys=True, separators=(",", ":"))
|
||||||
return hashlib.sha3_256(json_str.encode()).hexdigest()
|
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 for public access to IPFS content
|
||||||
IPFS_GATEWAY_URL = os.environ.get("IPFS_GATEWAY_URL", "")
|
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>
|
Logged in as <a href="{l2_user_url}" class="text-blue-400 hover:text-blue-300">{actor_id}</a>
|
||||||
</div>'''
|
</div>'''
|
||||||
else:
|
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"""
|
return f"""
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -967,7 +964,7 @@ async def run_detail(run_id: str, request: Request):
|
|||||||
if wants_html(request):
|
if wants_html(request):
|
||||||
ctx = await get_user_context_from_cookie(request)
|
ctx = await get_user_context_from_cookie(request)
|
||||||
if not ctx:
|
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)
|
return HTMLResponse(render_page("Login Required", content, None, active_tab="runs"), status_code=401)
|
||||||
|
|
||||||
# Check user owns this run
|
# 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 wants_html(request):
|
||||||
if not ctx:
|
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"))
|
return HTMLResponse(render_page("Runs", content, None, active_tab="runs"))
|
||||||
|
|
||||||
if not runs_page:
|
if not runs_page:
|
||||||
@@ -1402,7 +1399,7 @@ async def list_recipes_api(request: Request, page: int = 1, limit: int = 20):
|
|||||||
if not ctx:
|
if not ctx:
|
||||||
return HTMLResponse(render_page(
|
return HTMLResponse(render_page(
|
||||||
"Recipes",
|
"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,
|
None,
|
||||||
active_tab="recipes"
|
active_tab="recipes"
|
||||||
))
|
))
|
||||||
@@ -1895,7 +1892,7 @@ async def ui_recipes_list(request: Request):
|
|||||||
ctx = await get_user_context_from_cookie(request)
|
ctx = await get_user_context_from_cookie(request)
|
||||||
|
|
||||||
if not ctx:
|
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()
|
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
|
# Raw data is only served from /cache/{hash}/raw endpoint
|
||||||
if True: # Always show HTML page, raw data via /raw endpoint
|
if True: # Always show HTML page, raw data via /raw endpoint
|
||||||
if not ctx:
|
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)
|
return HTMLResponse(render_page("Login Required", content, None, active_tab="media"), status_code=401)
|
||||||
|
|
||||||
# Check user has access
|
# Check user has access
|
||||||
@@ -2661,7 +2658,7 @@ async def list_media(
|
|||||||
if wants_html(request):
|
if wants_html(request):
|
||||||
# Require login for HTML media view
|
# Require login for HTML media view
|
||||||
if not ctx:
|
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"))
|
return HTMLResponse(render_page("Media", content, None, active_tab="media"))
|
||||||
|
|
||||||
# Get hashes owned by/associated with this user
|
# 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:
|
else:
|
||||||
user_info = '''
|
user_info = '''
|
||||||
<div class="text-sm">
|
<div class="text-sm text-gray-400">
|
||||||
<a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a>
|
Not logged in
|
||||||
</div>
|
</div>
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -3789,8 +3786,8 @@ def render_ui_html(actor_id: Optional[str] = None, tab: str = "runs") -> str:
|
|||||||
'''
|
'''
|
||||||
else:
|
else:
|
||||||
user_info = '''
|
user_info = '''
|
||||||
<div class="text-sm">
|
<div class="text-sm text-gray-400">
|
||||||
<a href="/login" class="text-blue-400 hover:text-blue-300">Login via L2</a>
|
Not logged in
|
||||||
</div>
|
</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
|
# Auth - L1 doesn't handle login (user logs in at their L2 server)
|
||||||
# L2 sets auth_token cookie with domain=.rose-ash.com for shared auth
|
# Shared cookie authenticates across L1 and L2
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/logout")
|
@app.get("/logout")
|
||||||
async def logout():
|
async def logout():
|
||||||
"""Logout - clear cookie and redirect to L2 logout."""
|
"""Logout - clear local cookie and redirect to home."""
|
||||||
# Clear local cookie and redirect to L2 to clear shared cookie
|
response = RedirectResponse(url="/", status_code=302)
|
||||||
response = RedirectResponse(url=f"{DEFAULT_L2_SERVER}/logout?return_to={L1_PUBLIC_URL}/", status_code=302)
|
|
||||||
response.delete_cookie("auth_token")
|
response.delete_cookie("auth_token")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -3965,7 +3943,7 @@ async def ui_runs(request: Request):
|
|||||||
|
|
||||||
# Require login to see runs
|
# Require login to see runs
|
||||||
if not ctx:
|
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)
|
# 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)]
|
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
|
# Require login to see media
|
||||||
if not ctx:
|
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
|
# Get hashes owned by/associated with this user
|
||||||
user_hashes = await get_user_cache_hashes(ctx.username, ctx.actor_id)
|
user_hashes = await get_user_cache_hashes(ctx.username, ctx.actor_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user