From d58ce941e65e1a437936f3e27da90e00a68ebbda Mon Sep 17 00:00:00 2001 From: Snider Date: Fri, 17 Apr 2026 17:57:17 +0100 Subject: [PATCH] Fix window state load hardening --- pkg/window/state.go | 13 ++++++++++--- pkg/window/state_test.go | 10 ++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pkg/window/state.go b/pkg/window/state.go index 82209839..5412cb18 100644 --- a/pkg/window/state.go +++ b/pkg/window/state.go @@ -2,6 +2,7 @@ package window import ( + "io/fs" "sync" "time" @@ -89,6 +90,9 @@ func (sm *StateManager) load() { } content, err := coreio.Local.Read(sm.filePath()) if err != nil { + if core.Is(err, fs.ErrNotExist) { + return + } core.Error( "window state load failed", "path", sm.filePath(), @@ -96,9 +100,8 @@ func (sm *StateManager) load() { ) return } - sm.mu.Lock() - defer sm.mu.Unlock() - result := core.JSONUnmarshalString(content, &sm.states) + loaded := make(map[string]WindowState) + result := core.JSONUnmarshalString(content, &loaded) if !result.OK { if decodeErr, ok := result.Value.(error); ok { core.Error( @@ -107,7 +110,11 @@ func (sm *StateManager) load() { "err", core.E("window.StateManager.load", "failed to decode window state", decodeErr), ) } + return } + sm.mu.Lock() + sm.states = loaded + sm.mu.Unlock() } func (sm *StateManager) save() error { diff --git a/pkg/window/state_test.go b/pkg/window/state_test.go index 592b45a7..ce7b398a 100644 --- a/pkg/window/state_test.go +++ b/pkg/window/state_test.go @@ -27,6 +27,16 @@ func TestStateManagerState_NewStateManagerWithDir_Bad(t *testing.T) { assert.Empty(t, sm.dataDir()) } +func TestStateManagerState_NewStateManagerWithDir_InvalidFile_Good(t *testing.T) { + dir := t.TempDir() + require.NoError(t, os.WriteFile(filepath.Join(dir, "window_state.json"), []byte("{invalid"), 0o644)) + + sm := NewStateManagerWithDir(dir) + + require.NotNil(t, sm) + assert.Empty(t, sm.ListStates()) +} + func TestStateManagerState_SetPath_Good(t *testing.T) { dir := t.TempDir() sm := NewStateManagerWithDir(dir)