Files
omega-server/local/utl/configs/config.go
Fran Jurmanović 016728532c init bootstrap
2025-07-06 15:02:09 +02:00

221 lines
6.2 KiB
Go

package configs
import (
"os"
"strconv"
"time"
)
// API configuration constants
const (
// Prefix for all API routes
Prefix = "/api/v1"
// Default values
DefaultPort = "3000"
DefaultDatabaseName = "app.db"
DefaultJWTExpiryHours = 24
DefaultPasswordMinLen = 8
DefaultMaxLoginAttempts = 5
DefaultLockoutMinutes = 30
DefaultRateLimitReqs = 100
DefaultRateLimitWindow = 1 // minute
)
// Environment variable keys
const (
EnvPort = "PORT"
EnvDatabaseName = "DB_NAME"
EnvJWTSecret = "JWT_SECRET"
EnvAppSecret = "APP_SECRET"
EnvAppSecretCode = "APP_SECRET_CODE"
EnvEncryptionKey = "ENCRYPTION_KEY"
EnvCORSAllowedOrigin = "CORS_ALLOWED_ORIGIN"
EnvLogLevel = "LOG_LEVEL"
EnvDebugMode = "DEBUG_MODE"
EnvDefaultAdminPassword = "DEFAULT_ADMIN_PASSWORD"
EnvJWTAccessTTLHours = "JWT_ACCESS_TTL_HOURS"
EnvJWTRefreshTTLDays = "JWT_REFRESH_TTL_DAYS"
EnvJWTIssuer = "JWT_ISSUER"
)
// GetEnv returns environment variable value or default
func GetEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
// GetEnvInt returns environment variable as integer or default
func GetEnvInt(key string, defaultValue int) int {
if value := os.Getenv(key); value != "" {
if intValue, err := strconv.Atoi(value); err == nil {
return intValue
}
}
return defaultValue
}
// GetEnvBool returns environment variable as boolean or default
func GetEnvBool(key string, defaultValue bool) bool {
if value := os.Getenv(key); value != "" {
if boolValue, err := strconv.ParseBool(value); err == nil {
return boolValue
}
}
return defaultValue
}
// GetEnvDuration returns environment variable as duration or default
func GetEnvDuration(key string, defaultValue time.Duration) time.Duration {
if value := os.Getenv(key); value != "" {
if duration, err := time.ParseDuration(value); err == nil {
return duration
}
}
return defaultValue
}
// Config holds application configuration
type Config struct {
// Server configuration
Port string
DatabaseName string
LogLevel string
DebugMode bool
// Security configuration
JWTSecret string
AppSecret string
AppSecretCode string
EncryptionKey string
JWTAccessTTLHours int
JWTRefreshTTLDays int
JWTIssuer string
PasswordMinLength int
MaxLoginAttempts int
LockoutDurationMins int
// CORS configuration
CORSAllowedOrigin string
// Rate limiting
RateLimitRequests int
RateLimitWindow int // minutes
// Admin configuration
DefaultAdminPassword string
}
// LoadConfig loads configuration from environment variables
func LoadConfig() *Config {
return &Config{
// Server configuration
Port: GetEnv(EnvPort, DefaultPort),
DatabaseName: GetEnv(EnvDatabaseName, DefaultDatabaseName),
LogLevel: GetEnv(EnvLogLevel, "INFO"),
DebugMode: GetEnvBool(EnvDebugMode, false),
// Security configuration
JWTSecret: GetEnv(EnvJWTSecret, ""),
AppSecret: GetEnv(EnvAppSecret, ""),
AppSecretCode: GetEnv(EnvAppSecretCode, ""),
EncryptionKey: GetEnv(EnvEncryptionKey, ""),
JWTAccessTTLHours: GetEnvInt(EnvJWTAccessTTLHours, DefaultJWTExpiryHours),
JWTRefreshTTLDays: GetEnvInt(EnvJWTRefreshTTLDays, 7),
JWTIssuer: GetEnv(EnvJWTIssuer, "omega-server"),
PasswordMinLength: GetEnvInt("PASSWORD_MIN_LENGTH", DefaultPasswordMinLen),
MaxLoginAttempts: GetEnvInt("MAX_LOGIN_ATTEMPTS", DefaultMaxLoginAttempts),
LockoutDurationMins: GetEnvInt("LOCKOUT_DURATION_MINUTES", DefaultLockoutMinutes),
// CORS configuration
CORSAllowedOrigin: GetEnv(EnvCORSAllowedOrigin, "http://localhost:5173"),
// Rate limiting
RateLimitRequests: GetEnvInt("RATE_LIMIT_REQUESTS", DefaultRateLimitReqs),
RateLimitWindow: GetEnvInt("RATE_LIMIT_WINDOW_MINUTES", DefaultRateLimitWindow),
// Admin configuration
DefaultAdminPassword: GetEnv(EnvDefaultAdminPassword, ""),
}
}
// Validate validates the configuration
func (c *Config) Validate() []string {
var errors []string
// Required security settings
if c.JWTSecret == "" {
errors = append(errors, "JWT_SECRET is required")
}
if c.AppSecret == "" {
errors = append(errors, "APP_SECRET is required")
}
if c.AppSecretCode == "" {
errors = append(errors, "APP_SECRET_CODE is required")
}
if c.EncryptionKey == "" {
errors = append(errors, "ENCRYPTION_KEY is required")
}
// Validate encryption key length (must be 32 characters for AES-256)
if len(c.EncryptionKey) != 32 {
errors = append(errors, "ENCRYPTION_KEY must be exactly 32 characters long")
}
// Validate JWT settings
if c.JWTAccessTTLHours <= 0 {
errors = append(errors, "JWT_ACCESS_TTL_HOURS must be greater than 0")
}
if c.JWTRefreshTTLDays <= 0 {
errors = append(errors, "JWT_REFRESH_TTL_DAYS must be greater than 0")
}
// Validate password settings
if c.PasswordMinLength < 8 {
errors = append(errors, "PASSWORD_MIN_LENGTH must be at least 8")
}
// Validate rate limiting
if c.RateLimitRequests <= 0 {
errors = append(errors, "RATE_LIMIT_REQUESTS must be greater than 0")
}
if c.RateLimitWindow <= 0 {
errors = append(errors, "RATE_LIMIT_WINDOW_MINUTES must be greater than 0")
}
return errors
}
// IsProduction returns true if running in production mode
func (c *Config) IsProduction() bool {
env := GetEnv("GO_ENV", "development")
return env == "production"
}
// IsDevelopment returns true if running in development mode
func (c *Config) IsDevelopment() bool {
return !c.IsProduction()
}
// GetJWTAccessTTL returns JWT access token TTL as duration
func (c *Config) GetJWTAccessTTL() time.Duration {
return time.Duration(c.JWTAccessTTLHours) * time.Hour
}
// GetJWTRefreshTTL returns JWT refresh token TTL as duration
func (c *Config) GetJWTRefreshTTL() time.Duration {
return time.Duration(c.JWTRefreshTTLDays) * 24 * time.Hour
}
// GetLockoutDuration returns account lockout duration
func (c *Config) GetLockoutDuration() time.Duration {
return time.Duration(c.LockoutDurationMins) * time.Minute
}
// GetRateLimitWindow returns rate limit window as duration
func (c *Config) GetRateLimitWindow() time.Duration {
return time.Duration(c.RateLimitWindow) * time.Minute
}