feat(auth): migrate console login to passwordless
Replace console password auth with a passwordless surface — the pre-session
login doors plus an identifier-first discovery endpoint — and remove the
password paths.
- Login doors (Public, pre-session): email-OTP, passkey assertion, op.console
login with in-game approval, and setup-token redeem.
- /api/v1/auth/options: identifier-first discovery reporting which console
methods an email can use. The single sanctioned existence oracle; methods
are computed with no role branch, so staff and player accounts in the same
credential state return byte-identical bodies (staffness invisible by
construction).
- Remove password auth: drop StaffUser.PasswordHash and the /auth/login,
/auth/change-password and /users/{id}/reset-password endpoints (and test).
- Data layer: UserByEmail, verified-email uniqueness, setup-token store
(migration 0012).
- Reconcile docs/openapi.yaml with the served surface; the method/path/face/
tier parity gate (TestOpenAPIMatchesServedRoutes) passes.
- felis TUI: in-game MC bind, owner/break-glass OP provisioning, version.
- Velocity /felis command suite.
Consolidates the accumulated backend migration work; the frontend (panel/)
is left untouched. Full Go tree green on WSL (go build ./... && go test ./...).
This commit is contained in:
46 files changed
+5554
-1651
No files matched your search
+14
-7
@@ -21,16 +21,23 @@ type Principal struct {
|
||||
Role string
|
||||
// ViaAdminAccess is true only when the request arrived through an admin-graded
|
||||
// path: the admin.* Zero-Trust hostname (Cloudflare Access, the remote face) OR
|
||||
// a local-password session presented on the op.console host (SessionAuth, the
|
||||
// break-glass-enabled face). Admin-tier operations require it in addition to
|
||||
// a local session presented on the op.console host (SessionAuth, the
|
||||
// passwordless face). Admin-tier operations require it in addition to
|
||||
// Role=="admin" (spec §14: ZT is graded by operation). A role=admin session
|
||||
// arriving on the player console (console.*) never sets it.
|
||||
ViaAdminAccess bool
|
||||
// MustChangePassword is set only on the local-password (SessionAuth) path when
|
||||
// the staff account still owes a first-login change. The JWT path leaves it
|
||||
// false. The lockdown middleware fences such a principal to the change-password
|
||||
// and logout surface until it is cleared.
|
||||
MustChangePassword bool
|
||||
// EmailVerified mirrors users.email_verified. The lockdown middleware gates
|
||||
// setup-incomplete accounts (EmailVerified=false, e.g. a freshly bootstrapped
|
||||
// Owner who has not yet proven control of their mailbox) to the setup-wizard
|
||||
// routes only, so an intercepted setup URL cannot yield full admin access
|
||||
// before the email-OTP verification step completes.
|
||||
EmailVerified bool
|
||||
// ViaSession is true when the principal was authenticated via a local session
|
||||
// cookie (SessionAuth), not a Cloudflare-Access JWT. The setup-lockdown gate
|
||||
// only applies to session-authenticated principals — a JWT caller already
|
||||
// passed Zero Trust at the edge, so the local-email-verification gate is not
|
||||
// the right boundary for them.
|
||||
ViaSession bool
|
||||
}
|
||||
|
||||
// IsAdmin reports whether the principal may perform admin-tier operations.
|
||||
|
||||
Reference in new issue
Block a user