1
0
mirror of https://github.com/e107inc/e107.git synced 2025-08-06 22:57:14 +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:
Nick Liu
2020-03-22 19:54:13 -05:00
parent 695774569c
commit 0494000356
3 changed files with 191 additions and 151 deletions

View File

@@ -16,6 +16,8 @@ require_once("e_file_inspector_interface.php");
*/ */
abstract class e_file_inspector implements e_file_inspector_interface abstract class e_file_inspector implements e_file_inspector_interface
{ {
private $validatedBitmask;
/** /**
* Check the integrity of the provided path * Check the integrity of the provided path
* *
@@ -28,24 +30,26 @@ abstract class e_file_inspector implements e_file_inspector_interface
public function validate($path, $version = null) public function validate($path, $version = null)
{ {
if ($version === null) $version = $this->getCurrentVersion(); if ($version === null) $version = $this->getCurrentVersion();
$absolutePath = realpath($path);
$bits = 0x0;
$absolutePath = realpath(e_BASE . $path);
$actualChecksum = $this->checksumPath($absolutePath); $actualChecksum = $this->checksumPath($absolutePath);
$dbChecksum = $this->getChecksum($path, $version); $dbChecksum = $this->getChecksum($path, $version);
if ($dbChecksum === false) return self::VALIDATION_IGNORE; if ($dbChecksum !== false) $bits |= self::VALIDATED_RELEVANCE;
if (!file_exists($absolutePath)) return self::VALIDATION_MISSING; if (file_exists($absolutePath)) $bits |= self::VALIDATED_PRESENCE;
if ($this->isInsecure($path)) return self::VALIDATION_INSECURE; if (!$this->isInsecure($path)) $bits |= self::VALIDATED_SECURITY;
if ($actualChecksum === false) return self::VALIDATION_INCALCULABLE; if ($actualChecksum !== false) $bits |= self::VALIDATED_DETERMINABLE;
if ($actualChecksum === $dbChecksum) return self::VALIDATION_PASS; if ($actualChecksum === $dbChecksum) $bits |= self::VALIDATED_UPTODATE;
foreach ($this->getChecksums($path) as $dbVersion => $dbChecksum) foreach ($this->getChecksums($path) as $dbVersion => $dbChecksum)
{ {
if (version_compare($dbVersion, $version, ">=")) continue; if ($dbChecksum === $actualChecksum) $bits |= self::VALIDATED_HASH;
if ($dbChecksum === $actualChecksum) return self::VALIDATION_OLD;
} }
return self::VALIDATION_FAIL; if ($bits + 0x1 === $this->getValidatedBitmask()) $bits |= self::VALIDATED;
return $bits;
} }
/** /**
@@ -85,7 +89,7 @@ abstract class e_file_inspector implements e_file_inspector_interface
*/ */
public function checksum($content) public function checksum($content)
{ {
return md5(str_replace(array(chr(13),chr(10)), "", $content)); return md5(str_replace(array(chr(13), chr(10)), "", $content));
} }
/** /**
@@ -133,4 +137,18 @@ abstract class e_file_inspector implements e_file_inspector_interface
# TODO # TODO
return false; 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;
}
} }

View File

@@ -10,33 +10,40 @@
interface e_file_inspector_interface interface e_file_inspector_interface
{ {
/** /**
* The file is present, and its hash matches the specified version. * TRUE: All validations pass for the provided file.
* FALSE: One or more validations failed for the provided file.
*/ */
const VALIDATION_PASS = 1; const VALIDATED = 1 << 0;
/** /**
* The file is present, but the hash does not match the specified version. VALIDATION_OLD takes precedence. * TRUE: The file path is known in this database, regardless of version.
* FALSE: The file path is not in this database.
*/ */
const VALIDATION_FAIL = 2; const VALIDATED_RELEVANCE = 1 << 1;
/** /**
* The file is absent, but a hash exists for the specified version. * TRUE: The file exists.
* FALSE: The file doesn't exist.
*/ */
const VALIDATION_MISSING = 3; const VALIDATED_PRESENCE = 1 << 2;
/** /**
* The file is present, and its hash matches a version older than the specified version. * TRUE: The file's hash matches a known version.
* FALSE: The file's hash does not match any known versions.
*/ */
const VALIDATION_OLD = 4; const VALIDATED_HASH = 1 << 3;
/** /**
* A hash cannot be determined for the provided file. * 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 VALIDATION_INCALCULABLE = 5; const VALIDATED_UPTODATE = 1 << 4;
/** /**
* The file is present, but it should be deleted due to security concerns * TRUE: The file hash is calculable.
* FALSE: The file hash is not calculable (e.g. the core image itself, a user configuration file).
*/ */
const VALIDATION_INSECURE = 6; const VALIDATED_DETERMINABLE = 1 << 5;
/** /**
* The file, present or absent, is not in this database. * TRUE: The file is not known to be insecure.
* FALSE: The file should be deleted due to security concerns.
*/ */
const VALIDATION_IGNORE = 7; const VALIDATED_SECURITY = 1 << 6;
/** /**
* Return an Iterator that can enumerate every path in the image database * Return an Iterator that can enumerate every path in the image database

View File

@@ -16,7 +16,7 @@ class e_file_inspectorTest extends \Codeception\Test\Unit
public function _before() public function _before()
{ {
require_once(e_HANDLER."e_file_inspector_sqlphar.php"); require_once(e_HANDLER . "e_file_inspector_sqlphar.php");
$this->e_integrity = new e_file_inspector_sqlphar(); $this->e_integrity = new e_file_inspector_sqlphar();
} }
@@ -38,4 +38,19 @@ class e_file_inspectorTest extends \Codeception\Test\Unit
$this->assertIsString($actualVersion); $this->assertIsString($actualVersion);
$this->assertNotEmpty($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);
}
} }