// Package config holds the small set of deployment-specific settings the // tool needs: how this box is reached from the outside, and where its state // lives on disk. package config import ( "fmt" "os" "gopkg.in/yaml.v3" ) // Config is the tool's deployment configuration, normally loaded from // /etc/ssh-access-tui/config.yaml (see scripts/install.sh). type Config struct { // JumpHost is the address end users' ssh clients connect to — usually // this box's public hostname/IP, used only to render client configs. JumpHost string `yaml:"jump_host"` JumpPort int `yaml:"jump_port"` StateDir string `yaml:"state_dir"` // git-backed YAML state (groups/users) ExportDir string `yaml:"export_dir"` // where finished .7z archives are written ScratchDir string `yaml:"scratch_dir"` // ephemeral working dir, wiped after each export AuditLog string `yaml:"audit_log"` // append-only JSONL connect/disconnect log } // Default returns sane defaults for an install following scripts/install.sh. func Default() Config { return Config{ JumpPort: 22, StateDir: "/var/lib/ssh-access-tui/state", ExportDir: "/var/lib/ssh-access-tui/exports", ScratchDir: "/var/lib/ssh-access-tui/scratch", AuditLog: "/var/lib/ssh-access-tui/audit/audit.jsonl", } } // Load reads path if it exists, overlaying it on Default(); missing fields // keep their default. A missing file is not an error (first run). func Load(path string) (Config, error) { cfg := Default() data, err := os.ReadFile(path) if os.IsNotExist(err) { return cfg, nil } if err != nil { return cfg, fmt.Errorf("read config %s: %w", path, err) } if err := yaml.Unmarshal(data, &cfg); err != nil { return cfg, fmt.Errorf("parse config %s: %w", path, err) } return cfg, nil } // Save writes cfg to path as YAML, creating parent directories as needed. func Save(path string, cfg Config) error { data, err := yaml.Marshal(cfg) if err != nil { return err } return os.WriteFile(path, data, 0o644) }