From 5eb44de02d65a1643b13dc3e338531d11ca7c64a Mon Sep 17 00:00:00 2001 From: Jansen Price Date: Wed, 9 Sep 2020 01:37:24 -0500 Subject: [PATCH] Handle correctly symlinked files in server content files --- src/Orbit/Module/Statics.php | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Orbit/Module/Statics.php b/src/Orbit/Module/Statics.php index a5e8772..4307c74 100644 --- a/src/Orbit/Module/Statics.php +++ b/src/Orbit/Module/Statics.php @@ -28,8 +28,8 @@ class Statics extends Module $resource_path = rtrim($real_root_dir, "/") . $request->path; // Check if within the server root - // Realpath will translate any '..' in the path - $realpath = realpath($resource_path); + // getAbsolutePath will translate any '..' in the path + $realpath = self::getAbsolutePath($resource_path); if ($realpath && strpos($realpath, $real_root_dir) !== 0) { $response->setStatus(Response::STATUS_PERMANENT_FAILURE); $response->setMeta("Invalid location"); @@ -165,4 +165,33 @@ class Statics extends Module { return (bool)(fileperms($file) & self::WORLD_READABLE); } + + /** + * Get an absolute path for a filename + * + * Translates .. and . to the real locations. The reason I am not using + * realpath() to do it is it resolves symlinks + * + * @param string $path + * @return string + */ + public static function getAbsolutePath($path): string + { + $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); + $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); + $absolutes = []; + + foreach ($parts as $part) { + if ('.' == $part) { + continue; + } + if ('..' == $part) { + array_pop($absolutes); + } else { + $absolutes[] = $part; + } + } + + return "/" . implode(DIRECTORY_SEPARATOR, $absolutes); + } }