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