127 lines
3.6 KiB
Go
127 lines
3.6 KiB
Go
// Keywarden - Centralized SSH Key Management and Deployment
|
||
// Copyright (C) 2026 Patrick Asmus (scriptos)
|
||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||
|
||
package config
|
||
|
||
import (
|
||
"os"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// Config holds all application configuration
|
||
type Config struct {
|
||
Port string
|
||
DBPath string
|
||
DataDir string
|
||
KeysDir string
|
||
MasterDir string
|
||
SessionKey string
|
||
EncryptionKey string
|
||
LogLevel string // ERROR, WARN, INFO (default), DEBUG, TRACE
|
||
|
||
// SMTP / Email
|
||
SMTPHost string
|
||
SMTPPort string
|
||
SMTPUser string
|
||
SMTPPassword string
|
||
SMTPFrom string
|
||
SMTPTLS bool
|
||
SMTPEnabled bool
|
||
|
||
// Timezone
|
||
Timezone *time.Location // parsed from TZ env var; defaults to UTC
|
||
|
||
// Security / Hardening
|
||
BaseURL string // e.g. "https://keywarden.example.com" (used for emails, cookie config)
|
||
TrustedProxies string // comma-separated CIDRs, e.g. "10.0.0.0/8,172.16.0.0/12"
|
||
SecureCookies bool // set Secure flag on cookies (enable when behind HTTPS proxy)
|
||
RateLimitLogin int // max login POST attempts per IP per minute (0 = disabled)
|
||
MaxRequestSize int64 // max request body in bytes (0 = no limit)
|
||
}
|
||
|
||
// Load reads configuration from environment variables with sensible defaults
|
||
func Load() *Config {
|
||
smtpHost := getEnv("KEYWARDEN_SMTP_HOST", "")
|
||
|
||
// Parse BaseURL – auto-derive SecureCookies from scheme if not explicitly set
|
||
baseURL := strings.TrimRight(getEnv("KEYWARDEN_BASE_URL", ""), "/")
|
||
secureCookiesExplicit := getEnv("KEYWARDEN_SECURE_COOKIES", "")
|
||
secureCookies := false
|
||
if secureCookiesExplicit != "" {
|
||
secureCookies = secureCookiesExplicit == "true"
|
||
} else if strings.HasPrefix(baseURL, "https://") {
|
||
secureCookies = true
|
||
}
|
||
|
||
rateLimitLogin := getEnvInt("KEYWARDEN_RATE_LIMIT_LOGIN", 10)
|
||
maxRequestSize := getEnvInt64("KEYWARDEN_MAX_REQUEST_SIZE", 10*1024*1024) // 10 MB
|
||
|
||
// Load timezone from TZ environment variable (standard for Docker)
|
||
tzName := getEnv("TZ", "UTC")
|
||
tz, err := time.LoadLocation(tzName)
|
||
if err != nil {
|
||
tz = time.UTC
|
||
}
|
||
|
||
return &Config{
|
||
Port: getEnv("KEYWARDEN_PORT", "8080"),
|
||
DBPath: getEnv("KEYWARDEN_DB_PATH", "./data/keywarden.db"),
|
||
DataDir: getEnv("KEYWARDEN_DATA_DIR", "./data"),
|
||
KeysDir: getEnv("KEYWARDEN_KEYS_DIR", "./data/keys"),
|
||
MasterDir: getEnv("KEYWARDEN_MASTER_DIR", "./data/master"),
|
||
SessionKey: getEnv("KEYWARDEN_SESSION_KEY", "change-me-in-production-please"),
|
||
EncryptionKey: getEnv("KEYWARDEN_ENCRYPTION_KEY", "change-me-encryption-key-32chars"),
|
||
LogLevel: getEnv("KEYWARDEN_LOG_LEVEL", "INFO"),
|
||
|
||
SMTPHost: smtpHost,
|
||
SMTPPort: getEnv("KEYWARDEN_SMTP_PORT", "587"),
|
||
SMTPUser: getEnv("KEYWARDEN_SMTP_USER", ""),
|
||
SMTPPassword: getEnv("KEYWARDEN_SMTP_PASSWORD", ""),
|
||
SMTPFrom: getEnv("KEYWARDEN_SMTP_FROM", "keywarden@localhost"),
|
||
SMTPTLS: getEnv("KEYWARDEN_SMTP_TLS", "true") == "true",
|
||
SMTPEnabled: smtpHost != "",
|
||
|
||
Timezone: tz,
|
||
|
||
BaseURL: baseURL,
|
||
TrustedProxies: getEnv("KEYWARDEN_TRUSTED_PROXIES", ""),
|
||
SecureCookies: secureCookies,
|
||
RateLimitLogin: rateLimitLogin,
|
||
MaxRequestSize: maxRequestSize,
|
||
}
|
||
}
|
||
|
||
func getEnv(key, fallback string) string {
|
||
if val, ok := os.LookupEnv(key); ok {
|
||
return val
|
||
}
|
||
return fallback
|
||
}
|
||
|
||
func getEnvInt(key string, fallback int) int {
|
||
s := getEnv(key, "")
|
||
if s == "" {
|
||
return fallback
|
||
}
|
||
v, err := strconv.Atoi(s)
|
||
if err != nil {
|
||
return fallback
|
||
}
|
||
return v
|
||
}
|
||
|
||
func getEnvInt64(key string, fallback int64) int64 {
|
||
s := getEnv(key, "")
|
||
if s == "" {
|
||
return fallback
|
||
}
|
||
v, err := strconv.ParseInt(s, 10, 64)
|
||
if err != nil {
|
||
return fallback
|
||
}
|
||
return v
|
||
}
|