Use secure temporary config files

This commit is contained in:
Brandon McGinty (chatgpt)
2026-08-10 08:44:58 -04:00
committed by Brandon McGinty
parent 3ba5e03208
commit dcffa1efa1
2 changed files with 35 additions and 5 deletions
+15 -5
View File
@@ -8,6 +8,7 @@ import (
"io/ioutil"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
@@ -61,15 +62,24 @@ func (c *Config) saveConfigLocked() error {
if err != nil {
return err
}
tmp := c.fn + ".tmp"
if err := ioutil.WriteFile(tmp, data, 0600); err != nil {
file, err := os.CreateTemp(filepath.Dir(c.fn), filepath.Base(c.fn)+".tmp-")
if err != nil {
return err
}
if err := os.Rename(tmp, c.fn); err != nil {
_ = os.Remove(tmp)
tmp := file.Name()
defer os.Remove(tmp)
if err := file.Chmod(0600); err != nil {
file.Close()
return err
}
return nil
if _, err := file.Write(data); err != nil {
file.Close()
return err
}
if err := file.Close(); err != nil {
return err
}
return os.Rename(tmp, c.fn)
}
func key(k uiterm.Key) *uiterm.Key {
+20
View File
@@ -1,6 +1,7 @@
package config
import (
"os"
"path/filepath"
"sync"
"testing"
@@ -16,6 +17,25 @@ func TestSaveConfigReturnsWriteError(t *testing.T) {
}
}
func TestSaveConfigDoesNotUsePredictableTemporaryPath(t *testing.T) {
path := filepath.Join(t.TempDir(), "barnard.toml")
legacyTemp := path + ".tmp"
if err := os.WriteFile(legacyTemp, []byte("sentinel"), 0600); err != nil {
t.Fatal(err)
}
cfg := NewConfig(&path)
if err := cfg.SaveConfig(); err != nil {
t.Fatal(err)
}
contents, err := os.ReadFile(legacyTemp)
if err != nil {
t.Fatal(err)
}
if string(contents) != "sentinel" {
t.Fatalf("predictable temporary file was modified: %q", contents)
}
}
func TestConcurrentConfigurationUpdatesAndWrites(t *testing.T) {
path := filepath.Join(t.TempDir(), "barnard.toml")
cfg := NewConfig(&path)