package logging import ( "regexp" "strings" ) // RedactedValue is the replacement string for sensitive data. const RedactedValue = "[REDACTED]" // sensitiveFieldPatterns are field name patterns that indicate sensitive data. // These are matched case-insensitively. var sensitiveFieldPatterns = []string{ "password", "passwd", "secret", "token", "api_key", "apikey", "api-key", "auth", "bearer", "credential", "private", "key", "cert", "certificate", } // sensitiveValuePatterns are regex patterns to detect sensitive values. var sensitiveValuePatterns = []*regexp.Regexp{ // Bearer tokens regexp.MustCompile(`(?i)bearer\s+[a-zA-Z0-9\-_.~+/]+=*`), // API keys (common formats) regexp.MustCompile(`(?i)(?:api[_-]?key|token|secret)[=:]\s*["']?[a-zA-Z0-9\-_.~+/]{16,}["']?`), // AWS access keys regexp.MustCompile(`AKIA[0-9A-Z]{16}`), // Private keys regexp.MustCompile(`-----BEGIN [A-Z]+ PRIVATE KEY-----`), // Connection strings with passwords (supports empty username like redis://:pass@host) regexp.MustCompile(`(?i)(?:postgres|mysql|mongodb|redis)://[^:]*:[^@]+@`), // JWT tokens (three base64 parts separated by dots) regexp.MustCompile(`eyJ[a-zA-Z0-9\-_]+\.eyJ[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+`), } // exactSensitiveFields are field names that are always sensitive. var exactSensitiveFields = map[string]bool{ "password": true, "passwd": true, "secret": true, "token": true, "api_key": true, "apikey": true, "api-key": true, "bearer": true, "authorization": true, "auth_token": true, "access_token": true, "refresh_token": true, "private_key": true, "secret_key": true, "encryption_key": true, "signing_key": true, "client_secret": true, "cookie": true, "session": true, "session_id": true, "x-api-key": true, "x-auth-token": true, "credentials": true, "credit_card": true, "cc_number": true, "cvv": true, "ssn": true, "social_security": true, "bank_account": true, "routing_number": true, "cloudflare_token": true, "gitea_token": true, "woodpecker_secret": true, } // IsSensitiveField checks if a field name indicates sensitive data. func IsSensitiveField(fieldName string) bool { lower := strings.ToLower(fieldName) // Check exact matches first (fast path) if exactSensitiveFields[lower] { return true } // Check pattern matches for _, pattern := range sensitiveFieldPatterns { if strings.Contains(lower, pattern) { return true } } return false } // RedactValue redacts a value if it matches sensitive patterns. func RedactValue(value string) string { for _, pattern := range sensitiveValuePatterns { if pattern.MatchString(value) { return RedactedValue } } return value } // ContainsSensitiveData checks if a string contains sensitive data patterns. func ContainsSensitiveData(value string) bool { for _, pattern := range sensitiveValuePatterns { if pattern.MatchString(value) { return true } } return false }