120 lines
3.1 KiB
Go
120 lines
3.1 KiB
Go
package validation
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
)
|
|
|
|
// ValidatePathUUID validates a UUID path parameter
|
|
// CWE-20: Improper Input Validation
|
|
func ValidatePathUUID(r *http.Request, paramName string) (string, error) {
|
|
value := r.PathValue(paramName)
|
|
if value == "" {
|
|
return "", fmt.Errorf("%s is required", paramName)
|
|
}
|
|
|
|
validator := NewValidator()
|
|
if err := validator.ValidateUUID(value, paramName); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
// ValidatePathSlug validates a slug path parameter
|
|
// CWE-20: Improper Input Validation
|
|
func ValidatePathSlug(r *http.Request, paramName string) (string, error) {
|
|
value := r.PathValue(paramName)
|
|
if value == "" {
|
|
return "", fmt.Errorf("%s is required", paramName)
|
|
}
|
|
|
|
validator := NewValidator()
|
|
if err := validator.ValidateSlug(value, paramName); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
// ValidatePathInt validates an integer path parameter
|
|
// CWE-20: Improper Input Validation
|
|
func ValidatePathInt(r *http.Request, paramName string) (int64, error) {
|
|
valueStr := r.PathValue(paramName)
|
|
if valueStr == "" {
|
|
return 0, fmt.Errorf("%s is required", paramName)
|
|
}
|
|
|
|
value, err := strconv.ParseInt(valueStr, 10, 64)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("%s must be a valid integer", paramName)
|
|
}
|
|
|
|
if value <= 0 {
|
|
return 0, fmt.Errorf("%s must be greater than 0", paramName)
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
// ValidatePagination validates pagination query parameters
|
|
// Returns limit and offset with defaults and bounds checking
|
|
func ValidatePagination(r *http.Request, defaultLimit int) (limit int, offset int, err error) {
|
|
limit = defaultLimit
|
|
offset = 0
|
|
|
|
// Validate limit
|
|
if limitStr := r.URL.Query().Get("limit"); limitStr != "" {
|
|
parsedLimit, err := strconv.Atoi(limitStr)
|
|
if err != nil || parsedLimit <= 0 || parsedLimit > 100 {
|
|
return 0, 0, fmt.Errorf("limit must be between 1 and 100")
|
|
}
|
|
limit = parsedLimit
|
|
}
|
|
|
|
// Validate offset
|
|
if offsetStr := r.URL.Query().Get("offset"); offsetStr != "" {
|
|
parsedOffset, err := strconv.Atoi(offsetStr)
|
|
if err != nil || parsedOffset < 0 {
|
|
return 0, 0, fmt.Errorf("offset must be >= 0")
|
|
}
|
|
offset = parsedOffset
|
|
}
|
|
|
|
return limit, offset, nil
|
|
}
|
|
|
|
// ValidateSortField validates sort field against whitelist
|
|
// CWE-89: SQL Injection prevention via whitelist
|
|
func ValidateSortField(r *http.Request, allowedFields []string) (string, error) {
|
|
sortBy := r.URL.Query().Get("sort_by")
|
|
if sortBy == "" {
|
|
return "", nil // Optional field
|
|
}
|
|
|
|
for _, allowed := range allowedFields {
|
|
if sortBy == allowed {
|
|
return sortBy, nil
|
|
}
|
|
}
|
|
|
|
return "", fmt.Errorf("invalid sort_by field (allowed: %v)", allowedFields)
|
|
}
|
|
|
|
// ValidateQueryEmail validates an email query parameter
|
|
// CWE-20: Improper Input Validation
|
|
func ValidateQueryEmail(r *http.Request, paramName string) (string, error) {
|
|
email := r.URL.Query().Get(paramName)
|
|
if email == "" {
|
|
return "", fmt.Errorf("%s is required", paramName)
|
|
}
|
|
|
|
emailValidator := NewEmailValidator()
|
|
normalizedEmail, err := emailValidator.ValidateAndNormalize(email, paramName)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return normalizedEmail, nil
|
|
}
|