Merged in feature/HOR-4508 (pull request #6649)

HOR-4508

Approved-by: Julio Cesar Laura Avendaño <contact@julio-laura.com>
This commit is contained in:
Paula Quispe
2018-11-12 17:42:09 +00:00
committed by Julio Cesar Laura Avendaño
28 changed files with 831 additions and 99 deletions

View File

@@ -88,7 +88,8 @@
"thirdparty/pake/pakeFunction.php",
"thirdparty/HTMLPurifier/HTMLPurifier.auto.php",
"workflow/engine/classes/class.pmFunctions.php",
"workflow/engine/src/ProcessMaker/Util/helpers.php"
"workflow/engine/src/ProcessMaker/Util/helpers.php",
"framework/src/Maveriks/Extension/Restler/UploadFormat.php"
]
},
"autoload-dev": {

View File

@@ -0,0 +1,36 @@
<?php
/**
* This is a partial list of the known types, add the type you want to be recognized,
* this affects the whole application globally.
*
* https://www.iana.org/assignments/media-types/media-types.xml
*/
return [
'dat' => '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',
'pmx' => 'application/xml',
'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',
];

View File

@@ -3,14 +3,16 @@
namespace Maveriks;
use Bootstrap;
use G;
use Illuminate\Foundation\Http\Kernel;
use Luracast\Restler\Format\UploadFormat;
use Luracast\Restler\RestException;
use Maveriks\Util;
use ProcessMaker\Core\System;
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Services;
use ProcessMaker\Services\Api;
use Luracast\Restler\RestException;
use Illuminate\Foundation\Http\Kernel;
use G;
use ProcessMaker\Validation\ValidationUploadedFiles;
/**
* Web application bootstrap
@@ -252,8 +254,6 @@ class WebApplication
*/
protected function initRest($uri, $version, $multipart = false)
{
require_once $this->rootDir . "/framework/src/Maveriks/Extension/Restler/UploadFormat.php";
// $servicesDir contains directory where Services Classes are allocated
$servicesDir = $this->workflowDir . 'engine' . DS . 'src' . DS . 'ProcessMaker' . DS . 'Services' . DS;
// $apiDir - contains directory to scan classes and add them to Restler
@@ -331,6 +331,17 @@ class WebApplication
$this->rest->setOverridingFormats('JsonFormat', 'UploadFormat');
UploadFormat::$customValidationFunction = function($target) {
$validator = ValidationUploadedFiles::getValidationUploadedFiles()->runRules([
'filename' => $target['name'],
'path' => $target['tmp_name']
]);
if ($validator->fails()) {
throw new RestException($validator->getStatus(), $validator->getMessage());
}
return true;
};
// scan all api directory to find api classes
$classesList = Util\Common::rglob($apiDir . "/*");

View File

@@ -4,6 +4,7 @@ use ProcessMaker\Core\System;
use ProcessMaker\AuditLog\AuditLog;
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Services\OAuth2\Server;
use ProcessMaker\Validation\ValidationUploadedFiles;
class G
{
@@ -1183,7 +1184,7 @@ class G
\Bootstrap::registerMonologPhpUploadExecution('phpExecution', 200, 'Php Execution', $filename);
require_once($filename);
} else {
$message = G::LoadTranslation('THE_PHP_FILES_EXECUTION_WAS_DISABLED');
$message = G::LoadTranslation('ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED');
\Bootstrap::registerMonologPhpUploadExecution('phpExecution', 550, $message, $filename);
echo $message;
}
@@ -5488,6 +5489,16 @@ class G
*/
public static function verifyInputDocExtension($InpDocAllowedFiles, $fileName, $filesTmpName)
{
$error = null;
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) use(&$error) {
$error = new stdclass();
$error->status = false;
$error->message = $validator->getMessage();
});
if (!is_null($error)) {
return $error;
}
// Initialize variables
$res = new stdclass();
$res->status = false;
@@ -5497,14 +5508,6 @@ class G
$aux = pathinfo($fileName);
$fileExtension = isset($aux['extension']) ? strtolower($aux['extension']) : '';
if (\Bootstrap::getDisablePhpUploadExecution() === 1 && $fileExtension === 'php') {
$message = \G::LoadTranslation('THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED');
\Bootstrap::registerMonologPhpUploadExecution('phpUpload', 550, $message, $fileName);
$res->status = false;
$res->message = $message;
return $res;
}
// If required extension is *.* don't validate
if (in_array('*', $allowedTypes)) {
$res->status = true;

View File

@@ -24851,18 +24851,36 @@ 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
msgid "The change might cause data loss in the PM table. Do you want to continue?"
msgstr "The change might cause data loss in the PM table. Do you want to continue?"
# TRANSLATION
# LABEL/ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED
#: LABEL/ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED
msgid "The PHP files execution was disabled please contact the system administrator."
msgstr "The PHP files execution was disabled please contact the system administrator."
# TRANSLATION
# LABEL/ID_THE_REASON_REASSIGN_USER_EMPTY
#: LABEL/ID_THE_REASON_REASSIGN_USER_EMPTY
msgid "Please complete the reassign reason."
msgstr "Please complete the reassign reason."
# TRANSLATION
# LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED
#: LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED
msgid "The upload of PHP files was disabled please contact the system administrator."
msgstr "The upload of PHP files was disabled please contact the system administrator."
# TRANSLATION
# LABEL/ID_THE_USERNAME_EMAIL_IS_INCORRECT
#: LABEL/ID_THE_USERNAME_EMAIL_IS_INCORRECT
@@ -25187,6 +25205,12 @@ msgstr "Today"
msgid "Tools"
msgstr "Tools"
# TRANSLATION
# LABEL/ID_TOO_MANY_REQUESTS
#: LABEL/ID_TOO_MANY_REQUESTS
msgid "Too many requests"
msgstr "Too many requests"
# TRANSLATION
# LABEL/ID_TOP_MARGIN
#: LABEL/ID_TOP_MARGIN
@@ -25913,6 +25937,18 @@ msgstr "The uploaded file exceeds the upload_max_filesize directive in php.ini"
msgid "The file has not been attached because the extension is not allowed or because the content doesn't correspond."
msgstr "The file has not been attached because the extension is not allowed or because the content doesn't correspond."
# TRANSLATION
# LABEL/ID_UPLOAD_INVALID_DOC_MAX_FILESIZE
#: LABEL/ID_UPLOAD_INVALID_DOC_MAX_FILESIZE
msgid "File size exceeds the allowable limit of {0}"
msgstr "File size exceeds the allowable limit of {0}"
# TRANSLATION
# LABEL/ID_UPLOAD_INVALID_DOC_TYPE_FILE
#: LABEL/ID_UPLOAD_INVALID_DOC_TYPE_FILE
msgid "Invalid file format, please upload a file with one of the following formats {0}"
msgstr "Invalid file format, please upload a file with one of the following formats {0}"
# TRANSLATION
# LABEL/ID_UPLOAD_ERR_NO_FILE
#: LABEL/ID_UPLOAD_ERR_NO_FILE

View File

@@ -2,6 +2,7 @@
use ProcessMaker\Core\System;
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Validation\ValidationUploadedFiles;
/**
* adminProxy.php
@@ -1025,7 +1026,14 @@ class adminProxy extends HttpProxyController
*/
public function uploadImage()
{
//!dataSystem
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
echo G::json_encode([
'success' => true,
'failed' => true,
'message' => $validator->getMessage()
]);
exit();
});
$filter = new InputFilter();
$_SERVER["REQUEST_URI"] = $filter->xssFilterHard($_SERVER["REQUEST_URI"]);

View File

@@ -8,6 +8,8 @@
*/
use ProcessMaker\Core\System;
use ProcessMaker\Validation\ExceptionRestApi;
use ProcessMaker\Validation\ValidationUploadedFiles;
header("Content-type: text/html;charset=utf-8");
require_once 'classes/model/AdditionalTables.php';
@@ -723,6 +725,9 @@ class pmTablesProxy extends HttpProxyController
}
try {
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
throw new ExceptionRestApi($validator->getMessage());
});
$result = new stdClass();
$errors = '';
$fromConfirm = false;
@@ -891,6 +896,11 @@ class pmTablesProxy extends HttpProxyController
}
$result->message = $msg;
} catch (ExceptionRestApi $e) {
$result = new stdClass();
$result->success = false;
$result->errorType = 'notice';
$result->message = $e->getMessage();
} catch (Exception $e) {
$result = new stdClass();
$result->fromAdmin = $fromAdmin;

View File

@@ -61035,8 +61035,11 @@ 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') ,
( 'LABEL','ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED','en','The upload of PHP files was disabled please contact the system administrator.','2018-04-20') ,
( 'LABEL','ID_THE_USERNAME_EMAIL_IS_INCORRECT','en','The username or email is incorrect','2018-01-18') ,
( 'LABEL','ID_THIS_MONTH','en','This Month','2014-01-15') ,
( 'LABEL','ID_THIS_QUARTER','en','This quarter','2014-01-15') ,
@@ -61093,6 +61096,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE
( 'LABEL','ID_TO','en','To','2014-01-15') ,
( 'LABEL','ID_TODAY','en','Today','2014-01-15') ,
( 'LABEL','ID_TOOLS','en','Tools','2014-01-15') ,
( 'LABEL','ID_TOO_MANY_REQUESTS','en','Too many requests','2018-04-25') ,
( 'LABEL','ID_TOP_MARGIN','en','Top Margin','2014-01-15') ,
( 'LABEL','ID_TOTAL_CASES','en','Total Cases','2014-01-15') ,
( 'LABEL','ID_TOTAL_CASES_REASSIGNED','en','Total Cases Reassigned','2014-01-15') ,
@@ -61216,6 +61220,8 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE
( 'LABEL','ID_UPLOAD_ERR_FORM_SIZE','en','The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form','2014-01-15') ,
( 'LABEL','ID_UPLOAD_ERR_INI_SIZE','en','The uploaded file exceeds the upload_max_filesize directive in php.ini','2014-01-15') ,
( 'LABEL','ID_UPLOAD_ERR_NOT_ALLOWED_EXTENSION','en','The file has not been attached because the extension is not allowed or because the content doesn''t correspond.','2014-10-21') ,
( 'LABEL','ID_UPLOAD_INVALID_DOC_MAX_FILESIZE','en','File size exceeds the allowable limit of {0}','2018-11-06') ,
( 'LABEL','ID_UPLOAD_INVALID_DOC_TYPE_FILE','en','Invalid file format, please upload a file with one of the following formats {0}','2018-11-05') ,
( 'LABEL','ID_UPLOAD_ERR_NO_FILE','en','No file was uploaded','2014-01-15') ,
( 'LABEL','ID_UPLOAD_ERR_NO_TMP_DIR','en','Missing a temporary folder','2014-01-15') ,
( 'LABEL','ID_UPLOAD_ERR_PARTIAL','en','The uploaded file was only partially uploaded','2014-01-15') ,

View File

@@ -1,6 +1,7 @@
<?php
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Validation\ValidationUploadedFiles;
$filter = new InputFilter();
$_POST = $filter->xssFilterHard($_POST);
@@ -1445,6 +1446,15 @@ function checkTree($uidOriginFolder, $uidNewFolder)
*/
function uploadExternalDocument()
{
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
$response = [
'error' => $validator->getMessage(),
'message' => $validator->getMessage(),
'success' => false
];
print_r(G::json_encode($response));
die();
});
$response = [];
$response['action'] = $_POST['action'] . " - " . $_POST['option'];
$response['error'] = "error";
@@ -1531,18 +1541,6 @@ function uploadExternalDocument()
//Read. Instance Document classes
if (!empty($quequeUpload)) {
foreach ($quequeUpload as $key => $fileObj) {
$extension = pathinfo($fileObj['fileName'], PATHINFO_EXTENSION);
if (\Bootstrap::getDisablePhpUploadExecution() === 1 && $extension === 'php') {
$message = \G::LoadTranslation('THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED');
\Bootstrap::registerMonologPhpUploadExecution('phpUpload', 550, $message, $fileObj['fileName']);
$response['error'] = $message;
$response['message'] = $message;
$response['success'] = false;
print_r(G::json_encode($response));
exit();
}
}
$docUid = $_POST['docUid'];
$appDocUid = isset($_POST['APP_DOC_UID']) ? $_POST['APP_DOC_UID'] : "";
$docVersion = isset($_POST['docVersion']) ? $_POST['docVersion'] : "";

View File

@@ -2,6 +2,8 @@
use ProcessMaker\Core\System;
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Validation\ExceptionRestApi;
use ProcessMaker\Validation\ValidationUploadedFiles;
function runBgProcessmaker($task, $log)
{
@@ -16,6 +18,9 @@ function runBgProcessmaker($task, $log)
}
try {
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
throw new ExceptionRestApi($validator->getMessage());
});
if (isset($_REQUEST["action"])) {
$action = $_REQUEST["action"];
} else {
@@ -312,6 +317,15 @@ try {
$result["addons"] = array();
}
G::outRes(G::json_encode($result));
} catch (ExceptionRestApi $e) {
$token = strtotime("now");
PMException::registerErrorLog($e, $token);
G::outRes(
G::json_encode(array(
"success" => false,
"errors" => $e->getMessage()
))
);
} catch (Exception $e) {
$token = strtotime("now");
PMException::registerErrorLog($e, $token);

View File

@@ -27,6 +27,7 @@
global $RBAC;
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Validation\ValidationUploadedFiles;
$RBAC->requirePermissions("PM_SETUP_ADVANCE");
require_once PATH_CORE . 'methods' . PATH_SEP . 'enterprise' . PATH_SEP . 'enterprise.php';
@@ -35,6 +36,9 @@ $response = array();
$status = 1;
try {
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
throw new Exception($validator->getMessage());
});
if (!isset($_FILES["form"]["error"]["PLUGIN_FILENAME"]) || $_FILES["form"]["error"]["PLUGIN_FILENAME"] == 1) {
$str = "There was an error uploading the file, probably the file size if greater than upload_max_filesize parameter in php.ini, please check this parameter and try again.";

View File

@@ -23,6 +23,16 @@
*/
use \ProcessMaker\Importer\XmlImporter;
use ProcessMaker\Validation\ValidationUploadedFiles;
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
echo G::json_encode([
'status' => 'ERROR',
'success' => true,
'catchMessage' => $validator->getMessage()
]);
exit();
});
ini_set("max_execution_time", 0);
$affectedGroups = array();

View File

@@ -1,5 +1,7 @@
<?php
use ProcessMaker\Validation\ValidationUploadedFiles;
sleep(1);
global $RBAC;
if ($RBAC->userCanAccess('PM_FACTORY') == 1) {
@@ -25,26 +27,23 @@ if ($RBAC->userCanAccess('PM_FACTORY') == 1) {
}
}
$fileName = $_FILES['form']['name'];
$canUploadPhpFile = true;
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
if (\Bootstrap::getDisablePhpUploadExecution() === 1 && $extension === 'php') {
$message = \G::LoadTranslation('THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED');
\Bootstrap::registerMonologPhpUploadExecution('phpUpload', 550, $message, $fileName);
$canUploadPhpFile = false;
}
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
$response = [
'result' => 0,
'msg' => $validator->getMessage()
];
print_r(G::json_encode($response));
die();
});
if ($_FILES['form']['error'] == "0" && $canUploadPhpFile) {
$fileName = $_FILES['form']['name'];
if ($_FILES['form']['error'] == "0") {
G::uploadFile($_FILES['form']['tmp_name'], $sDirectory, $fileName);
$msg = "Uploaded (" . (round((filesize($sDirectory . $fileName) / 1024) * 10) / 10) . " kb)";
$result = 1;
} else {
$msg = "Failed";
if ($canUploadPhpFile === false) {
$msg = $message;
}
$result = 0;
}
echo "{'result': $result, 'msg':'$msg'}";
}

