From b894f70f576b99cf97ca2afec74f0ecbe9df9191 Mon Sep 17 00:00:00 2001 From: faisd405 Date: Thu, 10 Oct 2024 14:19:39 +0700 Subject: [PATCH 1/6] refactor: file upload event classes to support multiple uploaded files --- src/Events/FilesUploaded.php | 2 +- src/Events/FilesUploading.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Events/FilesUploaded.php b/src/Events/FilesUploaded.php index 69be788..ebd4d19 100644 --- a/src/Events/FilesUploaded.php +++ b/src/Events/FilesUploaded.php @@ -17,7 +17,7 @@ class FilesUploaded private $path; /** - * @var \Illuminate\Http\UploadedFile + * @var \Illuminate\Http\UploadedFile[] */ private $files; diff --git a/src/Events/FilesUploading.php b/src/Events/FilesUploading.php index 6f51484..c7f3c24 100644 --- a/src/Events/FilesUploading.php +++ b/src/Events/FilesUploading.php @@ -17,7 +17,7 @@ class FilesUploading private $path; /** - * @var \Illuminate\Http\UploadedFile + * @var \Illuminate\Http\UploadedFile[] */ private $files; From 1d63c1e97640c90214f448b0227c911c6e70251f Mon Sep 17 00:00:00 2001 From: faisd405 Date: Thu, 10 Oct 2024 14:40:29 +0700 Subject: [PATCH 2/6] refactor: Validation Extenstion at Rename and CreateFile Function --- src/FileManager.php | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/FileManager.php b/src/FileManager.php index aa879cd..cce935b 100644 --- a/src/FileManager.php +++ b/src/FileManager.php @@ -273,6 +273,15 @@ public function paste($disk, $path, $clipboard): array */ public function rename($disk, $newName, $oldName): array { + if(!$this->AllowTypes($newName)){ + return [ + 'result' => [ + 'status' => 'error', + 'message' => "Failed to create file because extension is not allowed", + ], + ]; + } + Storage::disk($disk)->move($oldName, $newName); return [ @@ -414,6 +423,15 @@ public function createDirectory($disk, $path, $name) */ public function createFile($disk, $path, $name): array { + if(!$this->AllowTypes($name)){ + return [ + 'result' => [ + 'status' => 'error', + 'message' => "Failed to create file because extension is not allowed", + ], + ]; + } + $path = $this->newPath($path, $name); if (Storage::disk($disk)->exists($path)) { @@ -485,4 +503,22 @@ public function streamFile($disk, $path): StreamedResponse return Storage::disk($disk)->response($path, $filename, ['Accept-Ranges' => 'bytes']); } + + private function AllowTypes($name) + { + $ext = explode('.', $name); + $ext = end($ext); + + if ( + $this->configRepository->getAllowFileTypes() + && !in_array( + $ext, + $this->configRepository->getAllowFileTypes() + ) + ) { + return false; + } else { + return true; + } + } } From 6be6947832c44d969c3961cafc54628c47ecbdcb Mon Sep 17 00:00:00 2001 From: faisd405 Date: Thu, 10 Oct 2024 15:27:18 +0700 Subject: [PATCH 3/6] security fix: Add Validation File Types and Mime Types --- config/file-manager.php | 31 ++++++++++ src/FileManager.php | 58 ++++++++++++++++--- .../ConfigService/ConfigRepository.php | 14 +++++ .../ConfigService/DefaultConfigRepository.php | 52 +++++++++++++++++ 4 files changed, 146 insertions(+), 9 deletions(-) diff --git a/config/file-manager.php b/config/file-manager.php index 63fd749..2ec49db 100644 --- a/config/file-manager.php +++ b/config/file-manager.php @@ -84,6 +84,37 @@ */ 'allowFileTypes' => [], + /** + * File upload - disallow these executable file types + * + * [] - default disallowed file types + * default: php, php3, php4, php5, phtml, js, html, htm, xhtml, shtml, jhtml, pl, py, cgi, exe + */ + 'disallowFileTypes' => [], + + /** + * File upload - disallow these executable file mimetypes + * + * [] - default disallowed mimetypes + * default: + * - text/x-php + * - text/html + * - text/javascript + * - application/x-javascript + * - text/x-javascript + * - application/javascript + * - application/x-sh + * - text/x-python + * - application/x-python + * - text/x-perl + * - application/x-perl + * - application/x-httpd-cgi + * - application/x-executable + * - application/x-msdownload + * - application/octet-stream + */ + 'disallowFileMimeTypes' => [], + /** * Show / Hide system files and folders */ diff --git a/src/FileManager.php b/src/FileManager.php index cce935b..2a8bb5f 100644 --- a/src/FileManager.php +++ b/src/FileManager.php @@ -167,15 +167,37 @@ public function upload($disk, $path, $files, $overwrite): array continue; } + // check file disallow type + if ($this->configRepository->getDisallowFileTypes() + && in_array( + $file->getClientOriginalExtension(), + $this->configRepository->getDisallowFileTypes() + ) + ) { + $fileNotUploaded = true; + continue; + } + + // check file mime type + if ($this->configRepository->getDisallowFileMimeTypes() + && in_array( + $file->getMimeType(), + $this->configRepository->getDisallowFileMimeTypes() + ) + ) { + $fileNotUploaded = true; + continue; + } + $name = $file->getClientOriginalName(); if ($this->configRepository->getSlugifyNames()) { $name = Str::slug( - Str::replace( - '.' . $file->getClientOriginalExtension(), - '', - $name - ) - ) . '.' . $file->getClientOriginalExtension(); + Str::replace( + '.' . $file->getClientOriginalExtension(), + '', + $name + ) + ) . '.' . $file->getClientOriginalExtension(); } // overwrite or save file Storage::disk($disk)->putFileAs( @@ -273,7 +295,7 @@ public function paste($disk, $path, $clipboard): array */ public function rename($disk, $newName, $oldName): array { - if(!$this->AllowTypes($newName)){ + if (!$this->AllowTypeFileName($newName) || !$this->DisallowTypeFileName($newName)) { return [ 'result' => [ 'status' => 'error', @@ -423,7 +445,7 @@ public function createDirectory($disk, $path, $name) */ public function createFile($disk, $path, $name): array { - if(!$this->AllowTypes($name)){ + if (!$this->AllowTypeFileName($name) || !$this->DisallowTypeFileName($name)) { return [ 'result' => [ 'status' => 'error', @@ -504,7 +526,7 @@ public function streamFile($disk, $path): StreamedResponse return Storage::disk($disk)->response($path, $filename, ['Accept-Ranges' => 'bytes']); } - private function AllowTypes($name) + private function AllowTypeFileName($name) { $ext = explode('.', $name); $ext = end($ext); @@ -521,4 +543,22 @@ private function AllowTypes($name) return true; } } + + private function DisallowTypeFileName($name) + { + $ext = explode('.', $name); + $ext = end($ext); + + if ( + $this->configRepository->getDisallowFileTypes() + && in_array( + $ext, + $this->configRepository->getDisallowFileTypes() + ) + ) { + return false; + } else { + return true; + } + } } diff --git a/src/Services/ConfigService/ConfigRepository.php b/src/Services/ConfigService/ConfigRepository.php index 915b9ff..91d9d4c 100644 --- a/src/Services/ConfigService/ConfigRepository.php +++ b/src/Services/ConfigService/ConfigRepository.php @@ -87,6 +87,20 @@ public function getMaxUploadFileSize(): ?int; */ public function getAllowFileTypes(): array; + /** + * File upload - disallow these executable file types + * + * [] - no restrictions + */ + public function getDisallowFileTypes(): array; + + /** + * File upload - disallow these executable file mimetypes + * + * [] - no restrictions + */ + public function getDisallowFileMimeTypes(): array; + /** * Show / Hide system files and folders * diff --git a/src/Services/ConfigService/DefaultConfigRepository.php b/src/Services/ConfigService/DefaultConfigRepository.php index 2ea4b98..9b64cbd 100644 --- a/src/Services/ConfigService/DefaultConfigRepository.php +++ b/src/Services/ConfigService/DefaultConfigRepository.php @@ -114,6 +114,58 @@ final public function getAllowFileTypes(): array return config('file-manager.allowFileTypes'); } + /** + * File upload - disallow these executable file types + * + * [] - no restrictions + */ + final public function getDisallowFileTypes(): array + { + return config('file-manager.disallowFileTypes', [ + 'php', + 'php3', + 'php4', + 'php5', + 'phtml', + 'js', + 'html', + 'htm', + 'xhtml', + 'shtml', + 'jhtml', + 'pl', + 'py', + 'cgi', + 'exe', + ]); + } + + /** + * File upload - disallow these executable file mimetypes + * + * [] - no restrictions + */ + final public function getDisallowFileMimeTypes(): array + { + return config('file-manager.disallowFileMimeTypes', [ + 'text/x-php', + 'text/html', + 'text/javascript', + 'application/x-javascript', + 'text/x-javascript', + 'application/javascript', + 'application/x-sh', + 'text/x-python', + 'application/x-python', + 'text/x-perl', + 'application/x-perl', + 'application/x-httpd-cgi', + 'application/x-executable', + 'application/x-msdownload', + 'application/octet-stream', + ]); + } + /** * Show / Hide system files and folders * From 10675afdc9d8a048bfd3ca30ffd2e0061e84105e Mon Sep 17 00:00:00 2001 From: faisd405 Date: Thu, 10 Oct 2024 17:13:35 +0700 Subject: [PATCH 4/6] refactor: Update disallowed file types and mimetypes in file-manager.php --- config/file-manager.php | 59 ++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/config/file-manager.php b/config/file-manager.php index 2ec49db..9697c0c 100644 --- a/config/file-manager.php +++ b/config/file-manager.php @@ -87,33 +87,48 @@ /** * File upload - disallow these executable file types * - * [] - default disallowed file types - * default: php, php3, php4, php5, phtml, js, html, htm, xhtml, shtml, jhtml, pl, py, cgi, exe + * [] - no restrictions */ - 'disallowFileTypes' => [], + 'disallowFileTypes' => [ + 'php', + 'php3', + 'php4', + 'php5', + 'phtml', + 'js', + 'html', + 'htm', + 'xhtml', + 'shtml', + 'jhtml', + 'pl', + 'py', + 'cgi', + 'exe', + ], /** * File upload - disallow these executable file mimetypes * - * [] - default disallowed mimetypes - * default: - * - text/x-php - * - text/html - * - text/javascript - * - application/x-javascript - * - text/x-javascript - * - application/javascript - * - application/x-sh - * - text/x-python - * - application/x-python - * - text/x-perl - * - application/x-perl - * - application/x-httpd-cgi - * - application/x-executable - * - application/x-msdownload - * - application/octet-stream - */ - 'disallowFileMimeTypes' => [], + * [] - no restrictions + */ + 'disallowFileMimeTypes' => [ + 'text/x-php', + 'text/html', + 'text/javascript', + 'application/x-javascript', + 'text/x-javascript', + 'application/javascript', + 'application/x-sh', + 'text/x-python', + 'application/x-python', + 'text/x-perl', + 'application/x-perl', + 'application/x-httpd-cgi', + 'application/x-executable', + 'application/x-msdownload', + 'application/octet-stream', + ], /** * Show / Hide system files and folders From 7dfa90369d275efe083e5afe126d7098613aae3c Mon Sep 17 00:00:00 2001 From: faisd405 Date: Thu, 10 Oct 2024 17:34:51 +0700 Subject: [PATCH 5/6] fix: Security Fix Add Validation File Types and Mime Types when Extract Zip at File Manager - Modified the extractArchive() method to loop through each file in the ZIP archive and check for disallowed file types and mime types - Skipped extraction for files with disallowed file types or mime types --- src/Services/Zip.php | 55 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/Services/Zip.php b/src/Services/Zip.php index bdd1583..f1ad508 100644 --- a/src/Services/Zip.php +++ b/src/Services/Zip.php @@ -6,6 +6,7 @@ use Alexusmai\LaravelFileManager\Events\UnzipFailed; use Alexusmai\LaravelFileManager\Events\ZipCreated; use Alexusmai\LaravelFileManager\Events\ZipFailed; +use Alexusmai\LaravelFileManager\Services\ConfigService\ConfigRepository; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; use RecursiveIteratorIterator; @@ -15,6 +16,7 @@ class Zip { protected $zip; + protected $configRepository; protected $request; //protected $pathPrefix; @@ -22,16 +24,14 @@ class Zip * Zip constructor. * * @param ZipArchive $zip + * @param ConfigRepository $configRepository * @param Request $request */ - public function __construct(ZipArchive $zip, Request $request) + public function __construct(ZipArchive $zip, ConfigRepository $configRepository, Request $request) { $this->zip = $zip; $this->request = $request; - //$this->pathPrefix = Storage::disk($request->input('disk'))->path(); - //->getDriver() - //->getAdapter() - //->getPathPrefix(); + $this->configRepository = $configRepository; } /** @@ -140,23 +140,56 @@ protected function createArchive(): bool protected function extractArchive(): bool { $zipPath = $this->prefixer($this->request->input('path')); - $rootPath = dirname($zipPath); - - // extract to new folder $folder = $this->request->input('folder'); + $extractPath = $folder ? $rootPath.'/'.$folder : $rootPath; + + // Initialize file info for mime-type checking + $finfo = new \finfo(FILEINFO_MIME_TYPE); if ($this->zip->open($zipPath) === true) { - $this->zip->extractTo($folder ? $rootPath.'/'.$folder : $rootPath); + // Loop through each file in the ZIP archive + for ($i = 0; $i < $this->zip->numFiles; $i++) { + $fileInfo = $this->zip->statIndex($i); + $fileName = $fileInfo['name']; + + // Get the file contents + $fileContents = $this->zip->getFromIndex($i); + + // Check the MIME type of the file + $mimeType = $finfo->buffer($fileContents); + + // Skip extraction if the file extension is .php + if (in_array(pathinfo($fileName, PATHINFO_EXTENSION), $this->configRepository->getDisallowFileTypes())) { + // Optionally log or handle the ignored file + continue; + } + + // Skip extraction if the file MIME type is text/x-php + if (in_array($mimeType, $this->configRepository->getDisallowFileMimeTypes())) { + // Optionally log or handle the ignored file + continue; + } + + // Extract each file + $filePath = $extractPath . '/' . $fileName; + + // Ensure the directory exists + if (!file_exists(dirname($filePath))) { + mkdir(dirname($filePath), 0755, true); + } + + // Write the file + file_put_contents($filePath, $fileContents); + } + $this->zip->close(); event(new UnzipCreated($this->request)); - return true; } event(new UnzipFailed($this->request)); - return false; } From 75deab448aea0ecaf60f46acc4485d33858bf101 Mon Sep 17 00:00:00 2001 From: faisd405 Date: Fri, 11 Oct 2024 15:34:55 +0700 Subject: [PATCH 6/6] refactor: Add file extension and mime types validation in updateFile function --- src/FileManager.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/FileManager.php b/src/FileManager.php index 2a8bb5f..aacf68f 100644 --- a/src/FileManager.php +++ b/src/FileManager.php @@ -488,6 +488,15 @@ public function createFile($disk, $path, $name): array */ public function updateFile($disk, $path, $file): array { + if (!$this->AllowTypeFileName($file->getClientOriginalName()) || !$this->DisallowTypeFileName($file->getClientOriginalName())) { + return [ + 'result' => [ + 'status' => 'error', + 'message' => "Failed to create file because extension is not allowed", + ], + ]; + } + Storage::disk($disk)->putFileAs( $path, $file,