Files
keywarden/internal/config/config.go

127 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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
}