| @@ -7,8 +7,9 @@ | ||
| 7 | 7 | use FluentBoards\App\Models\CommentImage; |
| 8 | 8 | use FluentBoards\App\Models\Task; |
| 9 | 9 | use FluentBoards\App\Models\TaskImage; |
| 10 | 10 | use FluentBoards\App\Services\Libs\FileSystem; |
| 11 | +use Exception; | |
| 11 | 12 | |
| 12 | 13 | class AttachmentFileService |
| 13 | 14 | { |
| 14 | 15 | protected $createdFiles = []; |
| @@ -298,8 +299,11 @@ | ||
| 298 | 299 | |
| 299 | 300 | return array_fill_keys($sharedUrls, true); |
| 300 | 301 | } |
| 301 | 302 | |
| 303 | + /** | |
| 304 | + * Copy a local file into a protected board directory and track it for rollback. | |
| 305 | + */ | |
| 302 | 306 | protected function copyAttachmentFileData(Attachment $source, Attachment $target, $sourceBoardId, $targetBoardId) |
| 303 | 307 | { |
| 304 | 308 | $result = [ |
| 305 | 309 | 'old_path' => null, |
| @@ -317,8 +321,12 @@ | ||
| 317 | 321 | |
| 318 | 322 | $sourcePath = $this->resolveLocalPath($source, $sourceBoardId); |
| 319 | 323 | if (!$sourcePath || !is_file($sourcePath) || !is_readable($sourcePath)) { |
| 320 | 324 | return $result; |
| 325 | + } | |
| 326 | + | |
| 327 | + if (!FileSystem::installUploadProtectionRules()) { | |
| 328 | + throw new Exception(__('Could not prepare upload-directory protection. Please ask your hosting provider to block direct file access and check directory permissions.', 'fluent-boards')); | |
| 321 | 329 | } |
| 322 | 330 | |
| 323 | 331 | $targetDir = $this->getBoardDir($targetBoardId); |
| 324 | 332 | if (!is_dir($targetDir)) { |