Spaces:
Sleeping
Sleeping
| """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", | |
| ) | |
| 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() | |
| 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 | |