package testutils import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "regexp" "strings" "unicode/utf8" ) type FuzzInputValidator struct { MaxInputLength int MinInputLength int } func NewFuzzInputValidator() *FuzzInputValidator { return &FuzzInputValidator{ MaxInputLength: 10000, MinInputLength: 0, } } func (f *FuzzInputValidator) ValidateFuzzInput(data []byte) bool { if !utf8.Valid(data) { return false } if len(data) < f.MinInputLength || len(data) > f.MaxInputLength { return false } return true } func (f *FuzzInputValidator) ValidateFuzzInputStrict(data []byte) bool { if !f.ValidateFuzzInput(data) { return false } input := string(data) if len(strings.TrimSpace(input)) == 0 { return false } return true } func ValidateUTF8String(s string) { if !utf8.ValidString(s) { panic("String contains invalid UTF-8") } } func ValidateNoNullBytes(s string) { if strings.Contains(s, "\x00") { panic("String contains null bytes") } } func ValidateNoScriptTags(s string) { if strings.Contains(strings.ToLower(s), "", "\"", "'", "&", "|", ";", "`", "$", "(", ")", "{", "}", "[", "]", "\\", "/", "*", "?", "!", "@", "#", "%", "^", "~"} for _, char := range dangerousChars { if strings.Contains(s, char) { panic("String contains dangerous character: " + char) } } } func ValidateNoDangerousHTMLTags(s string) { dangerousTags := []string{ "", "", "", "", "", "", } for _, tag := range dangerousTags { if strings.Contains(strings.ToLower(s), tag) { panic("String contains dangerous HTML tag: " + tag) } } } func ValidateNoPrivateIPs(s string) { privateIPs := []string{ "localhost", "127.0.0.1", "0.0.0.0", "10.", "172.", "192.168.", "169.254.169.254", } for _, ip := range privateIPs { if strings.Contains(strings.ToLower(s), ip) { panic("String contains private IP: " + ip) } } } func ValidateNoSQLInjectionPatterns(s string) { sqlPatterns := []string{ "';", "--", "/*", "*/", "xp_", "sp_", "exec", "execute", "union", "select", "insert", "update", "delete", "drop", "create", "alter", "grant", "revoke", "truncate", } lowerS := strings.ToLower(s) for _, pattern := range sqlPatterns { if strings.Contains(lowerS, pattern) { panic("String contains SQL injection pattern: " + pattern) } } } func ValidateNoExcessiveRepetition(s string, maxRepeats int) { if hasRepeatedCharacters(s, maxRepeats) { panic("String contains excessive character repetition") } words := strings.Fields(s) wordCount := make(map[string]int) for _, word := range words { wordCount[strings.ToLower(word)]++ if wordCount[strings.ToLower(word)] > 3 { panic("String contains excessive word repetition") } } } func hasRepeatedCharacters(str string, maxRepeats int) bool { if len(str) <= maxRepeats { return false } currentChar := rune(0) count := 0 for _, char := range str { if char == currentChar { count++ if count > maxRepeats { return true } } else { currentChar = char count = 1 } } return false } type FuzzJSONParser struct{} func NewFuzzJSONParser() *FuzzJSONParser { return &FuzzJSONParser{} } func (p *FuzzJSONParser) ParseJSON(data []byte) bool { var result map[string]any err := json.Unmarshal(data, &result) return err == nil } func (p *FuzzJSONParser) ParseJSONWithValidation(data []byte) { var result map[string]any err := json.Unmarshal(data, &result) if err != nil { return } for key, value := range result { ValidateUTF8String(key) if str, ok := value.(string); ok { ValidateUTF8String(str) } } } type FuzzHTTPRequest struct{} func NewFuzzHTTPRequest() *FuzzHTTPRequest { return &FuzzHTTPRequest{} } func (r *FuzzHTTPRequest) CreateTestRequest(method, url string, body []byte, headers map[string]string) *http.Request { var reqBody bytes.Buffer if body != nil { reqBody.Write(body) } req := httptest.NewRequest(method, url, &reqBody) for name, value := range headers { req.Header.Set(name, value) } return req } func (r *FuzzHTTPRequest) ValidateHTTPRequest(req *http.Request) { pathParts := strings.Split(req.URL.Path, "/") for _, part := range pathParts { ValidateUTF8String(part) } for name, values := range req.URL.Query() { ValidateUTF8String(name) for _, value := range values { ValidateUTF8String(value) } } for name, values := range req.Header { ValidateUTF8String(name) for _, value := range values { ValidateUTF8String(value) } } } type FuzzSanitizer struct{} func NewFuzzSanitizer() *FuzzSanitizer { return &FuzzSanitizer{} } func (s *FuzzSanitizer) SanitizeHTML(input string) string { scriptRegex := regexp.MustCompile(`(?i)]*>.*?`) result := scriptRegex.ReplaceAllString(input, "") jsRegex := regexp.MustCompile(`(?i)javascript:`) result = jsRegex.ReplaceAllString(result, "") eventRegex := regexp.MustCompile(`(?i)\son\w+\s*=\s*"[^"]*"`) result = eventRegex.ReplaceAllString(result, "") return result } func (s *FuzzSanitizer) SanitizeSQL(input string) string { result := strings.ReplaceAll(input, "'", "''") result = strings.ReplaceAll(result, ";", "") return result } func (s *FuzzSanitizer) SanitizeXSS(input string) string { result := strings.ReplaceAll(input, "<", "<") result = strings.ReplaceAll(result, ">", ">") result = strings.ReplaceAll(result, "\"", """) result = strings.ReplaceAll(result, "'", "'") result = strings.ReplaceAll(result, "&", "&") return result } func (s *FuzzSanitizer) SanitizeControlChars(input string) string { result := strings.ReplaceAll(input, "\x00", "") result = strings.ReplaceAll(result, "\r", "") result = strings.ReplaceAll(result, "\n", "") result = strings.ReplaceAll(result, "\t", "") return strings.TrimSpace(result) } func (s *FuzzSanitizer) ValidateSanitizedInput(input string) { ValidateUTF8String(input) ValidateNoNullBytes(input) ValidateNoScriptTags(input) ValidateNoJavascriptProtocol(input) } type FuzzValidationPipeline struct{} func NewFuzzValidationPipeline() *FuzzValidationPipeline { return &FuzzValidationPipeline{} } func (p *FuzzValidationPipeline) ProcessInput(input string) string { result := strings.TrimSpace(input) if len(result) > 1000 { result = result[:1000] } result = strings.ReplaceAll(result, "\x00", "") result = strings.ReplaceAll(result, "\r", "") result = strings.ReplaceAll(result, "\n", "") return result } func (p *FuzzValidationPipeline) ValidateProcessedInput(input string) { ValidateUTF8String(input) ValidateNoNullBytes(input) ValidateNoExcessiveRepetition(input, 5) } type FuzzTestRunner struct{} func NewFuzzTestRunner() *FuzzTestRunner { return &FuzzTestRunner{} } func (r *FuzzTestRunner) RunFuzzTest(data []byte, testFunc func(string)) int { validator := NewFuzzInputValidator() if !validator.ValidateFuzzInput(data) { return -1 } input := string(data) testFunc(input) return 0 } func (r *FuzzTestRunner) RunFuzzTestStrict(data []byte, testFunc func(string)) int { validator := NewFuzzInputValidator() if !validator.ValidateFuzzInputStrict(data) { return -1 } input := string(data) testFunc(input) return 0 } type CommonFuzzTestCases struct{} func NewCommonFuzzTestCases() *CommonFuzzTestCases { return &CommonFuzzTestCases{} } func (c *CommonFuzzTestCases) GetAuthTestCases(fuzzedData string) []map[string]any { return []map[string]any{ { "name": "auth_login", "body": `{"username":"` + fuzzedData + `","password":"test123"}`, }, { "name": "auth_register", "body": `{"username":"` + fuzzedData + `","email":"test@example.com","password":"test123"}`, }, } } func (c *CommonFuzzTestCases) GetPostTestCases(fuzzedData string) []map[string]any { return []map[string]any{ { "name": "post_create", "body": `{"title":"` + fuzzedData + `","url":"https://example.com","content":"test"}`, }, { "name": "post_search", "url": "/api/posts/search?q=" + fuzzedData, }, } } func (c *CommonFuzzTestCases) GetVoteTestCases(fuzzedData string) []map[string]any { return []map[string]any{ { "name": "vote_cast", "body": `{"type":"` + fuzzedData + `"}`, }, } }