| Current Path : /home/echanges/www/administrator/components/com_watchfulli/classes/ |
| Current File : /home/echanges/www/administrator/components/com_watchfulli/classes/integrity.php |
<?php
/**
* @version admin/classes/integrity.php 2024-03-27 zanardigit
* @package Watchful Client
* @author Watchful
* @authorUrl https://watchful.net
* @copyright Copyright (c) 2012-2025 Watchful
* @license GNU/GPL v3 or later
*/
defined('_JEXEC') or die('Restricted access');
class WatchfulliIntegrity extends WatchfulliAuditProcess
{
/**
* Compare the hashes of the core files
*/
public function auditJoomlaCoreIntegrity(int $start): stdClass
{
$helper = new WatchfulliHelper();
$data = $this->cache->get(['WatchfulliConnection', 'getHash']);
$current = $start;
$file_path = null;
$result = new stdClass();
$result->wrong = []; // files with wrong checksums
$result->missing = []; // files missing
$result->skipped = []; // files skipped
$result->size = count($data);
$result->start = $start;
while ($this->haveTime() && $current < count($data))
{
$file_path = $data[$current][0];
$file_officialHash = $data[$current][1];
$full_path = JPATH_SITE . '/' . $file_path;
if (empty($file_path))
{
$current++;
continue;
}
list($status, $file_hash) = $this->checkIntegrityFile($full_path, $file_officialHash, $helper->getMemoryLimitInBytes());
if ($status <> 'ok')
{
$result->$status[] = ['path' => '/' . $file_path, 'hash' => $file_hash];
}
$current++;
}
$result->lastFileChecked = $file_path;
$result->end = $current;
return $result;
}
/**
* Compare known non-core files against protected core directories
*/
public function auditJoomlaProtectedCoreDirectories(int $start): stdClass
{
$structure = $this->cache->get(['WatchfulliRecursiveListing', 'getStructure'], [JPATH_SITE]);
$hashes = $this->cache->get(['WatchfulliConnection', 'getHash']);
$nonCoreFiles = $this->cache->get(['WatchfulliRecursiveListing', 'getNonCoreFiles'], [$structure, $hashes]);
$file_path = null;
$data = $this->cache->get(['WatchfulliConnection', 'getProtectedCoreDirectories']);
$current = $start;
$result = new stdClass();
$result->extra = []; // files that should not be there
$result->size = count($nonCoreFiles);
$result->start = $start;
while ($this->haveTime() && $current < count($nonCoreFiles))
{
$file_path = $nonCoreFiles[$current];
// at most (J 3.x) this list should be no longer than 175
foreach ($data as $dir)
{
// if the directory is the start of the path, it's a match
if (0 === strpos($file_path, $dir))
{
$result->extra[] = $file_path;
break;
}
}
}
$result->lastFileChecked = $file_path;
$result->end = $current;
return $result;
}
/**
* Compare the md5 hash of a file with a reference
*/
private function checkIntegrityFile(string $full_path, string $file_officialHash, int $memory_limit): array
{
if (!file_exists($full_path))
{
return ['missing', null];
}
$memory_usage = memory_get_usage();
$file_size = filesize($full_path);
// let's hope the file can be read
$memoryNeeded = $memory_usage + $file_size;
if ($memoryNeeded > $memory_limit)
{
return ['skipped', null];
}
// does this file have a wrong checksum ?
$file_hash = md5_file($full_path);
if ($file_hash != $file_officialHash)
{
return ['wrong', $file_hash];
}
return ['ok', $file_hash];
}
}