Files
hetzner-api-dyndns-records-…/internal/config/config.go
T
admin df7516e7ab
Container-Image veröffentlichen / container (push) Has been cancelled
feat: production-ready domain control dashboard
2026-07-12 20:56:45 +02:00

93 lines
2.4 KiB
Go

package config
import (
"fmt"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
const (
DefaultIPv4Primary = "https://api.ipify.org"
DefaultIPv4Fallback = "https://ifconfig.co/ip"
DefaultIPv6Primary = "https://api6.ipify.org"
DefaultIPv6Fallback = "https://ifconfig.co/ip"
)
type Config struct {
Address string
DataDir string
DatabasePath string
MasterKeyFile string
CookieSecure bool
SessionTTL time.Duration
HCloudBaseURL string
Mode string
ShutdownTimeout time.Duration
}
func Load() (Config, error) {
dataDir := value("APP_DATA_DIR", "/data")
address := value("APP_ADDRESS", ":8080")
if _, _, err := net.SplitHostPort(address); err != nil {
return Config{}, fmt.Errorf("APP_ADDRESS must be host:port: %w", err)
}
mode := strings.ToLower(value("APP_MODE", "lan"))
if mode != "lan" && mode != "https" {
return Config{}, fmt.Errorf("APP_MODE must be either lan or https")
}
ttl, err := duration("APP_SESSION_TTL", 8*time.Hour)
if err != nil || ttl < time.Hour || ttl > 7*24*time.Hour {
return Config{}, fmt.Errorf("APP_SESSION_TTL must be between 1h and 168h")
}
shutdownTimeout, err := duration("APP_SHUTDOWN_TIMEOUT", 15*time.Second)
if err != nil {
return Config{}, fmt.Errorf("APP_SHUTDOWN_TIMEOUT: %w", err)
}
keyFile := os.Getenv("APP_MASTER_KEY_FILE")
if keyFile == "" {
return Config{}, fmt.Errorf("APP_MASTER_KEY_FILE is required (mount a Docker secret there)")
}
cookieSecure := mode == "https"
if raw := os.Getenv("APP_COOKIE_SECURE"); raw != "" {
parsed, parseErr := strconv.ParseBool(raw)
if parseErr != nil {
return Config{}, fmt.Errorf("APP_COOKIE_SECURE: %w", parseErr)
}
cookieSecure = parsed
}
return Config{
Address: address,
DataDir: dataDir,
DatabasePath: value("APP_DATABASE_PATH", filepath.Join(dataDir, "dyndns.db")),
MasterKeyFile: keyFile,
CookieSecure: cookieSecure,
SessionTTL: ttl,
HCloudBaseURL: strings.TrimRight(value("APP_HCLOUD_BASE_URL", "https://api.hetzner.cloud/v1"), "/"),
Mode: mode,
ShutdownTimeout: shutdownTimeout,
}, nil
}
func value(name, fallback string) string {
if v := strings.TrimSpace(os.Getenv(name)); v != "" {
return v
}
return fallback
}
func duration(name string, fallback time.Duration) (time.Duration, error) {
if raw := strings.TrimSpace(os.Getenv(name)); raw != "" {
return time.ParseDuration(raw)
}
return fallback, nil
}