diff --git a/src/Form/AttachmentFormType.php b/src/Form/AttachmentFormType.php index 54f789ba..29730848 100644 --- a/src/Form/AttachmentFormType.php +++ b/src/Form/AttachmentFormType.php @@ -46,6 +46,7 @@ use App\Entity\Attachments\Attachment; use App\Entity\Attachments\AttachmentType; use App\Form\Type\StructuralEntityType; use App\Services\Attachments\AttachmentManager; +use App\Services\Attachments\AttachmentSubmitHandler; use App\Validator\Constraints\AllowedFileExtension; use App\Validator\Constraints\UrlOrBuiltin; use Symfony\Component\Form\AbstractType; @@ -53,13 +54,16 @@ use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Security; use Symfony\Component\Validator\Constraints\File; use Symfony\Component\Validator\Constraints\Url; +use Symfony\Contracts\Translation\TranslatorInterface; class AttachmentFormType extends AbstractType { @@ -67,14 +71,19 @@ class AttachmentFormType extends AbstractType protected $urlGenerator; protected $allow_attachments_download; protected $security; + protected $submitHandler; + protected $translator; public function __construct(AttachmentManager $attachmentHelper, - UrlGeneratorInterface $urlGenerator, Security $security, bool $allow_attachments_downloads) + UrlGeneratorInterface $urlGenerator, Security $security, + bool $allow_attachments_downloads, AttachmentSubmitHandler $submitHandler, TranslatorInterface $translator) { $this->attachment_helper = $attachmentHelper; $this->urlGenerator = $urlGenerator; $this->allow_attachments_download = $allow_attachments_downloads; $this->security = $security; + $this->submitHandler = $submitHandler; + $this->translator = $translator; } public function buildForm(FormBuilderInterface $builder, array $options): void @@ -153,13 +162,29 @@ class AttachmentFormType extends AbstractType 'data-show-upload' => 'false', ], 'constraints' => [ - new AllowedFileExtension(), + //new AllowedFileExtension(), new File([ 'maxSize' => $options['max_file_size'], ]), ], ]); + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event): void { + $form = $event->getForm(); + $attachment = $form->getData(); + + $file_form = $form->get('file'); + $file = $file_form->getData(); + + if ($attachment instanceof Attachment && $file instanceof UploadedFile && $attachment->getAttachmentType()) { + if (!$this->submitHandler->isValidFileExtension($attachment->getAttachmentType(), $file)) { + $event->getForm()->get('file')->addError( + new FormError($this->translator->trans("validator.file_ext_not_allowed")) + ); + } + } + }); + //Check the secure file checkbox, if file is in securefile location $builder->get('secureFile')->addEventListener( FormEvents::PRE_SET_DATA, diff --git a/src/Services/Attachments/AttachmentSubmitHandler.php b/src/Services/Attachments/AttachmentSubmitHandler.php index 2ae3e4c8..b6a9ffe0 100644 --- a/src/Services/Attachments/AttachmentSubmitHandler.php +++ b/src/Services/Attachments/AttachmentSubmitHandler.php @@ -44,6 +44,7 @@ namespace App\Services\Attachments; use App\Entity\Attachments\Attachment; use App\Entity\Attachments\AttachmentContainingDBElement; +use App\Entity\Attachments\AttachmentType; use App\Entity\Attachments\AttachmentTypeAttachment; use App\Entity\Attachments\CategoryAttachment; use App\Entity\Attachments\CurrencyAttachment; @@ -57,6 +58,7 @@ use App\Entity\Attachments\StorelocationAttachment; use App\Entity\Attachments\SupplierAttachment; use App\Entity\Attachments\UserAttachment; use App\Exceptions\AttachmentDownloadException; +use Symfony\Component\Form\FormInterface; use const DIRECTORY_SEPARATOR; use function get_class; use InvalidArgumentException; @@ -78,15 +80,20 @@ class AttachmentSubmitHandler protected $allow_attachments_downloads; protected $httpClient; protected $mimeTypes; + protected $filterTools; + public function __construct(AttachmentPathResolver $pathResolver, bool $allow_attachments_downloads, - HttpClientInterface $httpClient, MimeTypesInterface $mimeTypes) + HttpClientInterface $httpClient, MimeTypesInterface $mimeTypes, + FileTypeFilterTools $filterTools) { $this->pathResolver = $pathResolver; $this->allow_attachments_downloads = $allow_attachments_downloads; $this->httpClient = $httpClient; $this->mimeTypes = $mimeTypes; + $this->filterTools = $filterTools; + //The mapping used to determine which folder will be used for an attachment type $this->folder_mapping = [ PartAttachment::class => 'part', @@ -104,6 +111,26 @@ class AttachmentSubmitHandler ]; } + /** + * Check if the extension of the uploaded file is allowed for the given attachment type. + * Returns true, if the file is allowed, false if not. + * @param Attachment $attachment + * @param UploadedFile $uploadedFile + * @return bool + */ + public function isValidFileExtension(AttachmentType $attachment_type, UploadedFile $uploadedFile): bool + { + //Only validate if the attachment type has specified an filetype filter: + if (empty($attachment_type->getFiletypeFilter())) { + return true; + } + + return $this->filterTools->isExtensionAllowed( + $attachment_type->getFiletypeFilter(), + $uploadedFile->getClientOriginalExtension() + ); + } + /** * Generates a filename for the given attachment and extension. * The filename contains a random id, so every time this function is called you get an unique name. diff --git a/src/Validator/Constraints/AllowedFileExtension.php b/src/Validator/Constraints/AllowedFileExtension.php deleted file mode 100644 index e12a6dda..00000000 --- a/src/Validator/Constraints/AllowedFileExtension.php +++ /dev/null @@ -1,52 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -namespace App\Validator\Constraints; - -use Symfony\Component\Validator\Constraint; - -/** - * @Annotation - */ -class AllowedFileExtension extends Constraint -{ -} diff --git a/src/Validator/Constraints/AllowedFileExtensionValidator.php b/src/Validator/Constraints/AllowedFileExtensionValidator.php deleted file mode 100644 index ee313c22..00000000 --- a/src/Validator/Constraints/AllowedFileExtensionValidator.php +++ /dev/null @@ -1,99 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -namespace App\Validator\Constraints; - -use App\Entity\Attachments\Attachment; -use App\Services\Attachments\FileTypeFilterTools; -use Symfony\Component\Form\FormInterface; -use Symfony\Component\HttpFoundation\File\UploadedFile; -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Validator\Exception\UnexpectedTypeException; - -class AllowedFileExtensionValidator extends ConstraintValidator -{ - protected $filterTools; - - public function __construct(FileTypeFilterTools $filterTools) - { - $this->filterTools = $filterTools; - } - - /** - * Checks if the passed value is valid. - * - * @param mixed $value The value that should be validated - * @param Constraint $constraint The constraint for the validation - */ - public function validate($value, Constraint $constraint): void - { - if (! $constraint instanceof AllowedFileExtension) { - throw new UnexpectedTypeException($constraint, AllowedFileExtension::class); - } - - if ($value instanceof UploadedFile) { - if ($this->context->getObject() instanceof Attachment) { - /** @var Attachment $attachment */ - $attachment = $this->context->getObject(); - } elseif ($this->context->getObject() instanceof FormInterface) { - $attachment = $this->context->getObject()->getParent()->getData(); - } else { - return; - } - - $attachment_type = $attachment->getAttachmentType(); - - //Only validate if the attachment type has specified an filetype filter: - if (null === $attachment_type || empty($attachment_type->getFiletypeFilter())) { - return; - } - - if (! $this->filterTools->isExtensionAllowed( - $attachment_type->getFiletypeFilter(), - $value->getClientOriginalExtension() - )) { - $this->context->buildViolation('validator.file_ext_not_allowed')->addViolation(); - } - } - } -} diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index dba4a47f..c51aa3a5 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -9219,5 +9219,11 @@ Element 3 Save and clone + + + validator.file_ext_not_allowed + File extension not allowed for this attachment type. + +