id = 1;
diff --git a/lib/API/JsonApi/v1/Resource/SuiteBeanResource.php b/lib/API/JsonApi/v1/Resource/SuiteBeanResource.php
index 1ab79698fbc..7252625cdf7 100644
--- a/lib/API/JsonApi/v1/Resource/SuiteBeanResource.php
+++ b/lib/API/JsonApi/v1/Resource/SuiteBeanResource.php
@@ -115,6 +115,13 @@ public function fromSugarBean($sugarBean, $source = ResourceEnum::DEFAULT_SOURCE
throw $exception;
}
+ $isSensitive = isTrue($definition['sensitive'] ?? false);
+ $notApiVisible = isFalse($definition['api-visible'] ?? true);
+
+ if ($isSensitive || $notApiVisible){
+ continue;
+ }
+
if ($definition['type'] === 'datetime' && isset($sugarBean->$fieldName)) {
// Convert to DB date
$datetime = $dateTimeConverter->fromUser($sugarBean->$fieldName);
diff --git a/modules/AOS_Products/AOS_Products.php b/modules/AOS_Products/AOS_Products.php
index 54e276ce135..07ee4080d03 100755
--- a/modules/AOS_Products/AOS_Products.php
+++ b/modules/AOS_Products/AOS_Products.php
@@ -64,6 +64,12 @@ public function save($check_notify = false)
require_once('include/upload_file.php');
$GLOBALS['log']->debug('UPLOADING PRODUCT IMAGE');
+ $imageFileName = $_FILES['uploadimage']['name'] ?? '';
+ if (!has_valid_image_extension('AOS_Products Uploaded image file: ' . $imageFileName , $imageFileName)) {
+ LoggerManager::getLogger()->fatal("AOS_Products save - Invalid image file ext : '$imageFileName'.");
+ throw new RuntimeException('Invalid request');
+ }
+
if (!empty($_FILES['uploadimage']['tmp_name']) && verify_uploaded_image($_FILES['uploadimage']['tmp_name'])) {
if ($_FILES['uploadimage']['size'] > $sugar_config['upload_maxsize']) {
die($mod_strings['LBL_IMAGE_UPLOAD_FAIL'] . $sugar_config['upload_maxsize']);
diff --git a/modules/Administration/UpgradeWizard.php b/modules/Administration/UpgradeWizard.php
index 4229efb46ff..a6e138a0226 100755
--- a/modules/Administration/UpgradeWizard.php
+++ b/modules/Administration/UpgradeWizard.php
@@ -106,9 +106,15 @@ function unlinkTempFiles()
$perform = true;
$base_filename = urldecode($tempFile);
} elseif (!empty($_REQUEST['load_module_from_dir'])) {
- $moduleDir = $_REQUEST['load_module_from_dir'];
- if (strpos($moduleDir, 'phar://') !== false) {
- die();
+ $moduleDir = $_REQUEST['load_module_from_dir'] ?? '';
+ if (stripos($moduleDir, 'phar://') !== false) {
+ LoggerManager::getLogger()->fatal("UpgradeWizard - invalid load_module_from_dir: " . $moduleDir);
+ throw new RuntimeException('Invalid request');
+ }
+
+ if (strtolower(pathinfo(urldecode($_REQUEST['upgrade_zip_escaped'] ?? ''), PATHINFO_EXTENSION)) !== 'zip'){
+ LoggerManager::getLogger()->fatal("UpgradeWizard - invalid upgrade_zip_escaped: " . $_REQUEST['upgrade_zip_escaped'] ?? '');
+ throw new RuntimeException("Invalid request");
}
//copy file to proper location then call performSetup
copy($moduleDir . '/' . $_REQUEST['upgrade_zip_escaped'], "upload://" . $_REQUEST['upgrade_zip_escaped']);
diff --git a/modules/Campaigns/WebToPersonCapture.php b/modules/Campaigns/WebToPersonCapture.php
index 2014ca2d179..e73e50a0616 100644
--- a/modules/Campaigns/WebToPersonCapture.php
+++ b/modules/Campaigns/WebToPersonCapture.php
@@ -54,6 +54,11 @@
die('Not a valid module directory');
}
+if (!isValidWebToPersonModule($moduleDir)) {
+ LoggerManager::getLogger()->fatal('Trying to run WepToPersonCapture for invalid module: ' . $moduleDir);
+ throw new RuntimeException('Not a valid module');
+}
+
global $app_strings, $sugar_config, $timedate, $current_user;
$mod_strings = return_module_language($sugar_config['default_language'], $moduleDir);
@@ -120,7 +125,7 @@
//As form base items are not necessarily in place for the custom classes that extend Person, cannot use
//the hendleSave method of the formbase
-
+
$optInEmailFields = array();
$optInPrefix = 'opt_in_';
@@ -209,8 +214,8 @@
$sea->AddUpdateEmailAddress($person->email2, 0, 1);
}
}
-
-
+
+
if (!empty($optInEmailFields)) {
// Look for opted out
$optedOut = array();
@@ -342,7 +347,7 @@
$log = LoggerManager::getLogger();
$log->error('Success but some error occurred: ' . implode(', ', $errors));
}
-
+
//If the custom module does not have a LBL_THANKS_FOR_SUBMITTING label, default to this general one
echo $app_strings['LBL_THANKS_FOR_SUBMITTING'];
}
diff --git a/modules/Campaigns/utils.php b/modules/Campaigns/utils.php
index ca66c5ebeb8..a2c7687fc04 100755
--- a/modules/Campaigns/utils.php
+++ b/modules/Campaigns/utils.php
@@ -54,7 +54,7 @@
*name and list of all prospects associated with this campaign..
*
*/
-function get_message_scope_dom($campaign_id, $campaign_name, $db=null, $mod_strings=array())
+function get_message_scope_dom($campaign_id, $campaign_name, $db = null, $mod_strings = array())
{
if (empty($db)) {
$db = DBManagerFactory::getInstance();
@@ -65,7 +65,7 @@ function get_message_scope_dom($campaign_id, $campaign_name, $db=null, $mod_stri
}
//find prospect list attached to this campaign..
- $query = "SELECT prospect_list_id, prospect_lists.name ";
+ $query = "SELECT prospect_list_id, prospect_lists.name ";
$query .= "FROM prospect_list_campaigns ";
$query .= "INNER join prospect_lists on prospect_lists.id = prospect_list_campaigns.prospect_list_id ";
$query .= "WHERE prospect_lists.deleted = 0 ";
@@ -297,7 +297,7 @@ function log_campaign_activity($identifier, $activity, $update = true, $clicked_
//values for return array..
$return_array['target_id'] = $row['target_id'];
$return_array['target_type'] = $row['target_type'];
-
+
// quote variable first
$dataArrayKeys = array_keys($data);
$dataArrayKeysQuoted = array();
@@ -305,13 +305,13 @@ function log_campaign_activity($identifier, $activity, $update = true, $clicked_
$dataArrayKeysQuoted[] = $db->quote($dataArrayKey);
}
$dataArrayKeysQuotedImplode = implode(', ', $dataArrayKeysQuoted);
-
+
$insert_query = "INSERT into campaign_log (" . $dataArrayKeysQuotedImplode . ")";
-
+
$dataArrayValuesQuotedImplode = implode(', ', array_values($data));
-
+
$insert_query .= " VALUES (" . $dataArrayValuesQuotedImplode . ")";
-
+
$db->query($insert_query);
}
} else {
@@ -331,7 +331,7 @@ function log_campaign_activity($identifier, $activity, $update = true, $clicked_
$rowCampaignIdQuoted = $db->quote($row['campaign_id']);
$query = "SELECT campaigns.* FROM campaigns WHERE campaigns.id = '" . $rowCampaignIdQuoted . "' ";
$result = $db->query($query);
-
+
if (!empty($result)) {
$c_row = $db->fetchByAssoc($result);
@@ -1160,3 +1160,33 @@ function filterFieldsFromBeans($beans)
}
return $formattedBeans;
}
+
+/**
+ * Get valid web to person modules
+ * @return array
+ */
+function getValidWebToPersonModules(): array
+{
+ $superclass = 'Person';
+ $modules = [];
+ foreach ($GLOBALS['moduleList'] as $mod) {
+ $item = BeanFactory::getBean($mod);
+ if ($item && is_subclass_of($item, $superclass)) {
+ $modules[] = $item->module_name;
+ }
+ }
+
+ return $modules;
+}
+
+/**
+ * Check if it is a valid WebToPerson module
+ * @param string $module
+ * @return bool
+ */
+function isValidWebToPersonModule(string $module): bool
+{
+ $validModules = getValidWebToPersonModules();
+
+ return in_array($module, $validModules, true);
+}
diff --git a/modules/Contacts/ContactFormBase.php b/modules/Contacts/ContactFormBase.php
index 11ecbe0d96a..b9dffc451bd 100755
--- a/modules/Contacts/ContactFormBase.php
+++ b/modules/Contacts/ContactFormBase.php
@@ -73,15 +73,21 @@ public function getDuplicateQuery($focus, $prefix='')
// Bug #46427 : Records from other Teams shown on Potential Duplicate Contacts screen during Lead Conversion
// add team security
+ $dbManager = DBManagerFactory::getInstance();
+
$query .= ' where contacts.deleted = 0 AND ';
if (isset($_POST[$prefix.'first_name']) && strlen($_POST[$prefix.'first_name']) != 0 && isset($_POST[$prefix.'last_name']) && strlen($_POST[$prefix.'last_name']) != 0) {
- $query .= " contacts.first_name LIKE '". $_POST[$prefix.'first_name'] . "%' AND contacts.last_name = '". $_POST[$prefix.'last_name'] ."'";
+ $firstName = $dbManager->quote($_POST[$prefix.'first_name' ?? '']);
+ $lastName = $dbManager->quote($_POST[$prefix.'last_name' ?? '']);
+ $query .= " contacts.first_name LIKE '". $firstName . "%' AND contacts.last_name = '". $lastName ."'";
} else {
- $query .= " contacts.last_name = '". $_POST[$prefix.'last_name'] ."'";
+ $lastName = $dbManager->quote($_POST[$prefix.'last_name' ?? '']);
+ $query .= " contacts.last_name = '". $lastName ."'";
}
if (!empty($_POST[$prefix.'record'])) {
- $query .= " AND contacts.id != '". $_POST[$prefix.'record'] ."'";
+ $record = $dbManager->quote($_POST[$prefix.'record' ?? '']);
+ $query .= " AND contacts.id != '". $record ."'";
}
return $query;
}
diff --git a/modules/EmailTemplates/AttachFiles.php b/modules/EmailTemplates/AttachFiles.php
index d725cee178c..fdd09762919 100755
--- a/modules/EmailTemplates/AttachFiles.php
+++ b/modules/EmailTemplates/AttachFiles.php
@@ -61,6 +61,13 @@
foreach ($_FILES as $k => $file) {
if (in_array(strtolower($_FILES[$k]['type']), $imgType) && $_FILES[$k]['size'] > 0) {
+ $fileName = $_FILES[$k]['name'] ?? '';
+
+ if (!has_valid_image_extension('Attach Files Uploaded file: ' . $fileName , $fileName)) {
+ LoggerManager::getLogger()->fatal("EmailTemplates AttachFiles - Invalid file ext : '$fileName'.");
+ throw new RuntimeException('Invalid request');
+ }
+
$upload_file = new UploadFile($k);
// check the file
if ($upload_file->confirm_upload()) {
diff --git a/modules/Emails/include/ComposeView/ComposeView.tpl b/modules/Emails/include/ComposeView/ComposeView.tpl
index d38319acfd9..87808e14a8d 100644
--- a/modules/Emails/include/ComposeView/ComposeView.tpl
+++ b/modules/Emails/include/ComposeView/ComposeView.tpl
@@ -256,8 +256,8 @@
$(document).ready(function() {ldelim}
$('#ComposeView').EmailsComposeView({if $RETURN_MODULE != 'Emails' && $RETURN_ID}{ldelim}
'attachment': {ldelim}
- 'module': '{$RETURN_MODULE}',
- 'id': '{$RETURN_ID}'
+ 'module': '{$RETURN_MODULE|escape:'javascript'}',
+ 'id': '{$RETURN_ID|escape:'javascript'}'
{rdelim}
{rdelim}{/if});
{rdelim});
diff --git a/modules/Employees/Employee.php b/modules/Employees/Employee.php
index 214a12ba5b2..80bb010e040 100755
--- a/modules/Employees/Employee.php
+++ b/modules/Employees/Employee.php
@@ -318,6 +318,9 @@ public function save($check_notify = false)
throw new RuntimeException('Not authorized');
}
+ // If the current user is not an admin, reset the admin flag to the original value.
+ $this->setIsAdmin();
+
return parent::save($check_notify);
}
@@ -341,4 +344,36 @@ protected function hasSaveAccess(): bool
return $sameUser || is_admin($current_user);
}
+
+ /**
+ * Reset is_admin if current user is not an admin user
+ * @return void
+ */
+ protected function setIsAdmin(): void
+ {
+ global $current_user;
+
+ if (!isset($this->is_admin)) {
+ return;
+ }
+
+ $originalIsAdminValue = $this->is_admin ?? false;
+ if ($this->isUpdate() && isset($this->fetched_row['is_admin'])) {
+ $originalIsAdminValue = isTrue($this->fetched_row['is_admin'] ?? false);
+ }
+
+ $currentUserReloaded = BeanFactory::getReloadedBean('Users', $current_user->id);
+ if (!is_admin($currentUserReloaded)) {
+ $this->is_admin = $originalIsAdminValue;
+ }
+
+ }
+
+ /**
+ * @return bool
+ */
+ protected function isUpdate(): bool
+ {
+ return !empty($this->id) && !$this->new_with_id;
+ }
}
diff --git a/modules/Leads/LeadFormBase.php b/modules/Leads/LeadFormBase.php
index 52c96ba7bd2..dffdb2c9799 100755
--- a/modules/Leads/LeadFormBase.php
+++ b/modules/Leads/LeadFormBase.php
@@ -67,11 +67,15 @@ public function getDuplicateQuery($focus, $prefix='')
$query .= " WHERE deleted != 1 AND (status <> 'Converted' OR status IS NULL) AND ";
+ $dbManager = DBManagerFactory::getInstance();
//Use the first and last name from the $_POST to filter. If only last name supplied use that
if (isset($_POST[$prefix.'first_name']) && strlen($_POST[$prefix.'first_name']) != 0 && isset($_POST[$prefix.'last_name']) && strlen($_POST[$prefix.'last_name']) != 0) {
- $query .= " (first_name='". $_POST[$prefix.'first_name'] . "' AND last_name = '". $_POST[$prefix.'last_name'] ."')";
+ $firstName = $dbManager->quote($_POST[$prefix.'first_name' ?? '']);
+ $lastName = $dbManager->quote($_POST[$prefix.'last_name' ?? '']);
+ $query .= " (first_name='". $firstName . "' AND last_name = '". $lastName ."')";
} else {
- $query .= " last_name = '". $_POST[$prefix.'last_name'] ."'";
+ $lastName = $dbManager->quote($_POST[$prefix.'last_name' ?? '']);
+ $query .= " last_name = '". $lastName ."'";
}
return $query;
}
diff --git a/modules/Prospects/ProspectFormBase.php b/modules/Prospects/ProspectFormBase.php
index bc0529e0263..204b56549e7 100755
--- a/modules/Prospects/ProspectFormBase.php
+++ b/modules/Prospects/ProspectFormBase.php
@@ -55,36 +55,44 @@ public function checkForDuplicates($prefix)
{
global $local_log;
require_once('include/formbase.php');
-
+
$focus = BeanFactory::newBean('Prospects');
if (!checkRequired($prefix, array_keys($focus->required_fields))) {
return null;
}
+
+ $dbManager = DBManagerFactory::getInstance();
+
$query = '';
$baseQuery = 'select id,first_name, last_name, title, email1, email2 from prospects where deleted!=1 and (';
if (!empty($_POST[$prefix.'first_name']) && !empty($_POST[$prefix.'last_name'])) {
- $query = $baseQuery ." (first_name like '". $_POST[$prefix.'first_name'] . "%' and last_name = '". $_POST[$prefix.'last_name'] ."')";
+ $firstName = $dbManager->quote($_POST[$prefix.'first_name' ?? '']);
+ $lastName = $dbManager->quote($_POST[$prefix.'last_name' ?? '']);
+ $query = $baseQuery ." (first_name like '". $firstName . "%' and last_name = '". $lastName ."')";
} else {
- $query = $baseQuery ." last_name = '". $_POST[$prefix.'last_name'] ."'";
+ $lastName = $dbManager->quote($_POST[$prefix.'last_name' ?? '']);
+ $query = $baseQuery ." last_name = '". $lastName ."'";
}
if (!empty($_POST[$prefix.'email1'])) {
+ $email1 = $dbManager->quote($_POST[$prefix.'email1' ?? '']);
if (empty($query)) {
- $query = $baseQuery. " email1='". $_POST[$prefix.'email1'] . "' or email2 = '". $_POST[$prefix.'email1'] ."'";
+ $query = $baseQuery. " email1='". $email1 . "' or email2 = '". $email1 ."'";
} else {
- $query .= "or email1='". $_POST[$prefix.'email1'] . "' or email2 = '". $_POST[$prefix.'email1'] ."'";
+ $query .= "or email1='". $email1 . "' or email2 = '". $email1 ."'";
}
}
if (!empty($_POST[$prefix.'email2'])) {
+ $email2 = $dbManager->quote($_POST[$prefix.'email2' ?? '']);
if (empty($query)) {
- $query = $baseQuery. " email1='". $_POST[$prefix.'email2'] . "' or email2 = '". $_POST[$prefix.'email2'] ."'";
+ $query = $baseQuery. " email1='". $email2 . "' or email2 = '". $email2 ."'";
} else {
- $query .= "or email1='". $_POST[$prefix.'email2'] . "' or email2 = '". $_POST[$prefix.'email2'] ."'";
+ $query .= "or email1='". $email2 . "' or email2 = '". $email2 ."'";
}
}
if (!empty($query)) {
$rows = array();
-
+
$db = DBManagerFactory::getInstance();
$result = $db->query($query.');');
while ($row = $db->fetchByAssoc($result)) {
@@ -138,7 +146,7 @@ public function buildTableForm($rows, $mod='')
if ($action != 'ShowDuplicates') {
$form .= "[${app_strings['LBL_SELECT_BUTTON_LABEL']}] | \n";
}
-
+
$wasSet = false;
foreach ($row as $key=>$value) {
@@ -172,7 +180,7 @@ public function getWideFormBody($prefix, $mod='', $formname='', $prospect = '')
if (!ACLController::checkAccess('Prospects', 'edit', true)) {
return '';
}
-
+
if (empty($prospect)) {
$prospect = BeanFactory::newBean('Prospects');
}
@@ -401,15 +409,15 @@ public function getForm($prefix, $mod='')
public function handleSave($prefix, $redirect=true, $useRequired=false)
{
global $theme;
-
-
-
-
+
+
+
+
require_once('include/formbase.php');
-
+
global $timedate;
-
-
+
+
$focus = BeanFactory::newBean('Prospects');
if ($useRequired && !checkRequired($prefix, array_keys($focus->required_fields))) {
return null;
@@ -421,14 +429,14 @@ public function handleSave($prefix, $redirect=true, $useRequired=false)
if (!isset($GLOBALS['check_notify'])) {
$GLOBALS['check_notify']=false;
}
-
+
if (!isset($_POST[$prefix.'email_opt_out'])) {
$focus->email_opt_out = 0;
}
if (!isset($_POST[$prefix.'do_not_call'])) {
$focus->do_not_call = 0;
}
-
+
if (empty($_POST['record']) && empty($_POST['dup_checked'])) {
/*
// we don't check dupes on Prospects - this is the dirtiest data in the system
@@ -479,7 +487,7 @@ public function handleSave($prefix, $redirect=true, $useRequired=false)
$focus->save($GLOBALS['check_notify']);
$return_id = $focus->id;
-
+
$GLOBALS['log']->debug("Saved record with id of ".$return_id);
if (isset($_POST['popup']) && $_POST['popup'] == 'true') {
$get = '&module=';
diff --git a/modules/Users/User.php b/modules/Users/User.php
index 6686cd90dde..085d7241551 100755
--- a/modules/Users/User.php
+++ b/modules/Users/User.php
@@ -612,7 +612,7 @@ public function save($check_notify = false)
$msg = '';
- $isUpdate = !empty($this->id) && !$this->new_with_id;
+ $isUpdate = $this->isUpdate();
//No SMTP server is set up Error.
$admin = BeanFactory::newBean('Administration');
@@ -664,17 +664,16 @@ public function save($check_notify = false)
// wp: do not save user_preferences in this table, see user_preferences module
$this->user_preferences = '';
+
+ // If the current user is not an admin, reset the admin flag to the original value.
+ $this->setIsAdmin();
+
// if this is an admin user, do not allow is_group or portal_only flag to be set.
if ($this->is_admin) {
$this->is_group = 0;
$this->portal_only = 0;
}
- // If the current user is not an admin, do not allow them to set the admin flag to true.
- if (!is_admin($current_user)) {
- $this->is_admin = 0;
- }
-
// set some default preferences when creating a new user
$setNewUserPreferences = empty($this->id) || !empty($this->new_with_id);
@@ -2467,4 +2466,36 @@ protected function hasSaveAccess(): bool
return $sameUser || is_admin($current_user);
}
+
+ /**
+ * Reset is_admin if current user is not an admin user
+ * @return void
+ */
+ protected function setIsAdmin(): void
+ {
+ global $current_user;
+ if (!isset($this->is_admin)) {
+ return;
+ }
+
+
+ $originalIsAdminValue = $this->is_admin ?? false;
+ if ($this->isUpdate() && isset($this->fetched_row['is_admin'])) {
+ $originalIsAdminValue = isTrue($this->fetched_row['is_admin'] ?? false);
+ }
+
+ $currentUserReloaded = BeanFactory::getReloadedBean('Users', $current_user->id);
+ if (!is_admin($currentUserReloaded)) {
+ $this->is_admin = $originalIsAdminValue;
+ }
+
+ }
+
+ /**
+ * @return bool
+ */
+ protected function isUpdate(): bool
+ {
+ return !empty($this->id) && !$this->new_with_id;
+ }
}
diff --git a/suitecrm_version.php b/suitecrm_version.php
index bcb93259c2f..0c1ebd04c3a 100755
--- a/suitecrm_version.php
+++ b/suitecrm_version.php
@@ -3,5 +3,5 @@
die('Not A Valid Entry Point');
}
-$suitecrm_version = '7.12.8';
-$suitecrm_timestamp = '2022-11-17 12:00:00';
+$suitecrm_version = '7.12.9';
+$suitecrm_timestamp = '2023-01-25 12:00:00';