package logger import ( "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io" "time" ) // FilterMessageEnhanced provides comprehensive filtering with audit logging func (sf *SecureFilter) FilterMessageEnhanced(message string, context map[string]interface{}) string { originalMessage := message filtered := sf.FilterMessage(message) // Audit sensitive data detection if enabled if sf.auditEnabled { auditData := sf.detectSensitiveData(originalMessage, context) if len(auditData) > 0 { sf.logAuditEvent(auditData) } } return filtered } // detectSensitiveData identifies and catalogs sensitive data found in messages func (sf *SecureFilter) detectSensitiveData(message string, context map[string]interface{}) map[string]interface{} { detected := make(map[string]interface{}) detected["timestamp"] = time.Now().UTC().Format(time.RFC3339) detected["security_level"] = sf.level if context != nil { detected["context"] = context } // Check for different types of sensitive data sensitiveTypes := []string{} // Check for private keys (CRITICAL) for _, pattern := range sf.privateKeyPatterns { if pattern.MatchString(message) { sensitiveTypes = append(sensitiveTypes, "private_key") detected["severity"] = "CRITICAL" break } } // Check for transaction hashes BEFORE addresses (64 chars vs 40 chars) for _, pattern := range sf.hashPatterns { if pattern.MatchString(message) { sensitiveTypes = append(sensitiveTypes, "transaction_hash") if detected["severity"] == nil { detected["severity"] = "LOW" } break } } // Check for addresses AFTER hashes for _, pattern := range sf.addressPatterns { if pattern.MatchString(message) { sensitiveTypes = append(sensitiveTypes, "address") if detected["severity"] == nil { detected["severity"] = "MEDIUM" } break } } // Check for amounts/values for _, pattern := range sf.amountPatterns { if pattern.MatchString(message) { sensitiveTypes = append(sensitiveTypes, "amount") if detected["severity"] == nil { detected["severity"] = "LOW" } break } } if len(sensitiveTypes) > 0 { detected["types"] = sensitiveTypes detected["message_length"] = len(message) detected["filtered_length"] = len(sf.FilterMessage(message)) return detected } return nil } // logAuditEvent logs sensitive data detection events func (sf *SecureFilter) logAuditEvent(auditData map[string]interface{}) { // Create audit log entry auditEntry := map[string]interface{}{ "event_type": "sensitive_data_detected", "timestamp": auditData["timestamp"], "severity": auditData["severity"], "types": auditData["types"], "message_stats": map[string]interface{}{ "original_length": auditData["message_length"], "filtered_length": auditData["filtered_length"], }, } if auditData["context"] != nil { auditEntry["context"] = auditData["context"] } // Encrypt audit data if encryption is enabled if sf.auditEncryption && len(sf.encryptionKey) > 0 { encrypted, err := sf.encryptAuditData(auditEntry) if err == nil { auditEntry = map[string]interface{}{ "encrypted": true, "data": encrypted, "timestamp": auditData["timestamp"], } } } // Log to audit trail (this would typically go to a separate audit log file) // For now, we'll add it to a structured format that can be easily extracted auditJSON, _ := json.Marshal(auditEntry) fmt.Printf("AUDIT_LOG: %s\n", string(auditJSON)) } // encryptAuditData encrypts sensitive audit data func (sf *SecureFilter) encryptAuditData(data map[string]interface{}) (string, error) { if len(sf.encryptionKey) == 0 { return "", fmt.Errorf("no encryption key available") } // Serialize data to JSON jsonData, err := json.Marshal(data) if err != nil { return "", fmt.Errorf("failed to marshal audit data: %w", err) } // Create AES-GCM cipher (AEAD - authenticated encryption) key := sha256.Sum256(sf.encryptionKey) block, err := aes.NewCipher(key[:]) if err != nil { return "", fmt.Errorf("failed to create cipher: %w", err) } // Create GCM instance gcm, err := cipher.NewGCM(block) if err != nil { return "", fmt.Errorf("failed to create GCM: %w", err) } // Generate random nonce nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", fmt.Errorf("failed to generate nonce: %w", err) } // Encrypt and authenticate data encrypted := gcm.Seal(nonce, nonce, jsonData, nil) return hex.EncodeToString(encrypted), nil } // DecryptAuditData decrypts audit data (for authorized access) func (sf *SecureFilter) DecryptAuditData(encryptedHex string) (map[string]interface{}, error) { if len(sf.encryptionKey) == 0 { return nil, fmt.Errorf("no encryption key available") } // Decode hex encryptedData, err := hex.DecodeString(encryptedHex) if err != nil { return nil, fmt.Errorf("failed to decode hex: %w", err) } // Create AES-GCM cipher (AEAD - authenticated encryption) key := sha256.Sum256(sf.encryptionKey) block, err := aes.NewCipher(key[:]) if err != nil { return nil, fmt.Errorf("failed to create cipher: %w", err) } // Create GCM instance gcm, err := cipher.NewGCM(block) if err != nil { return nil, fmt.Errorf("failed to create GCM: %w", err) } // Check minimum length (nonce + encrypted data + tag) if len(encryptedData) < gcm.NonceSize() { return nil, fmt.Errorf("encrypted data too short") } // Extract nonce and encrypted data nonce := encryptedData[:gcm.NonceSize()] ciphertext := encryptedData[gcm.NonceSize():] // Decrypt and authenticate data decrypted, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, fmt.Errorf("failed to decrypt data: %w", err) } // Unmarshal JSON var result map[string]interface{} err = json.Unmarshal(decrypted, &result) if err != nil { return nil, fmt.Errorf("failed to unmarshal decrypted data: %w", err) } return result, nil } // EnableAuditLogging enables audit logging with optional encryption func (sf *SecureFilter) EnableAuditLogging(encryptionKey []byte) { sf.auditEnabled = true if len(encryptionKey) > 0 { sf.encryptionKey = encryptionKey sf.auditEncryption = true } } // DisableAuditLogging disables audit logging func (sf *SecureFilter) DisableAuditLogging() { sf.auditEnabled = false sf.auditEncryption = false } // SetSecurityLevel changes the security level dynamically func (sf *SecureFilter) SetSecurityLevel(level SecurityLevel) { sf.level = level } // GetSecurityLevel returns the current security level func (sf *SecureFilter) GetSecurityLevel() SecurityLevel { return sf.level }