From 153acb7f644d755c45533b7c5311e3ffa47e8973 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Fri, 18 Sep 2026 05:31:09 -0400 Subject: fix: harden engine across casino, economy, concurrency, security, and content --- internal/game/core_admin.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'internal/game/core_admin.go') diff --git a/internal/game/core_admin.go b/internal/game/core_admin.go index e1236ab..848130f 100644 --- a/internal/game/core_admin.go +++ b/internal/game/core_admin.go @@ -2,6 +2,24 @@ package game import "thehouseoficarus/internal/net" +// checkAdmin reports whether the session belongs to an account with the +// on-disk admin flag set. The cached sess.Account copy is only refreshed on +// login or account republish, so it is NOT trusted as the source of truth: +// removing admin: true from an account file (or the admin API's reload) must +// demote an already-connected admin without requiring a relog. The account +// file is re-read on the owner goroutine, which serializes with logins and +// account saves, so the check cannot race a concurrent hash/admin change. +// Privilege checks fail closed when the account cannot be read. func (g *Game) checkAdmin(sess *net.Session) bool { - return sess.Account != nil && sess.Account.Admin + if sess.Account == nil { + return false + } + acc, err := g.AccountStore.LoadAccount(sess.Account.Name) + if err != nil || !acc.Admin { + // Drop the stale cached privilege too, so command gating and any + // code reading sess.Account.Admin agree with disk. + sess.Account.Admin = false + return false + } + return true } -- cgit v1.2.3