Validate identifiers and file paths

This commit is contained in:
root 2022-11-27 18:19:05 +01:00
parent 607f3d8159
commit 571c24e5b7

View File

@ -55,12 +55,6 @@ class JsonDatabase implements IJsonUnflattener
}
}
private function migrate()
{
// TODO: This is a stub
// Make this function migrate between different settings
}
private function getObjectPath($class, $name, ?int $time = null)
{
$retPath = $this->storagePath;
@ -75,6 +69,10 @@ class JsonDatabase implements IJsonUnflattener
$segments = array_filter(explode('\\', $class));
for ($i = 0; $i < count($segments); $i++) {
$segments[$i] = JsonDatabase::SanitizeIdentifier($segments[$i]);
}
if ($this->fullDomain)
$retPath .= DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $segments);
else
@ -92,15 +90,24 @@ class JsonDatabase implements IJsonUnflattener
public function load(string $class, string $name, ?int $timestamp = null): JsonSerializable|null
{
// TODO: Do some basic validation of class and name to
// avoid path traversal and make sure a class is specified
// This is really fucking important, implement it, or don't and watch someone use your code
// and get their production machine hacked
if ($class == null || empty(trim($name)))
return null;
if ($name != null && !empty(trim(strval($name))))
$name = JSONDatabase::SanitizeIdentifier($name);
else
return null;
$class = trim($class);
if (!$this->audit && $timestamp != null)
return null;
$objPath = $this->getObjectPath($class, $name, ($timestamp != null));
if (strlen($objPath) > PHP_MAXPATHLEN)
return null;
if (!is_file($objPath))
return null;
@ -115,22 +122,29 @@ class JsonDatabase implements IJsonUnflattener
return JsonSerializable::Deserialize($json, $this->nested, $this, $class);
}
public function save(JsonSerializable $obj, string $name = null)
public function save(JsonSerializable $obj, ?string $name = null)
{
if ($name == null || empty(trim(strval($name))))
if ($name != null && !empty(trim($name))) {
$name = JSONDatabase::SanitizeIdentifier($name);
} else {
if ($obj instanceof IJsonIdentifiable)
$name = $obj->flatIdentifier() ?? uniqid();
$name = JSONDatabase::SanitizeIdentifier($obj->flatIdentifier() ?? uniqid());
else
$name = uniqid();
$name = JSONDatabase::SanitizeIdentifier($name);
}
$objPath = $this->getObjectPath(get_class($obj), $name);
if (strlen($objPath) > PHP_MAXPATHLEN)
throw new Exception('JsonDatabase: Specified Path ' . $objPath . ' is longer than allowed.');
$objJson = $obj->Serialize(nested: $this->nested, to_array: false);
if ($this->audit)
{
$historyPath = $this->getObjectPath(get_class($obj), $name, time());
if (strlen($historyPath) > PHP_MAXPATHLEN)
throw new Exception('JsonDatabase: Specified Path ' . $objPath . ' is longer than allowed.');
// For Historic files we always save the whole Object Tree since
// dependencies might have different timestamps
// and resolving that would be annoying
@ -149,8 +163,15 @@ class JsonDatabase implements IJsonUnflattener
return $name;
}
/**
* Restore a JsonSerializable from the Database by using it's Identifier reference.
* @param string $className the full class name with domain of the JsonSerializable property
* @param $identifer The identifier that uniquely identifies the object
* @return JsonSerializable|null
*/
public function unflattenByID(string $className, $identifier) : JsonSerializable | null
{
// Fetch JsonSerializable Object from Database using given Identifier
return $this->load($className, strval($identifier));
}
}