diff --git a/htdocs/blockedlog/class/blockedlog.class.php b/htdocs/blockedlog/class/blockedlog.class.php index e81fabbeac0..11cfbf5dbe6 100644 --- a/htdocs/blockedlog/class/blockedlog.class.php +++ b/htdocs/blockedlog/class/blockedlog.class.php @@ -1423,6 +1423,10 @@ class BlockedLog // The new ID $this->id = $id; + // Store the signature of this new line + $this->getObfuscationKey(); + + $this->db->commit(); // Call remote API service to record the last counter @@ -1573,10 +1577,10 @@ class BlockedLog } /** - * Return a hash that is the signature of a line (hash_hmac en SHA256 des données + clé secrète) + * Return a hash that is the signature of a line data $clearstring (hash_hmac SHA256 of data + secret key) * - * @param string $clearstring Data to sign - * @param string $format Force format to use + * @param string $clearstring Data string to sign + * @param string $format Force encryption format version to use ('V1', 'V2', ...) * @return string Signature string */ private function buildFinalSignatureHash($clearstring, $format = '') @@ -1602,44 +1606,22 @@ class BlockedLog // Here we have the obfuscated value of BLOCKEDLOG_HMAC_KEY in $hmac_encoded_secret_key. We need to unobfuscate it. $hmac_secret_key = ''; - - // Get the obfuscation key from ping.dolibarr.org (to be used just after to decode HMAC secret key) - if (preg_match('/^dolobfuscation/', $hmac_encoded_secret_key)) { - $errormsg = ''; - $obfuscationkey = ''; - try { - $obfuscationkey = $this->getObfuscationKey(); // Get obfuscation key providing $mysoc->idprof1 and $registrationnumber. Note: On network trouble, an Exception is thrown to the caller - } catch (Exception $e) { - $errormsg = $e->getMessage(); - } - if (!$errormsg && $obfuscationkey) { - // Decode the encrypted parameter using the obfuscation key to get the HMAC key in memory. - $hmac_secret_key = dolDecrypt($hmac_encoded_secret_key, $obfuscationkey); - } + try { + $hmac_secret_key = $this->getClearHMACSecretKey($hmac_encoded_secret_key); // Note: On network trouble, an Exception is thrown to the caller + } catch (Exception $e) { + throw new Exception($e->getMessage()); } + // Last check on validity of key if (!preg_match('/^BLOCKEDLOGHMAC/', (string) $hmac_secret_key)) { - // Failed to get the clear HMAC value. May be we are using an old obfuscated HMAC key, so we retry with the old method (used by webhosting providers using the attestation with previous versions). - // We test this and we force a migrate data if this is the case. - // Example with the old demo sample database: - // dolcrypt:AES-256-CTR:46cb611f00c4cff8:XVfEh15vX/JOYmpiw2QPNamcTQwdbBZJTcXBh9rMpzYJOpVPZubIWcgA8wHMXA== - // instance_unique_id=11f3c81e86fc9e3b3fd11d81c9a31bd0 - // HMAC key=BLOCKEDLOGHMACY3Ewx37RXbSd8gL9JV8p7Wqw7qvq2K2A - - // We fall back on the instance_unique_id (coming from $dolibarr_main_instance_unique_id, for backward compatibility). - $oldobfuscationkey = !empty($conf->file->instance_unique_id) ? $conf->file->instance_unique_id : ""; - - $hmac_secret_key = dolDecrypt($hmac_encoded_secret_key, $oldobfuscationkey); // Decode the encrypted parameter using the obfuscation key from ping.dolibarr.org to decode HMAC key - - if (!preg_match('/^BLOCKEDLOGHMAC/', (string) $hmac_secret_key)) { - //throw new Exception('Error: Failed to decode the crypted value of the parameter BLOCKEDLOG_HMAC_KEY using the obfuscation key. A value was found but decoding failed. May be the database data were restored onto another environment and the coding/decoding key $dolibarr_main_dolcrypt_key or $dolibarr_main_instance_unique_id was not restored with the same value in conf.php file.'); - throw new Exception('Error: Failed to decode the crypted value of the parameter BLOCKEDLOG_HMAC_KEY using the obfuscation key. A value was found in database but decoding failed. May be you modified the SIREN used to get the obfuscation key from ping.dolibarr.org (or old config key $dolibarr_main_instance_unique_id).'.($errormsg ? ' Additional message: '.$errormsg : '')); - } + //throw new Exception('Error: Failed to decode the crypted value of the parameter BLOCKEDLOG_HMAC_KEY using the obfuscation key. A value was found but decoding failed. May be the database data were restored onto another environment and the coding/decoding key $dolibarr_main_dolcrypt_key or $dolibarr_main_instance_unique_id was not restored with the same value in conf.php file.'); + throw new Exception('Error: Failed to decode the crypted value of the parameter BLOCKEDLOG_HMAC_KEY using the obfuscation key. A value was found in database but decoding failed. May be you modified the SIREN used to get the obfuscation key from ping.dolibarr.org (or old config key $dolibarr_main_instance_unique_id).'); } + // On old versions, we must switch the data saving mode to use the new method. if (isALNERunningVersion(1) && !preg_match('/^dolobfuscationv1/', $hmac_encoded_secret_key) && preg_match('/^BLOCKEDLOGHMAC/', (string) $hmac_secret_key) && $mysoc->country_code == 'FR') { - // On old versions, we must switch the data saving mode to use the new method. $obfuscationkey = ''; + $errormsg = ''; try { $obfuscationkey = $this->getObfuscationKey(); // Get obfuscation key providing $mysoc->idprof1 and $registrationnumber. Note: On network trouble, an Exception is thrown to the caller } catch (Exception $e) { @@ -1647,6 +1629,8 @@ class BlockedLog } if (!$errormsg && $obfuscationkey) { $this->saveHMACSecretKey((string) $hmac_secret_key, 'dolobfuscationv1-'.$mysoc->idprof1, $obfuscationkey); // gitleaks:allow + } else { + throw new Exception('Error: Failed to convert the old saving mode of HMAC key (crypted by $dolibarr_main_instance_unique_id) into the new saving (crypted by obfuscation key from ping.dolibarr.org). '.$errormsg); } } @@ -1730,9 +1714,6 @@ class BlockedLog return -1; } - - - return 1; } @@ -1814,6 +1795,55 @@ class BlockedLog return $hmac_encoded_secret_key; } + /** + * Get the HMAC secret key. + * + * @param string $hmac_encoded_secret_key HMAC encode string retrieved with getEncodedHMACSecretKey() + * @return string Encoded HMAC secret key. + */ + public function getClearHMACSecretKey($hmac_encoded_secret_key) + { + global $conf; + + // Here we have the obfuscated value of BLOCKEDLOG_HMAC_KEY in $hmac_encoded_secret_key. We need to unobfuscate it. + $hmac_secret_key = ''; + $errormsg = ''; + + // Get the obfuscation key from ping.dolibarr.org (to be used just after to decode HMAC secret key) + if (preg_match('/^dolobfuscation/', $hmac_encoded_secret_key)) { + $obfuscationkey = ''; + try { + $obfuscationkey = $this->getObfuscationKey(); // Get obfuscation key providing $mysoc->idprof1 and $registrationnumber. Note: On network trouble, an Exception is thrown to the caller + } catch (Exception $e) { + $errormsg = $e->getMessage(); + } + if (!$errormsg && $obfuscationkey) { + // Decode the encrypted parameter using the obfuscation key to get the HMAC key in memory. + $hmac_secret_key = dolDecrypt($hmac_encoded_secret_key, $obfuscationkey); + } + } + + if (preg_match('/^dolcrypt/', $hmac_encoded_secret_key) || !preg_match('/^BLOCKEDLOGHMAC/', (string) $hmac_secret_key)) { + // Failed to get the clear HMAC value. May be we are using an old obfuscated HMAC key, so we retry with the old method (used by webhosting providers using the attestation with old versions). + // We test this and we force a migration of data to use the new storage if this is the case. + // Example with the old demo sample database: + // dolcrypt:AES-256-CTR:46cb611f00c4cff8:XVfEh15vX/JOYmpiw2QPNamcTQwdbBZJTcXBh9rMpzYJOpVPZubIWcgA8wHMXA== + // instance_unique_id=11f3c81e86fc9e3b3fd11d81c9a31bd0 + // HMAC key=BLOCKEDLOGHMACY3Ewx37RXbSd8gL9JV8p7Wqw7qvq2K2A + + // We fall back on the instance_unique_id (coming from $dolibarr_main_instance_unique_id, for backward compatibility). + $oldobfuscationkey = !empty($conf->file->instance_unique_id) ? $conf->file->instance_unique_id : ""; + + $hmac_secret_key = dolDecrypt($hmac_encoded_secret_key, $oldobfuscationkey); // Decode the encrypted parameter using the obfuscation key from ping.dolibarr.org to decode HMAC key + } + + if (!preg_match('/^BLOCKEDLOGHMAC/', (string) $hmac_secret_key)) { + throw new Exception('Error: Failed to decode the crypted value of the parameter BLOCKEDLOG_HMAC_KEY using the obfuscation key. A value was found in database but decoding failed. May be you modified the SIREN used to get the obfuscation key from ping.dolibarr.org (or old config key $dolibarr_main_instance_unique_id).'.($errormsg ? ' Additional message: '.$errormsg : '')); + } + + return $hmac_secret_key; + } + /** * Get previous signature/hash in chain. If there is no previous line, return the init hash. * @@ -1982,7 +2012,7 @@ class BlockedLog } } if (!empty($search_module_source)) { - $sql .= natural_search("module_source", implode(',', $search_module_source), 3, 1); + $sql .= natural_search("module_source", implode(',', $search_module_source), 0, 1); } $sql .= " OR module_source = 'mix'"; // When a payment was recorded and payment was on an invoice with different origins (pos and not pos) $sql .= ")"; diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 469c81523c9..32eba4c116b 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -977,7 +977,7 @@ class FormFile $documenturl = getDolGlobalString('DOL_URL_ROOT_DOCUMENT_PHP', DOL_URL_ROOT.'/document.php'); // DOL_URL_ROOT_DOCUMENT_PHP can be used to set another wrapper // Show file name with link to download - $imgpreview = $this->showPreview($file, $modulepart, $relativepath, 0, $param); + $imgpreview = $this->showPreview($file, $modulepart, $relativepath, 0, $param.'&preview=1'); $out .= ''; if ($imgpreview) { $out .= ''; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 81e4700be18..e6a4ee7f967 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -13520,14 +13520,31 @@ function natural_search($fields, $value, $mode = 0, $nofirstand = 0, $sqltoadd = $tmparray = explode(',', $crit); if (count($tmparray)) { $listofcodes = ''; + $listofcodesnot = ''; foreach ($tmparray as $val) { $val = trim($val); - if ($val) { // TODO Test with if ($val !== '') { - $listofcodes .= ($listofcodes ? ',' : ''); - $listofcodes .= "'" . $db->escape($val) . "'"; + if ($val !== '') { + if (preg_match('/^!/', $val)) { + $listofcodesnot .= ($listofcodesnot ? ',' : ''); + $listofcodesnot .= "'" . $db->escape(preg_replace('/^!=?/', '', $val)) . "'"; + } else { + $listofcodes .= ($listofcodes ? ',' : ''); + $listofcodes .= "'" . $db->escape($val) . "'"; + } } } - $newres .= ($i2 > 0 ? ' OR ' : '') . $db->sanitize($field) . " " . ($mode == -3 ? 'NOT ' : '') . "IN (" . $db->sanitize($listofcodes, 1, 0, 1) . ")"; + $newres .= ($i2 > 0 ? ' OR ' : ''); + $newres .= '('; + if ($listofcodes) { + $newres .= $db->sanitize($field) . " " . ($mode == -3 ? 'NOT IN' : 'IN') . " (" . $db->sanitize($listofcodes, 1, 0, 1) . ")"; + } + if ($listofcodes && $listofcodesnot) { + $newres .= ' AND '; + } + if ($listofcodesnot) { + $newres .= $db->sanitize($field) . " " . ($mode == -3 ? 'IN ' : 'NOT IN') . " (" . $db->sanitize($listofcodesnot, 1, 0, 1) . ")"; + } + $newres .= ')'; $i2++; // a criteria for 1 more field was added to string } if ($mode == -3) { diff --git a/htdocs/document.php b/htdocs/document.php index e46f8943d84..37069e2ae95 100644 --- a/htdocs/document.php +++ b/htdocs/document.php @@ -399,7 +399,7 @@ if ($modulepart == 'facture') { // We are on the download or print of the main document if ($invoice instanceOf Facture && $invoice->status > Facture::STATUS_DRAFT) { $action = 'DOC_DOWNLOAD'; - if (GETPOSTISSET('attachement')) { + if (GETPOSTISSET('attachement') || GETPOST('preview')) { $action = 'DOC_PREVIEW'; } diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index 87ecadc8d3e..fa8b1da1c90 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -3925,6 +3925,7 @@ if (!function_exists("llxFooter")) { // JS wrapper to add an unalterable log when clicking on Download or Preview // This is done on customer invoices only. // This add a log and increase the pos_print_counter too (done by block-add.php). + /* NOTE: No more required, the trigger is now included into the call of the wrapper documents.php if (isModEnabled('blockedlog') && is_object($object) && !empty($object->id) && $object->id > 0) { if (in_array($object->element, array('facture')) && $object->statut > 0) { // Restrict for the moment to element 'facture' print "\n\n"; @@ -3932,7 +3933,7 @@ if (!function_exists("llxFooter")) {