fix(auth): epoch-check the target on account switch to avoid a full wallet logout (B-core-9)
POST /api/me/switch validated wallet membership, access and suspension but not the target account's session epoch. Switching to an account revoked elsewhere (a password reset/change or "log out everywhere" bumped its epoch) made it the session default, so the next request's current_user hit the epoch mismatch on the default identity and cleared the WHOLE wallet session — logging out every account in the browser. Mirror the suspend guard: drop the stale account from the switch list and return 403 instead of switching.
This commit is contained in:
@@ -72,6 +72,18 @@ def switch_account(
|
|||||||
# Don't make a suspended account the active one — the next request's current_user would
|
# Don't make a suspended account the active one — the next request's current_user would
|
||||||
# see the suspension and clear the WHOLE wallet session, logging out every account here.
|
# see the suspension and clear the WHOLE wallet session, logging out every account here.
|
||||||
raise HTTPException(status_code=403, detail="That account is suspended.")
|
raise HTTPException(status_code=403, detail="That account is suspended.")
|
||||||
|
# Same reasoning for a REVOKED session (a password reset/change or "log out everywhere" bumped the
|
||||||
|
# account's epoch): making it the session default would trip current_user's epoch check on the next
|
||||||
|
# request and clear the whole wallet. Mirror the suspend guard — drop the stale account from the
|
||||||
|
# switch list and refuse, rather than logging everyone out. (B-core-9)
|
||||||
|
epochs = request.session.get("epochs") or {}
|
||||||
|
if int(epochs.get(str(target), 0)) != (u.session_epoch or 0):
|
||||||
|
request.session["account_ids"] = [
|
||||||
|
a for a in (request.session.get("account_ids") or []) if a != target
|
||||||
|
]
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403, detail="That account was signed out elsewhere — sign in again."
|
||||||
|
)
|
||||||
request.session["user_id"] = target
|
request.session["user_id"] = target
|
||||||
return {"ok": True, "user_id": target}
|
return {"ok": True, "user_id": target}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user