rss email digests over ssh because you're a cool kid herald.dunkirk.sh
go rss rss-reader ssh charm
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 173 lines 4.5 kB view raw
1package config 2 3import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strconv" 8 "strings" 9 10 "github.com/joho/godotenv" 11 "gopkg.in/yaml.v3" 12) 13 14type AppConfig struct { 15 Host string `yaml:"host"` 16 SSHPort int `yaml:"ssh_port"` 17 ExternalSSHPort int `yaml:"external_ssh_port"` 18 HTTPPort int `yaml:"http_port"` 19 HostKeyPath string `yaml:"host_key_path"` 20 DBPath string `yaml:"db_path"` 21 Origin string `yaml:"origin"` 22 LogLevel string `yaml:"log_level"` 23 SMTP SMTPConfig `yaml:"smtp"` 24 AllowAllKeys bool `yaml:"allow_all_keys"` 25 AllowedKeys []string `yaml:"allowed_keys"` 26} 27 28type SMTPConfig struct { 29 Host string `yaml:"host"` 30 Port int `yaml:"port"` 31 User string `yaml:"user"` 32 Pass string `yaml:"pass"` 33 From string `yaml:"from"` 34 DKIMPrivateKey string `yaml:"dkim_private_key"` 35 DKIMPrivateKeyFile string `yaml:"dkim_private_key_file"` 36 DKIMSelector string `yaml:"dkim_selector"` 37 DKIMDomain string `yaml:"dkim_domain"` 38} 39 40func DefaultAppConfig() *AppConfig { 41 return &AppConfig{ 42 Host: "0.0.0.0", 43 SSHPort: 2222, 44 HTTPPort: 8080, 45 HostKeyPath: "./host_key", 46 DBPath: "./herald.db", 47 Origin: "http://localhost:8080", 48 LogLevel: "info", 49 SMTP: SMTPConfig{ 50 Host: "localhost", 51 Port: 587, 52 From: "herald@localhost", 53 }, 54 AllowAllKeys: true, 55 } 56} 57 58func LoadAppConfig(path string) (*AppConfig, error) { 59 cfg := DefaultAppConfig() 60 61 // Load .env file if it exists (silently ignore if not found) 62 if envPath := findEnvFile(path); envPath != "" { 63 _ = godotenv.Load(envPath) 64 } 65 66 if path != "" { 67 data, err := os.ReadFile(path) //nolint:gosec // Config file path from CLI flag 68 if err != nil { 69 return nil, fmt.Errorf("failed to read config file: %w", err) 70 } 71 72 expanded := os.Expand(string(data), func(key string) string { 73 return os.Getenv(key) 74 }) 75 76 if err := yaml.Unmarshal([]byte(expanded), cfg); err != nil { 77 return nil, fmt.Errorf("failed to parse config file: %w", err) 78 } 79 } 80 81 applyEnvOverrides(cfg) 82 83 // Default external_ssh_port to ssh_port if not set 84 if cfg.ExternalSSHPort == 0 { 85 cfg.ExternalSSHPort = cfg.SSHPort 86 } 87 88 return cfg, nil 89} 90 91// findEnvFile looks for .env file in the config file's directory or current directory 92func findEnvFile(configPath string) string { 93 // If config path provided, look in its directory 94 if configPath != "" { 95 dir := filepath.Dir(configPath) 96 envPath := filepath.Join(dir, ".env") 97 if _, err := os.Stat(envPath); err == nil { 98 return envPath 99 } 100 } 101 102 // Otherwise check current directory 103 if _, err := os.Stat(".env"); err == nil { 104 return ".env" 105 } 106 107 return "" 108} 109 110func applyEnvOverrides(cfg *AppConfig) { 111 if v := os.Getenv("HERALD_HOST"); v != "" { 112 cfg.Host = v 113 } 114 if v := os.Getenv("HERALD_SSH_PORT"); v != "" { 115 if port, err := strconv.Atoi(v); err == nil { 116 cfg.SSHPort = port 117 } 118 } 119 if v := os.Getenv("HERALD_EXTERNAL_SSH_PORT"); v != "" { 120 if port, err := strconv.Atoi(v); err == nil { 121 cfg.ExternalSSHPort = port 122 } 123 } 124 if v := os.Getenv("HERALD_HTTP_PORT"); v != "" { 125 if port, err := strconv.Atoi(v); err == nil { 126 cfg.HTTPPort = port 127 } 128 } 129 if v := os.Getenv("HERALD_HOST_KEY_PATH"); v != "" { 130 cfg.HostKeyPath = v 131 } 132 if v := os.Getenv("HERALD_DB_PATH"); v != "" { 133 cfg.DBPath = v 134 } 135 if v := os.Getenv("HERALD_SMTP_HOST"); v != "" { 136 cfg.SMTP.Host = v 137 } 138 if v := os.Getenv("HERALD_SMTP_PORT"); v != "" { 139 if port, err := strconv.Atoi(v); err == nil { 140 cfg.SMTP.Port = port 141 } 142 } 143 if v := os.Getenv("HERALD_SMTP_USER"); v != "" { 144 cfg.SMTP.User = v 145 } 146 if v := os.Getenv("HERALD_SMTP_PASS"); v != "" { 147 cfg.SMTP.Pass = v 148 } 149 if v := os.Getenv("HERALD_SMTP_FROM"); v != "" { 150 cfg.SMTP.From = v 151 } 152 if v := os.Getenv("HERALD_SMTP_DKIM_PRIVATE_KEY"); v != "" { 153 cfg.SMTP.DKIMPrivateKey = v 154 } 155 if v := os.Getenv("HERALD_SMTP_DKIM_PRIVATE_KEY_FILE"); v != "" { 156 cfg.SMTP.DKIMPrivateKeyFile = v 157 } 158 if v := os.Getenv("HERALD_SMTP_DKIM_SELECTOR"); v != "" { 159 cfg.SMTP.DKIMSelector = v 160 } 161 if v := os.Getenv("HERALD_SMTP_DKIM_DOMAIN"); v != "" { 162 cfg.SMTP.DKIMDomain = v 163 } 164 if v := os.Getenv("HERALD_ALLOW_ALL_KEYS"); v != "" { 165 cfg.AllowAllKeys = strings.ToLower(v) == "true" 166 } 167 if v := os.Getenv("HERALD_ORIGIN"); v != "" { 168 cfg.Origin = v 169 } 170 if v := os.Getenv("HERALD_LOG_LEVEL"); v != "" { 171 cfg.LogLevel = v 172 } 173}