package validation import ( "html" "regexp" "strings" "unicode/utf8" ) // InputSanitizer provides comprehensive input sanitization type InputSanitizer struct { maxLength int } // NewInputSanitizer creates a new input sanitizer func NewInputSanitizer(maxLength int) *InputSanitizer { return &InputSanitizer{maxLength: maxLength} } // SanitizeString performs comprehensive sanitization on a string func (s *InputSanitizer) SanitizeString(input string) string { if input == "" { return input } // Check length limit if utf8.RuneCountInString(input) > s.maxLength { input = string([]rune(input)[:s.maxLength]) } // Remove null bytes and control characters input = strings.Map(func(r rune) rune { if r < 32 && r != 9 && r != 10 && r != 13 { // Allow tab, LF, CR return -1 } return r }, input) // HTML escape to prevent XSS input = html.EscapeString(input) // Remove potentially dangerous patterns dangerousPatterns := []string{ `]*>.*?`, `]*>.*?`, `]*>.*?`, `]*>.*?`, `javascript:`, `vbscript:`, `data:`, `on\w+\s*=`, } for _, pattern := range dangerousPatterns { re := regexp.MustCompile(`(?i)` + pattern) input = re.ReplaceAllString(input, "") } // Trim whitespace return strings.TrimSpace(input) } // SanitizeSQLInput sanitizes input specifically for SQL queries func (s *InputSanitizer) SanitizeSQLInput(input string) string { input = s.SanitizeString(input) // Additional SQL-specific sanitization sqlPatterns := []string{ `;`, `--`, `/*`, `*/`, `@@`, `@`, `xp_`, `sp_`, `exec`, `execute`, `information_schema`, `sysobjects`, `syscolumns`, `sysdatabases`, } for _, pattern := range sqlPatterns { input = strings.ReplaceAll(input, pattern, "") } return input } // ValidateSQLSafe checks if input is safe for SQL queries func (s *InputSanitizer) ValidateSQLSafe(input string) bool { if input == "" { return true } // Check for SQL injection patterns suspiciousPatterns := []string{ "union select", "union all select", "select.*from", "insert.*into", "update.*set", "delete.*from", "drop table", "drop database", "alter table", "create table", "information_schema", "sysobjects", "syscolumns", "sysdatabases", "mysql.", "pg_", "sqlite_", ";--", "/*", "*/", "@@", "script>", "", "|"} for _, char := range dangerousChars { filename = strings.ReplaceAll(filename, char, "") } return filename } // BatchSanitize sanitizes multiple inputs at once func (s *InputSanitizer) BatchSanitize(inputs map[string]string) map[string]string { sanitized := make(map[string]string) for key, value := range inputs { sanitized[key] = s.SanitizeString(value) } return sanitized } // IsValidInputLength checks if input length is within acceptable limits func (s *InputSanitizer) IsValidInputLength(input string, minLen, maxLen int) bool { length := utf8.RuneCountInString(input) return length >= minLen && length <= maxLen } // ContainsHTML checks if input contains HTML tags func (s *InputSanitizer) ContainsHTML(input string) bool { htmlRegex := regexp.MustCompile(`<[^>]+>`) return htmlRegex.MatchString(input) } // StripHTML removes HTML tags from input func (s *InputSanitizer) StripHTML(input string) string { htmlRegex := regexp.MustCompile(`<[^>]+>`) return htmlRegex.ReplaceAllString(input, "") }