Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
238 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,107 @@ | |||
<?php | |||
|
|||
/** | |||
* This file is part of the Latte (https://latte.nette.org) | |||
* Copyright (c) 2008 David Grudl (https://davidgrudl.com) | |||
*/ | |||
|
|||
declare(strict_types=1); | |||
|
|||
namespace Latte\Sandbox; | |||
|
|||
use Latte; | |||
|
|||
|
|||
class Policy implements Latte\Policy | |||
{ | |||
use Latte\Strict; | |||
|
|||
public const ALL = ['*']; | |||
|
|||
/** @var string[] */ | |||
private $macros = []; | |||
|
|||
/** @var string[] */ | |||
private $filters = []; | |||
|
|||
/** @var string[] */ | |||
private $functions = []; | |||
|
|||
/** @var string[][] */ | |||
private $methods = []; | |||
|
|||
/** @var string[][] */ | |||
private $properties = []; | |||
|
|||
|
|||
public function allowMacros(array $macros): void | |||
{ | |||
$this->macros += array_flip(array_map('strtolower', $macros)); | |||
} | |||
|
|||
|
|||
public function allowFilters(array $filters): void | |||
{ | |||
$this->filters += array_flip(array_map('strtolower', $filters)); | |||
} | |||
|
|||
|
|||
public function allowFunctions(array $functions): void | |||
{ | |||
$this->functions += array_flip(array_map('strtolower', $functions)); | |||
} | |||
|
|||
|
|||
public function allowMethods(string $class, array $methods): void | |||
{ | |||
$this->methods[$class] = array_flip(array_map('strtolower', $methods)); | |||
} | |||
|
|||
|
|||
public function allowProperties(string $class, array $properties): void | |||
{ | |||
$this->properties[$class] = array_flip(array_map('strtolower', $properties)); | |||
} | |||
|
|||
|
|||
public function isMacroAllowed(string $macro): bool | |||
{ | |||
return isset($this->macros[strtolower($macro)]) || isset($this->macros['*']); | |||
} | |||
|
|||
|
|||
public function isFilterAllowed(string $filter): bool | |||
{ | |||
return isset($this->filters[strtolower($filter)]) || isset($this->filters['*']); | |||
} | |||
|
|||
|
|||
public function isFunctionAllowed(string $function): bool | |||
{ | |||
return isset($this->functions[strtolower($function)]) || isset($this->functions['*']); | |||
} | |||
|
|||
|
|||
public function isMethodAllowed(string $class, string $method): bool | |||
{ | |||
$method = strtolower($method); | |||
foreach ($this->methods as $c => $methods) { | |||
if (is_a($class, $c, true) && (isset($methods[$method]) || isset($methods['*']))) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
|
|||
|
|||
public function isPropertyAllowed(string $class, string $property): bool | |||
{ | |||
$property = strtolower($property); | |||
foreach ($this->properties as $c => $properties) { | |||
if (is_a($class, $c, true) && (isset($properties[$property]) || isset($properties['*']))) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,131 @@ | |||
<?php | |||
|
|||
declare(strict_types=1); | |||
|
|||
use Tester\Assert; | |||
|
|||
|
|||
require __DIR__ . '/../bootstrap.php'; | |||
|
|||
|
|||
$latte = new Latte\Engine; | |||
$latte->setLoader(new Latte\Loaders\StringLoader); | |||
$policy = new Latte\Sandbox\Policy; | |||
$latte->setPolicy($policy); | |||
$latte->setSandboxMode(); | |||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->compile('{$abc}'); | |||
}, Latte\CompileException::class, 'Macro {=} is not allowed.'); | |||
|
|||
$policy->allowMacros(['=']); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->compile('{$abc}'); | |||
}); | |||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->compile('{var $abc}'); | |||
}, Latte\CompileException::class, 'Macro {var} is not allowed.'); | |||
|
|||
$policy->allowMacros($policy::ALL); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->compile('{var $abc}'); | |||
}); | |||
|
|||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->compile('{$abc|upper}'); | |||
}, Latte\CompileException::class, 'Filter |upper is not allowed.'); | |||
|
|||
$policy->allowFilters(['UppeR']); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->compile('{$abc|upper}'); | |||
}); | |||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->compile('{$abc|lower}'); | |||
}, Latte\CompileException::class, 'Filter |lower is not allowed.'); | |||
|
|||
$policy->allowFilters($policy::ALL); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->compile('{$abc|lower}'); | |||
}); | |||
|
|||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->compile('{trim(123)}'); | |||
}, Latte\CompileException::class, 'Function trim() is not allowed.'); | |||
|
|||
$policy->allowFunctions(['tRim']); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->compile('{trim(123)}'); | |||
$latte->renderToString('{="trim"(123)}'); | |||
}); | |||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->compile('{ltrim(123)}'); | |||
}, Latte\CompileException::class, 'Function ltrim() is not allowed.'); | |||
|
|||
$policy->allowFunctions($policy::ALL); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->compile('{ltrim(123)}'); | |||
}); | |||
|
|||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->renderToString('{=$obj->format("u")}', ['obj' => new DateTime]); | |||
}, Latte\SecurityViolation::class, 'Calling DateTime::format() is not allowed.'); | |||
|
|||
$policy->allowMethods('dAtetime', ['fOrmat']); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->renderToString('{=$obj->format("u")}', ['obj' => new DateTime]); | |||
}); | |||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->renderToString('{=$obj->getTimestamp()}', ['obj' => new DateTime]); | |||
}, Latte\SecurityViolation::class, 'Calling DateTime::getTimestamp() is not allowed.'); | |||
|
|||
$policy->allowMethods('dAtetime', $policy::ALL); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->renderToString('{=$obj->getTimestamp()}', ['obj' => new DateTime]); | |||
}); | |||
|
|||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->renderToString('{=$obj->format("u")}', ['obj' => new DateTimeImmutable]); | |||
}, Latte\SecurityViolation::class, 'Calling DateTimeImmutable::format() is not allowed.'); | |||
|
|||
$policy->allowMethods('DateTimeInterface', ['fOrmat']); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->renderToString('{=$obj->format("u")}', ['obj' => new DateTimeImmutable]); | |||
}); | |||
|
|||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->renderToString('{=$obj->prop}', ['obj' => (object) ['prop' => 123]]); | |||
}, Latte\SecurityViolation::class, "Access to 'prop' property on a stdClass object is not allowed."); | |||
|
|||
$policy->allowProperties('sTdClass', ['pRop']); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->renderToString('{=$obj->prop}', ['obj' => (object) ['prop' => 123]]); | |||
}); | |||
|
|||
Assert::exception(function () use ($latte) { | |||
$latte->renderToString('{=$obj->prop2}', ['obj' => (object) []]); | |||
}, Latte\SecurityViolation::class, "Access to 'prop2' property on a stdClass object is not allowed."); | |||
|
|||
$policy->allowProperties('sTdClass', $policy::ALL); | |||
|
|||
Assert::noError(function () use ($latte) { | |||
$latte->renderToString('{=$obj->prop2}', ['obj' => (object) ['prop2' => 123]]); | |||
}); |