diff --git a/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php b/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php index fe1f152..8d5034c 100644 --- a/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php +++ b/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Template; -use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Site\Settings; /** * Default sandbox policy for Twig templates. @@ -35,26 +35,44 @@ public function checkPropertyAllowed($obj, $property) {} public function checkMethodAllowed($obj, $method) { if ($obj instanceof Attribute) { // Allow any operations on the Attribute object as it is intended to be - // changed from a Twig template, for example calling addClass(). + // changed from a Twig template, for example calling addClass(). This + // cannot be overridden by settings.php. return TRUE; } - // Only allow idempotent methods to be called on objects. - $whitelist = [ - 'id' => TRUE, - 'label' => TRUE, - 'bundle' => TRUE, - 'get' => TRUE, - '__toString' => TRUE, - ]; - if (isset($whitelist[$method])) { + // Allow settings.php to override our default whitelisted methods and + // prefixes. + static $whitelisted_methods = NULL; + static $whitelisted_prefixes = NULL; + + if (is_null($whitelisted_methods) || is_null($whitelisted_prefixes)) { + $whitelisted_methods = Settings::get('twig_sandbox_whitelisted_methods') ?: [ + // Only allow idempotent methods. Note: using the form method_name => + // TRUE allows us to use isset() which is faster than in_array(). + 'id' => TRUE, + 'label' => TRUE, + 'bundle' => TRUE, + 'get' => TRUE, + '__toString' => TRUE, + ]; + $whitelisted_prefixes = Settings::get('twig_sandbox_whitelisted_prefixes') ?: [ + 'get', + 'has', + 'is', + ]; + } + + // Return quickly for an exact match of the method name. + if (isset($whitelisted_methods[$method])) { return TRUE; } // If the method name starts with a whitelisted prefix, allow it. // Note: strpos() is between 3x and 7x faster than preg_match in this case. - if (strpos($method, 'get') === 0 || strpos($method, 'has') === 0 || strpos($method, 'is') === 0) { - return TRUE; + foreach ($whitelisted_prefixes as $prefix) { + if (strpos($method, $prefix) === 0) { + return TRUE; + } } throw new \Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj)));