package utils
import (
"html"
"regexp"
"strings"
"unicode/utf8"
)
// Sanitizer provides input sanitization utilities
type Sanitizer struct {
// Max lengths for common fields
MaxNameLength int
MaxDescriptionLength int
MaxEmailLength int
}
// DefaultSanitizer returns a sanitizer with default settings
func DefaultSanitizer() *Sanitizer {
return &Sanitizer{
MaxNameLength: 255,
MaxDescriptionLength: 10000,
MaxEmailLength: 320,
}
}
// SanitizeString escapes HTML and trims whitespace
func (s *Sanitizer) SanitizeString(input string) string {
if input == "" {
return ""
}
// Trim whitespace
result := strings.TrimSpace(input)
// Escape HTML entities to prevent XSS
result = html.EscapeString(result)
return result
}
// SanitizeName sanitizes a name field
func (s *Sanitizer) SanitizeName(input string) string {
sanitized := s.SanitizeString(input)
if utf8.RuneCountInString(sanitized) > s.MaxNameLength {
runes := []rune(sanitized)
sanitized = string(runes[:s.MaxNameLength])
}
return sanitized
}
// SanitizeEmail sanitizes and validates email format
func (s *Sanitizer) SanitizeEmail(input string) string {
sanitized := strings.TrimSpace(strings.ToLower(input))
if utf8.RuneCountInString(sanitized) > s.MaxEmailLength {
return ""
}
return sanitized
}
// SanitizeDescription sanitizes long text fields
func (s *Sanitizer) SanitizeDescription(input string) string {
sanitized := s.SanitizeString(input)
if utf8.RuneCountInString(sanitized) > s.MaxDescriptionLength {
runes := []rune(sanitized)
sanitized = string(runes[:s.MaxDescriptionLength])
}
return sanitized
}
// SanitizeSlug creates a URL-safe slug
func (s *Sanitizer) SanitizeSlug(input string) string {
// Convert to lowercase
result := strings.ToLower(strings.TrimSpace(input))
// Replace spaces with hyphens
result = strings.ReplaceAll(result, " ", "-")
// Remove non-alphanumeric characters except hyphens
reg := regexp.MustCompile(`[^a-z0-9-]`)
result = reg.ReplaceAllString(result, "")
// Remove multiple consecutive hyphens
reg = regexp.MustCompile(`-+`)
result = reg.ReplaceAllString(result, "-")
// Trim hyphens from ends
result = strings.Trim(result, "-")
return result
}
// StripHTML removes all HTML tags from input
func StripHTML(input string) string {
reg := regexp.MustCompile(`<[^>]*>`)
return reg.ReplaceAllString(input, "")
}
// SanitizePhone cleans a phone number, keeping only digits and an optional
// leading '+' (international dialing prefix). Removes all formatting characters
// such as spaces, dashes, parentheses, and dots.
//
// Examples:
//
// "+55 (11) 99999-8888" → "+5511999998888"
// "(11) 99999-8888" → "11999998888"
// "+1-800-555-0100" → "+18005550100"
func SanitizePhone(phone string) string {
phone = strings.TrimSpace(phone)
if phone == "" {
return ""
}
hasPlus := strings.HasPrefix(phone, "+")
digitsOnly := regexp.MustCompile(`\D`).ReplaceAllString(phone, "")
if hasPlus {
return "+" + digitsOnly
}
return digitsOnly
}