login: honour next on both exits, same-origin only
The console's 401 redirect carries next=/leaders/ and /login dropped it, so a leader arriving cold landed on /account. next now rides the form as a hidden field and is applied after a successful POST and when an already-signed-in person hits /login. identity.safe_next() admits only a relative path with a single leading slash - no scheme, no //, no backslash, no control characters - so the login page cannot become an open redirect. Ten checks added to tests/smoke_identity.py; the suite is 59 + 24 + 53, all green.
This commit is contained in:
@@ -606,6 +606,20 @@ def consume_invite(token, full_name, password, preferred_name=None, phone=None,
|
||||
# Rows, not signed cookies. A leader stepping down has to be revocable now
|
||||
# rather than at token expiry, and "sign out everywhere" has to be possible.
|
||||
|
||||
def safe_next(value, default="/account"):
|
||||
"""Where to send someone after login. Only a same-origin relative path
|
||||
survives: a single leading slash, no scheme, no protocol-relative `//`,
|
||||
no backslash or control character that a browser might normalise into
|
||||
one. Anything else falls back to default. This is what keeps /login from
|
||||
being an open redirect the moment it starts honouring `next`."""
|
||||
v = (value or "").strip()
|
||||
if not v.startswith("/") or v.startswith("//") or v.startswith("/\\"):
|
||||
return default
|
||||
if any(ord(c) < 32 or c in "\\" for c in v):
|
||||
return default
|
||||
return v
|
||||
|
||||
|
||||
def start_session(person_id, ip=None, user_agent=None):
|
||||
tok = secrets.token_urlsafe(32)
|
||||
con = connect()
|
||||
|
||||
Reference in New Issue
Block a user