From dc79f8d26b6f3bbd618c914ffa6b7129d9767845 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 16:52:36 +0200 Subject: [PATCH 01/21] Code comment --- htdocs/core/ajax/extraparams.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/ajax/extraparams.php b/htdocs/core/ajax/extraparams.php index 7ef25e62b8b..e039529eef7 100644 --- a/htdocs/core/ajax/extraparams.php +++ b/htdocs/core/ajax/extraparams.php @@ -17,7 +17,7 @@ /** * \file /htdocs/core/ajax/extraparams.php - * \brief File to return Ajax response on set extra parameters of elements + * \brief File to make Ajax action on setting extra parameters of elements */ if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Disables token renewal From 89a5a8188fd5df83f1a55e095b4d241e79017393 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 17:12:03 +0200 Subject: [PATCH 02/21] Fix A file for a hidden feature provides a service without security checks. --- htdocs/core/ajax/objectonoff.php | 26 ++++++++++++++++++++++++-- htdocs/core/ajax/security.php | 2 +- htdocs/core/lib/ajax.lib.php | 5 +++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/htdocs/core/ajax/objectonoff.php b/htdocs/core/ajax/objectonoff.php index 6b06cccd50c..987a59ec3fb 100644 --- a/htdocs/core/ajax/objectonoff.php +++ b/htdocs/core/ajax/objectonoff.php @@ -15,8 +15,9 @@ */ /** - * \file htdocs/core/ajax/productonoff.php - * \brief File to set tosell and tobuy for product + * \file htdocs/core/ajax/objectonoff.php + * \brief File to set status for an object + * This Ajax service is called when option MAIN_DIRECT_STATUS_UPDATE is set. */ if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Disables token renewal @@ -36,6 +37,13 @@ $field=GETPOST('field', 'alpha'); $element=GETPOST('element', 'alpha'); $object = new GenericObject($db); + +// Security check +if (! empty($user->societe_id)) + $socid = $user->societe_id; + + + /* * View */ @@ -44,6 +52,20 @@ top_httphead(); print ''."\n"; +if ($element == 'societe' && in_array($field, array('status'))) +{ + $result = restrictedArea($user, 'societe', $id); +} +elseif ($element == 'product' && in_array($field, array('tosell', 'tobuy', 'tobatch'))) +{ + $result = restrictedArea($user, 'produit|service', $id, 'product&product', '', '', 'rowid'); +} +else +{ + accessforbidden("Bad value for combination of parameters element/field.", 0, 0, 1); + exit; +} + // Registering new values if (($action == 'set') && ! empty($id)) $object->setValueFrom($field, $value, $element, $id); diff --git a/htdocs/core/ajax/security.php b/htdocs/core/ajax/security.php index 9e7dea2ef95..faaddd31b23 100644 --- a/htdocs/core/ajax/security.php +++ b/htdocs/core/ajax/security.php @@ -17,7 +17,7 @@ /** * \file htdocs/core/ajax/security.php - * \brief This ajax component is used to generated has keys for security purposes + * \brief This ajax component is used to generated hash keys for security purposes * like key to use into URL to protect them. */ diff --git a/htdocs/core/lib/ajax.lib.php b/htdocs/core/lib/ajax.lib.php index a96e63a4f43..43f4723d695 100644 --- a/htdocs/core/lib/ajax.lib.php +++ b/htdocs/core/lib/ajax.lib.php @@ -538,11 +538,12 @@ function ajax_constantonoff($code, $input = array(), $entity = null, $revertonof } /** - * On/off button for object + * On/off button to change status of an object + * This is called when MAIN_DIRECT_STATUS_UPDATE is set and it use tha ajax service objectonoff.php * * @param Object $object Object to set * @param string $code Name of constant : status or status_buy for product by example - * @param string $field Name of database field : tosell or tobuy for product by example + * @param string $field Name of database field : 'tosell' or 'tobuy' for product by example * @param string $text_on Text if on * @param string $text_off Text if off * @param array $input Array of type->list of CSS element to switch. Example: array('disabled'=>array(0=>'cssid')) From b9ee95314ad89591be18b3aeff1615170615e2b7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 17:12:59 +0200 Subject: [PATCH 03/21] SEC restrictedArea protects also the 'update' action --- htdocs/core/lib/security.lib.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index 051f3a5392a..2ee5a45c010 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -279,7 +279,7 @@ function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $f // Check write permission from module (we need to know write permission to create but also to delete drafts record) $createok=1; $nbko=0; - if (GETPOST('action', 'aZ09') == 'create' || ((GETPOST("action", "aZ09") == 'confirm_delete' && GETPOST("confirm", "aZ09") == 'yes') || GETPOST("action", "aZ09") == 'delete')) + if (GETPOST('action', 'aZ09') == 'create' || GETPOST('action', 'aZ09') == 'update' || ((GETPOST("action", "aZ09") == 'confirm_delete' && GETPOST("confirm", "aZ09") == 'yes') || GETPOST("action", "aZ09") == 'delete')) { foreach ($featuresarray as $feature) { @@ -329,7 +329,7 @@ function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $f // If a or and at least one ok if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) $createok=1; - if (GETPOST('action', 'aZ09') == 'create' && ! $createok) accessforbidden(); + if ((GETPOST('action', 'aZ09') == 'create' || GETPOST('action', 'aZ09') == 'update') && ! $createok) accessforbidden(); //print "Write access is ok"; } From 4fb8f6663a74b9d6268199e4ce0ed543986fd67a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 17:16:13 +0200 Subject: [PATCH 04/21] Fix code comment --- htdocs/core/class/fileupload.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/fileupload.class.php b/htdocs/core/class/fileupload.class.php index ee090fed65d..2f0ae34b529 100644 --- a/htdocs/core/class/fileupload.class.php +++ b/htdocs/core/class/fileupload.class.php @@ -17,7 +17,7 @@ */ /** - * \file htdocs/core/ajax/fileupload.php + * \file htdocs/core/ajax/fileupload.class.php * \brief File to return Ajax response on file upload */ From 55e8aca47ec955ab18ed57e2716e2053df23021e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 19:06:40 +0200 Subject: [PATCH 05/21] Fix skeleton of module --- htdocs/modulebuilder/template/class/myobject.class.php | 2 +- htdocs/modulebuilder/template/myobject_list.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/modulebuilder/template/class/myobject.class.php b/htdocs/modulebuilder/template/class/myobject.class.php index f6020882502..3c68b0472e2 100644 --- a/htdocs/modulebuilder/template/class/myobject.class.php +++ b/htdocs/modulebuilder/template/class/myobject.class.php @@ -60,7 +60,7 @@ class MyObject extends CommonObject const STATUS_DRAFT = 0; const STATUS_VALIDATED = 1; - const STATUS_DISABLED = 9; + const STATUS_CANCELED = 9; /** diff --git a/htdocs/modulebuilder/template/myobject_list.php b/htdocs/modulebuilder/template/myobject_list.php index 5e6388d55f9..25279be4f03 100644 --- a/htdocs/modulebuilder/template/myobject_list.php +++ b/htdocs/modulebuilder/template/myobject_list.php @@ -493,7 +493,7 @@ while ($i < min($num, $limit)) if (in_array($val['type'], array('timestamp'))) $cssforfield.=($cssforfield?' ':'').'nowrap'; elseif ($key == 'ref') $cssforfield.=($cssforfield?' ':'').'nowrap'; - if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price'))) $cssforfield.=($cssforfield?' ':'').'right'; + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $key != 'status') $cssforfield.=($cssforfield?' ':'').'right'; if (! empty($arrayfields['t.'.$key]['checked'])) { From 76b7aa2e0fe954bd01bc7cdcbe711bc05cd72c84 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 19:20:19 +0200 Subject: [PATCH 06/21] Fix fields with visible = 3 must not be visible into list --- htdocs/modulebuilder/template/myobject_list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/modulebuilder/template/myobject_list.php b/htdocs/modulebuilder/template/myobject_list.php index 25279be4f03..11fafd59ab5 100644 --- a/htdocs/modulebuilder/template/myobject_list.php +++ b/htdocs/modulebuilder/template/myobject_list.php @@ -135,7 +135,7 @@ $arrayfields=array(); foreach($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field - if (! empty($val['visible'])) $arrayfields['t.'.$key]=array('label'=>$val['label'], 'checked'=>(($val['visible']<0)?0:1), 'enabled'=>$val['enabled'], 'position'=>$val['position']); + if (! empty($val['visible'])) $arrayfields['t.'.$key]=array('label'=>$val['label'], 'checked'=>(($val['visible']<0)?0:1), 'enabled'=>($val['enabled'] && ($val['visible'] != 3)), 'position'=>$val['position']); } // Extra fields if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) From 5ee9a88181094c2d4cc4f5eadf05a214a3abec31 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 19:21:25 +0200 Subject: [PATCH 07/21] NEW Add anonymous telemetry --- htdocs/core/ajax/pingresult.php | 72 +++++++++++++++++++++++++++++++++ htdocs/main.inc.php | 49 ++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 htdocs/core/ajax/pingresult.php diff --git a/htdocs/core/ajax/pingresult.php b/htdocs/core/ajax/pingresult.php new file mode 100644 index 00000000000..9b46546f5c3 --- /dev/null +++ b/htdocs/core/ajax/pingresult.php @@ -0,0 +1,72 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/core/ajax/pingresult.php + * \brief File to save result of anonymous ping + * Example: captureserver/public/index.php?action=dolibarrping + */ + +if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Disables token renewal +if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); +if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); +if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); +if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); +if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; + +$action=GETPOST('action', 'alpha'); +$hash_unique_id=GETPOST('hash_unique_id', 'alpha'); +$hash_algo=GETPOST('hash', 'alpha'); + + +// Security check +if (! empty($user->societe_id)) + $socid = $user->societe_id; + +$now = dol_now(); + + +/* + * View + */ + +top_httphead(); + +print ''."\n"; + +// If ok +if ($action == 'firstpingok') +{ + // Note: pings are by entities + dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_DATE', dol_print_date($now, 'dayhourlog', 'gmt')); + dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_ID', $hash_unique_id); + + print 'First ping OK saved for entity '.$conf->entity; +} +// If ko +elseif ($action == 'firstpingko') +{ + // Note: pings are by entities + dolibarr_set_const($db, 'MAIN_LAST_PING_KO_DATE', dol_print_date($now, 'dayhourlog'), 'gmt'); + print 'First ping KO saved for entity '.$conf->entity; +} +else { + print 'Error action='.$action.' not supported'; +} diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index bf4c40a4176..96ddd9696a7 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1124,6 +1124,7 @@ function top_httphead($contenttype = 'text/html', $forcenocache = 0) if ($contenttype == 'text/html' ) header("Content-Type: text/html; charset=".$conf->file->character_set_client); else header("Content-Type: ".$contenttype); + // Security options header("X-Content-Type-Options: nosniff"); // With the nosniff option, if the server says the content is text/html, the browser will render it as text/html (note that most browsers now force this option to on) if (! defined('XFRAMEOPTIONS_ALLOWALL')) header("X-Frame-Options: SAMEORIGIN"); // Frames allowed only if on same domain (stop some XSS attacks) @@ -2319,6 +2320,54 @@ if (! function_exists("llxFooter")) print "\n\n"; print ''."\n"; + // Add code for the fist asynchronous anonymous ping + if (($_SERVER["PHP_SELF"] == DOL_URL_ROOT.'/index.php') || GETPOST('forceping', 'alpha')) + { + if (empty($conf->global->MAIN_FIRST_PING_OK_DATE) + || (! empty($conf->file->instance_unique_id) && $conf->file->instance_unique_id != $conf->global->MAIN_FIRST_PING_OK_ID) + || GETPOST('forceping', 'alpha')) + { + print "\n".''."\n"; + print "\n\n"; + ?> + + \n"; print "\n"; From c34739ab3fb6c84b8f0d569f30e20e984e3b173c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 17:12:03 +0200 Subject: [PATCH 08/21] Fix A file for a hidden feature provides a service without security checks. --- htdocs/core/ajax/objectonoff.php | 26 ++++++++++++++++++++++++-- htdocs/core/ajax/security.php | 2 +- htdocs/core/lib/ajax.lib.php | 5 +++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/htdocs/core/ajax/objectonoff.php b/htdocs/core/ajax/objectonoff.php index 6b06cccd50c..987a59ec3fb 100644 --- a/htdocs/core/ajax/objectonoff.php +++ b/htdocs/core/ajax/objectonoff.php @@ -15,8 +15,9 @@ */ /** - * \file htdocs/core/ajax/productonoff.php - * \brief File to set tosell and tobuy for product + * \file htdocs/core/ajax/objectonoff.php + * \brief File to set status for an object + * This Ajax service is called when option MAIN_DIRECT_STATUS_UPDATE is set. */ if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Disables token renewal @@ -36,6 +37,13 @@ $field=GETPOST('field', 'alpha'); $element=GETPOST('element', 'alpha'); $object = new GenericObject($db); + +// Security check +if (! empty($user->societe_id)) + $socid = $user->societe_id; + + + /* * View */ @@ -44,6 +52,20 @@ top_httphead(); print ''."\n"; +if ($element == 'societe' && in_array($field, array('status'))) +{ + $result = restrictedArea($user, 'societe', $id); +} +elseif ($element == 'product' && in_array($field, array('tosell', 'tobuy', 'tobatch'))) +{ + $result = restrictedArea($user, 'produit|service', $id, 'product&product', '', '', 'rowid'); +} +else +{ + accessforbidden("Bad value for combination of parameters element/field.", 0, 0, 1); + exit; +} + // Registering new values if (($action == 'set') && ! empty($id)) $object->setValueFrom($field, $value, $element, $id); diff --git a/htdocs/core/ajax/security.php b/htdocs/core/ajax/security.php index 9e7dea2ef95..faaddd31b23 100644 --- a/htdocs/core/ajax/security.php +++ b/htdocs/core/ajax/security.php @@ -17,7 +17,7 @@ /** * \file htdocs/core/ajax/security.php - * \brief This ajax component is used to generated has keys for security purposes + * \brief This ajax component is used to generated hash keys for security purposes * like key to use into URL to protect them. */ diff --git a/htdocs/core/lib/ajax.lib.php b/htdocs/core/lib/ajax.lib.php index a96e63a4f43..43f4723d695 100644 --- a/htdocs/core/lib/ajax.lib.php +++ b/htdocs/core/lib/ajax.lib.php @@ -538,11 +538,12 @@ function ajax_constantonoff($code, $input = array(), $entity = null, $revertonof } /** - * On/off button for object + * On/off button to change status of an object + * This is called when MAIN_DIRECT_STATUS_UPDATE is set and it use tha ajax service objectonoff.php * * @param Object $object Object to set * @param string $code Name of constant : status or status_buy for product by example - * @param string $field Name of database field : tosell or tobuy for product by example + * @param string $field Name of database field : 'tosell' or 'tobuy' for product by example * @param string $text_on Text if on * @param string $text_off Text if off * @param array $input Array of type->list of CSS element to switch. Example: array('disabled'=>array(0=>'cssid')) From 55e9335cd2a9814b8d5462fe8546252918ebde34 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 17:16:13 +0200 Subject: [PATCH 09/21] Fix code comment --- htdocs/core/class/fileupload.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/fileupload.class.php b/htdocs/core/class/fileupload.class.php index bd36dba199b..40dd4783a60 100644 --- a/htdocs/core/class/fileupload.class.php +++ b/htdocs/core/class/fileupload.class.php @@ -17,7 +17,7 @@ */ /** - * \file htdocs/core/ajax/fileupload.php + * \file htdocs/core/ajax/fileupload.class.php * \brief File to return Ajax response on file upload */ From a6fdec5713e8f06f3b72dca0fe15e997eee4915b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 2 Aug 2019 20:11:55 +0200 Subject: [PATCH 10/21] Fix ping --- htdocs/main.inc.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 96ddd9696a7..ff599f7567f 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -2320,15 +2320,15 @@ if (! function_exists("llxFooter")) print "\n\n"; print ''."\n"; - // Add code for the fist asynchronous anonymous ping + // Add code for the asynchronous anonymous first ping (for telemetry) if (($_SERVER["PHP_SELF"] == DOL_URL_ROOT.'/index.php') || GETPOST('forceping', 'alpha')) { if (empty($conf->global->MAIN_FIRST_PING_OK_DATE) - || (! empty($conf->file->instance_unique_id) && $conf->file->instance_unique_id != $conf->global->MAIN_FIRST_PING_OK_ID) + || (! empty($conf->file->instance_unique_id) && (md5($conf->file->instance_unique_id) != $conf->global->MAIN_FIRST_PING_OK_ID)) || GETPOST('forceping', 'alpha')) { - print "\n".''."\n"; - print "\n\n"; + print "\n".''."\n"; + print "\n\n"; ?>