107 lines
2.1 KiB
Go
107 lines
2.1 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
type Config struct {
|
|
SSH SSHConfig `toml:"ssh"`
|
|
Vault VaultConfig `toml:"vault"`
|
|
UI UIConfig `toml:"ui"`
|
|
|
|
// resolved paths
|
|
ConfigDir string `toml:"-"`
|
|
DataDir string `toml:"-"`
|
|
}
|
|
|
|
type SSHConfig struct {
|
|
Binary string `toml:"binary"`
|
|
ConnectTimeoutSec int `toml:"connect_timeout_seconds"`
|
|
TestCommand string `toml:"test_command"`
|
|
}
|
|
|
|
type VaultConfig struct {
|
|
AutoLockMinutes int `toml:"auto_lock_minutes"`
|
|
}
|
|
|
|
type UIConfig struct {
|
|
ShowSecurityHints bool `toml:"show_security_hints"`
|
|
}
|
|
|
|
func defaultConfig() *Config {
|
|
return &Config{
|
|
SSH: SSHConfig{
|
|
Binary: "/usr/bin/ssh",
|
|
ConnectTimeoutSec: 10,
|
|
TestCommand: "echo SSHKEEPER_OK",
|
|
},
|
|
Vault: VaultConfig{
|
|
AutoLockMinutes: 15,
|
|
},
|
|
UI: UIConfig{
|
|
ShowSecurityHints: false,
|
|
},
|
|
}
|
|
}
|
|
|
|
func Load() (*Config, error) {
|
|
cfg := defaultConfig()
|
|
|
|
// XDG paths
|
|
configDir := os.Getenv("XDG_CONFIG_HOME")
|
|
if configDir == "" {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
configDir = filepath.Join(home, ".config", "sshkeeper")
|
|
}
|
|
cfg.ConfigDir = configDir
|
|
|
|
dataDir := os.Getenv("XDG_DATA_HOME")
|
|
if dataDir == "" {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dataDir = filepath.Join(home, ".local", "share", "sshkeeper")
|
|
}
|
|
cfg.DataDir = dataDir
|
|
|
|
// Ensure dirs exist
|
|
if err := os.MkdirAll(configDir, 0700); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := os.MkdirAll(dataDir, 0700); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
configFile := filepath.Join(configDir, "config.toml")
|
|
|
|
// Write default config if not exists
|
|
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
|
f, err := os.OpenFile(configFile, os.O_CREATE|os.O_WRONLY, 0600)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
if err := toml.NewEncoder(f).Encode(cfg); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Parse existing config
|
|
if _, err := toml.DecodeFile(configFile, cfg); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Re-apply paths since toml decode might overwrite
|
|
cfg.ConfigDir = configDir
|
|
cfg.DataDir = dataDir
|
|
|
|
return cfg, nil
|
|
}
|