From 194164a77eb4f2479b94c19e6f0e1278ab608781 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Fri, 18 Sep 2026 16:13:49 -0400 Subject: fix: more casino, economy, gameplay, security, and world data hardening gaps --- internal/world/room.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'internal/world/room.go') diff --git a/internal/world/room.go b/internal/world/room.go index f4390da..3783a73 100644 --- a/internal/world/room.go +++ b/internal/world/room.go @@ -1,6 +1,7 @@ package world import ( + "fmt" "strings" "gopkg.in/yaml.v3" @@ -122,6 +123,28 @@ type RoomObject struct { } func (ro *RoomObject) UnmarshalYAML(value *yaml.Node) error { + // yaml.v3's Node.Decode builds a fresh decoder that does NOT inherit + // KnownFields(true), so a misspelled key inside a room's objects: entry + // (inroom_description, onlook, ...) would be silently discarded even + // though the top-level room file is decoded strictly. Reject unknown + // keys here so the startup validator's "unknown field is an ERROR" + // guarantee extends to the region authors edit most. + if value.Kind != yaml.MappingNode { + return fmt.Errorf("room object must be a mapping") + } + allowed := map[string]bool{ + "id": true, "wander_rooms": true, "wander_interval": true, "hidden": true, + "name": true, "aliases": true, "color": true, "inroom_description": true, + "removal_item": true, "description": true, "on_use": true, "steal": true, + "gather": true, "talk": true, "safespot": true, "on_look": true, + } + for i := 0; i+1 < len(value.Content); i += 2 { + key := value.Content[i].Value + if !allowed[key] { + return fmt.Errorf("unknown room object field %q", key) + } + } + type rawRef struct { ID string `yaml:"id"` WanderRooms []int `yaml:"wander_rooms"` -- cgit v1.2.3