Spaces:
Sleeping
Sleeping
File size: 3,152 Bytes
6424951 2619049 6424951 2619049 6424951 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | """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
|