diff --git a/htdocs/blockedlog/admin/blockedlog_archives.php b/htdocs/blockedlog/admin/blockedlog_archives.php index 0c498bd6249..486711e67c4 100644 --- a/htdocs/blockedlog/admin/blockedlog_archives.php +++ b/htdocs/blockedlog/admin/blockedlog_archives.php @@ -751,92 +751,222 @@ print "\n"; if ($action == 'check' || $action == 'checkconfirmed') { print '
'; - print '
'; + print '
'; print ''.$langs->trans("File").' : '.GETPOST('urlfile').'
'; $fullpath = $upload_dir.'/'.GETPOST('urlfile'); + $handle = fopen($fullpath, "r"); $line = fgets($handle); fclose($handle); $reg = array(); $period = ''; + $formatexport = ''; if (preg_match('/\speriod=([^\s]+)/', $line, $reg)) { $period = $reg[1]; // Get period on first line } if (preg_match('/\sregnumber=([^\s]+)/', $line, $reg)) { $regnumber = str_replace(array('.', '…'), '', $reg[1]); // Get period on first line } + if (preg_match('/\sformatexport=([^\s]+)/', $line, $reg)) { + $formatexport = $reg[1]; // Get export format (VE1, VE2...) + } print ''.$langs->trans("Period").' : '.$period.'
'; + print '
'; + + $registrationnumber = getHashUniqueIdOfRegistration(); $secretkey = $registrationnumber; + // Prepare to create a temporary file + $fullpathtmp = $upload_dir.'/tmp/'.GETPOST('urlfile').'.tmp'; + + dol_mkdir($upload_dir.'/tmp'); + $result = dol_copy($fullpath, $fullpathtmp); + + // Generate tmp file content without the last line + // TODO Move this into removeLastLine() function into files.lib.php + $fp = fopen($fullpathtmp, "r"); + fseek($fp, -1, SEEK_END); + $pos = -1; + $char = fgetc($fp); + while ($char === "\n" || $char === "\r") { // Go to last real char of last line + fseek($fp, $pos--, SEEK_END); + $char = fgetc($fp); + } + while ($char !== "\n" && $char !== false) { + fseek($fp, $pos--, SEEK_END); + $char = fgetc($fp); + } + /* + while ($char === "\n" || $char === "\r") { // Go to last real char of last-1 line + fseek($fp, $pos--, SEEK_END); + $char = fgetc($fp); + } + */ + $truncatePos = ftell($fp); + fclose($fp); + // Truncate the tmp file to remove the last line + $fp = fopen($fullpathtmp, "c+"); + ftruncate($fp, $truncatePos); + fclose($fp); + + print $langs->trans("FileHasBeenEncodedWithASecretKeyStartingWith").' : '.$regnumber.'...
'; if (preg_match('/^'.$regnumber.'/', $secretkey)) { - print 'As this matches the 10 first characters of the full registration number of this instance, we will use this full registration number to control the archive file...'; + print 'As this matches the 10 first characters of the full registration number of this instance, we will use the full registration number to control the archive file...'; } else { print 'This archive file was not generated by this instance. The control of authenticity is possible only if you know the full registration number.'; print ''; } - print '
'; - print ''.$langs->trans("ControlFile").''; + print '

'; + print '
'.$langs->trans("ControlFile").'
'; //'; + print '
'; + if ($action == 'checkconfirmed') { - // TODO - - print '

'; - print 'File integrity: '.img_picto('', 'tick').'
'; - print 'File authenticity: '.img_picto('', 'tick').'
'; - print 'Detection of database restoration or not allowed line deletion in period: This feature is available only from www.dolibarr.org/onlinecheckarchive.php
'; - $totalamount = array( 'BILL_VALIDATE' => 0, 'PAYMENT_CUSTOMER_CREATE' => 0 ); + $reg = array(); + $refinvoicefound = array(); + $recalculatedhashsign = ''; + $recalculatedhashauth = ''; + $hashsign = ''; + $hashauth = ''; + $algosign = ''; + $algoauth = ''; - foreach ($totalamount as $key => $totalamountperref) { - if ($key == 'BILL_VALIDATE' || $key == 'PAYMENT_CUSTOMER_CREATE') { - $totalhttoshow = 0; - foreach ($totalhtamount[$key] as $value) { // Loop on each module - $totalhttoshow += $value; - } - $totalvattoshow = 0; - foreach ($totalvatamount[$key] as $value) { - $totalvattoshow += $value; - } - $totaltoshow = 0; - foreach ($totalamountperref as $value) { - $totaltoshow += $value; - } + $handle = fopen($fullpath, "r"); + if ($handle) { + $numline=0; + while ($line = fgetcsv($handle, 10000, ';', '"', '')) { + $numline++; - print ''.dolPrintHTML($langs->trans("TotalForAction").' '.$langs->trans('log'.$key)).': '; + $linetech = $linerowid = $linedatecreation = $lineactioncode = $lineorigin = ''; + $lineamountht = $lineamountttc = 0; + $lineref = $linedate = $lineuser = $linelinkto = $linelinktype = $linecontent = ''; + $lineversiondoli = $lineversionsign = $linesignaturedb = $linesignatureexport = ''; - if ($key == 'PAYMENT_CUSTOMER_CREATE') { - print price($totaltoshow); + if ($formatexport == 'VE1') { + $linetech = $line[0]; + $linerowid = $line[1]; + $linedatecreation = $line[2]; + $lineactioncode = $line[3]; + $lineorigin = $line[4]; + $lineamountht = $line[5]; + $lineamountttc = $line[6]; + $lineref = $line[7]; + $linedate = $line[8]; + $lineuser = $line[9]; + $linelinkto = $line[10]; + $linelinktype = $line[11]; + $linecontent = $line[12]; + $lineversiondoli = $line[13]; + $lineversionsign = $line[14]; + $linesignaturedb = $line[15]; + $linesignatureexport = $line[16]; } else { - print $langs->trans("HT").': '; - print price($totalhttoshow); - - print ' - '; - - print $langs->trans("VAT").': '; - print price($totalvattoshow); - - print ' - '; - - print $langs->trans("TTC").': '; - print price($totaltoshow); + print 'Line '.$numline.' has format '.$formatexport.' that is not supported'; + } + + if ($lineactioncode == 'BILL_VALIDATE' || $lineactioncode == 'PAYMENT_CUSTOMER_CREATE') { + // For action = BILL_VALIDATE, we keep only first invoice found, but this should not happen because edition of invoice is never possible on + // certified version and very difficult on other version. + if ($lineactioncode != 'BILL_VALIDATE' || empty($refinvoicefound[$lineref])) { + $totalhtamount[$lineactioncode] += $lineamountht; + $totalvatamount[$lineactioncode] += ($lineamountttc - $lineamountht); + $totalamount[$lineactioncode] += $lineamountttc; + } + if ($lineactioncode == 'BILL_VALIDATE') { + $refinvoicefound[$lineref] = 1; + } + } + + if (preg_match('/END - ([a-z0-9_]+)=([a-z0-9]+) - ([a-z0-9_]+)=([a-z0-9]+)$/', $linetech, $reg)) { + $algosign=$reg[1]; + $hashsign=$reg[2]; + $algoauth=$reg[3]; + $hashauth=$reg[4]; + + if ($algosign == 'sha256') { + $algo = 'sha256'; + $recalculatedhashsign = hash_file($algo, $fullpathtmp); + } + if ($algoauth == 'hmac_sha256') { + $algo = 'sha256'; + $recalculatedhashauth = hash_hmac_file($algo, $fullpathtmp, $secretkey); + } } - print '
'; } + fclose($handle); + } else { + print 'Failed to open file '.GETPOST('urlfile'); + } + + print '

'; + print ''.$langs->trans("FileIntegrity").': '; + if ($recalculatedhashsign && $recalculatedhashsign == $hashsign) { + print img_picto('', 'tick', 'class="valignmiddle"'); + print ' '.$form->textwithpicto('', $algosign.' = '.$recalculatedhashsign); + } else { + print img_picto('', 'cross', 'class="error valignmiddle"'); + print ' '.$form->textwithpicto('', $langs->trans("FileHasBeenCorrupted").'
Recalculated '.$recalculatedhashsign.' != Found in file '.$hashsign); + } + print '

'; + + print ''.$langs->trans("FileAuthenticity").': '; + if ($recalculatedhashauth && $recalculatedhashauth == $hashauth) { + print img_picto('', 'tick', 'class="valignmiddle"'); + print ' - '.$langs->trans("FileWasGeneratedByThisInstance").''; + print ' '.$form->textwithpicto('', $algoauth.' = '.$recalculatedhashauth); + } elseif ($recalculatedhashsign == $hashsign) { + print img_picto('', 'cross', 'class="error valignmiddle"'); + print ' '.$form->textwithpicto('', $langs->trans("FileNotFromInstance").'

Recalculated '.$recalculatedhashauth.' != Found in file '.$hashauth); + } else { + print img_picto('', 'cross', 'class="error valignmiddle"'); + print ' '.$form->textwithpicto('', $langs->trans("FileHasBeenCorruptedOrNotFromInstance").'

Recalculated '.$recalculatedhashauth.' != Found in file '.$hashauth); + } + print '

'; + + print 'Detection of database restoration or not allowed line deletion in period: '; + print 'This feature is for the moment available only from https://www.dolibarr.org/onlinecheckarchive.php
'; + print '
'; + + $arraykeys = array('BILL_VALIDATE', 'PAYMENT_CUSTOMER_CREATE'); + foreach ($arraykeys as $key) { + $totalhttoshow = $totalhtamount[$key]; + $totalvattoshow = $totalvatamount[$key]; + $totaltoshow = $totalamount[$key]; + + print ''.dolPrintHTML($langs->trans("TotalForAction").' '.$langs->trans('log'.$key)).': '; + + if ($key == 'PAYMENT_CUSTOMER_CREATE') { + print price($totaltoshow); + } else { + print $langs->trans("HT").': '; + print price($totalhttoshow); + + print ' - '; + + print $langs->trans("VAT").': '; + print price($totalvattoshow); + + print ' - '; + + print $langs->trans("TTC").': '; + print price($totaltoshow); + } + print '

'; } } - print '
'; print '

'; print '
'.$langs->trans("BackToList").'
'; diff --git a/htdocs/langs/en_US/blockedlog.lang b/htdocs/langs/en_US/blockedlog.lang index 3c14a5a2975..6d6bc896a69 100644 --- a/htdocs/langs/en_US/blockedlog.lang +++ b/htdocs/langs/en_US/blockedlog.lang @@ -30,8 +30,8 @@ ListOfTrackedEvents=List of tracked events Fingerprint=Signature FingerprintInBlockedLog=Signature in Unalterable Log table FingerprintDatabase=Signature in database -FingerprintExport=Signature export -FingerprintExportHMAC=Signature export HMAC +FingerprintExport=Signature of export +FingerprintExportHMAC=Signature of export HMAC DownloadLogCSV=Export unalterable logs (CSV) DataOfArchivedEvent=Complete data of archived event DataOfArchivedEventHelp=This field contains the complementary data that was archived on real time. Even if some parent business event could have been canceled or modified, the data stored here is the original data, and it can't be modified. @@ -89,7 +89,13 @@ MAIN_INFO_ITPROVIDER_TOWN=IT supplier town RegistrationDoneAndModuleEnabled=The new registration information have been saved and registered. The module %s is enabled. UserRegistration=User registration RegistrationRequired=Registration expected -FileHasBeenEncodedWithASecretKeyStartingWith=The archive file content says it has been encoded with a secret key starting with +FileHasBeenEncodedWithASecretKeyStartingWith=The archive file content says it has been signed with a secret key starting with +FileIntegrity=File integrity +FileAuthenticity=File authenticity +FileWasGeneratedByThisInstance=File was generated by this instance +FileHasBeenCorrupted=The file integrity is wrong. It may have been altered (by a disk problem or manual corruption). +FileHasBeenCorruptedOrNotFromInstance=The file integrity/authenticity is wrong. File may have been altered (by a disk problem or a manual corruption. +FileNotFromInstance=The file integrity seems good but authenticity is wrong. File has not been generated by this instance. ## logTypes logBILL_DELETE=Customer invoice logically deleted @@ -122,7 +128,7 @@ DebugInfo=Debug info PreviousFingerprint=Previous signature PaymentOf=Payment of ReplacedBy=Replaced by -VersionSignature=Version signature +VersionSignature=Version of signature DebugTools=Debug tools URLToForceRegistration=URL to force the registration URLToForcePushOfBlockedLogCounter=URL to force the push of the last unalterable record counter diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 8b34b14386f..586db46dc84 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -883,7 +883,7 @@ input#onlinepaymenturl, input#directdownloadlink { background: #efefef; /* background: #f3f3f3; */ - padding: 20px 0px 20px 0px; + padding: 20px 20px 20px 20px; border-radius: 8px; } diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 7021f659400..3aa25c49b94 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1046,7 +1046,7 @@ input#onlinepaymenturl, input#directdownloadlink { .formconsumeproduce { background: #f0f0f0; - padding: 20px 0px 20px 0px; + padding: 20px 20px 20px 20px; border-radius: 8px; }