package config import ( "log" "os" "strconv" "github.com/joho/godotenv" ) type Config struct { AppPort string DBHost string DBPort string DBUser string DBPassword string DBName string RedisAddr string RedisPassword string JWTSecret string RefreshSecret string JWTExpiryHours int AdminUsername string AdminPassword string BaseURL string GameDir string // Chain integration ChainNodeURL string ChainID string OperatorKeyHex string WalletEncryptionKey string // Server-to-server auth InternalAPIKey string // SSAFY OAuth 2.0 SSAFYClientID string SSAFYClientSecret string SSAFYRedirectURI string } var C Config func Load() { _ = godotenv.Load() hours, _ := strconv.Atoi(getEnv("JWT_EXPIRY_HOURS", "24")) C = Config{ AppPort: getEnv("APP_PORT", "8080"), DBHost: getEnv("DB_HOST", "localhost"), DBPort: getEnv("DB_PORT", "3306"), DBUser: getEnv("DB_USER", "root"), DBPassword: getEnv("DB_PASSWORD", ""), DBName: getEnv("DB_NAME", "a301"), RedisAddr: getEnv("REDIS_ADDR", "localhost:6379"), RedisPassword: getEnv("REDIS_PASSWORD", ""), JWTSecret: getEnv("JWT_SECRET", "secret"), RefreshSecret: getEnv("REFRESH_SECRET", "refresh-secret"), JWTExpiryHours: hours, AdminUsername: getEnv("ADMIN_USERNAME", "admin"), AdminPassword: getEnv("ADMIN_PASSWORD", "admin1234"), BaseURL: getEnv("BASE_URL", "http://localhost:8080"), GameDir: getEnv("GAME_DIR", "/data/game"), ChainNodeURL: getEnv("CHAIN_NODE_URL", "http://localhost:8545"), ChainID: getEnv("CHAIN_ID", "tolchain-dev"), OperatorKeyHex: getEnv("OPERATOR_KEY_HEX", ""), WalletEncryptionKey: getEnv("WALLET_ENCRYPTION_KEY", ""), InternalAPIKey: getEnv("INTERNAL_API_KEY", ""), SSAFYClientID: getEnv("SSAFY_CLIENT_ID", ""), SSAFYClientSecret: getEnv("SSAFY_CLIENT_SECRET", ""), SSAFYRedirectURI: getEnv("SSAFY_REDIRECT_URI", ""), } } // WarnInsecureDefaults logs warnings for security-sensitive settings left at defaults. // In production mode (APP_ENV=production), insecure defaults cause a fatal exit. func WarnInsecureDefaults() { isProd := getEnv("APP_ENV", "") == "production" insecure := false if C.JWTSecret == "secret" { log.Println("WARNING: JWT_SECRET is using the default value — set a strong secret for production") insecure = true } if C.RefreshSecret == "refresh-secret" { log.Println("WARNING: REFRESH_SECRET is using the default value — set a strong secret for production") insecure = true } if C.AdminPassword == "admin1234" { log.Println("WARNING: ADMIN_PASSWORD is using the default value — change it for production") insecure = true } if C.WalletEncryptionKey == "" { log.Println("WARNING: WALLET_ENCRYPTION_KEY is empty — blockchain wallet features will fail") } if isProd && insecure { log.Fatal("FATAL: insecure default secrets detected in production — set JWT_SECRET, REFRESH_SECRET, and ADMIN_PASSWORD") } } func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback }