rackham-meeting-analyzer/backend/tests/test_security.py
2025-11-03 08:15:51 -06:00

143 lines
5.3 KiB
Python

"""
Security tests for file upload validation and sanitization.
"""
import pytest
from app.core.security import (
sanitize_filename,
validate_video_file_extension,
validate_file_size
)
class TestFilenameSanitization:
"""Tests for filename sanitization to prevent security issues"""
def test_sanitize_normal_filename(self):
"""Test that normal filenames pass through correctly"""
assert sanitize_filename("meeting_video.mp4") == "meeting_video.mp4"
assert sanitize_filename("sales-call-2024.mov") == "sales-call-2024.mov"
def test_sanitize_path_traversal_attempts(self):
"""Test that path traversal attempts are blocked"""
# Unix path traversal
result = sanitize_filename("../../../etc/passwd")
assert ".." not in result
assert "/" not in result
# Windows path traversal
result = sanitize_filename("..\\..\\..\\windows\\system32\\config")
assert ".." not in result
assert "\\" not in result
# Absolute paths
result = sanitize_filename("/etc/passwd")
assert not result.startswith("/")
result = sanitize_filename("C:\\Windows\\System32\\file.mp4")
assert ":\\" not in result
def test_sanitize_null_bytes(self):
"""Test that null bytes are removed"""
result = sanitize_filename("file\x00name.mp4")
assert "\x00" not in result
def test_sanitize_special_characters(self):
"""Test that dangerous special characters are replaced"""
result = sanitize_filename("file<name>.mp4")
assert "<" not in result
assert ">" not in result
result = sanitize_filename('file"name".mp4')
assert '"' not in result
def test_sanitize_preserves_extension(self):
"""Test that file extension is preserved"""
assert sanitize_filename("test.mp4").endswith(".mp4")
assert sanitize_filename("test.MOV").endswith(".MOV")
def test_sanitize_empty_filename(self):
"""Test that empty filename gets default name"""
result = sanitize_filename("")
assert result == "unnamed_file"
result = sanitize_filename("...")
assert result == "unnamed_file"
def test_sanitize_long_filename(self):
"""Test that very long filenames are truncated"""
long_name = "a" * 300 + ".mp4"
result = sanitize_filename(long_name)
assert len(result) <= 255
assert result.endswith(".mp4")
class TestVideoFileValidation:
"""Tests for video file extension validation"""
def test_valid_video_extensions(self):
"""Test that valid video extensions are accepted"""
assert validate_video_file_extension("video.mp4") == True
assert validate_video_file_extension("video.MP4") == True
assert validate_video_file_extension("video.mov") == True
assert validate_video_file_extension("video.avi") == True
assert validate_video_file_extension("video.mkv") == True
def test_invalid_video_extensions(self):
"""Test that invalid extensions are rejected"""
assert validate_video_file_extension("document.pdf") == False
assert validate_video_file_extension("image.jpg") == False
assert validate_video_file_extension("script.exe") == False
assert validate_video_file_extension("archive.zip") == False
assert validate_video_file_extension("video.mp3") == False
def test_no_extension(self):
"""Test that files without extension are rejected"""
assert validate_video_file_extension("videofile") == False
class TestFileSizeValidation:
"""Tests for file size validation"""
def test_valid_file_sizes(self):
"""Test that reasonable file sizes are accepted"""
max_size = 2 * 1024 * 1024 * 1024 # 2GB
assert validate_file_size(100000, max_size) == True # 100KB
assert validate_file_size(1024 * 1024, max_size) == True # 1MB
assert validate_file_size(500 * 1024 * 1024, max_size) == True # 500MB
assert validate_file_size(max_size, max_size) == True # Exactly 2GB
def test_file_too_large(self):
"""Test that oversized files are rejected"""
max_size = 2 * 1024 * 1024 * 1024 # 2GB
assert validate_file_size(max_size + 1, max_size) == False
def test_zero_or_negative_size(self):
"""Test that zero or negative file sizes are rejected"""
max_size = 2 * 1024 * 1024 * 1024
assert validate_file_size(0, max_size) == False
assert validate_file_size(-1, max_size) == False
class TestCombinedSecurityScenarios:
"""Integration tests for combined security scenarios"""
def test_malicious_filename_with_valid_extension(self):
"""Test malicious path with valid extension"""
malicious = "../../etc/passwd.mp4"
sanitized = sanitize_filename(malicious)
assert ".." not in sanitized
assert "/" not in sanitized
assert sanitized.endswith(".mp4")
assert validate_video_file_extension(sanitized) == True
def test_safe_filename_workflow(self):
"""Test complete safe filename workflow"""
original = "My Meeting Video (Jan 2024).mp4"
sanitized = sanitize_filename(original)
# Should preserve alphanumeric and extension
assert validate_video_file_extension(sanitized) == True
assert len(sanitized) > 0
assert sanitized.endswith(".mp4")