fix(setup): stop the forced-onboarding gate trapping players who have no email
setup_required is what the SPA polls to decide whether the onboarding wall is still owed, and it disagreed with the middleware that actually enforces the wall. requireOnboarded lifts on a verified email OR an enrolled passkey; setup_required answered `u.Email == "" || !hasPasskey`. A console-tier player joins through the bind-code door with no email at all — by design, there is no SMTP at that point — so the email term never clears and the SPA keeps them on the setup screen forever, even after they enroll the passkey that already unlocked the API for them. The predicate now lives in one place (setupRequired) and both endpoints call it, so the next edit to the unlock condition cannot drift them apart again. Keying it on EmailVerified rather than email presence is the deliberate part: presence is exactly the term that trapped the no-email player, and it was also wrong on its own terms — an unverified address is not an authentication factor, so it was never what the lockdown could safely lift on. Also lands the regression test for the mechanism behind the live claim-403 report: /me/servers answers 200 for a bind-onboarded player (which is why the dashboard renders the 认领 button at all) while claim, wake and status all answer 403 with code "setup_required" — i.e. the refusal comes from requireOnboarded before the handler, not from isOwnerOrAdmin inside it, which would have said "forbidden". Enrolling a passkey and changing nothing else lifts all three, which isolates the gate as the sole cause. The backend authz is correct; the button that leads a locked-down player into a 403 is the frontend's to hide.
This commit is contained in:
4 files changed
+198
-10
No files matched your search
@@ -624,6 +624,18 @@ func (a *API) requireOnboarded(h http.HandlerFunc) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// setupRequired reports whether the caller still owes the forced-onboarding step,
|
||||
// for the SPA to poll. It MUST stay in lockstep with requireOnboarded's unlock
|
||||
// condition above: the lockdown lifts on a verified email OR an enrolled passkey.
|
||||
// Keying on email PRESENCE instead of a passkey would trap a console-tier player —
|
||||
// they join through the bind-code door with no email by design (no SMTP) and can
|
||||
// only ever complete setup by enrolling a passkey, so any email term loops them
|
||||
// forever. Passkey alone is the durable gate; email verification is a later,
|
||||
// SMTP-dependent step.
|
||||
func setupRequired(emailVerified, hasPasskey bool) bool {
|
||||
return !emailVerified && !hasPasskey
|
||||
}
|
||||
|
||||
// ---- request context plumbing ----
|
||||
|
||||
type ctxKey int
|
||||
|
||||
Reference in new issue
Block a user