From 6f3c43aca62a7d33a19f14f6ad7c16891952673a Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Tue, 15 Sep 2026 19:55:21 -0400 Subject: fix: outstanding-stake ledger, owner backpressure, editor state preservation --- internal/admin/server.go | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'internal/admin/server.go') diff --git a/internal/admin/server.go b/internal/admin/server.go index 41c1e0f..81f0cce 100644 --- a/internal/admin/server.go +++ b/internal/admin/server.go @@ -364,6 +364,17 @@ func (s *AdminServer) handleLogin(w http.ResponseWriter, r *http.Request) { return } + // Transparent upgrade: legacy single-pass SHA-256 hashes rehash to + // Argon2id after a successful verification. + if player.NeedsRehash(acc.PasswordHash) { + if hash, hashErr := player.HashPassword(password); hashErr == nil { + acc.PasswordHash = hash + if err := s.accountStore.SaveAccount(acc); err != nil { + log.Printf("admin login: password rehash save for %s: %v", account, err) + } + } + } + if !acc.Admin { s.renderPage(w, r, "login.html", map[string]any{"Error": "Account is not authorized as admin."}) return @@ -649,12 +660,18 @@ func (s *AdminServer) rebuildAfterUndo(change *ChangeDesc) { name := filepath.Base(p) if idStr := strings.TrimSuffix(name, ".yaml"); idStr != name { if id, err := strconv.Atoi(idStr); err == nil && id > 0 { - s.world.ClearRoomState(id) - // If the room file is now gone (true after undo-of-create and - // redo-of-delete), drop any in-memory mob instances for it so - // they don't keep ticking against a room that no longer exists. - if _, statErr := os.Stat(p); os.IsNotExist(statErr) && s.mobStore != nil { - s.mobStore.RemoveMobsInRoom(id) + // Only drop runtime room state when the room file is now gone + // (undo-of-create, redo-of-delete, directory deletion): a + // rename's undo restores the file and the inverse migration + // rekeys its runtime state back — clearing it here would + // destroy the room's live contents. + if _, statErr := os.Stat(p); os.IsNotExist(statErr) { + s.world.ClearRoomState(id) + // Drop any in-memory mob instances too so they don't keep + // ticking against a room that no longer exists. + if s.mobStore != nil { + s.mobStore.RemoveMobsInRoom(id) + } } } } -- cgit v1.2.3