package ect import ( "os" "strconv" "time" ) // Env names for production configuration. All optional; zero values use defaults. const ( EnvIATMaxAgeMinutes = "ECT_IAT_MAX_AGE_MINUTES" // max age of iat (default 15) EnvIATMaxFutureSec = "ECT_IAT_MAX_FUTURE_SEC" // max iat in future / clock skew (default 30) EnvDefaultExpiryMin = "ECT_DEFAULT_EXPIRY_MIN" // default token expiry when exp is zero (default 10) EnvJTIReplayCacheSize = "ECT_JTI_REPLAY_CACHE_SIZE" // max JTIs to remember for replay check (0 = disabled) EnvJTIReplayTTLMin = "ECT_JTI_REPLAY_TTL_MIN" // TTL for JTI cache entries (default 60) ) // Config holds production-friendly settings loaded from environment. type Config struct { IATMaxAge time.Duration IATMaxFuture time.Duration DefaultExpiry time.Duration JTIReplaySize int // 0 = no replay cache JTIReplayTTL time.Duration } // DefaultConfig returns in-process defaults (no env). func DefaultConfig() Config { return Config{ IATMaxAge: 15 * time.Minute, IATMaxFuture: 30 * time.Second, DefaultExpiry: 10 * time.Minute, JTIReplayTTL: 60 * time.Minute, } } // LoadConfigFromEnv returns Config with values from environment where set. func LoadConfigFromEnv() Config { c := DefaultConfig() if v := os.Getenv(EnvIATMaxAgeMinutes); v != "" { if n, err := strconv.Atoi(v); err == nil && n > 0 { c.IATMaxAge = time.Duration(n) * time.Minute } } if v := os.Getenv(EnvIATMaxFutureSec); v != "" { if n, err := strconv.Atoi(v); err == nil && n >= 0 { c.IATMaxFuture = time.Duration(n) * time.Second } } if v := os.Getenv(EnvDefaultExpiryMin); v != "" { if n, err := strconv.Atoi(v); err == nil && n > 0 { c.DefaultExpiry = time.Duration(n) * time.Minute } } if v := os.Getenv(EnvJTIReplayCacheSize); v != "" { if n, err := strconv.Atoi(v); err == nil && n >= 0 { c.JTIReplaySize = n } } if v := os.Getenv(EnvJTIReplayTTLMin); v != "" { if n, err := strconv.Atoi(v); err == nil && n > 0 { c.JTIReplayTTL = time.Duration(n) * time.Minute } } return c } // CreateOptions returns CreateOptions from this config. func (c Config) CreateOptions(keyID string) CreateOptions { return CreateOptions{ KeyID: keyID, IATMaxAge: c.IATMaxAge, DefaultExpiry: c.DefaultExpiry, } } // VerifyOptions returns VerifyOptions from this config (VerifierID, ResolveKey, Store must be set by caller). func (c Config) VerifyOptions() VerifyOptions { opts := DefaultVerifyOptions() opts.IATMaxAge = c.IATMaxAge opts.IATMaxFuture = c.IATMaxFuture opts.DAG = DefaultDAGConfig() return opts }