Hatmanstack
test fixes
2619049
"""Input validation for user-provided data."""
import re
from pydantic import BaseModel, Field, field_validator
# Patterns that indicate SQL injection attempts
SQL_INJECTION_PATTERNS: list[str] = [
r'[";]', # Double quotes and semicolons (apostrophes allowed for names like O'Neal)
r"--", # SQL comment
r"/\*", # Block comment start
r"\*/", # Block comment end
r"\bUNION\b", # UNION keyword
r"\bSELECT\b", # SELECT keyword
r"\bINSERT\b", # INSERT keyword
r"\bUPDATE\b", # UPDATE keyword
r"\bDELETE\b", # DELETE keyword
r"\bDROP\b", # DROP keyword
r"\bEXEC\b", # EXEC keyword
r"\bOR\s+\d+=\d+", # OR 1=1 pattern
r"\bAND\s+\d+=\d+", # AND 1=1 pattern
r"'\s*OR\s", # ' OR pattern (SQL injection)
r"'\s*AND\s", # ' AND pattern (SQL injection)
]
# Compiled regex for efficiency
SQL_INJECTION_REGEX = re.compile(
"|".join(SQL_INJECTION_PATTERNS), re.IGNORECASE
)
class PlayerSearchInput(BaseModel):
"""Validated player search input."""
search_term: str = Field(
...,
min_length=1,
max_length=100,
description="Player name search term",
)
@field_validator("search_term")
@classmethod
def validate_no_sql_injection(cls, v: str) -> str:
"""Reject inputs containing SQL injection patterns.
Args:
v: Input search term
Returns:
Validated search term
Raises:
ValueError: If SQL injection pattern detected
"""
if SQL_INJECTION_REGEX.search(v):
raise ValueError(
"Invalid characters in search term. "
"Please use only letters, numbers, spaces, and hyphens."
)
return v.strip()
@field_validator("search_term")
@classmethod
def validate_reasonable_characters(cls, v: str) -> str:
"""Ensure search term contains only reasonable characters.
Args:
v: Input search term
Returns:
Validated search term
Raises:
ValueError: If invalid characters found
"""
# Allow letters, numbers, spaces, hyphens, periods, and apostrophes
# (e.g., "O'Neal", "J.R. Smith")
if not re.match(r"^[a-zA-Z0-9\s\-.']+$", v):
raise ValueError(
"Search term contains invalid characters. "
"Please use only letters, numbers, spaces, hyphens, "
"periods, and apostrophes."
)
return v
def validate_search_term(term: str) -> str | None:
"""Validate a player search term.
Args:
term: Raw search input
Returns:
Validated and cleaned search term, or None if invalid
"""
try:
validated = PlayerSearchInput(search_term=term)
return validated.search_term
except ValueError:
return None
def is_valid_search_term(term: str) -> bool:
"""Check if a search term is valid without raising exceptions.
Args:
term: Raw search input
Returns:
True if valid, False otherwise
"""
return validate_search_term(term) is not None