package config import ( "encoding/json" "os" ) // Config holds the heuristic service configuration type Config struct { Port string `json:"port"` RedisURL string `json:"redis_url"` JWTSecret string `json:"jwt_secret"` // Heuristic thresholds Thresholds ThresholdConfig `json:"thresholds"` // Heuristic weights Weights WeightConfig `json:"weights"` // Step-up configuration StepUp StepUpConfig `json:"step_up"` // Tick configuration Tick TickConfig `json:"tick"` // Compliance settings Compliance ComplianceConfig `json:"compliance"` } // ThresholdConfig defines score thresholds type ThresholdConfig struct { ScorePass float64 `json:"score_pass"` // Score to pass without step-up (e.g., 0.7) ScoreChallenge float64 `json:"score_challenge"` // Score below which step-up is required (e.g., 0.4) } // WeightConfig defines weights for each heuristic type WeightConfig struct { DwellRatio float64 `json:"dwell_ratio"` // Weight for dwell time ratio ScrollScore float64 `json:"scroll_score"` // Weight for scroll depth PointerVariance float64 `json:"pointer_variance"` // Weight for mouse movement patterns ClickRate float64 `json:"click_rate"` // Weight for click interactions } // StepUpConfig defines step-up verification methods type StepUpConfig struct { Methods []string `json:"methods"` // ["webauthn", "pow"] Primary string `json:"primary"` // Preferred method WebAuthn WebAuthnConfig `json:"webauthn"` PoW PoWConfig `json:"pow"` } // WebAuthnConfig for WebAuthn step-up type WebAuthnConfig struct { Enabled bool `json:"enabled"` UserVerification string `json:"userVerification"` // "preferred", "required", "discouraged" TimeoutMs int `json:"timeout_ms"` ChallengeEndpoint string `json:"challenge_endpoint"` } // PoWConfig for Proof-of-Work step-up type PoWConfig struct { Enabled bool `json:"enabled"` Difficulty int `json:"difficulty"` // Number of leading zero bits required MaxDurationMs int `json:"max_duration_ms"` // Max time for PoW computation } // TickConfig for periodic tick submissions type TickConfig struct { Endpoint string `json:"endpoint"` IntervalMs int `json:"interval_ms"` } // ComplianceConfig for privacy compliance type ComplianceConfig struct { GDPR bool `json:"gdpr"` AnonymizeIP bool `json:"anonymize_ip"` NoCookies bool `json:"no_cookies"` NoPII bool `json:"no_pii"` } // PathConfig for path-specific rules type PathConfig struct { MinScore float64 `json:"min_score"` StepUpMethod *string `json:"step_up_method"` // nil means no step-up } // DefaultConfig returns a default configuration func DefaultConfig() *Config { return &Config{ Port: getEnv("PORT", "8085"), RedisURL: getEnv("REDIS_URL", "redis://localhost:6379"), JWTSecret: getEnv("JWT_SECRET", "pca-secret-change-me"), Thresholds: ThresholdConfig{ ScorePass: 0.7, ScoreChallenge: 0.4, }, Weights: WeightConfig{ DwellRatio: 0.30, ScrollScore: 0.25, PointerVariance: 0.20, ClickRate: 0.25, }, StepUp: StepUpConfig{ Methods: []string{"webauthn", "pow"}, Primary: "webauthn", WebAuthn: WebAuthnConfig{ Enabled: true, UserVerification: "preferred", TimeoutMs: 60000, ChallengeEndpoint: "/pca/v1/webauthn-challenge", }, PoW: PoWConfig{ Enabled: true, Difficulty: 4, MaxDurationMs: 5000, }, }, Tick: TickConfig{ Endpoint: "/pca/v1/tick", IntervalMs: 5000, }, Compliance: ComplianceConfig{ GDPR: true, AnonymizeIP: true, NoCookies: true, NoPII: true, }, } } // LoadFromFile loads configuration from a JSON file func LoadFromFile(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return DefaultConfig(), nil // Return default if file not found } config := DefaultConfig() if err := json.Unmarshal(data, config); err != nil { return nil, err } return config, nil } func getEnv(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue }