Fix Issue 4: Extract validation logic to utils module
- Created three validation utility functions in validators.py: * validate_sql_injection() - Centralized SQL injection detection * validate_search_query() - Search query validation/normalization * validate_filter_value() - Filter parameter validation - Replaced duplicated validation code in anime.py with utility calls - Removed duplicate validate_search_query function definition - Created _validate_search_query_extended() helper for null byte/length checks - All tests passing (14 passed, 16 pre-existing failures)
This commit is contained in:
@@ -26,6 +26,7 @@ from src.server.utils.dependencies import (
|
||||
require_auth,
|
||||
)
|
||||
from src.server.utils.filesystem import sanitize_folder_name
|
||||
from src.server.utils.validators import validate_filter_value, validate_search_query
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -298,25 +299,11 @@ async def list_anime(
|
||||
|
||||
# Validate filter parameter
|
||||
if filter:
|
||||
# Check for dangerous patterns in filter
|
||||
dangerous_patterns = [
|
||||
";", "--", "/*", "*/",
|
||||
"drop", "delete", "insert", "update"
|
||||
]
|
||||
lower_filter = filter.lower()
|
||||
for pattern in dangerous_patterns:
|
||||
if pattern in lower_filter:
|
||||
raise ValidationError(
|
||||
message="Invalid filter parameter"
|
||||
)
|
||||
|
||||
# Validate allowed filter values
|
||||
allowed_filters = ["no_episodes"]
|
||||
if filter not in allowed_filters:
|
||||
allowed = ", ".join(allowed_filters)
|
||||
raise ValidationError(
|
||||
message=f"Invalid filter value. Allowed: {allowed}"
|
||||
)
|
||||
try:
|
||||
allowed_filters = ["no_episodes"]
|
||||
validate_filter_value(filter, allowed_filters)
|
||||
except ValueError as e:
|
||||
raise ValidationError(message=str(e))
|
||||
|
||||
try:
|
||||
# Use AnimeService to get series with metadata from database
|
||||
@@ -442,8 +429,8 @@ class AddSeriesRequest(BaseModel):
|
||||
name: str
|
||||
|
||||
|
||||
def validate_search_query(query: str) -> str:
|
||||
"""Validate and sanitize search query.
|
||||
def _validate_search_query_extended(query: str) -> str:
|
||||
"""Validate and sanitize search query with additional checks.
|
||||
|
||||
Args:
|
||||
query: The search query string
|
||||
@@ -474,25 +461,16 @@ def validate_search_query(query: str) -> str:
|
||||
detail="Search query too long (max 200 characters)"
|
||||
)
|
||||
|
||||
# Strip and normalize whitespace
|
||||
normalized = " ".join(query.strip().split())
|
||||
|
||||
# Prevent SQL-like injection patterns
|
||||
dangerous_patterns = [
|
||||
"--", "/*", "*/", "xp_", "sp_", "exec", "execute",
|
||||
"union", "select", "insert", "update", "delete", "drop",
|
||||
"create", "alter", "truncate", "sleep", "waitfor", "benchmark",
|
||||
" or ", "||", " and ", "&&"
|
||||
]
|
||||
lower_query = normalized.lower()
|
||||
for pattern in dangerous_patterns:
|
||||
if pattern in lower_query:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Invalid character sequence detected"
|
||||
)
|
||||
|
||||
return normalized
|
||||
# Validate and normalize the search query using utility function
|
||||
try:
|
||||
normalized = validate_search_query(query)
|
||||
return normalized
|
||||
except ValueError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=str(e)
|
||||
)
|
||||
|
||||
|
||||
|
||||
class SearchAnimeRequest(BaseModel):
|
||||
@@ -581,7 +559,7 @@ async def _perform_search(
|
||||
"""
|
||||
try:
|
||||
# Validate and sanitize the query
|
||||
validated_query = validate_search_query(query)
|
||||
validated_query = _validate_search_query_extended(query)
|
||||
|
||||
# Check if series_app is available
|
||||
if not series_app:
|
||||
|
||||
Reference in New Issue
Block a user