View File

@@ -2,6 +2,8 @@
require_once "classes/model/Language.php";
use ProcessMaker\Validation\ValidationUploadedFiles;
global $RBAC;
$access = $RBAC->userCanAccess('PM_SETUP_ADVANCE');
@@ -24,6 +26,9 @@ if ($access != 1) {
$result = new stdClass();
try {
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
throw new Exception($validator->getMessage());
});
//if the xmlform path is writeable
if (!is_writable(PATH_XMLFORM)) {
throw new Exception(G::LoadTranslation('IMPORT_LANGUAGE_ERR_NO_WRITABLE'));

View File

@@ -26,11 +26,15 @@
use ProcessMaker\Core\System;
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Validation\ValidationUploadedFiles;
global $RBAC;
$RBAC->requirePermissions('PM_SETUP_ADVANCE');
try {
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
throw new Exception($validator->getMessage());
});
//load the variables
if (!isset($_FILES['form']['error']['PLUGIN_FILENAME']) || $_FILES['form']['error']['PLUGIN_FILENAME'] == 1) {
throw (new Exception(G::loadTranslation('ID_ERROR_UPLOADING_PLUGIN_FILENAME')));

View File

@@ -1,6 +1,7 @@
<?php
use ProcessMaker\Core\System;
use ProcessMaker\Validation\ValidationUploadedFiles;
if (! isset( $_REQUEST['action'] )) {
$res['success'] = false;
@@ -199,6 +200,9 @@ function newSkin ($baseSkin = 'classic')
function importSkin ()
{
try {
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
throw new Exception($validator->getMessage());
});
if (! isset( $_FILES['uploadedFile'] )) {
throw (new Exception( G::LoadTranslation( 'ID_SKIN_FILE_REQUIRED' ) ));
}

View File

@@ -1,28 +1,29 @@
<?php
namespace ProcessMaker\BusinessModel\Cases;
use ProcessMaker\Plugins\PluginRegistry;
use AppDocument;
use AppDocumentPeer;
use Exception;
use Criteria;
use ResultSet;
use G;
use ObjectPermissionPeer;
use StepPeer;
use StepSupervisorPeer;
use AppDelegation;
use AppDelegationPeer;
use Users;
use Configurations;
use Bootstrap;
use WsBase;
use ApplicationPeer;
use ProcessMaker\BusinessModel\ProcessSupervisor;
use ProcessMaker\BusinessModel\Cases AS BusinessModelCases;
use Cases;
use ProcessUserPeer;
use AppDocument;
use AppDocumentPeer;
use AppFolder;
use ApplicationPeer;
use Bootstrap;
use Cases;
use Configurations;
use Criteria;
use Exception;
use G;
use ObjectPermissionPeer;
use ProcessMaker\BusinessModel\Cases AS BusinessModelCases;
use ProcessMaker\BusinessModel\ProcessSupervisor;
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Validation\ValidationUploadedFiles;
use ProcessUserPeer;
use ResultSet;
use StepPeer;
use StepSupervisorPeer;
use Users;
use WsBase;
class InputDocument
@@ -936,6 +937,12 @@ class InputDocument
*/
public function uploadFileCase($files, $caseInstance, $aData, $userUid, $appUid, $delIndex)
{
ValidationUploadedFiles::getValidationUploadedFiles()->dispach(function($validator) {
G::SendMessageText($validator->getMessage(), "ERROR");
$url = explode("sys" . config("system.workspace"), $_SERVER['HTTP_REFERER']);
G::header("location: " . "/sys" . config("system.workspace") . $url[1]);
die();
});
$arrayField = array();
$arrayFileName = array();
$arrayFileTmpName = array();
@@ -1034,16 +1041,6 @@ class InputDocument
$aFields = array("APP_UID" => $appUid, "DEL_INDEX" => $delIndex, "USR_UID" => $userUid, "DOC_UID" => -1, "APP_DOC_TYPE" => "ATTACHED", "APP_DOC_CREATE_DATE" => date("Y-m-d H:i:s"), "APP_DOC_COMMENT" => "", "APP_DOC_TITLE" => "", "APP_DOC_FILENAME" => $arrayFileName[$i], "APP_DOC_FIELDNAME" => $fieldName);
}
$sExtension = pathinfo($aFields["APP_DOC_FILENAME"]);
if (Bootstrap::getDisablePhpUploadExecution() === 1 && $sExtension["extension"] === 'php') {
$message = G::LoadTranslation('THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED');
Bootstrap::registerMonologPhpUploadExecution('phpUpload', 550, $message, 'processmaker.log');
G::SendMessageText($message, "ERROR");
$backUrlObj = explode("sys" . config("system.workspace"), $_SERVER['HTTP_REFERER']);
G::header("location: " . "/sys" . config("system.workspace") . $backUrlObj[1]);
die();
}
$oAppDocument = new AppDocument();
$oAppDocument->create($aFields);

View File

@@ -196,11 +196,6 @@ class FilesManager
if ($extention == '.exe') {
throw new \Exception(\G::LoadTranslation('ID_FILE_UPLOAD_INCORRECT_EXTENSION'));
}
if (\Bootstrap::getDisablePhpUploadExecution() === 1 && $extention === '.php' && !$isImport) {
$message = \G::LoadTranslation('THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED');
\Bootstrap::registerMonologPhpUploadExecution('phpUpload', 550, $message, $aData['prf_filename']);
throw new \Exception($message);
}
break;
default:
$sDirectory = PATH_DATA_MAILTEMPLATES . $sProcessUID . PATH_SEP . $sSubDirectory . $aData['prf_filename'];

View File

@@ -32,6 +32,8 @@ use ProcessMaker\Core\RoutingScreen;
use ProcessMaker\Core\System;
use ProcessMaker\Services\Api\Project\Activity\Step as ActivityStep;
use ProcessMaker\Util\DateTime;
use ProcessMaker\Validation\ExceptionRestApi;
use ProcessMaker\Validation\Validator;
use ProcessPeer;
use Propel;
use RBAC;
@@ -995,16 +997,6 @@ class Light
$confEnvSetting = $config->getFormats();
$user = new Users();
foreach ($requestData as $k => $file) {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
if (Bootstrap::getDisablePhpUploadExecution() === 1 && $ext === 'php') {
$message = G::LoadTranslation('THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED');
Bootstrap::registerMonologPhpUploadExecution('phpUpload', 550, $message, $file['name']);
$response[$k]['error'] = array(
"code" => "400",
"message" => $message
);
continue;
}
$cases = new Cases();
$delIndex = $cases->getCurrentDelegation($appUid, $userUid);
$docUid = !empty($file['docUid']) ? $file['docUid'] : -1;
@@ -1071,7 +1063,7 @@ class Light
*
* @throws Exception
*/
public function documentUploadFiles($userUid, $app_uid, $app_doc_uid, $request_data)
public function documentUploadFiles($userUid, $app_uid, $app_doc_uid)
{
$response = array("status" => "fail");
if (isset($_FILES["form"]["name"]) && count($_FILES["form"]["name"]) > 0) {
@@ -1107,6 +1099,58 @@ class Light
}
}
if (count($arrayField) > 0) {
//rule validation
$appDocument = new AppDocument();
$appDocument->load($app_doc_uid);
$inputDocument = new InputDocument();
$ifInputExist = $inputDocument->InputExists($appDocument->getDocUid());
if ($ifInputExist) {
$inputProperties = $inputDocument->load($appDocument->getDocUid());
$inpDocTypeFile = $inputProperties['INP_DOC_TYPE_FILE'];
$inpDocMaxFilesize = (int) $inputProperties["INP_DOC_MAX_FILESIZE"];
$inpDocMaxFilesizeUnit = $inputProperties["INP_DOC_MAX_FILESIZE_UNIT"];
}
for ($i = 0; $ifInputExist && $i < count($arrayField); $i++) {
$file = [
'filename' => $arrayFileName[$i],
'path' => $arrayFileTmpName[$i]
];
$validator = new Validator();
//rule: extension
$validator->addRule()
->validate($file, function($file) use($inpDocTypeFile) {
$result = G::verifyInputDocExtension($inpDocTypeFile, $file->filename, $file->path);
return $result->status === false;
})
->status(415)
->message(G::LoadTranslation('ID_UPLOAD_INVALID_DOC_TYPE_FILE', [$inpDocTypeFile]))
->log(function($rule) {
Bootstrap::registerMonologPhpUploadExecution('phpUpload', 250, $rule->getMessage(), $rule->getData()->filename);
});
//rule: maximum file size
$validator->addRule()
->validate($file, function($file) use($inpDocMaxFilesize, $inpDocMaxFilesizeUnit) {
if ($inpDocMaxFilesize > 0) {
$totalMaxFileSize = $inpDocMaxFilesize * ($inpDocMaxFilesizeUnit == "MB" ? 1024 * 1024 : 1024);
$fileSize = filesize($file->path);
if ($fileSize > $totalMaxFileSize) {
return true;
}
}
return false;
})
->status(413)
->message(G::LoadTranslation("ID_UPLOAD_INVALID_DOC_MAX_FILESIZE", [$inpDocMaxFilesize . $inpDocMaxFilesizeUnit]))
->log(function($rule) {
Bootstrap::registerMonologPhpUploadExecution('phpUpload', 250, $rule->getMessage(), $rule->getData()->filename);
});
$validator->validate();
if ($validator->fails()) {
throw new ExceptionRestApi($validator->getMessage(), $validator->getStatus());
}
}
for ($i = 0; $i <= count($arrayField) - 1; $i++) {
if ($arrayFileError[$i] == 0) {
$indocUid = null;

View File

@@ -66,7 +66,10 @@ class System
'logging_level' => 'INFO',
'smtp_timeout' => 20,
'google_map_api_key' => '',
'google_map_signature' => ''
'google_map_signature' => '',
'logging_level' => 'INFO',
'upload_attempts_limit_per_user' => '60,1',
'files_white_list' => ''
);
/**

View File

@@ -23,6 +23,7 @@ use ProcessMaker\Project\Adapter;
use ProcessMaker\Services\Api;
use ProcessMaker\Services\Api\Project\Activity\Step;
use ProcessMaker\Util\DateTime;
use ProcessMaker\Validation\ExceptionRestApi;
use RBAC;
use stdclass;
use StepPeer;
@@ -1466,10 +1467,11 @@ class Light extends Api
$userUid = $this->getUserId();
$oMobile = new BusinessModelLight();
$filesUids = $oMobile->postUidUploadFiles($userUid, $app_uid, $request_data);
} catch (ExceptionRestApi $e) {
throw new RestException($e->getCode(), $e->getMessage());
} catch (Exception $e) {
throw (new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage()));
throw new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage());
}
return $filesUids;
}
@@ -1500,11 +1502,12 @@ class Light extends Api
try {
$userUid = $this->getUserId();
$oMobile = new BusinessModelLight();
$response = $oMobile->documentUploadFiles($userUid, $app_uid, $app_doc_uid, $request_data);
$response = $oMobile->documentUploadFiles($userUid, $app_uid, $app_doc_uid);
} catch (ExceptionRestApi $e) {
throw new RestException($e->getCode(), $e->getMessage());
} catch (Exception $e) {
throw (new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage()));
}
return $response;
}

View File

@@ -1,8 +1,11 @@
<?php
namespace ProcessMaker\Services\Api\Project;
use \ProcessMaker\Services\Api;
use \Luracast\Restler\RestException;
use Exception;
use Luracast\Restler\RestException;
use ProcessMaker\BusinessModel\FilesManager as FilesManagerBusinessModel;
use ProcessMaker\Services\Api;
use ProcessMaker\Validation\ExceptionRestApi;
/**
* Project\ProjectUsers Api Controller
@@ -57,11 +60,13 @@ class FilesManager extends Api
$userUid = $this->getUserId();
$request_data = (array)($request_data);
$request_data = array_merge(array('prf_content' => $prf_content ), $request_data);
$filesManager = new \ProcessMaker\BusinessModel\FilesManager();
$filesManager = new FilesManagerBusinessModel();
$arrayData = $filesManager->addProcessFilesManager($prj_uid, $userUid, $request_data);
//Response
$response = $arrayData;
} catch (\Exception $e) {
} catch (ExceptionRestApi $e) {
throw new RestException($e->getCode(), $e->getMessage());
} catch (Exception $e) {
//response
throw new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage());
}
@@ -85,11 +90,13 @@ class FilesManager extends Api
public function doPostProcessFilesManagerUpload($prj_uid, $prf_uid)
{
try {
$filesManager = new \ProcessMaker\BusinessModel\FilesManager();
$filesManager = new FilesManagerBusinessModel();
$sData = $filesManager->uploadProcessFilesManager($prj_uid, $prf_uid);
//Response
$response = $sData;
} catch (\Exception $e) {
} catch (ExceptionRestApi $e) {
throw new RestException($e->getCode(), $e->getMessage());
} catch (Exception $e) {
//response
throw new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage());
}

View File

@@ -0,0 +1,10 @@
<?php
namespace ProcessMaker\Validation;
use Exception;
class ExceptionRestApi extends Exception
{
}

View File

@@ -0,0 +1,137 @@
<?php
namespace ProcessMaker\Validation;
/**
* It contains a validation rule defined by the Closure function that must
* return a boolean value, true if it has failed, and false if it has passed the
* validation rule.
*/
class Rule
{
/**
* Validation data defined by value and field.
* @var object
*/
private $data = null;
/**
* Validation rule.
* @var Closure
*/
private $callback = null;
/**
* Help to register when the rule is not met.
* @var Closure
*/
private $callbackLog = null;
/**
* Return message in case the rule is not met.
* @var string
*/
private $message = "";
/**
* Response status code.
* @var int
*/
private $status = 0;
/**
* Obtain validation data composed of field and value.
* @return object
*/
function getData()
{
return $this->data;
}
/**
* Get the Closure function.
* @return Closure
*/
function getCallback()
{
return $this->callback;
}
/**
* Gets the Closure function that applies the validation rule.
* @return Closure
*/
function getCallbackLog()
{
return $this->callbackLog;
}
/**
* Get the message to be saved in the log if the rule is not fulfilled.
* @return string
*/
function getMessage()
{
return $this->message;
}
/**
* Get status code.
* @return int
*/
function getStatus()
{
return $this->status;
}
/**
* Registers the data and the Closure function that contains the validation
* rule.
* @param array $data
* @param Closure $callback
* @return Rule
*/
public function validate($data, $callback = null)
{
$this->data = (object) $data;
if (is_callable($callback)) {
$this->callback = $callback;
}
return $this;
}
/**
* Registers the customized message in case the validation rule is not met.
* @param string $message
* @return Rule
*/
public function message($message = "")
{
$this->message = $message;
return $this;
}
/**
* Set status code.
* @param int $status
* @return $this
*/
function status($status = 0)
{
$this->status = $status;
return $this;
}
/**
* Registers the Closure function in case the validation rule is not met.
* @param Closure $callback
* @return Rule
*/
public function log($callback = null)
{
if (is_callable($callback)) {
$this->callbackLog = $callback;
}
return $this;
}
}

View File

@@ -0,0 +1,241 @@
<?php
namespace ProcessMaker\Validation;
use Bootstrap;
use G;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Cache;
use ProcessMaker\Core\System;
use ProcessMaker\Services\OAuth2\Server;
use Symfony\Component\HttpFoundation\File\File;
class ValidationUploadedFiles
{
/**
* Single object instance to be used in the entire environment.
*
* @var object
*/
private static $validationUploadedFiles = null;
/**
* List of evaluated items that have not passed the validation rules.
*
* @var array
*/
private $fails = [];
/**
* Check if the loaded files comply with the validation rules, add here if you
* want more validation rules.
* Accept per argument an array or object that contains a "filename" and "path" values.
* The rules are verified in the order in which they have been added.
*
* @param array|object $file
* @return Validator
*/
public function runRules($file)
{
$validator = new Validator();
//rule: disable_php_upload_execution
$validator->addRule()
->validate($file, function($file) {
$filesystem = new Filesystem();
$extension = $filesystem->extension($file->filename);
return Bootstrap::getDisablePhpUploadExecution() === 1 && $extension === 'php';
})
->status(550)
->message(G::LoadTranslation('ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED'))
->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', 550, $rule->getMessage(), $rule->getData()->filename);
});
//rule: upload_attempts_limit_per_user
$validator->addRule()
->validate($file, function($file) {
$systemConfiguration = System::getSystemConfiguration('', '', config("system.workspace"));
$filesWhiteList = explode(',', $systemConfiguration['upload_attempts_limit_per_user']);
$userId = Server::getUserId();
$key = config("system.workspace") . '/' . $userId;
$attemps = (int) trim($filesWhiteList[0]);
$minutes = (int) trim($filesWhiteList[1]);
$pastAttemps = Cache::remember($key, $minutes, function() {
return 1;
});
//We only increase when the file path exists, useful when pre-validation is done.
if (isset($file->path)) {
Cache::increment($key, 1);
}
if ($pastAttemps <= $attemps) {
return false;
}
return true;
})
->status(429)
->message(G::LoadTranslation('ID_TOO_MANY_REQUESTS'))
->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);
});
//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();
}
/**
* File upload validation.
*
* @return $this
*/
public function runRulesToAllUploadedFiles()
{
$files = $_FILES;
if (!is_array($files)) {
return;
}
$this->fails = [];
foreach ($files as $file) {
$data = (object) $file;
if (!is_array($data->name) || !is_array($data->tmp_name)) {
$data->name = [$data->name];
$data->tmp_name = [$data->tmp_name];
}
foreach ($data->name as $key => $value) {
if (empty($value)) {
continue;
}
if (is_array($value)) {
foreach ($value as $rowKey => $rowValue) {
foreach ($rowValue as $cellKey => $cellValue) {
if (empty($cellValue)) {
continue;
}
$validator = $this->runRules(['filename' => $cellValue, 'path' => $data->tmp_name[$key][$rowKey][$cellKey]]);
if ($validator->fails()) {
$this->fails[] = $validator;
}
}
}
continue;
}
$validator = $this->runRules(['filename' => $value, 'path' => $data->tmp_name[$key]]);
if ($validator->fails()) {
$this->fails[] = $validator;
}
}
}
return $this;
}
/**
* Get the first error and call the argument function.
*
* @param function $callback
* @return $this
*/
public function dispach($callback)
{
if (!empty($this->fails[0])) {
if (!empty($callback) && is_callable($callback)) {
$callback($this->fails[0], $this->fails);
}
}
return $this;
}
/**
* It obtains a single object to be used as a record of the whole environment.
*
* @return object
*/
public static function getValidationUploadedFiles()
{
if (self::$validationUploadedFiles === null) {
self::$validationUploadedFiles = new ValidationUploadedFiles();
}
return self::$validationUploadedFiles;
}
}

