fs: improve sanitization
Signed-off-by: Varun Patil <radialapps@gmail.com>pull/888/head
parent
73cc86c4a1
commit
f69765a42a
|
@ -72,6 +72,7 @@ class ArchiveController extends GenericApiController
|
||||||
$fileStorageId = $file->getStorage()->getId();
|
$fileStorageId = $file->getStorage()->getId();
|
||||||
$parent = $file->getParent();
|
$parent = $file->getParent();
|
||||||
$isArchived = false;
|
$isArchived = false;
|
||||||
|
$depth = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
/** @psalm-suppress DocblockTypeContradiction */
|
/** @psalm-suppress DocblockTypeContradiction */
|
||||||
if (null === $parent) {
|
if (null === $parent) {
|
||||||
|
@ -98,12 +99,17 @@ class ArchiveController extends GenericApiController
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hit an archive folder root
|
// Hit an archive folder root
|
||||||
if ($parent->getName() === \OCA\Memories\Util::$ARCHIVE_FOLDER) {
|
if (Util::ARCHIVE_FOLDER === $parent->getName()) {
|
||||||
$isArchived = true;
|
$isArchived = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Too deep
|
||||||
|
if (++$depth > 32) {
|
||||||
|
throw new \Exception('[Archive] Max recursion depth exceeded');
|
||||||
|
}
|
||||||
|
|
||||||
$parent = $parent->getParent();
|
$parent = $parent->getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,8 +139,10 @@ class ArchiveController extends GenericApiController
|
||||||
$parent = $parent->getParent();
|
$parent = $parent->getParent();
|
||||||
} else {
|
} else {
|
||||||
// file not in archive, put it in there
|
// file not in archive, put it in there
|
||||||
$af = \OCA\Memories\Util::$ARCHIVE_FOLDER;
|
$destinationPath = Util::sanitizePath(Util::ARCHIVE_FOLDER.$relativeFilePath);
|
||||||
$destinationPath = Util::sanitizePath($af.$relativeFilePath);
|
if (null === $destinationPath) {
|
||||||
|
throw Exceptions::BadRequest('Invalid archive destination path');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the filename
|
// Remove the filename
|
||||||
|
|
|
@ -189,10 +189,11 @@ class PublicController extends AuthPublicShareController
|
||||||
$foldersPath = Util::sanitizePath('/'.$foldersPath.'/');
|
$foldersPath = Util::sanitizePath('/'.$foldersPath.'/');
|
||||||
|
|
||||||
// Check if relPath starts with foldersPath
|
// Check if relPath starts with foldersPath
|
||||||
if (!str_starts_with($relPath, $foldersPath)) {
|
if (empty($foldersPath) || !str_starts_with($relPath, $foldersPath)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var string $foldersPath */
|
||||||
// Remove foldersPath from start of relPath
|
// Remove foldersPath from start of relPath
|
||||||
$relPath = substr($relPath, \strlen($foldersPath));
|
$relPath = substr($relPath, \strlen($foldersPath));
|
||||||
|
|
||||||
|
|
|
@ -114,14 +114,16 @@ class FsManager
|
||||||
|
|
||||||
try {
|
try {
|
||||||
foreach ($paths as $path) {
|
foreach ($paths as $path) {
|
||||||
$node = $userFolder->get(Util::sanitizePath($path));
|
if ($sanitized = Util::sanitizePath($path)) {
|
||||||
$root->addFolder($node);
|
$node = $userFolder->get($sanitized);
|
||||||
$etag .= $node->getEtag();
|
$root->addFolder($node);
|
||||||
|
$etag .= $node->getEtag();
|
||||||
|
} else {
|
||||||
|
throw new \Exception("invalid path {$path}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (\OCP\Files\NotFoundException $e) {
|
} catch (\Exception $e) {
|
||||||
$msg = $e->getMessage();
|
throw new \Exception("Folder not found: {$e->getMessage()}");
|
||||||
|
|
||||||
throw new \Exception("Folder not found: {$msg}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add shares or external stores inside the current folders
|
// Add shares or external stores inside the current folders
|
||||||
|
|
19
lib/Util.php
19
lib/Util.php
|
@ -18,7 +18,7 @@ class Util
|
||||||
{
|
{
|
||||||
use UtilController;
|
use UtilController;
|
||||||
|
|
||||||
public static string $ARCHIVE_FOLDER = '.archive';
|
public const ARCHIVE_FOLDER = '.archive';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get host CPU architecture (amd64 or aarch64).
|
* Get host CPU architecture (amd64 or aarch64).
|
||||||
|
@ -336,20 +336,27 @@ class Util
|
||||||
?: self::getSystemConfig('memories.timeline.default_path');
|
?: self::getSystemConfig('memories.timeline.default_path');
|
||||||
|
|
||||||
return array_map(
|
return array_map(
|
||||||
static fn ($p) => self::sanitizePath(trim($p)),
|
static fn ($path) => self::sanitizePath(trim($path))
|
||||||
|
?? throw new \InvalidArgumentException("Invalid timeline path: {$path}"),
|
||||||
explode(';', $paths),
|
explode(';', $paths),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanitize a path to keep only ASCII characters and special characters.
|
* Sanitize a path to keep only ASCII characters and special characters.
|
||||||
* Blank will be returned on error.
|
* Null will be returned on error.
|
||||||
*/
|
*/
|
||||||
public static function sanitizePath(string $path): string
|
public static function sanitizePath(string $path): ?string
|
||||||
{
|
{
|
||||||
$path = str_replace("\0", '', $path); // remove null characters
|
// remove double slashes and such
|
||||||
|
$normalized = \OC\Files\Filesystem::normalizePath($path, false);
|
||||||
|
|
||||||
return mb_ereg_replace('\/\/+', '/', $path) ?: ''; // remove extra slashes
|
// look for invalid characters and pattern
|
||||||
|
if (!\OC\Files\Filesystem::isValidPath($normalized)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue