feat(auth)!: go fully passwordless and fix cross-check review findings
Remove password authentication everywhere; the only session doors are passkey (WebAuthn), email OTP, in-game bind codes, QR scan-login, and op-login vouching. Remediates the 33-finding cross-check review across backend, CLI, panel, plugins, and docs. Backend/CLI: - Drop password routes and fields from account/user/onboard/auth handlers; align tests (new account subtests, naming reserves "console", op-login/onboard/qr-login test updates). - Add migrations 0016_op_login.sql and 0017_drop_password.sql. - Thread panel/admin hostnames from hostcfg through api.go, setup_panel.go, tui_root.go and tui_preflight.go instead of hardcoding; bootstrap.sh writes panel-hostname/admin-hostname into felis.toml. - Reword breakglass and TUI copy for passwordless flows. Panel: - Delete the ChangePassword page and all password UI; align login/auth/api/types with the passwordless contract; add the migration and op-login approval flows. - i18n: convert ImageBuildPage durations/status badges and ServerLuckPerms strings to translation keys; drop 72 orphan keys per locale; unify the title as "Felis - Console". Plugins (all six rebuilt): - Velocity waiting router returns 503 at_capacity during wake; MOTD/control-channel copy and config comments. - Paper zh menu title; Limbo bind-code TTL 600s with panel_url preference; unified /link lines in fabric/forge/neoforge; shared link-client javadoc contract fixes. Docs: openapi.yaml, sequence-diagrams.md, deploy/limbo/README.md and plugins/README.md aligned with the implementation. BREAKING CHANGE: migration 0017 irreversibly drops users.password_hash and users.must_change_password; password login cannot be restored after migrating.
This commit is contained in:
97 files changed
+1923
-1444
No files matched your search
@@ -52,7 +52,7 @@ type fakeRepo struct {
|
||||
linkAuthSource map[string]string
|
||||
// world backups (spec §7, §22). A nil slice lists empty.
|
||||
backups []fakeBackup
|
||||
// local-password auth (spec §B). staff is keyed by username (the login key);
|
||||
// session auth (spec §B, passwordless). staff is keyed by username (the login key);
|
||||
// sessions by token_hash; settings by key. They mirror the PG contract so the
|
||||
// hermetic tests exercise the same fail-closed semantics the integration impl
|
||||
// honors.
|
||||
@@ -1600,45 +1600,6 @@ func TestMeIdentity(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// ---- by-host ----
|
||||
|
||||
func TestByHost(t *testing.T) {
|
||||
cl := newFakeCluster()
|
||||
cl.bySub["survival"] = &ServerInfo{Name: "survival", Subdomain: "survival", Phase: "Running", Ready: true}
|
||||
api := newTestAPI(newFakeRepo(), cl)
|
||||
h := api.InternalHandler()
|
||||
tok := map[string]string{"Authorization": "Bearer "} // okInternal ignores it
|
||||
|
||||
t.Run("foreign domain rejected", func(t *testing.T) {
|
||||
w := do(h, "GET", "/api/v1/servers/by-host/survival.evil.example.org", "", tok)
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Fatalf("code = %d, want 400", w.Code)
|
||||
}
|
||||
})
|
||||
t.Run("multi-label rejected", func(t *testing.T) {
|
||||
w := do(h, "GET", "/api/v1/servers/by-host/a.b."+testRoot, "", tok)
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Fatalf("code = %d, want 400", w.Code)
|
||||
}
|
||||
})
|
||||
t.Run("unknown server 404", func(t *testing.T) {
|
||||
w := do(h, "GET", "/api/v1/servers/by-host/creative."+testRoot, "", tok)
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Fatalf("code = %d, want 404", w.Code)
|
||||
}
|
||||
})
|
||||
t.Run("found", func(t *testing.T) {
|
||||
w := do(h, "GET", "/api/v1/servers/by-host/survival."+testRoot, "", tok)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("code = %d, want 200 (%s)", w.Code, w.Body.String())
|
||||
}
|
||||
var info ServerInfo
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &info); err != nil || info.Name != "survival" {
|
||||
t.Fatalf("unexpected body %s err %v", w.Body.String(), err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ---- fleet (SysAdmin cockpit read) ----
|
||||
|
||||
// TestFleetAdminRead proves the SysAdmin cockpit's fleet read is admin-tier AND
|
||||
|
||||
Reference in new issue
Block a user