Files
michaelschiemer/tests/Application/Security/Services/FileUploadSecurityServiceTest.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

232 lines
7.0 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Application\Security\Services;
use App\Application\Security\Events\File\SuspiciousFileUploadEvent;
use App\Application\Security\Services\FileUploadSecurityService;
use App\Framework\Core\Events\EventDispatcher;
use App\Framework\Http\UploadedFile;
use App\Framework\Http\UploadError;
use Mockery;
describe('FileUploadSecurityService', function () {
beforeEach(function () {
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->service = new FileUploadSecurityService($this->eventDispatcher);
});
afterEach(function () {
Mockery::close();
});
it('validates a safe uploaded file', function () {
$file = UploadedFile::createForTesting(
name: 'test.jpg',
type: 'image/jpeg',
size: 1024 * 1024, // 1MB
tmpName: '/tmp/test_upload',
error: UploadError::OK
);
// Mock the file system
file_put_contents('/tmp/test_upload', 'fake image content');
$result = $this->service->validateUpload($file);
expect($result)->toBeTrue();
unlink('/tmp/test_upload');
});
it('rejects files with upload errors', function () {
$file = UploadedFile::createForTesting(
name: 'test.jpg',
type: 'image/jpeg',
size: 1024,
tmpName: '/tmp/test_upload',
error: UploadError::PARTIAL
);
$this->eventDispatcher
->shouldReceive('dispatch')
->once()
->with(Mockery::type(SuspiciousFileUploadEvent::class));
$result = $this->service->validateUpload($file);
expect($result)->toBeFalse();
});
it('rejects files that are too large', function () {
$file = UploadedFile::createForTesting(
name: 'large.jpg',
type: 'image/jpeg',
size: 20 * 1024 * 1024, // 20MB (exceeds 10MB limit)
tmpName: '/tmp/large_upload',
error: UploadError::OK
);
$this->eventDispatcher
->shouldReceive('dispatch')
->once()
->with(Mockery::type(SuspiciousFileUploadEvent::class));
$result = $this->service->validateUpload($file);
expect($result)->toBeFalse();
});
it('rejects files with dangerous extensions', function () {
$file = UploadedFile::createForTesting(
name: 'malicious.php',
type: 'application/x-php',
size: 1024,
tmpName: '/tmp/malicious_upload',
error: UploadError::OK
);
$this->eventDispatcher
->shouldReceive('dispatch')
->once()
->with(Mockery::type(SuspiciousFileUploadEvent::class));
$result = $this->service->validateUpload($file);
expect($result)->toBeFalse();
});
it('rejects files with forbidden MIME types', function () {
$file = UploadedFile::createForTesting(
name: 'test.txt',
type: 'application/x-executable',
size: 1024,
tmpName: '/tmp/executable_upload',
error: UploadError::OK
);
// Create mock file content
file_put_contents('/tmp/executable_upload', 'fake executable');
$this->eventDispatcher
->shouldReceive('dispatch')
->once()
->with(Mockery::type(SuspiciousFileUploadEvent::class));
$result = $this->service->validateUpload($file);
expect($result)->toBeFalse();
unlink('/tmp/executable_upload');
});
it('rejects files with malware signatures', function () {
$file = UploadedFile::createForTesting(
name: 'suspicious.txt',
type: 'text/plain',
size: 1024,
tmpName: '/tmp/suspicious_upload',
error: UploadError::OK
);
// Create file with malware signature
file_put_contents('/tmp/suspicious_upload', 'normal content <?php eval($_POST["cmd"]); ?>');
$this->eventDispatcher
->shouldReceive('dispatch')
->once()
->with(Mockery::type(SuspiciousFileUploadEvent::class));
$result = $this->service->validateUpload($file);
expect($result)->toBeFalse();
unlink('/tmp/suspicious_upload');
});
it('rejects files with double extensions', function () {
$file = UploadedFile::createForTesting(
name: 'image.jpg.php',
type: 'image/jpeg',
size: 1024,
tmpName: '/tmp/double_ext_upload',
error: UploadError::OK
);
// Create mock file
file_put_contents('/tmp/double_ext_upload', 'fake image content');
$this->eventDispatcher
->shouldReceive('dispatch')
->once()
->with(Mockery::type(SuspiciousFileUploadEvent::class));
$result = $this->service->validateUpload($file);
expect($result)->toBeFalse();
unlink('/tmp/double_ext_upload');
});
it('accepts various safe file types', function () {
$safeFiles = [
['test.jpg', 'image/jpeg'],
['test.png', 'image/png'],
['test.gif', 'image/gif'],
['test.webp', 'image/webp'],
['document.pdf', 'application/pdf'],
['data.csv', 'text/csv'],
];
foreach ($safeFiles as [$filename, $mimeType]) {
$file = UploadedFile::createForTesting(
name: $filename,
type: $mimeType,
size: 1024,
tmpName: '/tmp/safe_upload_' . $filename,
error: UploadError::OK
);
file_put_contents('/tmp/safe_upload_' . $filename, 'safe content');
$result = $this->service->validateUpload($file);
expect($result)->toBeTrue("File $filename should be valid");
unlink('/tmp/safe_upload_' . $filename);
}
});
it('handles multiple malware signatures', function () {
$malwareSignatures = [
'eval(',
'base64_decode(',
'system(',
'exec(',
'shell_exec(',
'<?php',
'<%',
'<script',
'javascript:',
];
foreach ($malwareSignatures as $signature) {
$file = UploadedFile::createForTesting(
name: 'test.txt',
type: 'text/plain',
size: 1024,
tmpName: '/tmp/malware_test',
error: UploadError::OK
);
file_put_contents('/tmp/malware_test', 'Normal content ' . $signature . ' more content');
$this->eventDispatcher
->shouldReceive('dispatch')
->once()
->with(Mockery::type(SuspiciousFileUploadEvent::class));
$result = $this->service->validateUpload($file);
expect($result)->toBeFalse("Signature '$signature' should be detected");
unlink('/tmp/malware_test');
}
});
});