package api import ( "net/url" "path" "regexp" "strings" ) const maxIconValueLength = 160 var ( legacyIconPattern = regexp.MustCompile(`^[A-Za-z0-9_-]+(?:\s+[A-Za-z0-9_-]+)*$`) iconifyValuePattern = regexp.MustCompile(`^iconify:[a-z0-9]+(?:-[a-z0-9]+)*:[a-z0-9]+(?:-[a-z0-9]+)*$`) ) func validHTTPURL(value string) bool { parsed, err := url.ParseRequestURI(strings.TrimSpace(value)) return err == nil && parsed.Host != "" && (parsed.Scheme == "http" || parsed.Scheme == "https") } func validContactURL(value string) bool { value = strings.TrimSpace(value) parsed, err := url.ParseRequestURI(value) if err != nil { return false } if parsed.Scheme == "http" || parsed.Scheme == "https" { return parsed.Host != "" } return parsed.Scheme == "mailto" || parsed.Scheme == "tel" } func validQRCode(value string) bool { value = strings.TrimSpace(value) if strings.HasPrefix(value, "/uploads/") { return !strings.Contains(value, "\\") && path.Clean(value) == value } return validHTTPURL(value) } func validIconValue(value string) bool { value = strings.TrimSpace(value) if value == "" || len(value) > maxIconValueLength { return false } if strings.HasPrefix(value, "iconify:") { return iconifyValuePattern.MatchString(value) } return legacyIconPattern.MatchString(value) }