Files

79 lines
1.7 KiB
Go

package app
import (
"bytes"
"os"
"path/filepath"
"syscall"
"github.com/pelletier/go-toml/v2"
)
// UpdateAccessConfig preserves all existing settings, ownership and permissions.
// It never opens the data directory; callers can prepare a candidate while serving.
func UpdateAccessConfig(path, listen string, additions []string, allowLAN bool) error {
data, err := os.ReadFile(path)
if err != nil {
return err
}
info, err := os.Stat(path)
if err != nil {
return err
}
cfg := DefaultConfig()
if err = toml.NewDecoder(bytes.NewReader(data)).DisallowUnknownFields().Decode(&cfg); err != nil {
return err
}
if listen != "" {
cfg.Listen = listen
}
cfg.AllowLANHTTP = cfg.AllowLANHTTP || allowLAN
for _, raw := range additions {
base, e := normalizeAccessURL(raw)
if e != nil {
return e
}
found := false
for _, existing := range cfg.accessOrigins() {
if base == existing {
found = true
break
}
}
if !found {
cfg.AccessURLs = append(cfg.AccessURLs, base)
}
}
if err = cfg.Validate(); err != nil {
return err
}
encoded, err := toml.Marshal(cfg)
if err != nil {
return err
}
out, err := os.CreateTemp(filepath.Dir(path), ".access-config-*.toml")
if err != nil {
return err
}
defer os.Remove(out.Name())
defer out.Close()
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
if err = out.Chown(int(stat.Uid), int(stat.Gid)); err != nil {
return err
}
}
if err = out.Chmod(info.Mode().Perm()); err != nil {
return err
}
if _, err = out.Write(encoded); err != nil {
return err
}
if err = out.Sync(); err != nil {
return err
}
if err = out.Close(); err != nil {
return err
}
return os.Rename(out.Name(), path)
}