From 5d67f570a9047e24f3a6539d712e4f7918c63490 Mon Sep 17 00:00:00 2001 From: Attila Kerekes <439392+keriati@users.noreply.github.com> Date: Mon, 5 Jun 2023 18:27:30 +0200 Subject: [PATCH] fix: validate icons to be images (#1167) --- app/Helper.php | 18 ++++++++ app/Http/Controllers/ItemController.php | 6 +++ app/Http/Controllers/SettingsController.php | 4 ++ app/Http/Controllers/TagController.php | 2 + app/Http/Controllers/UserController.php | 3 +- tests/Unit/helpers/IsImageTest.php | 42 ++++++++++++++++++ .../fixtures/heimdall-icon-small-php.php | Bin 0 -> 5362 bytes .../helpers/fixtures/heimdall-icon-small.png | Bin 0 -> 5337 bytes 8 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/helpers/IsImageTest.php create mode 100644 tests/Unit/helpers/fixtures/heimdall-icon-small-php.php create mode 100644 tests/Unit/helpers/fixtures/heimdall-icon-small.png diff --git a/app/Helper.php b/app/Helper.php index 99c807bd..f7fcd5e3 100644 --- a/app/Helper.php +++ b/app/Helper.php @@ -109,3 +109,21 @@ function className($name) { return preg_replace('/[^\p{L}\p{N}]/u', '', $name); } + +/** + * @param string $file + * @return bool + */ +function isImage(string $file):bool +{ + $tempFileName = tempnam("/tmp", "image-check-"); + $handle = fopen($tempFileName, "w"); + + fwrite($handle, $file); + + $size = @getimagesize($tempFileName); + + fclose($handle); + + return is_array($size) && str_starts_with($size['mime'], 'image'); +} diff --git a/app/Http/Controllers/ItemController.php b/app/Http/Controllers/ItemController.php index fd705b0b..20941e7f 100644 --- a/app/Http/Controllers/ItemController.php +++ b/app/Http/Controllers/ItemController.php @@ -18,6 +18,7 @@ use Illuminate\Routing\Redirector; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\URL; +use Illuminate\Validation\ValidationException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; @@ -203,6 +204,7 @@ class ItemController extends Controller $validatedData = $request->validate([ 'title' => 'required|max:255', 'url' => 'required', + 'file' => 'image' ]); if ($request->hasFile('file')) { @@ -219,6 +221,10 @@ class ItemController extends Controller ); $contents = file_get_contents($request->input('icon'), false, stream_context_create($options)); + if (!isImage($contents)) { + throw ValidationException::withMessages(['file' => 'Icon must be an image.']); + } + if ($application) { $icon = $application->icon; } else { diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 2adc7b2b..89af0dcf 100644 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -77,6 +77,10 @@ class SettingsController extends Controller } if ($setting->type === 'image') { + $validatedData = $request->validate([ + 'value' => 'image' + ]); + if (!$request->hasFile('value')) { throw new \Exception( 'file_too_big' diff --git a/app/Http/Controllers/TagController.php b/app/Http/Controllers/TagController.php index d5d95891..1b65a824 100644 --- a/app/Http/Controllers/TagController.php +++ b/app/Http/Controllers/TagController.php @@ -57,6 +57,7 @@ class TagController extends Controller { $validatedData = $request->validate([ 'title' => 'required|max:255', + 'file' => 'image' ]); if ($request->hasFile('file')) { @@ -129,6 +130,7 @@ class TagController extends Controller { $validatedData = $request->validate([ 'title' => 'required|max:255', + 'file' => 'image' ]); if ($request->hasFile('file')) { diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index d208d847..256cd0d8 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -62,7 +62,7 @@ class UserController extends Controller 'email' => 'required|email', 'password' => 'nullable|confirmed', 'password_confirmation' => 'nullable', - + 'file' => 'image' ]); $user = new User; $user->username = $request->input('username'); @@ -129,6 +129,7 @@ class UserController extends Controller 'email' => 'required|email', 'password' => 'nullable|confirmed', 'password_confirmation' => 'nullable', + 'file' => 'image' ]); //die(print_r($request->all())); diff --git a/tests/Unit/helpers/IsImageTest.php b/tests/Unit/helpers/IsImageTest.php new file mode 100644 index 00000000..0b3d16bc --- /dev/null +++ b/tests/Unit/helpers/IsImageTest.php @@ -0,0 +1,42 @@ +"); + + $this->assertFalse($actual); + } + + /** + * @return void + */ + public function test_isImage_returns_true_when_file_is_image() + { + $file = file_get_contents(__DIR__ . '/fixtures/heimdall-icon-small.png'); + + $actual = isImage($file); + + $this->assertTrue($actual); + } + + /** + * @return void + */ + public function test_isImage_returns_false_when_file_is_php_but_png() + { + $file = file_get_contents(__DIR__ . '/fixtures/heimdall-icon-small-php.php'); + + $actual = isImage($file); + + $this->assertTrue($actual); + } +} diff --git a/tests/Unit/helpers/fixtures/heimdall-icon-small-php.php b/tests/Unit/helpers/fixtures/heimdall-icon-small-php.php new file mode 100644 index 0000000000000000000000000000000000000000..107f9cd5e3e72bd4d3275229600638fd40382763 GIT binary patch literal 5362 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 literal 0 HcmV?d00001