Better Utils::normalizePath() logic #2216

This commit is contained in:
Andy Miller
2019-04-13 12:21:54 -06:00
parent dd134ad551
commit 40563ed2f8
3 changed files with 50 additions and 20 deletions

View File

@@ -1,3 +1,9 @@
# v1.6.4
## mm/dd/2019
1. [](#bugfix)
* Better logic in `Utils::normalizePath` to handle externals properly [#2216](https://github.com/getgrav/grav/issues/2216)
# v1.6.3
## 04/12/2019

View File

@@ -20,7 +20,9 @@ abstract class Utils
{
protected static $nonces = [];
protected const ROOTURL_REGEX = '{^(\/*)}';
protected const ROOTURL_REGEX = '{^((?:http[s]?:\/\/[^\/]+)|(?:\/\/[^\/]+))(.*)}';
// ^((?:http[s]?:)?[\/]?(?:\/))
/**
* Simple helper method to make getting a Grav URL easier
@@ -784,31 +786,43 @@ abstract class Utils
*/
public static function normalizePath($path)
{
if (Uri::isExternal($path)) {
return $path;
/** @var UniformResourceLocator $locator */
$locator = Grav::instance()['locator'];
if ($locator->isStream($path)) {
$path = $locator->findResource($path);
}
$root = '';
preg_match(self::ROOTURL_REGEX, $path, $matches);
if ($matches) {
$root = $matches[0];
$root = $matches[1];
$path = $matches[2];
}
$clean_path = static::replaceFirstOccurrence($root, '', $path);
$segments = explode('/', trim($clean_path, '/'));
$ret = [];
foreach ($segments as $segment) {
if (($segment === '.') || $segment === '') {
continue;
}
if ($segment === '..') {
array_pop($ret);
} else {
$ret[] = $segment;
}
if (Utils::startsWith($path,'/')) {
$root .= '/';
$path = ltrim($path, '/');
}
$normalized = $root . implode('/', $ret);
// $path = ltrim(static::replaceFirstOccurrence($root, '', $path), '/');
if (Utils::contains($path, '..')) {
$segments = explode('/', trim($path, '/'));
$ret = [];
foreach ($segments as $segment) {
if (($segment === '.') || $segment === '') {
continue;
}
if ($segment === '..') {
array_pop($ret);
} else {
$ret[] = $segment;
}
}
$path = implode('/', $ret);
}
$normalized = $root . $path;
return $normalized;
}

View File

@@ -224,9 +224,19 @@ class UtilsTest extends \Codeception\TestCase\Test
$this->assertEquals('test', Utils::normalizePath('../test'));
$this->assertEquals('/test', Utils::normalizePath('/../test'));
$this->assertEquals('/test2', Utils::normalizePath('/test/../test2'));
$this->assertEquals('/test/test2', Utils::normalizePath('/test/./test2'));
$this->assertEquals('/test3', Utils::normalizePath('/test/../test2/../test3'));
$this->assertEquals('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('//cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
$this->assertEquals('//use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/all.css'));
$this->assertEquals('//use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('//use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
$this->assertEquals('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('http://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
$this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/all.css'));
$this->assertEquals('http://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('http://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
$this->assertEquals('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css', Utils::normalizePath('https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css'));
$this->assertEquals('//something.com/../test/test2', Utils::normalizePath('//something.com/../test/test2'));
$this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/css/all.css', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/all.css'));
$this->assertEquals('https://use.fontawesome.com/releases/v5.8.1/webfonts/fa-brands-400.eot', Utils::normalizePath('https://use.fontawesome.com/releases/v5.8.1/css/../webfonts/fa-brands-400.eot'));
}
public function testIsFunctionDisabled()