fix(auth): a Google connect names its tab's account too, and a refused tab says why
- /auth/google/connect is a navigation and carries no headers: the tab names the account it was built for in `expect`, checked by the same comparison as the request header (built_for_another_account); a mismatch lands on /?account=changed - the link marker names the OAuth state of its own flow: an older flow coming back no longer spends the marker of the connect still open (which then returned as a plain sign-in) - a 401 account_changed reloads the tab with a one-time flag, and the reloaded tab says it now shows the account signed in - a refused switch to a suspended or not-yet-approved account says so in the signed-in app's words, naming the address a request was recorded for - the prefs merge locks FOR NO KEY UPDATE, so a transaction that only added a row referring to the account does not hold the save up; a test pins the lock - giving up a lost page closes a channel page open over it - e2e README names the chromium-only specs
This commit is contained in:
+15
-7
@@ -272,15 +272,23 @@ def stamp_session(request: Request, user: User) -> None:
|
||||
EXPECTED_ACCOUNT_HEADER = "x-siftlode-expect-account"
|
||||
|
||||
|
||||
def built_for_another_account(user_id: int, expected: str | None) -> bool:
|
||||
"""Whether a tab naming `expected` is showing another account than the one signed in. No name is
|
||||
no claim (a caller from before this check, a script): only a mismatch is refused, and the
|
||||
session stays — it is the other tab's sign-in, and it holds. The one comparison for every way a
|
||||
tab names its account: this header on a request, `expect` on a navigation."""
|
||||
if expected is None or expected == str(user_id):
|
||||
return False
|
||||
log.info(
|
||||
"a request from a tab built for another account was refused",
|
||||
extra=logs.event("auth.session.account_changed", user_id=user_id),
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def current_user(request: Request, db: Session = Depends(get_db)) -> User:
|
||||
user = _session_user(request, db, session_user_id(request))
|
||||
expected = request.headers.get(EXPECTED_ACCOUNT_HEADER)
|
||||
if expected is not None and expected != str(user.id):
|
||||
# The session stays: it is the other tab's sign-in, and it holds.
|
||||
log.info(
|
||||
"a request from a tab built for another account was refused",
|
||||
extra=logs.event("auth.session.account_changed", user_id=user.id),
|
||||
)
|
||||
if built_for_another_account(user.id, request.headers.get(EXPECTED_ACCOUNT_HEADER)):
|
||||
raise refused(401, "account_changed")
|
||||
return user
|
||||
|
||||
|
||||
Reference in New Issue
Block a user