Services: Admin-Compliance, Backend-Compliance, AI-Compliance-SDK, Consent-SDK, Developer-Portal, PCA-Platform, DSMS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
152 lines
4.1 KiB
Go
152 lines
4.1 KiB
Go
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
|
|
}
|