diff --git a/config/customMimeTypes.php b/config/customMimeTypes.php new file mode 100644 index 000000000..2469474e3 --- /dev/null +++ b/config/customMimeTypes.php @@ -0,0 +1,35 @@ + 'text/plain', + 'doc' => ['application/msword', 'text/html'], + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'exe' => ['application/x-msdownload', 'application/x-dosexec'], + 'gif' => 'image/gif', + 'htm' => 'text/html', + 'html' => 'text/html', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'ppt' => 'application/vnd.ms-office', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pm' => 'text/plain', + 'pmt' => 'text/plain', + 'po' => 'text/x-po', + 'pdf' => 'application/pdf', + 'png' => 'image/png', + 'php' => 'text/x-php', + 'rar' => 'application/x-rar', + 'txt' => 'text/plain', + 'wmv' => ['video/x-ms-asf', 'video/x-ms-wmv'], + 'xls' => ['application/vnd.ms-excel', 'text/plain'], + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'zip' => 'application/zip', +]; diff --git a/framework/src/Maveriks/WebApplication.php b/framework/src/Maveriks/WebApplication.php index 9344be9dd..8b93a5a28 100644 --- a/framework/src/Maveriks/WebApplication.php +++ b/framework/src/Maveriks/WebApplication.php @@ -337,9 +337,7 @@ class WebApplication 'path' => $target['tmp_name'] ]); if ($validator->fails()) { - if ($validator->getStatus() === 429) { - throw new RestException($validator->getStatus()); - } + throw new RestException($validator->getStatus(), $validator->getMessage()); } return true; }; diff --git a/workflow/engine/content/translations/english/processmaker.en.po b/workflow/engine/content/translations/english/processmaker.en.po index 68431bc17..489aee6c0 100644 --- a/workflow/engine/content/translations/english/processmaker.en.po +++ b/workflow/engine/content/translations/english/processmaker.en.po @@ -24845,6 +24845,12 @@ msgstr "Error: The application {0} is not canceled." msgid "The default configuration was not defined" msgstr "The default configuration was not defined" +# TRANSLATION +# LABEL/ID_THE_MIMETYPE_EXTENSION_ERROR +#: LABEL/ID_THE_MIMETYPE_EXTENSION_ERROR +msgid "The mime type does not correspond to the permitted extension, please verify your file." +msgstr "The mime type does not correspond to the permitted extension, please verify your file." + # TRANSLATION # LABEL/ID_THE_NAME_CHANGE_MAY_CAUSE_DATA_LOSS #: LABEL/ID_THE_NAME_CHANGE_MAY_CAUSE_DATA_LOSS diff --git a/workflow/engine/data/mysql/insert.sql b/workflow/engine/data/mysql/insert.sql index 346bffb5d..70a0e836a 100644 --- a/workflow/engine/data/mysql/insert.sql +++ b/workflow/engine/data/mysql/insert.sql @@ -61034,6 +61034,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_THERE_PROBLEM_SENDING_EMAIL','en','There was a problem sending the email to','2016-04-08') , ( 'LABEL','ID_THE_APPLICATION_IS_NOT_CANCELED','en','Error: The application {0} is not canceled.','2016-06-15') , ( 'LABEL','ID_THE_DEFAULT_CONFIGURATION','en','The default configuration was not defined','2016-11-16') , +( 'LABEL','ID_THE_MIMETYPE_EXTENSION_ERROR','en','The mime type does not correspond to the permitted extension, please verify your file.','2018-10-2') , ( 'LABEL','ID_THE_NAME_CHANGE_MAY_CAUSE_DATA_LOSS','en','The change might cause data loss in the PM table. Do you want to continue?','2017-03-30') , ( 'LABEL','ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED','en','The PHP files execution was disabled please contact the system administrator.','2018-04-20') , ( 'LABEL','ID_THE_REASON_REASSIGN_USER_EMPTY','en','Please complete the reassign reason.','2016-10-20') , diff --git a/workflow/engine/src/ProcessMaker/Core/System.php b/workflow/engine/src/ProcessMaker/Core/System.php index 5e5475ace..bcbdc0e8e 100644 --- a/workflow/engine/src/ProcessMaker/Core/System.php +++ b/workflow/engine/src/ProcessMaker/Core/System.php @@ -68,7 +68,8 @@ class System 'google_map_api_key' => '', 'google_map_signature' => '', 'logging_level' => 'INFO', - 'upload_attempts_limit_per_user' => '60,1' + 'upload_attempts_limit_per_user' => '60,1', + 'files_white_list' => '' ); /** diff --git a/workflow/engine/src/ProcessMaker/Validation/ValidationUploadedFiles.php b/workflow/engine/src/ProcessMaker/Validation/ValidationUploadedFiles.php index 05146777b..17f6442f0 100644 --- a/workflow/engine/src/ProcessMaker/Validation/ValidationUploadedFiles.php +++ b/workflow/engine/src/ProcessMaker/Validation/ValidationUploadedFiles.php @@ -8,7 +8,7 @@ use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Facades\Cache; use ProcessMaker\Core\System; use ProcessMaker\Services\OAuth2\Server; -use ProcessMaker\Validation\Validator; +use Symfony\Component\HttpFoundation\File\File; class ValidationUploadedFiles { @@ -102,6 +102,66 @@ class ValidationUploadedFiles Bootstrap::registerMonologPhpUploadExecution('phpUpload', 250, $rule->getMessage(), $rule->getData()->filename); }); + //rule: mimeType + $validator->addRule() + ->validate($file, function($file) { + $path = isset($file->path) ? $file->path : ""; + $filesystem = new Filesystem(); + if (!$filesystem->exists($path)) { + return false; + } + + $extension = $filesystem->extension($file->filename); + $mimeType = $filesystem->mimeType($path); + + $file = new File($path); + $guessExtension = $file->guessExtension(); + $mimeTypeFile = $file->getMimeType(); + + //mimeType known + if ($extension === $guessExtension && $mimeType === $mimeTypeFile) { + return false; + } + //mimeType custom + $customMimeTypes = config("customMimeTypes"); + $customMimeType = isset($customMimeTypes[$extension]) ? $customMimeTypes[$extension] : null; + if (is_string($customMimeType)) { + if ($customMimeType === $mimeType) { + return false; + } + } + if (is_array($customMimeType)) { + foreach ($customMimeType as $value) { + if ($value === $mimeType) { + return false; + } + } + } + //files_white_list + $systemConfiguration = System::getSystemConfiguration('', '', config("system.workspace")); + $filesWhiteList = explode(',', $systemConfiguration['files_white_list']); + if (in_array($extension, $filesWhiteList)) { + return false; + } + return true; + }) + ->status(415) + ->message(G::LoadTranslation('ID_THE_MIMETYPE_EXTENSION_ERROR')) + ->log(function($rule) { + /** + * Levels supported by MonologProvider is: + * 100 "DEBUG" + * 200 "INFO" + * 250 "NOTICE" + * 300 "WARNING" + * 400 "ERROR" + * 500 "CRITICAL" + * 550 "ALERT" + * 600 "EMERGENCY" + */ + Bootstrap::registerMonologPhpUploadExecution('phpUpload', 250, $rule->getMessage(), $rule->getData()->filename); + }); + return $validator->validate(); }