refactor: final-review cleanup

- delete dead magic-link helpers (resolve_token, ensure_project_client,
  mint_link_token, provision_preview_session) + now-unused datetime import
- key brute-force lockout on link_token alone (IP term only enabled a
  source-IP-rotation bypass; behind the proxy all clients share one IP)
- drop unused PORTAL_BASE_URL from the retired CLI
- add WebSocket ownership tests (unauth + cross-project both close 1008)
This commit is contained in:
2026-06-16 00:28:23 +00:00
parent da128f6173
commit 766f64f35f
4 changed files with 47 additions and 72 deletions
+4 -1
View File
@@ -140,7 +140,10 @@ def portal_password_submit(link_token: str, request: Request,
"portal/access_required.html", {"request": request, "reason": "invalid"},
status_code=404)
lock_key = f"{link_token}:{request.client.host if request.client else '?'}"
# Shared per-project password → lock per token. (Keying on IP too only enabled a
# bypass via source-IP rotation, and behind the reverse proxy every client shares
# one IP anyway.)
lock_key = link_token
if is_locked(lock_key):
return templates.TemplateResponse("portal/password.html", {
"request": request, "link_token": link_token, "project_name": project.name,