| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- package config
- import (
- "fmt"
- "os"
- "strings"
- "time"
- )
- // Config holds the application configuration
- type Config struct {
- DBHost string
- DBPort string
- DBUser string
- DBPassword string
- DBName string
- JWTSecret string
- ServerPort string
- GinMode string
- StoragePath string
- AccessTokenTTL time.Duration
- RefreshTokenTTL time.Duration
- }
- // Load reads configuration from environment variables with fallbacks
- func Load() *Config {
- return &Config{
- DBHost: getEnv("DB_HOST", "localhost"),
- DBPort: getEnv("DB_PORT", "5432"),
- DBUser: getEnv("DB_USER", "celestia"),
- DBPassword: getEnv("DB_PASSWORD", "celestia_secret"),
- DBName: getEnv("DB_NAME", "celestia_trace"),
- JWTSecret: getEnv("JWT_SECRET", "change-me-in-production"),
- ServerPort: getEnv("SERVER_PORT", "8080"),
- GinMode: getEnv("GIN_MODE", "release"),
- StoragePath: getEnv("STORAGE_PATH", "/data/uploads"),
- AccessTokenTTL: getDurationEnv("ACCESS_TOKEN_TTL", 30*time.Minute),
- RefreshTokenTTL: getDurationEnv("REFRESH_TOKEN_TTL", 30*24*time.Hour),
- }
- }
- // Validate prevents production from silently starting with repository defaults.
- func (c *Config) Validate() error {
- requiredDatabaseSettings := map[string]string{
- "DB_HOST": c.DBHost,
- "DB_PORT": c.DBPort,
- "DB_USER": c.DBUser,
- "DB_PASSWORD": c.DBPassword,
- "DB_NAME": c.DBName,
- }
- for name, value := range requiredDatabaseSettings {
- if strings.TrimSpace(value) == "" {
- return fmt.Errorf("%s must not be empty", name)
- }
- }
- if c.GinMode == "release" {
- weakSecrets := []string{"", "change-me-in-production", "your_jwt_secret_here_change_me"}
- for _, weak := range weakSecrets {
- if c.JWTSecret == weak {
- return fmt.Errorf("JWT_SECRET must be configured with a production secret")
- }
- }
- if len(c.JWTSecret) < 32 {
- return fmt.Errorf("JWT_SECRET must contain at least 32 characters")
- }
- }
- if strings.TrimSpace(c.StoragePath) == "" {
- return fmt.Errorf("STORAGE_PATH must not be empty")
- }
- return nil
- }
- func getEnv(key, fallback string) string {
- if value, exists := os.LookupEnv(key); exists {
- return value
- }
- return fallback
- }
- func getDurationEnv(key string, fallback time.Duration) time.Duration {
- value, exists := os.LookupEnv(key)
- if !exists {
- return fallback
- }
- parsed, err := time.ParseDuration(value)
- if err != nil || parsed <= 0 {
- return fallback
- }
- return parsed
- }
|