* Qual: Remove redundant tests # Qual: Remove redundant tests Remove redundant tests as reported by PHPStan * Qual: Fix missing initialisation # Qual: Fix missing initialisation In case of catched exception, $hmac_encoded_secret_key was not defined * Fix: search parameter re-encoding # Fix: search parameter re-encoding * Fix: Add new chain initialization in securitycore.lib.php # Fix: Add new chain initialization in securitycore.lib.php - Initialize `$newchain` variable before the loop to avoid potential undefined variable issues * Qual: Fix formatting in functions.lib.php - Fixed formatting and spacing issues * Qual: Cast nullable variable to string # Qual: Cast nullable variable to string preg_replace requires a string, ensured by casting nullable to string. --------- Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
398 lines
16 KiB
PHP
398 lines
16 KiB
PHP
<?php
|
|
/* Copyright (C) 2017 ATM Consulting <contact@atm-consulting.fr>
|
|
* Copyright (C) 2017-2018 Laurent Destailleur <eldy@destailleur.fr>
|
|
* Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
|
|
* Copyright (C) 2026-2026 Laurent Magnin <laurent.magnin@evarisk.com>
|
|
* Copyright (C) 2026 MDW <mdeweerd@users.noreply.github.com>
|
|
*
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* \file htdocs/blockedlog/admin/blockedlog.php
|
|
* \ingroup blockedlog
|
|
* \brief Page setup for blockedlog module
|
|
*/
|
|
|
|
|
|
// Load Dolibarr environment
|
|
require '../../main.inc.php';
|
|
/**
|
|
* @var Conf $conf
|
|
* @var DoliDB $db
|
|
* @var HookManager $hookmanager
|
|
* @var Societe $mysoc
|
|
* @var Translate $langs
|
|
* @var User $user
|
|
*/
|
|
require_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/blockedlog/class/blockedlog.class.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
|
|
|
|
// Load translation files required by the page
|
|
$langs->loadLangs(array('admin', 'blockedlog', 'other'));
|
|
|
|
// Get Parameters
|
|
$action = GETPOST('action', 'aZ09');
|
|
$backtopage = GETPOST('backtopage', 'alpha');
|
|
|
|
$withtab = GETPOSTINT('withtab');
|
|
$origin = GETPOST('origin');
|
|
$withtab = GETPOSTISSET('withtab') ? GETPOSTINT('withtab') : 1;
|
|
|
|
// Access Control
|
|
if (!$user->admin || !isModEnabled('blockedlog')) {
|
|
accessforbidden();
|
|
}
|
|
|
|
|
|
/*
|
|
* Actions
|
|
*/
|
|
|
|
$reg = array();
|
|
if (preg_match('/set_(.*)/', $action, $reg)) {
|
|
$code = $reg[1];
|
|
$values = GETPOST($code);
|
|
if (is_array($values)) {
|
|
$values = implode(',', $values);
|
|
}
|
|
|
|
if (dolibarr_set_const($db, $code, $values, 'chaine', 0, '', $conf->entity) > 0) {
|
|
header("Location: ".$_SERVER["PHP_SELF"].($withtab ? '?withtab='.$withtab : ''));
|
|
exit;
|
|
} else {
|
|
dol_print_error($db);
|
|
}
|
|
}
|
|
|
|
if (preg_match('/del_(.*)/', $action, $reg)) {
|
|
$code = $reg[1];
|
|
if (dolibarr_del_const($db, $code, 0) > 0) {
|
|
header("Location: ".$_SERVER["PHP_SELF"].($withtab ? '?withtab='.$withtab : ''));
|
|
exit;
|
|
} else {
|
|
dol_print_error($db);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* View
|
|
*/
|
|
|
|
$form = new Form($db);
|
|
$block_static = new BlockedLog($db);
|
|
$block_static->loadTrackedEvents();
|
|
|
|
$title = $langs->trans("ModuleSetup").' '.$langs->trans('BlockedLog');
|
|
$help_url = "EN:Module_Unalterable_Archives_-_Logs|FR:Module_Archives_-_Logs_Inaltérable";
|
|
|
|
llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-blockedlog page-admin_blockedlog');
|
|
|
|
$linkback = '';
|
|
if ($withtab) {
|
|
$linkback = '<a href="'.dolBuildUrl($backtopage ? $backtopage : DOL_URL_ROOT.'/admin/modules.php', ['restore_lastsearch_values' => 1]).'">'.img_picto($langs->trans("BackToModuleList"), 'back', 'class="pictofixedwidth"').'<span class="hideonsmartphone">'.$langs->trans("BackToModuleList").'</span></a>';
|
|
}
|
|
|
|
$morehtmlcenter = '';
|
|
|
|
$registrationnumber = getHashUniqueIdOfRegistration();
|
|
$texttop = '<small class="opacitymedium">'.$langs->trans("RegistrationNumber").':</small> <small>'.dol_trunc($registrationnumber, 10).'</small>';
|
|
if (!isRegistrationDataSavedAndPushed()) {
|
|
$texttop = '';
|
|
}
|
|
|
|
print load_fiche_titre($title.'<br>'.$texttop, $linkback, 'blockedlog', 0, '', '', $morehtmlcenter);
|
|
|
|
if ($withtab) {
|
|
$head = blockedlogadmin_prepare_head($withtab);
|
|
print dol_get_fiche_head($head, 'technicalinfo', '', -1);
|
|
}
|
|
|
|
print '<span class="opacitymedium">'.$langs->trans("BlockedLogDesc")."</span><br>\n";
|
|
|
|
$versionbadge = '<span class="badge-text badge-secondary">'.getBlockedLogVersionToShow().'</span>';
|
|
|
|
|
|
// Special additional message for FR only
|
|
$infotoshow = '';
|
|
if ($mysoc->country_code == 'FR') {
|
|
$islne = isALNEQualifiedVersion(1, 1);
|
|
if ($islne) {
|
|
if (preg_match('/\-/', getBlockedLogVersionToShow())) {
|
|
// This is an alpha or beta version
|
|
$infotoshow = $langs->trans("LNECandidateVersionForCertificationFR", $versionbadge);
|
|
} else {
|
|
$infotoshow = $langs->trans("LNECertifiedVersionFR", $versionbadge);
|
|
}
|
|
} else {
|
|
$infotoshow = $langs->trans("NotCertifiedVersionFR", $versionbadge);
|
|
}
|
|
|
|
$infotoshow .= ' - <a href="'.DOL_URL_ROOT.'/blockedlog/admin/filecheck.php">'.img_picto('', 'url', 'class="pictofixedwidth"').$langs->trans("FileCheck").'</a>';
|
|
}
|
|
|
|
// Show generic message (for countries that need registration) to explain we need registration to collect data and why
|
|
if (in_array($mysoc->country_code, array('FR'))) {
|
|
$organization_for_ping = getDolGlobalString('MAIN_ORGANIZATION_FOR_PING', "Association Dolibarr");
|
|
$dataprivacy_url = getDolGlobalString('MAIN_ORGANIZATION_URL_PRIVACY', "https://www.dolibarr.org/legal-privacy-gdpr.php");
|
|
|
|
if (!isRegistrationDataSavedAndPushed() || $origin == 'initmodule') {
|
|
if ($infotoshow) {
|
|
print info_admin($infotoshow, 0, 0, 'info');
|
|
}
|
|
/*
|
|
$htmltext = $langs->trans("UnalterableLogToolRegistrationFR").'<br>';
|
|
$htmltext .= $langs->trans("InformationWillBePublishedTo");
|
|
$htmltext .= '<br>'.$langs->trans("InformationWillBePublishedTo2", $organization_for_ping, $dataprivacy_url);
|
|
$htmltext .= '<br>'.$langs->trans("InformationWillBePublishedTo3");
|
|
|
|
print info_admin($htmltext, 0, 0, 'warning');
|
|
*/
|
|
} else {
|
|
$htmltext = ($infotoshow ? $infotoshow.'<br>' : '');
|
|
$htmltext .= $langs->trans("ApplicationHasBeenRegistered");
|
|
$htmltext .= ' '.$langs->trans("RegistrationNumber").': <span class="badge-text badge-secondary" title="Flag stored into MAIN_FIRST_REGISTRATION_OK_DATE. Registered data saved into BLOCKEDLOG_REGISTRATION_...">'.dol_trunc($registrationnumber, 10).'</span>';
|
|
$htmltext .= '<br>';
|
|
$htmltext .= $langs->trans("LastRegistrationDate").' : ';
|
|
//$htmltext .= dol_print_date(getDolGlobalString('MAIN_FIRST_REGISTRATION_OK_DATE'), 'dayhour', 'tzuserrel');
|
|
$htmltext .= getDolGlobalString('MAIN_FIRST_REGISTRATION_OK_DATE');
|
|
|
|
print info_admin($htmltext, 0, 0, 'info');
|
|
|
|
// Show remind on good practices related to archives
|
|
/*
|
|
$htmltext = $langs->trans("UnalterableLogTool1FR", $langs->transnoentitiesnoconv("Archives")).'<br>';
|
|
print info_admin($htmltext, 0, 0, 'warning');
|
|
*/
|
|
}
|
|
}
|
|
|
|
|
|
print '<br>';
|
|
|
|
print '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you don't need reserved height for your table
|
|
print '<table class="noborder centpercent">';
|
|
|
|
print '<tr class="liste_titre">';
|
|
print '<td>'.$langs->trans("Parameters").'</td>';
|
|
print '<td></td>';
|
|
print "</tr>\n";
|
|
|
|
// Initial signature
|
|
// Generated randomly when doing the first insert by blockedlog.class.php, and saved into BLOCKEDLOG_ENTITY_FINGERPRINT
|
|
print '<tr class="oddeven">';
|
|
print '<td class="titlefieldmiddle" title="Parameter BLOCKEDLOG_ENTITY_FINGERPRINT">';
|
|
print $langs->trans("CompanyInitialKey").'</td><td title="Parameter BLOCKEDLOG_ENTITY_FINGERPRINT">';
|
|
print $block_static->getOrInitFirstSignature();
|
|
print '</td></tr>';
|
|
|
|
/* Deprecated
|
|
if (getDolGlobalString('BLOCKEDLOG_USE_REMOTE_AUTHORITY')) {
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("BlockedLogAuthorityUrl").img_info($langs->trans('BlockedLogAuthorityNeededToStoreYouFingerprintsInNonAlterableRemote')).'</td>';
|
|
print '<td class="right" width="300">';
|
|
|
|
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="set_BLOCKEDLOG_AUTHORITY_URL">';
|
|
print '<input type="hidden" name="withtab" value="'.$withtab.'">';
|
|
print '<input type="text" name="BLOCKEDLOG_AUTHORITY_URL" value="' . getDolGlobalString('BLOCKEDLOG_AUTHORITY_URL').'" size="40" />';
|
|
print '<input type="submit" class="button button-edit" value="'.$langs->trans("Modify").'">';
|
|
print '</form>';
|
|
|
|
print '</td></tr>';
|
|
}
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td class="titlefieldmiddle" title="Debug obfuscation key">';
|
|
print "Debug obfuscation key".'</td><td title="Debug obfuscation key" class="small">';
|
|
try {
|
|
$a = $block_static->getObfuscationKey();
|
|
print 'block_static->getObfuscationKey(): '.$a;
|
|
print '<br>';
|
|
print '$_SESSION[obfuscationkey_'.((int) $conf->entity).']: '.$_SESSION['obfuscationkey_'.((int) $conf->entity)];
|
|
print '<br>';
|
|
$b = $block_static->getEncodedHMACSecretKey();
|
|
print $b;
|
|
print '<br>';
|
|
if (preg_match('/dolcrypt/', $b)) {
|
|
print dolDecrypt($b, '');
|
|
} elseif (preg_match('/dolobfuscationv1/', $b)) {
|
|
print dolDecrypt($b, $a);
|
|
}
|
|
print '<br>';
|
|
print '$conf->cache[obfuscationkey_'.((int) $conf->entity).']: '.$conf->cache['obfuscationkey_'.((int) $conf->entity)];
|
|
} catch (Exception $e) {
|
|
print $e->getMessage();
|
|
}
|
|
print '</td></tr>';
|
|
*/
|
|
|
|
|
|
// Show the input of countries not allowed for disabling
|
|
if ($mysoc->country_code != 'FR' || !isALNERunningVersion() || constant('CERTIF_LNE') != '1') {
|
|
print '<tr class="oddeven">';
|
|
print '<td>';
|
|
print $form->textwithpicto($langs->transnoentitiesnoconv("BlockedLogDisableNotAllowedForCountry"), $langs->transnoentitiesnoconv("BlockedLogDisableNotAllowedForCountry2"));
|
|
print '</td>';
|
|
print '<td>';
|
|
|
|
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="set_BLOCKEDLOG_DISABLE_NOT_ALLOWED_FOR_COUNTRY">';
|
|
print '<input type="hidden" name="withtab" value="'.$withtab.'">';
|
|
|
|
$sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite";
|
|
$sql .= " FROM ".MAIN_DB_PREFIX."c_country";
|
|
$sql .= " WHERE active > 0";
|
|
|
|
$countryArray = array();
|
|
$resql = $db->query($sql);
|
|
if ($resql) {
|
|
while ($obj = $db->fetch_object($resql)) {
|
|
$countryArray[$obj->code_iso] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country".$obj->code_iso) != "Country".$obj->code_iso ? $langs->transnoentitiesnoconv("Country".$obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
|
|
}
|
|
}
|
|
|
|
$selected = !getDolGlobalString('BLOCKEDLOG_DISABLE_NOT_ALLOWED_FOR_COUNTRY') ? array() : explode(',', getDolGlobalString('BLOCKEDLOG_DISABLE_NOT_ALLOWED_FOR_COUNTRY'));
|
|
|
|
// Can module be disabled
|
|
$canbedisabled = $block_static->canBeDisabled();
|
|
|
|
print $form->multiselectarray('BLOCKEDLOG_DISABLE_NOT_ALLOWED_FOR_COUNTRY', $countryArray, $selected, 0, 0, '', 0, 0, $canbedisabled ? '' : 'disabled');
|
|
print '<input type="submit" class="button button-edit" value="'.$langs->trans("Modify").'"'.($canbedisabled ? '' : ' disabled').'>';
|
|
print '</form>';
|
|
|
|
print '</td>';
|
|
print '</tr>';
|
|
}
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td class="">';
|
|
print $langs->trans("ListOfTrackedEvents").'</td><td>';
|
|
$arrayoftrackedevents = $block_static->trackedevents;
|
|
foreach ($arrayoftrackedevents as $key => $val) {
|
|
if (preg_match('/^separator/i', $key)) {
|
|
continue;
|
|
}
|
|
print $key.' - ';
|
|
if (is_array($val)) {
|
|
print $langs->trans($val['labelhtml']).'<br>';
|
|
} else {
|
|
print $langs->trans($val).'<br>';
|
|
}
|
|
}
|
|
|
|
print '</td></tr>';
|
|
|
|
print '</tr>';
|
|
|
|
print '</table>';
|
|
print '</div>';
|
|
|
|
|
|
print '<br><br>';
|
|
|
|
|
|
print '<!-- Link to pay -->';
|
|
print '<span class="fas fa-external-link-alt" style=""></span> <span class="opacitymedium">'.$langs->trans("DebugTools").'</span><br>';
|
|
print '<br>';
|
|
|
|
$urlforceregistration = DOL_MAIN_URL_ROOT.'/index.php?forceregistration=1';
|
|
print $langs->trans("URLToForceRegistration").'<br>';
|
|
print '<div class="urllink"><input type="text" id="forceregistration" spellcheck="false" class="quatrevingtpercentminusx" value="'.$urlforceregistration.'"><a class="" href="'.$urlforceregistration.'" target="_blank" rel="noopener noreferrer"><span class="fas fa-external-link-alt paddingleft" style=""></span></a></div>';
|
|
print ajax_autoselect('forceregistration');
|
|
|
|
print '<br>';
|
|
|
|
/*
|
|
$urlforcepushcounter = DOL_MAIN_URL_ROOT.'/index.php?forcepushcounter=1';
|
|
print $langs->trans("URLToForcePushOfBlockedLogCounter").'<br>';
|
|
print '<div class="urllink"><input type="text" id="forcepushcounter" spellcheck="false" class="quatrevingtpercentminusx" value="'.$urlforcepushcounter.'"><a class="" href="'.$urlforcepushcounter.'" target="_blank" rel="noopener noreferrer"><span class="fas fa-external-link-alt paddingleft" style=""></span></a></div>';
|
|
print ajax_autoselect('forcepushcounter');
|
|
*/
|
|
|
|
$urltogetkeyobfuscation = DOL_MAIN_URL_ROOT.'/blockedlog/admin/blockedlog.php?forcegetkeyobfuscation=1&token='.newToken();
|
|
print $langs->trans("URLToGetObfuscationkey").'<br>';
|
|
print '<div class="urllink"><input type="text" id="forcegetkeyobfuscation" spellcheck="false" class="quatrevingtpercentminusx" value="'.$urltogetkeyobfuscation.'"><a class="reposition" href="'.$urltogetkeyobfuscation.'" target="_blank" rel="noopener noreferrer"><span class="fas fa-external-link-alt paddingleft" style=""></span></a></div>';
|
|
print ajax_autoselect('forcegetkeyobfuscation');
|
|
|
|
if (GETPOST('forcegetkeyobfuscation')) {
|
|
unset($_SESSION['hmac_secret_key']);
|
|
unset($conf->cache['hmac_secret_key']);
|
|
|
|
$block_static->entity = $conf->entity;
|
|
|
|
$hmac_encoded_secret_key = '';
|
|
try {
|
|
$hmac_encoded_secret_key = $block_static->getEncodedHMACSecretKey();
|
|
print "\n<!-- READ TO GET HMAC KEY RETURNED result: ".$hmac_encoded_secret_key." -->\n";
|
|
} catch (Exception $e) {
|
|
print '<div class="error">'.$e->getMessage().'</div>';
|
|
}
|
|
|
|
$obfuscationkey = '';
|
|
try {
|
|
$obfuscationkey = $block_static->getObfuscationKey(); // Note: use the $mysoc->idprof1 and $registrationnumber. On network trouble, an Exception is thrown to the caller
|
|
print "\n<!-- API TO GET REMOTE OBFUSCATION KEY RETURNED result: ".$obfuscationkey." -->\n";
|
|
} catch (Exception $e) {
|
|
print '<div class="error">'.$e->getMessage().'</div>';
|
|
}
|
|
|
|
// Now test the keyfor debug purpose..
|
|
|
|
// 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('/^BLOCKEDLOGHMAC/', (string) $hmac_secret_key)) {
|
|
print '<!-- Failed to decode the encoded HMAC key using the remote obfuscation 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).
|
|
// 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('blockedlog.php 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.');
|
|
print '<!-- HMAC key can t be decoded -->';
|
|
} else { // $hmac_secret_key start with 'BLOCKEDLOGHMAC...' so it is a valid value
|
|
print '<!-- Success to decode HMAC key. It is encrypted with an old obfuscation method, we migrate it. -->';
|
|
print '<!-- '.$hmac_secret_key.' -->';
|
|
if ($obfuscationkey) {
|
|
$result = $block_static->saveHMACSecretKey($hmac_secret_key, 'dolobfuscationv1-'.$mysoc->idprof1, $obfuscationkey); // gitleaks:allow Save the HMAC key
|
|
print '<!-- Result to save the new HMAC key: '.$result.' -->';
|
|
}
|
|
}
|
|
} else {
|
|
print '<!-- Success to decode HMAC key from the remote obfuscation key, nothing to do more -->';
|
|
}
|
|
}
|
|
|
|
|
|
if ($withtab) {
|
|
print dol_get_fiche_end();
|
|
}
|
|
|
|
print '<br><br>';
|
|
|
|
// End of page
|
|
llxFooter();
|
|
$db->close();
|