Move algo for checksum file

This commit is contained in:
Laurent Destailleur 2025-12-22 04:52:12 +01:00
parent a6d1b2235e
commit 8db3a2e4fc
8 changed files with 90 additions and 64 deletions

View file

@ -284,11 +284,12 @@ repos:
(dev/build/perl/virtualmin/dolibarr.pl
)$
args: [ --tabs, --nola ]
- repo: https://github.com/henryykt/pre-commit-perl
rev: v0.0.5
hooks:
- id: perlcritic
# virtualmin excuded - reason https://github.com/Dolibarr/dolibarr/pull/36370#issuecomment-3565101823
exclude: (?x)^
(dev/build/perl/virtualmin/dolibarr.pl
)$
#- repo: https://github.com/henryykt/pre-commit-perl
# rev: v0.0.5
# hooks:
# - id: perlcritic
# # virtualmin excluded - reason https://github.com/Dolibarr/dolibarr/pull/36370#issuecomment-3565101823
# exclude: (?x)^
# (dev/build/perl/virtualmin/dolibarr.pl
# )$

View file

@ -7,3 +7,4 @@
/dolibarr-*.zip
/*.exe
/html
/makepack-dolibarr.pl.bak

View file

@ -40,6 +40,8 @@ if (substr($sapi_type, 0, 3) == 'cgi') {
define('DOL_DOCUMENT_ROOT', dirname(dirname($path)).'/htdocs');
$algo = 'sha256';
require_once $path."../../htdocs/master.inc.php";
require_once DOL_DOCUMENT_ROOT."/core/lib/files.lib.php";
@ -231,7 +233,7 @@ if ($release) {
$gitcommit = trim($fileforgitcontent);
fputs($fp, '<?xml version="1.0" encoding="UTF-8" ?>'."\n");
fputs($fp, '<checksum_list version="'.$release.'" date="'.dol_print_date(dol_now(), 'dayhourrfc').'" generator="'.$script_file.'" gitcommit="'.$gitcommit.'">'."\n");
fputs($fp, '<checksum_list version="'.$release.'" date="'.dol_print_date(dol_now(), 'dayhourrfc').'" generator="'.$script_file.'" algo="'.$algo.'" gitcommit="'.$gitcommit.'">'."\n");
foreach ($includeconstants as $countrycode => $tmp) {
fputs($fp, '<dolibarr_constants country="'.$countrycode.'">'."\n");
@ -265,9 +267,9 @@ if ($release) {
$needtoclose = 1;
}
if (filetype($file) == "file") {
$md5 = md5_file($file);
$checksumconcat[] = $md5;
fputs($fp, ' <md5file name="'.basename($file).'" size="'.filesize($file).'">'.$md5.'</md5file>'."\n");
$hashoffile = hash_file($algo, $file);
$checksumconcat[] = $hashoffile;
fputs($fp, ' <'.$algo.'file name="'.basename($file).'" size="'.filesize($file).'">'.$hashoffile.'</'.$algo.'file>'."\n");
}
}
if ($needtoclose) {
@ -277,10 +279,10 @@ if ($release) {
fputs($fp, '</dolibarr_htdocs_dir>'."\n");
asort($checksumconcat); // Sort list of checksum
$md5htdocsdir = md5(join(',', $checksumconcat));
$hashhtdocsdir = hash($algo, join(',', $checksumconcat));
fputs($fp, '<dolibarr_htdocs_dir_checksum>'."\n");
fputs($fp, $md5htdocsdir."\n");
fputs($fp, $hashhtdocsdir."\n");
fputs($fp, '</dolibarr_htdocs_dir_checksum>'."\n\n");
@ -308,9 +310,9 @@ if ($release) {
$needtoclose = 1;
}
if (filetype($file) == "file") {
$md5 = md5_file($file);
$checksumconcat[] = $md5;
fputs($fp, ' <md5file name="'.basename($file).'" size="'.filesize($file).'">'.$md5.'</md5file>'."\n");
$hashoffile = hash_file($algo, $file);
$checksumconcat[] = $hashoffile;
fputs($fp, ' <'.$algo.'file name="'.basename($file).'" size="'.filesize($file).'">'.$hashoffile.'</'.$algo.'file>'."\n");
}
}
if ($needtoclose) {
@ -320,10 +322,10 @@ if ($release) {
fputs($fp, '</dolibarr_scripts_dir>'."\n");
asort($checksumconcat); // Sort list of checksum
$md5scriptsdir = md5(join(',', $checksumconcat));
$hashscriptsdir = hash($algo, join(',', $checksumconcat));
fputs($fp, '<dolibarr_scripts_dir_checksum>'."\n");
fputs($fp, $md5scriptsdir."\n");
fputs($fp, $hashscriptsdir."\n");
fputs($fp, '</dolibarr_scripts_dir_checksum>'."\n\n");
}
@ -371,10 +373,10 @@ foreach ($arrayofunalterablefiles as $entry) {
$needtoclose = 1;
}
if (filetype($file) == "file") {
$md5 = md5_file($file);
$checksumconcat[] = $md5;
$hashoffile = hash_file($algo, $file);
$checksumconcat[] = $hashoffile;
if ($release) {
fputs($fp, ' <md5file name="'.basename($file).'" size="'.filesize($file).'">'.$md5.'</md5file>'."\n");
fputs($fp, ' <'.$algo.'file name="'.basename($file).'" size="'.filesize($file).'">'.$hashoffile.'</'.$algo.'file>'."\n");
}
}
}
@ -407,10 +409,10 @@ foreach ($arrayofunalterablefiles as $entry) {
$needtoclose = 1;
}
if (filetype($file) == "file") {
$md5 = md5_file($file);
$checksumconcat[] = $md5;
$hashoffile = hash_file($algo, $file);
$checksumconcat[] = $hashoffile;
if ($release) {
fputs($fp, ' <md5file name="'.basename($file).'" size="'.filesize($file).'">'.$md5.'</md5file>'."\n");
fputs($fp, ' <'.$algo.'file name="'.basename($file).'" size="'.filesize($file).'">'.$hashoffile.'</'.$algo.'file>'."\n");
}
}
if ($needtoclose) {
@ -423,13 +425,13 @@ foreach ($arrayofunalterablefiles as $entry) {
}
asort($checksumconcat); // Sort list of checksum
$md5unalterable_files = md5(join(',', $checksumconcat));
$hashunalterable_files = hash($algo, join(',', $checksumconcat));
if ($release) {
fputs($fp, '</dolibarr_unalterable_files>'."\n");
fputs($fp, '<dolibarr_unalterable_files_checksum>'."\n");
fputs($fp, $md5unalterable_files."\n");
fputs($fp, $hashunalterable_files."\n");
fputs($fp, '</dolibarr_unalterable_files_checksum>'."\n\n");
// End of file
@ -443,9 +445,9 @@ print "\n";
if ($release) {
if (empty($buildzip)) {
print "File ".$outputfile." generated.\n";
print "Signature for htdocs files: ".$md5htdocsdir."\n";
print "Signature for scripts files: ".$md5scriptsdir."\n";
print "Signature for the ".count($checksumconcat)." unalterable files: ".$md5unalterable_files."\n";
print "Signature for htdocs files: ".$hashhtdocsdir."\n";
print "Signature for scripts files: ".$hashscriptsdir."\n";
print "Signature for the ".count($checksumconcat)." unalterable files: ".$hashunalterable_files."\n";
} else {
if ($buildzip == '1' || $buildzip == 'zip') {
$result = dol_compress_file($outputfile, $outputfile.'.zip', 'zip');
@ -464,7 +466,7 @@ if ($release) {
}
if ($checklock) {
print "Signature for unalterable files: ".$md5unalterable_files."\n";
print "Signature for unalterable files: ".$algo." ".$hashunalterable_files."\n";
$lockedfile = DOL_DOCUMENT_ROOT.'/../dev/lockedfiles.txt';
$checksuminlockedfile = '';
@ -475,15 +477,15 @@ if ($checklock) {
// Now we check the content of lockedfiles.txt
$arraylocked = file($lockedfile);
foreach ($arraylocked as $line) {
$tmparray = preg_split("/\s+/", $line, 3);
if ($tmparray[0] == $checklockmajorversion) {
$checksuminlockedfile = $tmparray[2];
$tmparray = preg_split("/\s+/", $line, 4);
if ($tmparray[0] == $checklockmajorversion && $tmparray[2] == $algo) {
$checksuminlockedfile = $tmparray[3];
}
}
if (empty($checksuminlockedfile)) {
print "The major version ".$checklockmajorversion." is not locked on the scope ".$checksource." (file found but no matching entry found into dev/lockedfiles.txt).\n";
} elseif ($checksuminlockedfile != $md5unalterable_files) {
print "The major version ".$checklockmajorversion." is locked on scope '".$checksource."' to checksum ".$checksuminlockedfile."\n";
print "The major version ".$checklockmajorversion." is not locked on the scope '".$checksource."' (file found but no matching entry found into dev/lockedfiles.txt).\n";
} elseif ($checksuminlockedfile != $hashunalterable_files) {
print "The major version ".$checklockmajorversion." is locked on scope '".$checksource."' to checksum ".$algo." ".$checksuminlockedfile."\n";
if ($checklockmajorversion != $checksource) {
print "The checksum now differs from the locked one, so we return an error.\n";
print "\n";

View file

@ -14,7 +14,7 @@
#----------------------------------------------------------------------------
## no critic (InputOutput::ProhibitExplicitStdin,InputOutput::RequireBriefOpen)
use strict;
#use strict;
use warnings;
use Cwd;
use Term::ANSIColor;

View file

@ -2,6 +2,6 @@
This file is the list of the signatures of some set of files locked to block a commit if files are tried to be modified for a given version.
It is used by the CI or the script to check and guarantee that no change is done on a given scope of files.
Version Scope Signature (generated by dev/build/generate_filelist_xml.php) that must remain unchanged for this couple version/scope
Version Scope Algo Signature (generated by dev/build/generate_filelist_xml.php) that must remain unchanged for this couple version/scope
x.0.0 unalterable_files 123456
23.0.0 unalterable_files sha256 123456

View file

@ -233,6 +233,9 @@ if (empty($error) && !empty($xml)) {
$file_list = array();
$out = '';
//$algo = 'md5'; // For v22-
$algo = 'sha256'; // For v23+
// Forced constants
if (is_object($xml->dolibarr_constants[0]) || $mode == 'unalterable') {
$out .= load_fiche_titre($langs->trans("ForcedConstants"));
@ -349,6 +352,7 @@ if (empty($error) && !empty($xml)) {
$onlymodifiedorremoved = 0;
}
// Scan htdocs
if (is_object($listoffilestoanalyze)) {
// @phan-suppress-next-line PhanTypeArraySuspicious
@ -361,15 +365,15 @@ if (empty($error) && !empty($xml)) {
// Fill file_list with files in signature, new files, modified files
getFilesUpdated($file_list, $listoffilestoanalyze, '', DOL_DOCUMENT_ROOT, $checksumconcat); // Fill array $file_list
'@phan-var-force array{insignature:string[],missing?:array<array{filename:string,expectedmd5:string,expectedsize:string}>,updated:array<array{filename:string,expectedmd5:string,expectedsize:string,md5:string}>} $file_list';
'@phan-var-force array{insignature:string[],missing?:array<array{filename:string,expectedhash:string,expectedsize:string,algo:string}>,updated:array<array{filename:string,expectedhash:string,expectedsize:string,hash:string,algo:string}>} $file_list';
// Complete with list of new files into $file_list['added']
if ($onlymodifiedorremoved) {
if (empty($onlymodifiedorremoved)) {
foreach ($scanfiles as $valfile) {
$tmprelativefilename = preg_replace('/^'.preg_quote(DOL_DOCUMENT_ROOT, '/').'/', '', $valfile['fullname']);
if (!in_array($tmprelativefilename, $file_list['insignature'])) {
$md5newfile = @md5_file($valfile['fullname']); // Can fails if we don't have permission to open/read file
$file_list['added'][] = array('filename' => $tmprelativefilename, 'md5' => $md5newfile);
$hashnewfile = @hash_file($algo, $valfile['fullname']); // Can fails if we don't have permission to open/read file
$file_list['added'][] = array('filename' => $tmprelativefilename, 'hash' => $hashnewfile, 'algo' => $algo);
}
}
}
@ -398,7 +402,7 @@ if (empty($error) && !empty($xml)) {
$out .= dol_print_size((int) $file['expectedsize']);
}
$out .= '</td>'."\n";
$out .= '<td class="center">'.dol_escape_htmltag($file['expectedmd5']).'</td>'."\n";
$out .= '<td class="center">'.dol_escape_htmltag($file['expectedhash']).'</td>'."\n";
$out .= "</tr>\n";
}
} else {
@ -432,8 +436,8 @@ if (empty($error) && !empty($xml)) {
$out .= '<tr class="oddeven">';
$out .= '<td>'.$i.'</td>'."\n";
$out .= '<td>'.dol_escape_htmltag($file['filename']).'</td>'."\n";
$out .= '<td class="center">'.dol_escape_htmltag($file['expectedmd5']).'</td>'."\n";
$out .= '<td class="center">'.dol_escape_htmltag($file['md5']).'</td>'."\n";
$out .= '<td class="center">'.dol_escape_htmltag($file['expectedhash']).'</td>'."\n";
$out .= '<td class="center">'.dol_escape_htmltag($file['hash']).'</td>'."\n";
$out .= '<td class="right">';
if ($file['expectedsize']) {
$out .= dol_print_size((int) $file['expectedsize']);
@ -490,8 +494,8 @@ if (empty($error) && !empty($xml)) {
$out .= ' '.$form->textwithpicto('', $htmltext, 1, 'help', '', 0, 2, 'helprm'.$i);
}
$out .= '</td>'."\n";
$out .= '<td class="center">'.dol_escape_htmltag((string) $file['expectedmd5']).'</td>'."\n"; // @phan-suppress-current-line PhanTypeInvalidDimOffset
$out .= '<td class="center">'.dol_escape_htmltag($file['md5']).'</td>'."\n";
$out .= '<td class="center">'.dol_escape_htmltag((string) $file['expectedhash']).'</td>'."\n"; // @phan-suppress-current-line PhanTypeInvalidDimOffset
$out .= '<td class="center">'.dol_escape_htmltag($file['hash']).'</td>'."\n";
$size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
$totalsize += $size;
$out .= '<td class="right">'.dol_print_size($size).'</td>'."\n";
@ -525,14 +529,14 @@ if (empty($error) && !empty($xml)) {
if (is_object($xml->dolibarr_scripts_dir[0])) {
$file_list = array();
$ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', ???, $checksumconcat); // Fill array $file_list
'@phan-var-force array{insignature:string[],missing?:array<array{filename:string,expectedmd5:string,expectedsize:string}>,updated:array<array{filename:string,expectedmd5:string,expectedsize:string,md5:string}>} $file_list';
'@phan-var-force array{insignature:string[],missing?:array<array{filename:string,expectedhash:string,expectedsize:string,algo:string}>,updated:array<array{filename:string,expectedhash:string,expectedsize:string,hash:string,algo:string}>} $file_list';
}*/
// Section Globalchecksum
asort($checksumconcat); // Sort list of checksum
$checksumget = md5(implode(',', $checksumconcat));
$checksumget = hash($algo, implode(',', $checksumconcat));
if ($mode == 'unalterable') {
$nameofsection = 'dolibarr_unalterable_files_checksum';
@ -585,7 +589,16 @@ if (empty($error) && !empty($xml)) {
$outforlistoffiles .= '<textarea id="listofunalterablefiles" class="hideobject quatrevingtpercent" rows="12">';
$i = 0;
foreach ($listoffilestoanalyze as $dirtoanalyze) {
foreach ($dirtoanalyze->md5file as $filetoanalyze) {
$entry = array();
if (!empty($dirtoanalyze->md5file)) {
$entry = $dirtoanalyze->md5file;
$algo = 'md5';
} elseif (!empty($dirtoanalyze->sha256file)) {
$entry = $dirtoanalyze->sha256file;
$algo = 'sha256';
}
foreach ($entry as $filetoanalyze) {
if ($i) {
$outforlistoffiles .= "\n";
}

View file

@ -3875,12 +3875,12 @@ function dirbasename($pathfile)
* Function to get list of updated or modified files.
* $file_list is used as global variable
*
* @param array{}|array{insignature:string[],missing?:array<array{filename:string,expectedmd5:string,expectedsize:string}>,updated:array<array{filename:string,expectedmd5:string,expectedsize:string,md5:string}>} $file_list Array for response
* @param array{}|array{insignature:string[],missing?:array<array{filename:string,expectedhash:string,expectedsize:string,algo:string}>,updated:array<array{filename:string,expectedhash:string,expectedsize:string,hash:string,algo:string}>} $file_list Array for response
* @param SimpleXMLElement $dir SimpleXMLElement of files to test
* @param string $path Path of files relative to $pathref. We start with ''. Used by recursive calls.
* @param string $pathref Path ref (DOL_DOCUMENT_ROOT)
* @param string[] $checksumconcat Array of checksum
* @return array{insignature:string[],missing?:array<array{filename:string,expectedmd5:string,expectedsize:string}>,updated:array<array{filename:string,expectedmd5:string,expectedsize:string,md5:string}>} $file_list Array of filenames
* @return array{insignature:string[],missing?:array<array{filename:string,expectedhash:string,expectedsize:string,algo:string}>,updated:array<array{filename:string,expectedhash:string,expectedsize:string,hash:string,algo:string}>} $file_list Array of filenames
*/
function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
{
@ -3888,24 +3888,33 @@ function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathre
//$exclude = 'install';
foreach ($dir->md5file as $file) { // $file is a simpleXMLElement
$entry = array();
if (!empty($dir->md5file)) {
$entry = $dir->md5file;
$algo = 'md5';
} elseif (!empty($dir->sha256file)) {
$entry = $dir->sha256file;
$algo = 'sha256';
}
foreach ($entry as $file) { // $file is a simpleXMLElement
$filename = $path.$file['name'];
$file_list['insignature'][] = $filename;
$expectedsize = (empty($file['size']) ? '' : $file['size']);
$expectedmd5 = (string) $file;
$expectedhash = (string) $file;
if (!file_exists($pathref.'/'.$filename)) {
$file_list['missing'][] = array('filename' => $filename, 'expectedmd5' => $expectedmd5, 'expectedsize' => $expectedsize);
$file_list['missing'][] = array('filename' => $filename, 'expectedhash' => $expectedhash, 'expectedsize' => $expectedsize, 'algo' => (string) $algo);
} else {
$md5_local = md5_file($pathref.'/'.$filename);
$hash_local = hash_file($algo, $pathref.'/'.$filename);
if ($conffile == '/etc/dolibarr/conf.php' && $filename == '/filefunc.inc.php') { // For install with deb or rpm, we ignore test on filefunc.inc.php that was modified by package
$checksumconcat[] = $expectedmd5;
$checksumconcat[] = $expectedhash;
} else {
if ($md5_local != $expectedmd5) {
$file_list['updated'][] = array('filename' => $filename, 'expectedmd5' => $expectedmd5, 'expectedsize' => $expectedsize, 'md5' => (string) $md5_local);
if ($hash_local != $expectedhash) {
$file_list['updated'][] = array('filename' => $filename, 'expectedhash' => $expectedhash, 'expectedsize' => $expectedsize, 'hash' => (string) $hash_local, 'algo' => (string) $algo);
}
$checksumconcat[] = $md5_local;
$checksumconcat[] = $hash_local;
}
}
}

View file

@ -16,7 +16,7 @@ FileCheck=Fileset integrity check
FileCheckDesc=This tool checks the integrity of your files and application setup by comparing each file with the official version. It also verifies certain setup constants. Use this tool to detect if any files have been modified (e.g., by a hacker).
FileIntegrityIsStrictlyConformedWithReference=File integrity strictly matches the reference.
FileIntegrityIsOkButFilesWereAdded=File integrity check passed, but some new files were added.
FileIntegrityIsKO=File integrity check failed, some files were modified or removed. See the detail lower...
FileIntegrityIsKO=The check of file integrity has failed, some files were modified or removed. See the detail lower...
FileIntegritySomeFilesWereRemovedOrModified=File integrity check failed: some files were modified, removed, or added.
GlobalChecksum=Global checksum
MakeIntegrityAnalysisFrom=Perform integrity analysis of application files from
@ -26,7 +26,7 @@ FilesMissing=Missing files
FilesUpdated=Updated files
FilesModified=Modified files
FilesAdded=Added files
FileCheckDolibarr=Check application file integrity
FileCheckDolibarr=Check integrity of the application files
AvailableOnlyOnPackagedVersions=Local integrity file is only available for packaged installations. Use the remote signature if unavailable.
XmlNotFound=Application XML integrity file not found
SessionId=Session ID