Skip to content

Commit

Permalink
[Twig taint analysis] Support AbstractController::render() and Symf…
Browse files Browse the repository at this point in the history
…ony+custom twig extensions (#245)

* Allow analysing twig templates with custom extensions

* Add support for AbstractController::render() and ::renderView()
  • Loading branch information
wouterj committed Feb 9, 2022
1 parent f5348e9 commit 44f9a69
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 1 deletion.
16 changes: 16 additions & 0 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use Psalm\SymfonyPsalmPlugin\Twig\CachedTemplatesTainter;
use Psalm\SymfonyPsalmPlugin\Twig\TemplateFileAnalyzer;
use SimpleXMLElement;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\HttpKernel\Kernel;

/**
Expand Down Expand Up @@ -65,6 +66,21 @@ public function __invoke(RegistrationInterface $api, SimpleXMLElement $config =
$containerMeta = new ContainerMeta((array) $config->containerXml);
ContainerHandler::init($containerMeta);

try {
TemplateFileAnalyzer::initExtensions(array_filter(array_map(function (array $m) use ($containerMeta) {
if ('addExtension' !== $m[0]) {
return null;
}

try {
return $containerMeta->get($m[1][0])->getClass();
} catch (ServiceNotFoundException $e) {
return null;
}
}, $containerMeta->get('twig')->getMethodCalls())));
} catch (ServiceNotFoundException $e) {
}

require_once __DIR__.'/Handler/ParameterBagHandler.php';
ParameterBagHandler::init($containerMeta);
$api->registerHooksFromClass(ParameterBagHandler::class);
Expand Down
3 changes: 2 additions & 1 deletion src/Twig/AnalyzedTemplatesTainter.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Psalm\SymfonyPsalmPlugin\Exception\TemplateNameUnresolvedException;
use Psalm\Type\Atomic\TKeyedArray;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Twig\Environment;

/**
Expand All @@ -34,7 +35,7 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve

if (
null === $codebase->taint_flow_graph
|| !$expr instanceof MethodCall || $method_id !== Environment::class.'::render' || empty($expr->args)
|| !$expr instanceof MethodCall || !\in_array($method_id, [Environment::class.'::render', AbstractController::class.'::render', AbstractController::class.'::renderView'], true) || empty($expr->args)
|| !isset($expr->args[0]->value)
|| !isset($expr->args[1]->value)
) {
Expand Down
16 changes: 16 additions & 0 deletions src/Twig/TemplateFileAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Psalm\Context as PsalmContext;
use Psalm\Internal\Analyzer\FileAnalyzer;
use Twig\Environment;
use Twig\Extension\ExtensionInterface;
use Twig\Loader\FilesystemLoader;
use Twig\NodeTraverser;

Expand All @@ -22,6 +23,16 @@ class TemplateFileAnalyzer extends FileAnalyzer
*/
private static $rootPath = 'templates';

/**
* @var list<class-string>
*/
private static $extensionClasses = [];

public static function initExtensions(array $extensionClasses): void
{
self::$extensionClasses = $extensionClasses;
}

public function analyze(
PsalmContext $file_context = null,
PsalmContext $global_context = null
Expand All @@ -41,6 +52,11 @@ public function analyze(
'optimizations' => 0,
'strict_variables' => false,
]);
foreach (self::$extensionClasses as $extensionClass) {
if (class_exists($extensionClass) && is_a($extensionClass, ExtensionInterface::class, true)) {
$twig->addExtension((new \ReflectionClass($extensionClass))->newInstanceWithoutConstructor());
}
}

$local_file_name = str_replace(self::$rootPath.'/', '', $this->file_name);
$twig_source = $loader->getSourceContext($local_file_name);
Expand Down

0 comments on commit 44f9a69

Please sign in to comment.