Allow partial overrides in subfolders (#4652)

* Allow partial overrides in subfolders + security checker
This commit is contained in:
Tobias Kündig 2019-12-14 02:22:30 +01:00 committed by Samuel Georges
parent 6277f9b44c
commit 80f870c313
3 changed files with 60 additions and 10 deletions

View File

@ -107,6 +107,10 @@ class ComponentPartial extends Extendable implements CmsObjectContract
$partial = Partial::loadCached($theme, $component->alias . '/' . $fileName);
}
if ($partial !== null) {
static::ensureValidPartialPath($partial->getFileName(), $partial->getFilePath(), null);
}
return $partial;
}
@ -160,19 +164,36 @@ class ComponentPartial extends Extendable implements CmsObjectContract
*/
protected function validateFileName($fileName)
{
if (!FileHelper::validatePath($fileName, $this->maxNesting)) {
throw new ApplicationException(Lang::get('cms::lang.cms_object.invalid_file', [
'name' => $fileName
]));
}
if (!strlen(File::extension($fileName))) {
$fileName .= '.'.$this->defaultExtension;
}
static::ensureValidPartialPath($fileName, $this->getFilePath($fileName), $this->maxNesting);
return $fileName;
}
/**
* Ensures that a partial path is valid and local to the application.
*
* @param string $fileName
* @param $realpath
* @param int $maxNesting
*
* @return bool
* @throws ApplicationException
*/
protected static function ensureValidPartialPath($fileName, $realpath, $maxNesting = 2)
{
if (FileHelper::validatePath($fileName, $maxNesting) && FileHelper::validateIsLocalFile($realpath)) {
return true;
}
throw new ApplicationException(Lang::get('cms::lang.cms_object.invalid_file', [
'name' => $fileName,
]));
}
/**
* Returns the file content.
* @return string

View File

@ -24,6 +24,7 @@ use System\Classes\CombineAssets;
use System\Twig\Extension as SystemTwigExtension;
use October\Rain\Exception\AjaxException;
use October\Rain\Exception\ValidationException;
use October\Rain\Exception\ApplicationException;
use October\Rain\Parse\Bracket as TextParser;
use Illuminate\Http\RedirectResponse;
@ -996,15 +997,20 @@ class Controller
/*
* Check if the theme has an override
*/
if (strpos($partialName, '/') === false) {
$partial = ComponentPartial::loadOverrideCached($this->theme, $componentObj, $partialName);
}
$partial = ComponentPartial::loadOverrideCached($this->theme, $componentObj, $partialName);
/*
* Check the component partial
*/
if ($partial === null) {
$partial = ComponentPartial::loadCached($componentObj, $partialName);
try {
$partial = ComponentPartial::loadCached($componentObj, $partialName);
} catch (ApplicationException $e) {
if ($throwException) {
throw $e;
}
return false;
}
}
if ($partial === null) {

View File

@ -1,5 +1,8 @@
<?php namespace Cms\Helpers;
use Config;
use File as Filesystem;
/**
* Defines some file-system helpers for the CMS system.
*
@ -68,4 +71,24 @@ class File
return true;
}
/**
* Validates a CMS object path is inside the application's base directory.
* @param string $filePath Specifies a path to validate
* @return boolean Returns true if the file path is local. Otherwise returns false.
*/
public static function validateIsLocalFile($filePath)
{
$restrictBaseDir = Config::get('cms.restrictBaseDir', true);
if ($restrictBaseDir && !Filesystem::isLocalPath($filePath)) {
return false;
}
if (!$restrictBaseDir && realpath($filePath) === false) {
return false;
}
return true;
}
}