mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-10-22 23:21:18 +00:00
fix(server): keep config.json's file mode when saving the geo-filter (#2126)
`SaveGeoFilter` rewrote `config.json` through a temp file created with mode 0644, so a config an operator had made 0600 (it holds the API key and broker passwords) became world-readable after the first geo-filter save. **Fix:** stat the original and reuse its mode for the temp file. Falls back to 0644 when the stat fails. **Tests:** `config_mode_test.go` — a 0600 config stays 0600 after a save; a 0644 config stays 0644. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Mythos 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
523a5edfa1
commit
8b64439635
2 files changed
+48
-2
No files matched your search
@@ -996,9 +996,15 @@ func SaveGeoFilter(configDir string, gf *GeoFilterConfig) error {
|
||||
}
|
||||
out = append(out, '\n')
|
||||
|
||||
// Atomic write: temp file + rename.
|
||||
// Atomic write: temp file + rename. Keep the original file's mode:
|
||||
// config.json holds the API key and broker passwords, and an operator
|
||||
// who made it 0600 should not find it 0644 after a geo-filter save.
|
||||
mode := os.FileMode(0644)
|
||||
if fi, err := os.Stat(configPath); err == nil {
|
||||
mode = fi.Mode().Perm()
|
||||
}
|
||||
tmp := configPath + ".tmp"
|
||||
if err := os.WriteFile(tmp, out, 0644); err != nil {
|
||||
if err := os.WriteFile(tmp, out, mode); err != nil {
|
||||
return fmt.Errorf("write config: %w", err)
|
||||
}
|
||||
if err := os.Rename(tmp, configPath); err != nil {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// SaveGeoFilter rewrites config.json through a temp file. The file holds the
|
||||
// API key and broker passwords, so the rewrite must keep whatever mode the
|
||||
// operator set rather than resetting it to 0644.
|
||||
func TestSaveGeoFilterPreservesFileMode(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "config.json")
|
||||
if err := os.WriteFile(path, []byte(`{"apiKey":"secret-key-that-is-long-enough"}`+"\n"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
gf := &GeoFilterConfig{Polygon: [][2]float64{{0, 0}, {0, 1}, {1, 1}, {1, 0}}}
|
||||
if err := SaveGeoFilter(dir, gf); err != nil {
|
||||
t.Fatalf("SaveGeoFilter: %v", err)
|
||||
}
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := fi.Mode().Perm(); got != 0600 {
|
||||
t.Fatalf("config.json mode after save = %o, want 0600", got)
|
||||
}
|
||||
// Default stays 0644 for a file that was 0644.
|
||||
if err := os.Chmod(path, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := SaveGeoFilter(dir, nil); err != nil {
|
||||
t.Fatalf("SaveGeoFilter(nil): %v", err)
|
||||
}
|
||||
fi, _ = os.Stat(path)
|
||||
if got := fi.Mode().Perm(); got != 0644 {
|
||||
t.Fatalf("config.json mode after save = %o, want 0644", got)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user