Security fix and test reorganization
- Add sanitize_filename() to prevent Content-Disposition header injection - Remove unused imports from models.py and artifact_cleanup.py - Reorganize tests into unit/ and integration/ structure - Add factories.py for test data generation - Split old test files into focused test modules (143 tests)
This commit is contained in:
@@ -95,6 +95,18 @@ from .config import get_settings
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def sanitize_filename(filename: str) -> str:
|
||||
"""Sanitize filename for use in Content-Disposition header.
|
||||
|
||||
Removes characters that could enable header injection attacks:
|
||||
- Double quotes (") - could break out of quoted filename
|
||||
- Carriage return (\\r) and newline (\\n) - could inject headers
|
||||
"""
|
||||
import re
|
||||
|
||||
return re.sub(r'[\r\n"]', "", filename)
|
||||
|
||||
|
||||
def get_user_id(request: Request) -> str:
|
||||
"""Extract user ID from request (simplified for now)"""
|
||||
api_key = request.headers.get("X-Orchard-API-Key")
|
||||
@@ -1553,7 +1565,7 @@ def download_artifact(
|
||||
if not artifact:
|
||||
raise HTTPException(status_code=404, detail="Artifact not found")
|
||||
|
||||
filename = artifact.original_name or f"{artifact.id}"
|
||||
filename = sanitize_filename(artifact.original_name or f"{artifact.id}")
|
||||
|
||||
# Determine download mode (query param overrides server default)
|
||||
download_mode = mode or settings.download_mode
|
||||
@@ -1666,7 +1678,7 @@ def get_artifact_url(
|
||||
if not artifact:
|
||||
raise HTTPException(status_code=404, detail="Artifact not found")
|
||||
|
||||
filename = artifact.original_name or f"{artifact.id}"
|
||||
filename = sanitize_filename(artifact.original_name or f"{artifact.id}")
|
||||
url_expiry = expiry or settings.presigned_url_expiry
|
||||
|
||||
presigned_url = storage.generate_presigned_url(
|
||||
@@ -1717,7 +1729,7 @@ def head_artifact(
|
||||
if not artifact:
|
||||
raise HTTPException(status_code=404, detail="Artifact not found")
|
||||
|
||||
filename = artifact.original_name or f"{artifact.id}"
|
||||
filename = sanitize_filename(artifact.original_name or f"{artifact.id}")
|
||||
|
||||
return Response(
|
||||
content=b"",
|
||||
|
||||
Reference in New Issue
Block a user