From 26d83af298cdf577ed2e3599e75d1219e6029e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= <mail@jan-boehmer.de> Date: Tue, 14 May 2024 23:02:46 +0200 Subject: [PATCH] Use new settings systems for attachments settings --- .env | 8 --- .gitignore | 1 + config/parameters.yaml | 4 -- config/services.yaml | 8 --- src/Controller/ToolsController.php | 8 ++- src/Form/AttachmentFormType.php | 11 ++-- .../Attachments/AttachmentSubmitHandler.php | 18 +++--- src/Settings/AppSettings.php | 7 ++- .../{TestSettings.php => SystemSettings.php} | 15 ++--- .../SystemSettings/AttachmentsSettings.php | 56 +++++++++++++++++++ translations/messages.en.xlf | 36 ++++++++++++ translations/validators.en.xlf | 6 ++ 12 files changed, 129 insertions(+), 49 deletions(-) rename src/Settings/{TestSettings.php => SystemSettings.php} (79%) create mode 100644 src/Settings/SystemSettings/AttachmentsSettings.php diff --git a/.env b/.env index 8e48085e1..262043609 100644 --- a/.env +++ b/.env @@ -35,16 +35,8 @@ DEFAULT_TIMEZONE="Europe/Berlin" BASE_CURRENCY="EUR" # The name of this installation. This will be shown as title in the browser and in the header of the website INSTANCE_NAME="Part-DB" -# Allow users to download attachments to the server by providing an URL -# This could be a potential security issue, as the user can retrieve any file the server has access to (via internet) -ALLOW_ATTACHMENT_DOWNLOADS=0 -# Set this to 1, if the "download external files" checkbox should be checked by default for new attachments -ATTACHMENT_DOWNLOAD_BY_DEFAULT=0 # Use gravatars for user avatars, when user has no own avatar defined USE_GRAVATAR=0 -# The maximum allowed size for attachment files in bytes (you can use M for megabytes and G for gigabytes) -# Please note that the php.ini setting upload_max_filesize also limits the maximum size of uploaded files -MAX_ATTACHMENT_FILE_SIZE="100M" # The public reachable URL of this Part-DB installation. This is used for generating links in SAML and email templates # This must end with a slash! diff --git a/.gitignore b/.gitignore index b726f64c6..c8c59090d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /.env.local /.env.local.php /.env.*.local +/.env.local.bak /config/secrets/prod/prod.decrypt.private.php /public/bundles/ /var/ diff --git a/config/parameters.yaml b/config/parameters.yaml index 4caa5780c..205b31a86 100644 --- a/config/parameters.yaml +++ b/config/parameters.yaml @@ -34,11 +34,8 @@ parameters: ###################################################################################################################### # Attachments and files ###################################################################################################################### - partdb.attachments.allow_downloads: '%env(bool:ALLOW_ATTACHMENT_DOWNLOADS)%' # Allow users to download attachments to server. Warning: This can be dangerous, because via that feature attackers maybe can access ressources on your intranet! - partdb.attachments.download_by_default: '%env(bool:ATTACHMENT_DOWNLOAD_BY_DEFAULT)%' # If this is set the 'download external files' checkbox is set by default for new attachments (only if allow_downloads is set to true) partdb.attachments.dir.media: 'public/media/' # The folder where uploaded attachment files are saved (must be in public folder) partdb.attachments.dir.secure: 'uploads/' # The folder where secured attachment files are saved (must not be in public/) - partdb.attachments.max_file_size: '%env(string:MAX_ATTACHMENT_FILE_SIZE)%' # The maximum size of an attachment file (in bytes, you can use M for megabytes and G for gigabytes) ###################################################################################################################### # Error pages @@ -113,7 +110,6 @@ parameters: env(INSTANCE_NAME): 'Part-DB' env(BASE_CURRENCY): 'EUR' env(USE_GRAVATAR): '0' - env(MAX_ATTACHMENT_FILE_SIZE): '100M' env(REDIRECT_TO_HTTPS): 0 diff --git a/config/services.yaml b/config/services.yaml index 292c532f2..7264783ed 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -89,17 +89,9 @@ services: tags: - { name: 'doctrine.event_subscriber' } - App\Form\AttachmentFormType: - arguments: - $allow_attachments_download: '%partdb.attachments.allow_downloads%' - $max_file_size: '%partdb.attachments.max_file_size%' - $download_by_default: '%partdb.attachments.download_by_default%' - App\Services\Attachments\AttachmentSubmitHandler: arguments: - $allow_attachments_downloads: '%partdb.attachments.allow_downloads%' $mimeTypes: '@mime_types' - $max_upload_size: '%partdb.attachments.max_file_size%' App\Services\LogSystem\EventCommentNeededHelper: arguments: diff --git a/src/Controller/ToolsController.php b/src/Controller/ToolsController.php index 984e50eb2..040e418c3 100644 --- a/src/Controller/ToolsController.php +++ b/src/Controller/ToolsController.php @@ -28,6 +28,7 @@ use App\Services\Misc\GitVersionInfo; use App\Services\Misc\DBInfoHelper; use App\Services\System\UpdateAvailableManager; +use App\Settings\AppSettings; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; @@ -45,7 +46,8 @@ public function reelCalculator(): Response #[Route(path: '/server_infos', name: 'tools_server_infos')] public function systemInfos(GitVersionInfo $versionInfo, DBInfoHelper $DBInfoHelper, - AttachmentSubmitHandler $attachmentSubmitHandler, UpdateAvailableManager $updateAvailableManager): Response + AttachmentSubmitHandler $attachmentSubmitHandler, UpdateAvailableManager $updateAvailableManager, + AppSettings $settings): Response { $this->denyAccessUnlessGranted('@system.server_infos'); @@ -66,10 +68,10 @@ public function systemInfos(GitVersionInfo $versionInfo, DBInfoHelper $DBInfoHel 'is_debug' => $this->getParameter('kernel.debug'), 'email_sender' => $this->getParameter('partdb.mail.sender_email'), 'email_sender_name' => $this->getParameter('partdb.mail.sender_name'), - 'allow_attachments_downloads' => $this->getParameter('partdb.attachments.allow_downloads'), + 'allow_attachments_downloads' => $settings->system->attachments->allowDownloads, 'detailed_error_pages' => $this->getParameter('partdb.error_pages.show_help'), 'error_page_admin_email' => $this->getParameter('partdb.error_pages.admin_email'), - 'configured_max_file_size' => $this->getParameter('partdb.attachments.max_file_size'), + 'configured_max_file_size' => $settings->system->attachments->maxFileSize, 'effective_max_file_size' => $attachmentSubmitHandler->getMaximumAllowedUploadSize(), 'saml_enabled' => $this->getParameter('partdb.saml.enabled'), diff --git a/src/Form/AttachmentFormType.php b/src/Form/AttachmentFormType.php index 109c66025..b9963bed4 100644 --- a/src/Form/AttachmentFormType.php +++ b/src/Form/AttachmentFormType.php @@ -22,6 +22,7 @@ namespace App\Form; +use App\Settings\SystemSettings\AttachmentsSettings; use Symfony\Bundle\SecurityBundle\Security; use App\Entity\Attachments\Attachment; use App\Entity\Attachments\AttachmentType; @@ -54,9 +55,7 @@ public function __construct( protected Security $security, protected AttachmentSubmitHandler $submitHandler, protected TranslatorInterface $translator, - protected bool $allow_attachments_download, - protected bool $download_by_default, - protected string $max_file_size + protected AttachmentsSettings $settings, ) { } @@ -108,7 +107,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'required' => false, 'label' => 'attachment.edit.download_url', 'mapped' => false, - 'disabled' => !$this->allow_attachments_download, + 'disabled' => !$this->settings->allowDownloads, ]); $builder->add('file', FileType::class, [ @@ -177,7 +176,7 @@ static function (FormEvent $event): void { //If the attachment should be downloaded by default (and is download allowed at all), register a listener, // which sets the downloadURL checkbox to true for new attachments - if ($this->download_by_default && $this->allow_attachments_download) { + if ($this->settings->downloadByDefault && $this->settings->allowDownloads) { $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event): void { $form = $event->getForm(); $attachment = $form->getData(); @@ -204,7 +203,7 @@ public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => Attachment::class, - 'max_file_size' => $this->max_file_size, + 'max_file_size' => $this->settings->maxFileSize, 'allow_builtins' => true, ]); } diff --git a/src/Services/Attachments/AttachmentSubmitHandler.php b/src/Services/Attachments/AttachmentSubmitHandler.php index d5fe9370a..2cd9a153e 100644 --- a/src/Services/Attachments/AttachmentSubmitHandler.php +++ b/src/Services/Attachments/AttachmentSubmitHandler.php @@ -40,6 +40,7 @@ use App\Entity\Attachments\SupplierAttachment; use App\Entity\Attachments\UserAttachment; use App\Exceptions\AttachmentDownloadException; +use App\Settings\SystemSettings\AttachmentsSettings; use Hshn\Base64EncodedFile\HttpFoundation\File\Base64EncodedFile; use Hshn\Base64EncodedFile\HttpFoundation\File\UploadedBase64EncodedFile; use const DIRECTORY_SEPARATOR; @@ -64,12 +65,13 @@ class AttachmentSubmitHandler 'asp', 'cgi', 'py', 'pl', 'exe', 'aspx', 'js', 'mjs', 'jsp', 'css', 'jar', 'html', 'htm', 'shtm', 'shtml', 'htaccess', 'htpasswd', '']; - public function __construct(protected AttachmentPathResolver $pathResolver, protected bool $allow_attachments_downloads, - protected HttpClientInterface $httpClient, protected MimeTypesInterface $mimeTypes, - protected FileTypeFilterTools $filterTools, /** - * @var string The user configured maximum upload size. This is a string like "10M" or "1G" and will be converted to - */ - protected string $max_upload_size) + public function __construct( + protected AttachmentPathResolver $pathResolver, + protected HttpClientInterface $httpClient, + protected MimeTypesInterface $mimeTypes, + protected FileTypeFilterTools $filterTools, + protected AttachmentsSettings $settings, + ) { //The mapping used to determine which folder will be used for an attachment type $this->folder_mapping = [ @@ -334,7 +336,7 @@ protected function moveFile(Attachment $attachment, bool $secure_location): Atta protected function downloadURL(Attachment $attachment, bool $secureAttachment): Attachment { //Check if we are allowed to download files - if (!$this->allow_attachments_downloads) { + if (!$this->settings->allowDownloads) { throw new RuntimeException('Download of attachments is not allowed!'); } @@ -472,7 +474,7 @@ public function getMaximumAllowedUploadSize(): int $this->max_upload_size_bytes = min( $this->parseFileSizeString(ini_get('post_max_size')), $this->parseFileSizeString(ini_get('upload_max_filesize')), - $this->parseFileSizeString($this->max_upload_size), + $this->parseFileSizeString($this->settings->maxFileSize) ); return $this->max_upload_size_bytes; diff --git a/src/Settings/AppSettings.php b/src/Settings/AppSettings.php index fd0a8c6d1..6bd198940 100644 --- a/src/Settings/AppSettings.php +++ b/src/Settings/AppSettings.php @@ -24,6 +24,7 @@ namespace App\Settings; use App\Settings\InfoProviderSystem\InfoProviderSettings; +use App\Settings\SystemSettings\AttachmentsSettings; use Jbtronics\SettingsBundle\Settings\EmbeddedSettings; use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\SettingsTrait; @@ -33,9 +34,11 @@ class AppSettings { use SettingsTrait; + #[EmbeddedSettings()] - public ?InfoProviderSettings $infoProviders = null; + public ?SystemSettings $system; + #[EmbeddedSettings()] - public ?TestSettings $test = null; + public ?InfoProviderSettings $infoProviders = null; } \ No newline at end of file diff --git a/src/Settings/TestSettings.php b/src/Settings/SystemSettings.php similarity index 79% rename from src/Settings/TestSettings.php rename to src/Settings/SystemSettings.php index 420205465..b8aafd57f 100644 --- a/src/Settings/TestSettings.php +++ b/src/Settings/SystemSettings.php @@ -23,18 +23,13 @@ namespace App\Settings; +use App\Settings\SystemSettings\AttachmentsSettings; +use Jbtronics\SettingsBundle\Settings\EmbeddedSettings; use Jbtronics\SettingsBundle\Settings\Settings; -use Jbtronics\SettingsBundle\Settings\SettingsParameter; #[Settings] -class TestSettings +class SystemSettings { - #[SettingsParameter()] - public bool $bool = false; - - #[SettingsParameter()] - public int $int = 0; - - #[SettingsParameter()] - public float $float = 0.0; + #[EmbeddedSettings()] + public ?AttachmentsSettings $attachments = null; } \ No newline at end of file diff --git a/src/Settings/SystemSettings/AttachmentsSettings.php b/src/Settings/SystemSettings/AttachmentsSettings.php new file mode 100644 index 000000000..e7c49fd77 --- /dev/null +++ b/src/Settings/SystemSettings/AttachmentsSettings.php @@ -0,0 +1,56 @@ +<?php +/* + * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). + * + * Copyright (C) 2019 - 2024 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 Affero General Public License as published + * by the Free Software Foundation, either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +declare(strict_types=1); + + +namespace App\Settings\SystemSettings; + +use Jbtronics\SettingsBundle\Metadata\EnvVarMode; +use Jbtronics\SettingsBundle\Settings\Settings; +use Jbtronics\SettingsBundle\Settings\SettingsParameter; +use Symfony\Component\Translation\TranslatableMessage as TM; +use Symfony\Component\Validator\Constraints as Assert; + +#[Settings(label: new TM("settings.system.attachments"))] +class AttachmentsSettings +{ + #[SettingsParameter( + label: new TM("settings.system.attachments.maxFileSize"), + description: new TM("settings.system.attachments.maxFileSize.help"), + envVar: "MAX_ATTACHMENT_FILE_SIZE", envVarMode: EnvVarMode::OVERWRITE + )] + #[Assert\Regex("/^([1-9][0-9]*)([KMG])?$/", message: "validator.fileSize.invalidFormat")] + public string $maxFileSize = '100M'; + + #[SettingsParameter( + label: new TM("settings.system.attachments.allowDownloads"), + description: new TM("settings.system.attachments.allowDownloads.help"), + formOptions: ['help_html' => true], + envVar: "bool:ALLOW_ATTACHMENT_DOWNLOADS", envVarMode: EnvVarMode::OVERWRITE + )] + public bool $allowDownloads = false; + + #[SettingsParameter( + label: new TM("settings.system.attachments.downloadByDefault"), + envVar: "bool:ATTACHMENT_DOWNLOAD_BY_DEFAULT", envVarMode: EnvVarMode::OVERWRITE + )] + public bool $downloadByDefault = false; +} \ No newline at end of file diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 636b5b90f..a01658851 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -12377,5 +12377,41 @@ Please note, that you can not impersonate a disabled user. If you try you will g <target>Currency</target> </segment> </unit> + <unit id="g0AgaAf" name="settings.system.attachments"> + <segment> + <source>settings.system.attachments</source> + <target><![CDATA[Attachments & Files]]></target> + </segment> + </unit> + <unit id="1wsDvqz" name="settings.system.attachments.maxFileSize"> + <segment> + <source>settings.system.attachments.maxFileSize</source> + <target>Maximum file size</target> + </segment> + </unit> + <unit id="Gn0P1Bv" name="settings.system.attachments.maxFileSize.help"> + <segment> + <source>settings.system.attachments.maxFileSize.help</source> + <target>The maximum size of files that can be uploaded. Please note that this is also limited by PHP configuration.</target> + </segment> + </unit> + <unit id="DyIfVYH" name="settings.system.attachments.allowDownloads"> + <segment> + <source>settings.system.attachments.allowDownloads</source> + <target>Allow downloading of external files</target> + </segment> + </unit> + <unit id="jD.pgZL" name="settings.system.attachments.allowDownloads.help"> + <segment> + <source>settings.system.attachments.allowDownloads.help</source> + <target><![CDATA[With this option users can download external files into Part-DB by providing an URL. <b>Attention: This can be a security issue, as it might allow users to access intranet ressources via Part-DB!</b>]]></target> + </segment> + </unit> + <unit id="HRxjf.u" name="settings.system.attachments.downloadByDefault"> + <segment> + <source>settings.system.attachments.downloadByDefault</source> + <target>Download new attachment URLs by default</target> + </segment> + </unit> </file> </xliff> diff --git a/translations/validators.en.xlf b/translations/validators.en.xlf index cec89ea6d..5c4371293 100644 --- a/translations/validators.en.xlf +++ b/translations/validators.en.xlf @@ -347,5 +347,11 @@ <target>Due to technical limitations, it is not possible to select dates after the 2038-01-19 on 32-bit systems!</target> </segment> </unit> + <unit id="89nojXY" name="validator.fileSize.invalidFormat"> + <segment> + <source>validator.fileSize.invalidFormat</source> + <target>Invalid file size format. Use an integer number plus K, M, G as suffix for Kilo, Mega or Gigabytes.</target> + </segment> + </unit> </file> </xliff>