diff --git a/dashboard/api.py b/dashboard/api.py index 16d11e9..3b5dff1 100644 --- a/dashboard/api.py +++ b/dashboard/api.py @@ -10,7 +10,7 @@ import os import sys from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer from pathlib import Path -from urllib.parse import quote as _urlquote +from urllib.parse import quote as _urlquote, parse_qs, urlparse # Make dashboard/ importable for the handler submodules (constants, # habits_helpers, handlers.*). Tests rely on this as well. @@ -243,11 +243,19 @@ class TaskBoardHandler( return elif self.path in ('/echo/login', '/login') or \ self.path.startswith(('/echo/login?', '/login?')): - # If already logged in, redirect to workspace; otherwise serve - # login.html (created in Lane B2). + # If already logged in, redirect to next (or workspace); otherwise serve login.html. if self._check_dashboard_cookie(): + qs = parse_qs(urlparse(self.path).query) + next_vals = qs.get('next', []) + nxt = next_vals[0] if next_vals else '' + # Proxy strips /echo/ before Python, so nxt is e.g. /workspace.html. + # Re-add the prefix so the browser lands on the right public URL. + if nxt and nxt.startswith('/') and '://' not in nxt: + dest = '/echo' + nxt + else: + dest = '/echo/workspace.html' self.send_response(302) - self.send_header('Location', '/echo/workspace.html') + self.send_header('Location', dest) self.send_header('Content-Length', '0') self.end_headers() return diff --git a/dashboard/login.html b/dashboard/login.html index 46d5d36..b584190 100644 --- a/dashboard/login.html +++ b/dashboard/login.html @@ -257,8 +257,11 @@ // relative /echo/ path to prevent open-redirect attacks. var params = new URLSearchParams(window.location.search); var next = params.get('next') || ''; - var dest = (next && /^\/echo\/[^/]/.test(next) && next.indexOf('/echo/login') !== 0) - ? next + // The proxy strips /echo/ before Python, so `next` is + // e.g. "/workspace.html". Re-add the /echo prefix for + // the browser. Guard against open-redirect (no ://). + var dest = (next && /^\/[^/]/.test(next) && next.indexOf('://') === -1) + ? '/echo' + next : '/echo/workspace.html'; window.location.assign(dest); return;