View File

@@ -0,0 +1,138 @@
<?php
namespace ProcessMaker\Validation;
use ProcessMaker\Validation\Rule;
/**
* Performs the validation process based on a list of validation rules.
*/
class Validator
{
/**
* List of instances of the class 'Rule'.
* @var array
*/
private $rules = [];
/**
* Error message in the current validation rule.
* @var string
*/
private $message = "";
/**
* Response status code.
* @var int
*/
private $status = 0;
/**
* Current status of the validation, true if the validation has not been overcome.
* @var boolean
*/
private $fails = false;
/**
* Call after the validation process.
* @var Closure
*/
private $callback = null;
/**
* Get the message of the current validation if there was a failure.
* @return string
*/
function getMessage()
{
return $this->message;
}
/**
* Get status code.
* @return int
*/
function getStatus()
{
return $this->status;
}
/**
* Get the Closure function.
* @return Closure
*/
function getCallback()
{
return $this->callback;
}
/**
* Add a validation rule.
* The rules are verified in the order in which they have been added.
*
* @param Rule $rule
* @return Rule
*/
public function addRule($rule = null)
{
if (!$rule instanceof Rule) {
$rule = new Rule();
}
$this->rules[] = $rule;
return $rule;
}
/**
* Process all added validation rules.
* @return Validator
*/
public function validate()
{
$this->message = "";
$this->status = 0;
$this->fails = false;
foreach ($this->rules as $rule) {
$callback = $rule->getCallback();
if (is_callable($callback)) {
if ($callback($rule->getData())) {
$this->message = $rule->getMessage();
$this->status = $rule->getStatus();
$this->fails = true;
$getCallbackLog = $rule->getCallbackLog();
if (is_callable($getCallbackLog)) {
$getCallbackLog($rule);
}
break;
}
}
}
$callbackAfter = $this->getCallback();
if (is_callable($callbackAfter)) {
$callbackAfter($this);
}
return $this;
}
/**
* Get the current status of the validation, the value is true if there was a
* failure and false if all the validation rules have been passed.
* @return boolean
*/
public function fails()
{
return $this->fails;
}
/**
* The Closure function is called when the validation process is finished.
* @param Closure $callback
* @return Validator
*/
public function after($callback)
{
if (is_callable($callback)) {
$this->callback = $callback;
}
return $this;
}
}

