What happens
Close the app, open it again. A visitor who was signed in still looks signed in
— the header shows their name — but opening their profile says "no such
player". Logging out and back in fixes it.
Why
Two faults stacked.
Player sessions are memory-only. playerAuth persists accounts to
player-accounts.json and keeps sessions in a Map. Restarting the process
drops every session, while the browser still holds the token in localStorage
— so the page believes it is signed in and every authenticated request is
anonymous.
And the profile route reports that as a missing player. With the token dead,
resolvePlayerSession returns null, the viewer is anonymous, and the existence
check refuses because a name that has never played is only visible to its owner.
The answer is correct for a stranger and completely misleading for the person
whose session just expired.
That second half is a consequence of the enumeration fix in #107 — right for the
reason it was made, and it turned a silent wrong-content bug into a confusing
one. A request that carried a credential which did not resolve is not the same
as a request that carried none, and the route was treating them identically.
Scope
- Persist player sessions across restarts, expiring on their own schedule as
they already do. An operator restarting the manager should not sign out every
player on the website.
- Answer 401 for a dead token. A bearer that was supplied and did not
resolve gets 401, so the client knows to clear it and offer a login instead
of reporting on the player. This is a fact about the token, not about any
name, so it creates no enumeration oracle — the 404-vs-200 rule for unauth
requests is untouched.
- The site clears a rejected token and reopens the login, rather than
leaving a header that claims a session it does not have.
Verify
A session survives a reload of the store; a token that does not resolve gets
401 from the profile route while an anonymous request for the same name still
gets whatever a stranger would get; and the two remain indistinguishable for
names that differ only in whether they hold an account.
What happens
Close the app, open it again. A visitor who was signed in still looks signed in
— the header shows their name — but opening their profile says "no such
player". Logging out and back in fixes it.
Why
Two faults stacked.
Player sessions are memory-only.
playerAuthpersists accounts toplayer-accounts.jsonand keepssessionsin aMap. Restarting the processdrops every session, while the browser still holds the token in
localStorage— so the page believes it is signed in and every authenticated request is
anonymous.
And the profile route reports that as a missing player. With the token dead,
resolvePlayerSessionreturns null, the viewer isanonymous, and the existencecheck refuses because a name that has never played is only visible to its owner.
The answer is correct for a stranger and completely misleading for the person
whose session just expired.
That second half is a consequence of the enumeration fix in #107 — right for the
reason it was made, and it turned a silent wrong-content bug into a confusing
one. A request that carried a credential which did not resolve is not the same
as a request that carried none, and the route was treating them identically.
Scope
they already do. An operator restarting the manager should not sign out every
player on the website.
resolve gets
401, so the client knows to clear it and offer a login insteadof reporting on the player. This is a fact about the token, not about any
name, so it creates no enumeration oracle — the 404-vs-200 rule for unauth
requests is untouched.
leaving a header that claims a session it does not have.
Verify
A session survives a reload of the store; a token that does not resolve gets
401 from the profile route while an anonymous request for the same name still
gets whatever a stranger would get; and the two remain indistinguishable for
names that differ only in whether they hold an account.