diff --git a/ChangeLog b/ChangeLog index cd9397939f5..2e8bfc968c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,50 @@ English Dolibarr ChangeLog -------------------------------------------------------------- +***** ChangeLog for 14.0.2 compared to 14.0.1 ***** + +FIX: #18353 Invoice list translation issue +FIX: #18375 SQL Error on tasks statistics +FIX: #18465 +FIX: #18484 +FIX: #18531 +FIX: #18542 REST API: set global $user variable to DolibarrApiAccess::user. +FIX: #18544 Shipment REST API: load thirdparty object into the shipment before validating. +FIX: #18544 Shipment rest api: load thirdparty object when validating +FIX: #18565 +FIX: #18589 #18617 +FIX: #18591 : Remove double quotes of SQL Queries for postgresql compatibility +FIX: #18666 Order / Shipment list: Don't SQL JOIN category table when not necessary. +FIX: Accountancy - Some problems of length with general & subledger account +FIX: add DISTINCT +FIX: Add option $noescapecommand in executeCLI for better compatibility +FIX: Add token to remove error when removing widget +FIX: Add token when remove the last widget on home page +FIX: an approved holiday can be canceled by an admin. +FIX: better sql request +FIX: change LOG_DEBUG with LOG_WARNING in syslog and remove sql error in syslog (already done) +FIX: Collapsing of extrafields has disappeared. +FIX: Date of payment of subscription must not be set to 1970-01-01. +FIX: Export of website generates a package that contains a sql error +FIX: Field already present in SQL request +FIX: increase maxlength of password input +FIX: invoice fetch not found syslog debug level instead of error +FIX: Invoice list - Wrong name for column total_tva +FIX: invoice validation: when checking if any vat rate has a negative amount, prevent false positives with -1E-14 amounts +FIX: Manage credit note on situation invoice for calculate margin +FIX: Menu List of project was not visible. +FIX: migration script +FIX: multicompany transverse mode compatibility +FIX: option "Default value for field 'Refuse bulk emailings'" +FIX: Recommended session.cookie_samesite must be 'Lax' not 'Strict'. +FIX: Relative discount with high nb of decimals +FIX: salary extrafields don't work and table is not well named +FIX: Supplier invoice list - Wrong language key used +FIX: wrong table_element_line +FIX: wrong users count in multicompany transverse mode +FIX: #yogosha6944 Protection against traversal path. + + ***** ChangeLog for 14.0.1 compared to 14.0.0 ***** FIX: $conf->task used but it does not exist, use $conf->projet instead diff --git a/build/generate_filelist_xml.php b/build/generate_filelist_xml.php index 8e7ef3ef46c..e5a39c0d0a8 100755 --- a/build/generate_filelist_xml.php +++ b/build/generate_filelist_xml.php @@ -239,7 +239,7 @@ fclose($fp); if (empty($buildzip)) { print "File ".$outputfile." generated\n"; } else { - $result = dol_compress_file($outputfile, $outputfile.'.zip'); + $result = dol_compress_file($outputfile, $outputfile.'.zip', 'zip'); if ($result > 0) { dol_delete_file($outputfile); print "File ".$outputfile.".zip generated\n"; diff --git a/dev/examples/ldap/ldapsearch_sample1.txt b/dev/examples/ldap/ldapsearch_sample1.txt index 5f667ffd7a4..a02ad632cd0 100644 --- a/dev/examples/ldap/ldapsearch_sample1.txt +++ b/dev/examples/ldap/ldapsearch_sample1.txt @@ -3,11 +3,26 @@ # # Use this sample to search into a ldap # -# ldapsearch -h hostname -x -# ldapsearch -h hostname -x -b "ou=people,dc=teclib,dc=infra" -# ldapsearch -h hostname -x -z 0 -b "o=somecompany.com" -D "cn=manager,o=somecompany.com" -w password "(objectclass=*)" -# ldapsearch -h hostname -x -b "o=somecompany.com" -D "cn=manager,o=somecompany.com" -w password "(objectclass=*)" + +# Anonymous access +# ldapsearch -h hostname -p 389 +# +# Login access (using a Bind DN) +# ldapsearch -h hostname -p 389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password +# ldapsearch -H ldap://hostname:389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password +# ldapsearch -d1 -H ldap://hostname:389 -x -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password +# ldapsearch -H ldap://hostname:389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password +# +# Login access in SSL (using a Bind DN) +# ldapsearch -H ldaps://hostnamme:636 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password -b "cn=users,dc=ldap,dc=test,dc=local +# If it fails, you may try to use "hostname" that is real name of certificate. +# You must also check that /etc/ldap/ldap.conf contains the line TLS_CACERT /etc/ssl/certs/ca-certificates.crt + +# What to search +# ldapsearch -h hostname -p 389 -x -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password -b "cn=users,dc=ldap,dc=test,dc=local" +# ldapsearch -h hostname -p 389 -x -D "cn=manager,o=somecompany.com" -w password -b "ou=people,dc=teclib,dc=infra" +# ldapsearch -h hostname -p 389 -x -D "cn=manager,o=somecompany.com" -w password -b "o=somecompany.com" "(objectclass=*)" # # Example to test a ldap search: -# ldapsearch -h hostname -x -z 5 -b 'OU=Collaborateurs,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -D 'CN=UserAdmin,OU=Informatique,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -w password +# ldapsearch -h hostname -p 389 -x -z 5 -b 'OU=Collaborateurs,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -D 'CN=UserAdmin,OU=Informatique,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -w password diff --git a/htdocs/adherents/admin/member.php b/htdocs/adherents/admin/member.php index 5a589756feb..018498c2457 100644 --- a/htdocs/adherents/admin/member.php +++ b/htdocs/adherents/admin/member.php @@ -25,7 +25,7 @@ */ /** - * \file htdocs/adherents/admin/adherent.php + * \file htdocs/adherents/admin/member.php * \ingroup member * \brief Page to setup the module Foundation */ diff --git a/htdocs/admin/dolistore/class/dolistore.class.php b/htdocs/admin/dolistore/class/dolistore.class.php index bfcb751f9a9..5e7a229fee3 100644 --- a/htdocs/admin/dolistore/class/dolistore.class.php +++ b/htdocs/admin/dolistore/class/dolistore.class.php @@ -217,15 +217,15 @@ class Dolistore for ($i = 0; $i < $nbofcateg; $i++) { $cat = $this->categories[$i]; if ($cat->is_root_category == 1 && $parent == 0) { - $html .= '
  • description->language[$this->lang - 1])).'">'.$cat->name->language[$this->lang - 1].' '.$cat->nb_products_recursive.'

    '; + $html .= '
  • description->language[$this->lang - 1])).'">'.dol_escape_htmltag($cat->name->language[$this->lang - 1]).' '.dol_escape_htmltag($cat->nb_products_recursive).'

    '; $html .= self::get_categories($cat->id); $html .= "
  • \n"; } elseif (trim($cat->id_parent) == $parent && $cat->active == 1 && trim($cat->id_parent) != 0) { // si cat est de ce niveau $select = ($cat->id == $this->categorie) ? ' selected' : ''; - $html .= '
  • description->language[$this->lang - 1])).'" '; - $html .= '>'.$cat->name->language[$this->lang - 1].' '.$cat->nb_products_recursive.''; + $html .= '>'.dol_escape_htmltag($cat->name->language[$this->lang - 1]).' '.dol_escape_htmltag($cat->nb_products_recursive).''; $html .= self::get_categories($cat->id); $html .= "
  • \n"; } @@ -267,9 +267,9 @@ class Dolistore // add image or default ? if ($product->id_default_image != '') { - $image_url = DOL_URL_ROOT.'/admin/dolistore/ajax/image.php?id_product='.$product->id.'&id_image='.$product->id_default_image; - $images = ''; - $images .= ''; + $image_url = DOL_URL_ROOT.'/admin/dolistore/ajax/image.php?id_product='.((int) $product->id).'&id_image='.((int) $product->id_default_image); + $images = ''; + $images .= ''; } else { $images = ''; } @@ -277,11 +277,11 @@ class Dolistore // free or pay ? if ($product->price > 0) { $price = '

    '.price(price2num($product->price, 'MT'), 0, $langs, 1, -1, -1, 'EUR').' '.$langs->trans("HT").'

    '; - $download_link = ''; + $download_link = ''; } else { $price = '

    '.$langs->trans('Free').'

    '; - $download_link = ''; - $download_link .= '

    '; + $download_link = ''; + $download_link .= '

    '; } //checking versions @@ -319,14 +319,14 @@ class Dolistore //.'
    '.$langs->trans("SeeInMarkerPlace").' //output template - $html .= ' -
    '.$newapp.$images.'
    -

    '.$product->name->language[$this->lang - 1] - .'
    '.$version.'

    - '.dol_print_date(dol_stringtotime($product->date_upd), 'dayhour').' - '.$langs->trans('Ref').': '.$product->reference.' - '.$langs->trans('Id').': '.$product->id.'

    '.$product->description_short->language[$this->lang - 1].''; + $html .= ' +
    '.dol_escape_htmltag($newapp.$images).'
    +

    '.dol_escape_htmltag($product->name->language[$this->lang - 1]) + .'
    '.dol_escape_htmltag($version).'

    + '.dol_print_date(dol_stringtotime($product->date_upd), 'dayhour').' - '.$langs->trans('Ref').': '.dol_escape_htmltag($product->reference).' - '.dol_escape_htmltag($langs->trans('Id')).': '.((int) $product->id).'

    '.dol_escape_htmltag($product->description_short->language[$this->lang - 1]).''; // do not load if display none //$html .= ''.$product->description->language[$this->lang - 1].''; - $html .= ''.$price.''; + $html .= ''.dol_escape_htmltag($price).''; $html .= ''.$download_link.''; $html .= ''; } @@ -343,7 +343,7 @@ class Dolistore public function get_previous_link($text = '<<') { // phpcs:enable - return ''.$text.''; + return ''.dol_escape_htmltag($text).''; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps @@ -356,7 +356,7 @@ class Dolistore public function get_next_link($text = '>>') { // phpcs:enable - return ''.$text.''; + return ''.dol_escape_htmltag($text).''; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps diff --git a/htdocs/admin/ldap.php b/htdocs/admin/ldap.php index 80897320e90..1a274f8cec1 100644 --- a/htdocs/admin/ldap.php +++ b/htdocs/admin/ldap.php @@ -43,6 +43,7 @@ $action = GETPOST('action', 'aZ09'); // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context $hookmanager->initHooks(array('adminldap', 'globaladmin')); + /* * Actions */ @@ -150,7 +151,7 @@ $arraylist['0'] = $langs->trans("No"); $arraylist['ldap2dolibarr'] = $langs->trans("LDAPToDolibarr"); $arraylist['dolibarr2ldap'] = $langs->trans("DolibarrToLDAP"); print $form->selectarray('activesynchro', $arraylist, $conf->global->LDAP_SYNCHRO_ACTIVE); -print ''.$langs->trans("LDAPDnSynchroActiveExample"); +print ''.$langs->trans("LDAPDnSynchroActiveExample").''; if ($conf->global->LDAP_SYNCHRO_ACTIVE && !$conf->global->LDAP_USER_DN) { print '
    '.$langs->trans("LDAPSetupNotComplete").''; } @@ -163,7 +164,7 @@ if (!empty($conf->societe->enabled)) { $arraylist['0'] = $langs->trans("No"); $arraylist['1'] = $langs->trans("DolibarrToLDAP"); print $form->selectarray('activecontact', $arraylist, $conf->global->LDAP_CONTACT_ACTIVE); - print ''.$langs->trans("LDAPDnContactActiveExample").''; + print ''.$langs->trans("LDAPDnContactActiveExample").''; } // Synchro member active @@ -174,7 +175,7 @@ if (!empty($conf->adherent->enabled)) { $arraylist['1'] = $langs->trans("DolibarrToLDAP"); $arraylist['ldap2dolibarr'] = $langs->trans("LDAPToDolibarr").' ('.$langs->trans("SupportedForLDAPImportScriptOnly").')'; print $form->selectarray('activemembers', $arraylist, $conf->global->LDAP_MEMBER_ACTIVE); - print ''.$langs->trans("LDAPDnMemberActiveExample").''; + print ''.$langs->trans("LDAPDnMemberActiveExample").''; } // Synchro member type active @@ -185,7 +186,7 @@ if (!empty($conf->adherent->enabled)) { $arraylist['1'] = $langs->trans("DolibarrToLDAP"); $arraylist['ldap2dolibarr'] = $langs->trans("LDAPToDolibarr").' ('.$langs->trans("SupportedForLDAPImportScriptOnly").')'; print $form->selectarray('activememberstypes', $arraylist, $conf->global->LDAP_MEMBER_TYPE_ACTIVE); - print ''.$langs->trans("LDAPDnMemberTypeActiveExample").''; + print ''.$langs->trans("LDAPDnMemberTypeActiveExample").''; } // Fields from hook @@ -214,33 +215,33 @@ $arraylist = array(); $arraylist['3'] = 'Version 3'; $arraylist['2'] = 'Version 2'; print $form->selectarray('LDAP_SERVER_PROTOCOLVERSION', $arraylist, $conf->global->LDAP_SERVER_PROTOCOLVERSION); -print ''.$langs->trans("LDAPServerProtocolVersion").''; +print ''.$langs->trans("LDAPServerProtocolVersion").''; // Serveur primaire print ''; print $langs->trans("LDAPPrimaryServer").''; -print ''; -print ''.$langs->trans("LDAPServerExample").''; +print ''; +print ''.$langs->trans("LDAPServerExample").''; // Serveur secondaire print ''; print $langs->trans("LDAPSecondaryServer").''; -print ''; -print ''.$langs->trans("LDAPServerExample").''; +print ''; +print ''.$langs->trans("LDAPServerExample").''; // Port print ''.$langs->trans("LDAPServerPort").''; if (!empty($conf->global->LDAP_SERVER_PORT)) { - print ''; + print ''; } else { - print ''; + print ''; } -print ''.$langs->trans("LDAPServerPortExample").''; +print ''.$langs->trans("LDAPServerPortExample").''; // DNserver print ''.$langs->trans("LDAPServerDn").''; -print ''; -print ''.$langs->trans("LDAPServerDnExample").''; +print ''; +print ''.$langs->trans("LDAPServerDnExample").''; // Utiliser TLS print ''.$langs->trans("LDAPServerUseTLS").''; @@ -248,7 +249,7 @@ $arraylist = array(); $arraylist['0'] = $langs->trans("No"); $arraylist['1'] = $langs->trans("Yes"); print $form->selectarray('usetls', $arraylist, $conf->global->LDAP_SERVER_USE_TLS); -print ''.$langs->trans("LDAPServerUseTLSExample").''; +print ''.$langs->trans("LDAPServerUseTLSExample").''; print ''; print ''.$langs->trans("ForANonAnonymousAccess").''; @@ -257,18 +258,18 @@ print "\n"; // DNAdmin print ''; print ''.$langs->trans("LDAPAdminDn").''; -print ''; -print ''.$langs->trans("LDAPAdminDnExample").''; +print ''; +print ''.$langs->trans("LDAPAdminDnExample").''; // Pass print ''; print ''.$langs->trans("LDAPPassword").''; if (!empty($conf->global->LDAP_ADMIN_PASS)) { - print ''; // je le met en visible pour test + print ''; // je le met en visible pour test } else { - print ''; + print ''; } -print ''.$langs->trans('Password').' (ex: secret)'; +print ''.$langs->trans('Password').' (ex: secret)'; print ''; diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php index 658be446765..ccf12d5a104 100644 --- a/htdocs/admin/modules.php +++ b/htdocs/admin/modules.php @@ -1025,16 +1025,16 @@ if ($mode == 'marketplace') { print '
    '; - print '
    '; + print ''; ?>
    -
    +
    @@ -1051,7 +1051,7 @@ if ($mode == 'marketplace') {
      - get_categories(); ?> + get_categories()); ?>
    diff --git a/htdocs/core/class/ldap.class.php b/htdocs/core/class/ldap.class.php index a2e5d450869..0e8fd3ee7b4 100644 --- a/htdocs/core/class/ldap.class.php +++ b/htdocs/core/class/ldap.class.php @@ -205,14 +205,26 @@ class Ldap if ($this->serverPing($host, $this->serverPort) === true) { $this->connection = ldap_connect($host, $this->serverPort); } else { - continue; + if (preg_match('/^ldaps/i', $host)) { + // With host = ldaps://server, the serverPing to ssl://server sometimes fails, even if the ldap_connect succeed, so + // we test this case and continue in suche a case even if serverPing fails. + $this->connection = ldap_connect($host, $this->serverPort); + } else { + continue; + } } if (is_resource($this->connection)) { - // Begin TLS if requested by the configuration + // Upgrade connexion to TLS, if requested by the configuration if (!empty($conf->global->LDAP_SERVER_USE_TLS)) { - if (!ldap_start_tls($this->connection)) { + // For test/debug + //ldap_set_option($this->connection, LDAP_OPT_DEBUG_LEVEL, 7); + //ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3); + + $resulttls = ldap_start_tls($this->connection); + if (!$resulttls) { dol_syslog(get_class($this)."::connect_bind failed to start tls", LOG_WARNING); + $this->error = 'ldap_start_tls Failed to start TLS '.ldap_errno($this->connection).' '.ldap_error($this->connection); $connected = 0; $this->close(); } @@ -689,22 +701,38 @@ class Ldap /** * Ping a server before ldap_connect for avoid waiting * - * @param string $host Server host or address + * @param string $host Server host or address * @param int $port Server port (default 389) - * @param int $timeout Timeout in second (default 1s) + * @param int $timeout Timeout in second (default 1s) * @return boolean true or false */ public function serverPing($host, $port = 389, $timeout = 1) { - // Replace ldaps:// by ssl:// + $regs = array(); if (preg_match('/^ldaps:\/\/([^\/]+)\/?$/', $host, $regs)) { + // Replace ldaps:// by ssl:// $host = 'ssl://'.$regs[1]; - } - // Remove ldap:// - if (preg_match('/^ldap:\/\/([^\/]+)\/?$/', $host, $regs)) { + } elseif (preg_match('/^ldap:\/\/([^\/]+)\/?$/', $host, $regs)) { + // Remove ldap:// $host = $regs[1]; } + + //var_dump($newhostforstream); var_dump($host); var_dump($port); + //$host = 'ssl://ldap.test.local:636'; + //$port = 636; + + $errno = $errstr = 0; + /* + if ($methodtochecktcpconnect == 'socket') { + Try to use socket_create() method. + Method that use stream_context_create() works only on registered listed in stream stream_get_wrappers(): http, https, ftp, ... + } + */ + + // Use the method fsockopen to test tcp connect. No way to ignore ssl certificate errors with this method ! $op = @fsockopen($host, $port, $errno, $errstr, $timeout); + + //var_dump($op); if (!$op) { return false; //DC is N/A } else { diff --git a/htdocs/core/get_menudiv.php b/htdocs/core/get_menudiv.php index d45b6f2f350..84be9ff8e0f 100644 --- a/htdocs/core/get_menudiv.php +++ b/htdocs/core/get_menudiv.php @@ -110,14 +110,13 @@ print ' } a.alilevel0 { - background-image: url(\''.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/next.png\') !important; + background-image: url(\''.DOL_URL_ROOT.'/theme/'.urlencode($conf->theme).'/img/next.png\') !important; background-repeat: no-repeat !important; background-position-x: 10px; background-position-y: 16px; padding: 1em 15px 1em 40px; } li.lilevel0 font.vsmenudisabled { - /* background-image: url(/dolibarr_dev/htdocs/theme/eldy/img/next.png) !important; */ background-repeat: no-repeat !important; background-position-x: 10px; background-position-y: 16px; @@ -178,6 +177,9 @@ print ' white-space: nowrap; display: block; } + .vsmenudisabled .fa, .vsmenudisabled .fas, .vsmenudisabled .far { + color: #aaa !important; + }