diff --git a/ChangeLog b/ChangeLog index 1296c219d77..f1844fe5210 100644 --- a/ChangeLog +++ b/ChangeLog @@ -205,7 +205,7 @@ The following changes may create regressions for some external modules, but were * Because of the new TRIGGER_PREFIX property, the triggers SUPPLIER_PRODUCT_BUYPRICE_XXX are renamed into PRODUCT_BUYPRICE_XXX. * Function img_pdf() has been removed. Replace it with img_picto('', 'pdf') if you were using it. * The method run_trigger() was deprecated 10+ years ago in favor of runTrigger(). It has been removed. Change your trigger file if you still use it. -* Property ->picto of module descriptors must contains the image extension if it is not a font awesome tag. Example: $this->picto="mymoduleimg.png"; +* Property ->picto of module descriptors or menu entries must contains the image extension if it is not a font awesome tag. Example: $this->picto="mymoduleimg.png"; * Stock movement API GET method output variable names has been harmonized with POST input parameter names * Concatenation into computed property of extrafields is off by default. You can enable it from conf.php file by adding dol_concat to list of allowed function in $dolibarr_main_restrict_eval_methods, For example: $dolibarr_main_restrict_eval_methods='getDolGlobalString,getDolGlobalInt,getDolCurrency,fetchNoCompute,hasRight,isModEnabled,isStringVarMatching,abs,min,max,round,dol_now,dol_concat,preg_match'; diff --git a/htdocs/api/class/api_documents.class.php b/htdocs/api/class/api_documents.class.php index 785f000077e..657da88fab7 100644 --- a/htdocs/api/class/api_documents.class.php +++ b/htdocs/api/class/api_documents.class.php @@ -111,6 +111,23 @@ class Documents extends DolibarrApi throw new RestException(403); } + if (DolibarrApiAccess::$user->socid > 0) { + if ($sqlprotectagainstexternals) { + $resql = $this->db->query($sqlprotectagainstexternals); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + if (DolibarrApiAccess::$user->socid != $obj->fk_soc) { + throw new RestException(403, 'Not allowed to download documents with such a ref'); + } + $i++; + } + } + } + } + $filename = basename($original_file); $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset @@ -197,6 +214,23 @@ class Documents extends DolibarrApi throw new RestException(403); } + if (DolibarrApiAccess::$user->socid > 0) { + if ($sqlprotectagainstexternals) { + $resql = $this->db->query($sqlprotectagainstexternals); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + if (DolibarrApiAccess::$user->socid != $obj->fk_soc) { + throw new RestException(403, 'Not allowed to download documents with such a ref'); + } + $i++; + } + } + } + } + // --- Generates the document $hidedetails = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 0 : 1; $hidedesc = !getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 0 : 1; @@ -1283,6 +1317,23 @@ class Documents extends DolibarrApi throw new RestException(403); } + if (DolibarrApiAccess::$user->socid > 0) { + if ($sqlprotectagainstexternals) { + $resql = $this->db->query($sqlprotectagainstexternals); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + if (DolibarrApiAccess::$user->socid != $obj->fk_soc) { + throw new RestException(403, 'Not allowed to download documents with such a ref'); + } + $i++; + } + } + } + } + $filename = basename($original_file); $original_file_osencoded = dol_osencode($original_file); // New file name encoded in OS encoding charset diff --git a/htdocs/bookmarks/list.php b/htdocs/bookmarks/list.php index 36183573921..579cc7889a0 100644 --- a/htdocs/bookmarks/list.php +++ b/htdocs/bookmarks/list.php @@ -425,7 +425,6 @@ while ($i < $imaxinloop) { print img_picto('', 'url', 'class="pictofixedwidth"'); print 'target ? ' target="newlink" rel="noopener"' : '').'>'; } else { - //print img_picto('', 'rightarrow', 'class="pictofixedwidth"'); print ''; } print $link; diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 55bb431c3f6..bb1a95bae44 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -1712,12 +1712,12 @@ if ($action == 'create') { $description = $objp->description; if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { - print (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow') : '') . $text; + print (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow.png') : '') . $text; if (!getDolGlobalInt('PRODUIT_DESC_IN_FORM')) { print $form->textwithpicto('', $description); } } else { - print $form->textwithtooltip($text, $description, 3, 0, '', '', 0, (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow') : '')); + print $form->textwithtooltip($text, $description, 3, 0, '', '', 0, (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow.png') : '')); } // Add description in form @@ -2015,7 +2015,7 @@ if ($action == 'create') { $tmpactiontext = $langs->trans("Activate"); if ($objp->statut == 4) { $tmpaction = 'unactivateline'; - $tmpactionpicto = 'playstop'; + $tmpactionpicto = 'playstop.png'; $tmpactiontext = $langs->trans("Disable"); } if (($tmpaction == 'activateline' && $user->hasRight('contrat', 'activer')) || ($tmpaction == 'unactivateline' && $user->hasRight('contrat', 'desactiver'))) { diff --git a/htdocs/core/ajax/flowjs-server.php b/htdocs/core/ajax/flowjs-server.php index ac2c286364a..f10ff2115cb 100644 --- a/htdocs/core/ajax/flowjs-server.php +++ b/htdocs/core/ajax/flowjs-server.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2023-2026 Laurent Destailleur * Copyright (C) 2024 MDW * Copyright (C) 2024 Frédéric France * @@ -25,6 +25,7 @@ if (!defined('NOTOKENRENEWAL')) { define('NOTOKENRENEWAL', '1'); // Disables token renewal } +// If there is no need to load and show top and left menu if (!defined('NOREQUIREMENU')) { define('NOREQUIREMENU', '1'); } @@ -37,7 +38,6 @@ if (!defined('NOREQUIREAJAX')) { if (!defined('NOREQUIRESOC')) { define('NOREQUIRESOC', '1'); } -// If there is no need to load and show top and left menu if (!defined("NOLOGIN")) { define("NOLOGIN", '1'); } @@ -66,7 +66,11 @@ $flowChunkNumber = GETPOST('flowChunkNumber', 'alpha'); $flowChunkSize = GETPOST('flowChunkSize', 'alpha'); $flowTotalSize = GETPOST('flowTotalSize', 'alpha'); -$result = restrictedArea($user, $module, 0, '', '', 'fk_soc', 'rowid', 0, 1); // Call with mode return +$result = restrictedArea($user, ($module ? $module : 'unknown'), 0, '', '', 'fk_soc', 'rowid', 0, 1); // Call with mode return. Use 'unknown' if module not defined to be sure to have an error when module is not set + +if (!$result) { + httponly_accessforbidden("No permission on module ".$module); +} if ($action != 'upload') { httponly_accessforbidden("Param action must be 'upload'"); @@ -81,6 +85,7 @@ if (!empty($conf->$module->dir_temp)) { httponly_accessforbidden("Param module does not has a dir_temp directory. Module does not exists or is not activated."); } + /* * Action */ diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 4f78dddabfa..37f29adf645 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -5761,7 +5761,7 @@ abstract class CommonObject $this->tpl['label'] = ''; if (!empty($line->fk_parent_line)) { - $this->tpl['label'] .= img_picto('', 'rightarrow'); + $this->tpl['label'] .= img_picto('', 'rightarrow.png'); } if (((int) $line->info_bits & 2) == 2) { // TODO Not sure this is used for source object diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 1e5846ae9c9..8d47307676b 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -855,12 +855,6 @@ class Form $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt); } elseif ($type == 'helpclickable') { $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt); - } elseif ($type == 'superadmin') { - // @phan-suppress-next-line PhanPluginSuspiciousParamPosition - $img = img_picto($alt, 'redstar'); - } elseif ($type == 'admin') { - // @phan-suppress-next-line PhanPluginSuspiciousParamPosition - $img = img_picto($alt, 'star'); } elseif ($type == 'warning') { $img = img_warning($alt); } elseif ($type != 'none') { diff --git a/htdocs/core/customreports.php b/htdocs/core/customreports.php index 85b3f7e3349..ed51beba822 100644 --- a/htdocs/core/customreports.php +++ b/htdocs/core/customreports.php @@ -114,6 +114,9 @@ if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) { } } +// In customreport context, we force the protection to avoid forging of criteria including bind SQL injection +$conf->global->MAIN_DISALLOW_UNSECURED_SELECT_INTO_EXTRAFIELDS_FILTER = 1; + if (empty($mode)) { $mode = 'graph'; } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 86b8aecea88..55f1d82bab7 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -5937,6 +5937,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srco 'square' => '#888', 'stop-circle' => '#888', 'stats' => '#444', + 'superadmin' => '#600', 'switch_off' => '#999', 'technic' => '#999', 'tick' => '#282', @@ -6800,7 +6801,7 @@ function img_searchclear($titlealt = 'default', $other = '') $titlealt = $langs->trans('Search'); } - $img = img_picto($titlealt, 'searchclear', $other, 0, 1); + $img = img_picto($titlealt, 'searchclear.png', $other, 0, 1); $input = ''; diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index 457e7a6fdc2..2291df4273f 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -134,7 +134,7 @@ $coldisplay++; fk_parent_line > 0) { - echo img_picto('', 'rightarrow'); + echo img_picto('', 'rightarrow.png'); } ?> info_bits & 2) == 2) { if ($line->fk_product > 0) { if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { - print (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow') : '') . $text; + print (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow.png') : '') . $text; if (!getDolGlobalInt('PRODUIT_DESC_IN_FORM')) { print $form->textwithpicto('', $description); } } else { - print $form->textwithtooltip($text, $description, 3, 0, '', (string) $i, 0, (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow') : '')); + print $form->textwithtooltip($text, $description, 3, 0, '', (string) $i, 0, (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow.png') : '')); } } else { $type = (!empty($line->product_type) ? $line->product_type : $line->fk_product_type); @@ -206,7 +206,7 @@ if (($line->info_bits & 2) == 2) { print $form->textwithtooltip($text, dol_htmlentitiesbr($line->description), 3, 0, '', (string) $i, 0, (!empty($line->fk_parent_line) ? img_picto('', 'rightarrow') : '')); } else { if (!empty($line->fk_parent_line)) { - print img_picto('', 'rightarrow'); + print img_picto('', 'rightarrow.png'); } if (preg_match('/^\(DEPOSIT\)/', $line->description)) { $newdesc = preg_replace('/^\(DEPOSIT\)/', $langs->trans("Deposit"), $line->description); diff --git a/htdocs/document.php b/htdocs/document.php index 32f26290a42..2b4e0be1f65 100644 --- a/htdocs/document.php +++ b/htdocs/document.php @@ -33,7 +33,7 @@ * DOL_URL_ROOT.'/document.php?hashp=sharekey' */ -define('MAIN_SECURITY_FORCECSP', "default-src: 'none'"); +define('MAIN_SECURITY_FORCECSP', "default-src 'none'"); //if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Not disabled cause need to load personalized language //if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); // Not disabled cause need to load personalized language @@ -278,7 +278,7 @@ if (empty($modulepart)) { } // Check security and set return info with full path of file -$check_access = dol_check_secure_access_document($modulepart, $original_file, (int) $entity, $user, ''); +$check_access = dol_check_secure_access_document($modulepart, $original_file, (int) $entity, $user, '', 'read'); $accessallowed = $check_access['accessallowed']; $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals']; $fullpath_original_file = $check_access['original_file']; // $fullpath_original_file is now a full path name diff --git a/htdocs/langs/fr_FR/compta.lang b/htdocs/langs/fr_FR/compta.lang index e71ab61713f..14be1d55ccd 100644 --- a/htdocs/langs/fr_FR/compta.lang +++ b/htdocs/langs/fr_FR/compta.lang @@ -342,4 +342,4 @@ RuleForLinesDates=Règle pour les lignes dates Prepaid=Prépayé Postpaid=Port payé SetRuleForLinesDates=Définir une règle pour les dates des lignes -SomeNotConvertedCreditNoteExists=Il y a des avoirs %s non encore converties pour la consommation +SomeNotConvertedCreditNoteExists=Il y a %s avoir(s) non encore converti(s) pour consommation diff --git a/htdocs/salaries/payment_salary.php b/htdocs/salaries/payment_salary.php index 1ae19e8117f..eb31e83635f 100644 --- a/htdocs/salaries/payment_salary.php +++ b/htdocs/salaries/payment_salary.php @@ -294,7 +294,7 @@ if ($action == 'create') { $nameRemain = "remain_".$objp->id; /* Disabled, we autofil the amount with remain to pay by default if (!empty($conf->use_javascript_ajax)) { - print img_picto("Auto fill", 'rightarrow', "class='AutoFillAmount' data-rowid='".$namef."' data-value='".($objp->amount - $sumpaid)."'"); + print img_picto("Auto fill", 'rightarrow.png', "class='AutoFillAmount' data-rowid='".$namef."' data-value='".($objp->amount - $sumpaid)."'"); } */ $valuetoshow = GETPOSTISSET($namef) ? GETPOST($namef) : ((float) $objp->amount - $sumpaid); diff --git a/htdocs/takepos/index.php b/htdocs/takepos/index.php index 3a803b836bd..16f37fc8a62 100644 --- a/htdocs/takepos/index.php +++ b/htdocs/takepos/index.php @@ -1645,7 +1645,7 @@ if ($reshook == 0) { //add buttons print ''."\n"; print '
'; print ' '; - print ''.img_picto('', 'searchclear').''; + print ''.img_picto('', 'searchclear.png').''; print '
'; } ?> diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index 131ec5dc959..5f8005079bc 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -2069,7 +2069,7 @@ if ($placeid > 0) { } $htmlsupplements[$line->fk_parent_line] .= '>'; $htmlsupplements[$line->fk_parent_line] .= ''; - $htmlsupplements[$line->fk_parent_line] .= img_picto('', 'rightarrow'); + $htmlsupplements[$line->fk_parent_line] .= img_picto('', 'rightarrow.png'); if ($line->product_label) { $htmlsupplements[$line->fk_parent_line] .= $line->product_label; } diff --git a/htdocs/user/api_token/card.php b/htdocs/user/api_token/card.php index 11ade41bcfe..e2c6bb1f01c 100644 --- a/htdocs/user/api_token/card.php +++ b/htdocs/user/api_token/card.php @@ -303,9 +303,9 @@ if ($action == 'create') { print ''; $addadmin = ''; if (isModEnabled('multicompany') && !empty($object->admin) && empty($object->entity)) { - $addadmin .= img_picto($langs->trans("SuperAdministratorDesc"), "redstar", 'class="paddingleft valignmiddle"'); + $addadmin .= img_picto($langs->trans("SuperAdministratorDesc"), "superadmin", 'class="paddingleft valignmiddle"'); } elseif (!empty($object->admin)) { - $addadmin .= img_picto($langs->trans("AdministratorDesc"), "star", 'class="paddingleft valignmiddle"'); + $addadmin .= img_picto($langs->trans("AdministratorDesc"), "admin", 'class="paddingleft valignmiddle"'); } print showValueWithClipboardCPButton($object->login).$addadmin; print ''; diff --git a/htdocs/viewimage.php b/htdocs/viewimage.php index bfb453f8473..65c993c70c8 100644 --- a/htdocs/viewimage.php +++ b/htdocs/viewimage.php @@ -28,7 +28,7 @@ * DOL_URL_ROOT.'/viewimage.php?hashp=sharekey */ -define('MAIN_SECURITY_FORCECSP', "default-src: 'none'"); +define('MAIN_SECURITY_FORCECSP', "default-src 'none'"); //if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Not disabled cause need to load personalized language //if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); // Not disabled cause need to load personalized language diff --git a/htdocs/webportal/controllers/document.controller.class.php b/htdocs/webportal/controllers/document.controller.class.php index 310cecc18a8..aca2fbda8db 100644 --- a/htdocs/webportal/controllers/document.controller.class.php +++ b/htdocs/webportal/controllers/document.controller.class.php @@ -91,7 +91,7 @@ class DocumentController extends Controller { global $conf, $hookmanager; - define('MAIN_SECURITY_FORCECSP', "default-src: 'none'"); + define('MAIN_SECURITY_FORCECSP', "default-src 'none'"); if (!defined('NOTOKENRENEWAL')) { define('NOTOKENRENEWAL', '1'); diff --git a/htdocs/webportal/controllers/viewimage.controller.class.php b/htdocs/webportal/controllers/viewimage.controller.class.php index 6c82bb55496..4556009cd5a 100644 --- a/htdocs/webportal/controllers/viewimage.controller.class.php +++ b/htdocs/webportal/controllers/viewimage.controller.class.php @@ -81,7 +81,7 @@ class ViewImageController extends Controller { global $conf, $hookmanager, $dolibarr_nocache, $user; - define('MAIN_SECURITY_FORCECSP', "default-src: 'none'"); + define('MAIN_SECURITY_FORCECSP', "default-src 'none'"); if (!defined('NOREQUIRESOC')) { define('NOREQUIRESOC', '1');