View File

@@ -283,7 +283,10 @@ Ext.onReady(function () {
}
else {
var messageError = "";
if (obj.failed == "1") {
if (obj.failed === true) {
messageError = obj.message;
}
else if (obj.failed == "1") {
//| 1-> Fail in the type of the image
messageError = _('ID_ERROR_UPLOADING_IMAGE_TYPE');
}

View File

@@ -6,6 +6,7 @@ use ProcessMaker\Core\AppEvent;
use ProcessMaker\ChangeLog\ChangeLog;
/*----------------------------------********---------------------------------*/
use ProcessMaker\Plugins\PluginRegistry;
use ProcessMaker\Validation\ValidationUploadedFiles;
/**
* bootstrap - ProcessMaker Bootstrap
@@ -818,7 +819,7 @@ if (substr(SYS_COLLECTION, 0, 8) === 'gulliver') {
$isWebEntry = \ProcessMaker\BusinessModel\WebEntry::isWebEntry(SYS_COLLECTION, $phpFile);
if (\Bootstrap::getDisablePhpUploadExecution() === 1 && !$isWebEntry) {
$message = \G::LoadTranslation('THE_PHP_FILES_EXECUTION_WAS_DISABLED');
$message = \G::LoadTranslation('ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED');
\Bootstrap::registerMonologPhpUploadExecution('phpExecution', 550, $message, $phpFile);
echo $message;
die();
@@ -1085,6 +1086,8 @@ if (!defined('EXECUTE_BY_CRON')) {
$oPluginRegistry->init();
if ($isControllerCall) { //Instance the Controller object and call the request method
ValidationUploadedFiles::getValidationUploadedFiles()
->runRulesToAllUploadedFiles();
$controller = new $controllerClass();
$controller->setHttpRequestData($_REQUEST);//NewRelic Snippet - By JHL
transactionLog($controllerAction);
@@ -1105,6 +1108,8 @@ if (!defined('EXECUTE_BY_CRON')) {
->setLanguage(SYS_LANG)
->getUsrIdByUsrUid(empty($_SESSION['USER_LOGGED']) ? '' : $_SESSION['USER_LOGGED']);
/*----------------------------------********---------------------------------*/
ValidationUploadedFiles::getValidationUploadedFiles()
->runRulesToAllUploadedFiles();
require_once $phpFile;
}