mirror of
https://github.com/e107inc/e107.git
synced 2025-08-05 22:27:34 +02:00
Rewrote e_file_inspector validation constants
Now uses bit flags, as the previous approach of "overriding" the validation code may hide information. Previously, e_file_inspector::VALIDATION_FAIL could be overridden by e_file_inspector::VALIDATION_OLD. Now, e_file_inspector::VALIDATED_HASH and e_file_inspector::VALIDATED_UPTODATE provides information about both.
This commit is contained in:
@@ -16,77 +16,81 @@ require_once("e_file_inspector_interface.php");
|
||||
*/
|
||||
abstract class e_file_inspector implements e_file_inspector_interface
|
||||
{
|
||||
/**
|
||||
* Check the integrity of the provided path
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @param $version string The desired software release to match.
|
||||
* Leave blank for the current version.
|
||||
* Do not prepend the version number with "v".
|
||||
* @return int Validation code (see the constants of this class)
|
||||
*/
|
||||
public function validate($path, $version = null)
|
||||
{
|
||||
if ($version === null) $version = $this->getCurrentVersion();
|
||||
$absolutePath = realpath($path);
|
||||
$actualChecksum = $this->checksumPath($absolutePath);
|
||||
$dbChecksum = $this->getChecksum($path, $version);
|
||||
private $validatedBitmask;
|
||||
|
||||
if ($dbChecksum === false) return self::VALIDATION_IGNORE;
|
||||
if (!file_exists($absolutePath)) return self::VALIDATION_MISSING;
|
||||
if ($this->isInsecure($path)) return self::VALIDATION_INSECURE;
|
||||
if ($actualChecksum === false) return self::VALIDATION_INCALCULABLE;
|
||||
if ($actualChecksum === $dbChecksum) return self::VALIDATION_PASS;
|
||||
|
||||
foreach ($this->getChecksums($path) as $dbVersion => $dbChecksum)
|
||||
{
|
||||
if (version_compare($dbVersion, $version, ">=")) continue;
|
||||
|
||||
if ($dbChecksum === $actualChecksum) return self::VALIDATION_OLD;
|
||||
}
|
||||
|
||||
return self::VALIDATION_FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file integrity hash for the provided path and version
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @param $version string The software release version corresponding to the file hash.
|
||||
* Leave blank for the current version.
|
||||
* Do not prepend the version number with "v".
|
||||
* @return string|bool The database hash for the path and version specified. FALSE if the record does not exist.
|
||||
*/
|
||||
public function getChecksum($path, $version = null)
|
||||
{
|
||||
/**
|
||||
* Check the integrity of the provided path
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @param $version string The desired software release to match.
|
||||
* Leave blank for the current version.
|
||||
* Do not prepend the version number with "v".
|
||||
* @return int Validation code (see the constants of this class)
|
||||
*/
|
||||
public function validate($path, $version = null)
|
||||
{
|
||||
if ($version === null) $version = $this->getCurrentVersion();
|
||||
$checksums = $this->getChecksums($path);
|
||||
return isset($checksums[$version]) ? $checksums[$version] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hash of a path to compare with the hash database
|
||||
*
|
||||
* @param $absolutePath string Absolute path of the file to hash
|
||||
* @return string|bool The actual hash for the path. FALSE if the hash was incalculable.
|
||||
*/
|
||||
public function checksumPath($absolutePath)
|
||||
{
|
||||
if (!is_file($absolutePath) || !is_readable($absolutePath)) return false;
|
||||
$bits = 0x0;
|
||||
$absolutePath = realpath(e_BASE . $path);
|
||||
$actualChecksum = $this->checksumPath($absolutePath);
|
||||
$dbChecksum = $this->getChecksum($path, $version);
|
||||
|
||||
return $this->checksum(file_get_contents($absolutePath));
|
||||
}
|
||||
if ($dbChecksum !== false) $bits |= self::VALIDATED_RELEVANCE;
|
||||
if (file_exists($absolutePath)) $bits |= self::VALIDATED_PRESENCE;
|
||||
if (!$this->isInsecure($path)) $bits |= self::VALIDATED_SECURITY;
|
||||
if ($actualChecksum !== false) $bits |= self::VALIDATED_DETERMINABLE;
|
||||
if ($actualChecksum === $dbChecksum) $bits |= self::VALIDATED_UPTODATE;
|
||||
|
||||
/**
|
||||
* Calculate the hash of a string, which would be used to compare with the hash database
|
||||
*
|
||||
* @param $content string Full content to hash
|
||||
* @return string
|
||||
*/
|
||||
public function checksum($content)
|
||||
{
|
||||
return md5(str_replace(array(chr(13),chr(10)), "", $content));
|
||||
}
|
||||
foreach ($this->getChecksums($path) as $dbVersion => $dbChecksum)
|
||||
{
|
||||
if ($dbChecksum === $actualChecksum) $bits |= self::VALIDATED_HASH;
|
||||
}
|
||||
|
||||
if ($bits + 0x1 === $this->getValidatedBitmask()) $bits |= self::VALIDATED;
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file integrity hash for the provided path and version
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @param $version string The software release version corresponding to the file hash.
|
||||
* Leave blank for the current version.
|
||||
* Do not prepend the version number with "v".
|
||||
* @return string|bool The database hash for the path and version specified. FALSE if the record does not exist.
|
||||
*/
|
||||
public function getChecksum($path, $version = null)
|
||||
{
|
||||
if ($version === null) $version = $this->getCurrentVersion();
|
||||
$checksums = $this->getChecksums($path);
|
||||
return isset($checksums[$version]) ? $checksums[$version] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hash of a path to compare with the hash database
|
||||
*
|
||||
* @param $absolutePath string Absolute path of the file to hash
|
||||
* @return string|bool The actual hash for the path. FALSE if the hash was incalculable.
|
||||
*/
|
||||
public function checksumPath($absolutePath)
|
||||
{
|
||||
if (!is_file($absolutePath) || !is_readable($absolutePath)) return false;
|
||||
|
||||
return $this->checksum(file_get_contents($absolutePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the hash of a string, which would be used to compare with the hash database
|
||||
*
|
||||
* @param $content string Full content to hash
|
||||
* @return string
|
||||
*/
|
||||
public function checksum($content)
|
||||
{
|
||||
return md5(str_replace(array(chr(13), chr(10)), "", $content));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
@@ -108,22 +112,22 @@ abstract class e_file_inspector implements e_file_inspector_interface
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the matching version of the provided path
|
||||
*
|
||||
* Useful for looking up the versions of old files that no longer exist in the latest image
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @return string|bool PHP-standardized version of the file. FALSE if there is no match.
|
||||
*/
|
||||
public function getVersion($path)
|
||||
{
|
||||
$actualChecksum = $this->checksumPath($path);
|
||||
foreach ($this->getChecksums($path) as $dbVersion => $dbChecksum)
|
||||
{
|
||||
if ($actualChecksum === $dbChecksum) return $dbVersion;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
* Get the matching version of the provided path
|
||||
*
|
||||
* Useful for looking up the versions of old files that no longer exist in the latest image
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @return string|bool PHP-standardized version of the file. FALSE if there is no match.
|
||||
*/
|
||||
public function getVersion($path)
|
||||
{
|
||||
$actualChecksum = $this->checksumPath($path);
|
||||
foreach ($this->getChecksums($path) as $dbVersion => $dbChecksum)
|
||||
{
|
||||
if ($actualChecksum === $dbChecksum) return $dbVersion;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
@@ -133,4 +137,18 @@ abstract class e_file_inspector implements e_file_inspector_interface
|
||||
# TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getValidatedBitmask()
|
||||
{
|
||||
if ($this->validatedBitmask !== null) return $this->validatedBitmask;
|
||||
$constants = (new ReflectionClass(self::class))->getConstants();
|
||||
$validated_constants = array_filter($constants, function ($key)
|
||||
{
|
||||
$str = 'VALIDATED_';
|
||||
return substr($key, 0, strlen($str)) === $str;
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
|
||||
$this->validatedBitmask = (max($validated_constants) << 0x1) - 0x1;
|
||||
return $this->validatedBitmask;
|
||||
}
|
||||
}
|
@@ -9,34 +9,41 @@
|
||||
|
||||
interface e_file_inspector_interface
|
||||
{
|
||||
/**
|
||||
* The file is present, and its hash matches the specified version.
|
||||
*/
|
||||
const VALIDATION_PASS = 1;
|
||||
/**
|
||||
* The file is present, but the hash does not match the specified version. VALIDATION_OLD takes precedence.
|
||||
*/
|
||||
const VALIDATION_FAIL = 2;
|
||||
/**
|
||||
* The file is absent, but a hash exists for the specified version.
|
||||
*/
|
||||
const VALIDATION_MISSING = 3;
|
||||
/**
|
||||
* The file is present, and its hash matches a version older than the specified version.
|
||||
*/
|
||||
const VALIDATION_OLD = 4;
|
||||
/**
|
||||
* A hash cannot be determined for the provided file.
|
||||
*/
|
||||
const VALIDATION_INCALCULABLE = 5;
|
||||
/**
|
||||
* The file is present, but it should be deleted due to security concerns
|
||||
*/
|
||||
const VALIDATION_INSECURE = 6;
|
||||
/**
|
||||
* The file, present or absent, is not in this database.
|
||||
*/
|
||||
const VALIDATION_IGNORE = 7;
|
||||
/**
|
||||
* TRUE: All validations pass for the provided file.
|
||||
* FALSE: One or more validations failed for the provided file.
|
||||
*/
|
||||
const VALIDATED = 1 << 0;
|
||||
/**
|
||||
* TRUE: The file path is known in this database, regardless of version.
|
||||
* FALSE: The file path is not in this database.
|
||||
*/
|
||||
const VALIDATED_RELEVANCE = 1 << 1;
|
||||
/**
|
||||
* TRUE: The file exists.
|
||||
* FALSE: The file doesn't exist.
|
||||
*/
|
||||
const VALIDATED_PRESENCE = 1 << 2;
|
||||
/**
|
||||
* TRUE: The file's hash matches a known version.
|
||||
* FALSE: The file's hash does not match any known versions.
|
||||
*/
|
||||
const VALIDATED_HASH = 1 << 3;
|
||||
/**
|
||||
* TRUE: The file's hash matches the specified version.
|
||||
* FALSE: The file's hash matches a newer or older version than the one specified.
|
||||
*/
|
||||
const VALIDATED_UPTODATE = 1 << 4;
|
||||
/**
|
||||
* TRUE: The file hash is calculable.
|
||||
* FALSE: The file hash is not calculable (e.g. the core image itself, a user configuration file).
|
||||
*/
|
||||
const VALIDATED_DETERMINABLE = 1 << 5;
|
||||
/**
|
||||
* TRUE: The file is not known to be insecure.
|
||||
* FALSE: The file should be deleted due to security concerns.
|
||||
*/
|
||||
const VALIDATED_SECURITY = 1 << 6;
|
||||
|
||||
/**
|
||||
* Return an Iterator that can enumerate every path in the image database
|
||||
@@ -45,22 +52,22 @@ interface e_file_inspector_interface
|
||||
*/
|
||||
public function getPathIterator();
|
||||
|
||||
/**
|
||||
* Get all the known file integrity hashes for the provided path
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @return array Associative array where the keys are the PHP-standardized versions and the values are the checksums
|
||||
* for those versions.
|
||||
*/
|
||||
public function getChecksums($path);
|
||||
/**
|
||||
* Get all the known file integrity hashes for the provided path
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @return array Associative array where the keys are the PHP-standardized versions and the values are the checksums
|
||||
* for those versions.
|
||||
*/
|
||||
public function getChecksums($path);
|
||||
|
||||
/**
|
||||
* List of versions of the provided path for which the database has hashes
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @return array PHP-standardized versions. Empty if there are none.
|
||||
*/
|
||||
public function getVersions($path);
|
||||
/**
|
||||
* List of versions of the provided path for which the database has hashes
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @return array PHP-standardized versions. Empty if there are none.
|
||||
*/
|
||||
public function getVersions($path);
|
||||
|
||||
/**
|
||||
* Get the version of the software that goes with this image database.
|
||||
@@ -72,11 +79,11 @@ interface e_file_inspector_interface
|
||||
*/
|
||||
public function getCurrentVersion();
|
||||
|
||||
/**
|
||||
* Check if the file is insecure
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @return bool TRUE if the file should be deleted due to known security flaws; FALSE otherwise
|
||||
*/
|
||||
public function isInsecure($path);
|
||||
/**
|
||||
* Check if the file is insecure
|
||||
*
|
||||
* @param $path string Relative path of the file to look up
|
||||
* @return bool TRUE if the file should be deleted due to known security flaws; FALSE otherwise
|
||||
*/
|
||||
public function isInsecure($path);
|
||||
}
|
@@ -9,33 +9,48 @@
|
||||
|
||||
class e_file_inspectorTest extends \Codeception\Test\Unit
|
||||
{
|
||||
/**
|
||||
* @var e_file_inspector_sqlphar
|
||||
*/
|
||||
private $e_integrity;
|
||||
/**
|
||||
* @var e_file_inspector_sqlphar
|
||||
*/
|
||||
private $e_integrity;
|
||||
|
||||
public function _before()
|
||||
{
|
||||
require_once(e_HANDLER."e_file_inspector_sqlphar.php");
|
||||
$this->e_integrity = new e_file_inspector_sqlphar();
|
||||
}
|
||||
public function _before()
|
||||
{
|
||||
require_once(e_HANDLER . "e_file_inspector_sqlphar.php");
|
||||
$this->e_integrity = new e_file_inspector_sqlphar();
|
||||
}
|
||||
|
||||
public function testGetChecksums()
|
||||
{
|
||||
$checksums = $this->e_integrity->getChecksums("e107_admin/e107_update.php");
|
||||
$this->assertIsArray($checksums);
|
||||
$this->assertNotEmpty($checksums);
|
||||
public function testGetChecksums()
|
||||
{
|
||||
$checksums = $this->e_integrity->getChecksums("e107_admin/e107_update.php");
|
||||
$this->assertIsArray($checksums);
|
||||
$this->assertNotEmpty($checksums);
|
||||
|
||||
$checksums = $this->e_integrity->getChecksums("e107_handlers/nonexistent.php");
|
||||
$this->assertIsArray($checksums);
|
||||
$this->assertEmpty($checksums);
|
||||
}
|
||||
$checksums = $this->e_integrity->getChecksums("e107_handlers/nonexistent.php");
|
||||
$this->assertIsArray($checksums);
|
||||
$this->assertEmpty($checksums);
|
||||
}
|
||||
|
||||
public function testGetCurrentVersion()
|
||||
public function testGetCurrentVersion()
|
||||
{
|
||||
$actualVersion = $this->e_integrity->getCurrentVersion();
|
||||
|
||||
$this->assertIsString($actualVersion);
|
||||
$this->assertNotEmpty($actualVersion);
|
||||
}
|
||||
|
||||
public function testValidate()
|
||||
{
|
||||
$result = $this->e_integrity->validate("index.php");
|
||||
$this->assertGreaterThanOrEqual(1, $result & e_file_inspector::VALIDATED);
|
||||
$this->assertGreaterThanOrEqual(1, $result & e_file_inspector::VALIDATED_RELEVANCE);
|
||||
$this->assertGreaterThanOrEqual(1, $result & e_file_inspector::VALIDATED_PRESENCE);
|
||||
$this->assertGreaterThanOrEqual(1, $result & e_file_inspector::VALIDATED_HASH);
|
||||
$this->assertGreaterThanOrEqual(1, $result & e_file_inspector::VALIDATED_UPTODATE);
|
||||
$this->assertGreaterThanOrEqual(1, $result & e_file_inspector::VALIDATED_DETERMINABLE);
|
||||
$this->assertGreaterThanOrEqual(1, $result & e_file_inspector::VALIDATED_SECURITY);
|
||||
|
||||
$result = $this->e_integrity->validate("file/does/not/exist.php");
|
||||
$this->assertEquals(0, $result & e_file_inspector::VALIDATED_PRESENCE);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user