diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 224abe3..79fabba 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -44,6 +44,7 @@ 'static_lambda' => true, 'strict_param' => true, 'ternary_to_null_coalescing' => true, + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], ]) ->setUsingCache(true) ->setRiskyAllowed(true) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7a40f7a..76225e6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -18,5 +18,14 @@ parameters: - '#^Dynamic call to static method Symfony\\Bundle\\FrameworkBundle\\Test\\\S+\(\)\.$#' # Ignore typing providers in tests - '#^Method Nelmio\\SecurityBundle\\Tests\\[^:]+Test::(provide\w+|\w+Provider)\(\) return type has no value type specified in iterable type (array|iterable)\.#' + + # TODO: twig/twig:>3.12 remove this ignore + - + message: "#^Class Twig\\\\Node\\\\CaptureNode constructor invoked with 3 parameters, 2 required\\.$#" + count: 1 + path: src/Twig/Node/CSPNode.php + reportUnmatched: false + dynamicConstantNames: - Symfony\Component\HttpKernel\Kernel::VERSION + - Twig\Environment::VERSION_ID diff --git a/src/ContentSecurityPolicy/ContentSecurityPolicyParser.php b/src/ContentSecurityPolicy/ContentSecurityPolicyParser.php index 9da84a5..bb7125c 100644 --- a/src/ContentSecurityPolicy/ContentSecurityPolicyParser.php +++ b/src/ContentSecurityPolicy/ContentSecurityPolicyParser.php @@ -58,7 +58,7 @@ private function quoteKeywords(array $sourceList): array return array_map( static function (string $source) use ($keywords) { if (\in_array($source, $keywords, true)) { - return sprintf("'%s'", $source); + return \sprintf("'%s'", $source); } return $source; diff --git a/src/ContentSecurityPolicy/DirectiveSet.php b/src/ContentSecurityPolicy/DirectiveSet.php index 70fcdec..53afda2 100644 --- a/src/ContentSecurityPolicy/DirectiveSet.php +++ b/src/ContentSecurityPolicy/DirectiveSet.php @@ -243,7 +243,7 @@ private function normalizeSignatures(?array $signatures): ?array $normalizedSignatures['script-src'] = implode( ' ', array_map(static function (string $value): string { - return sprintf('\'%s\'', $value); + return \sprintf('\'%s\'', $value); }, $signatures['script-src']) ); } @@ -252,7 +252,7 @@ private function normalizeSignatures(?array $signatures): ?array $normalizedSignatures['style-src'] = implode( ' ', array_map(static function (string $value): string { - return sprintf('\'%s\'', $value); + return \sprintf('\'%s\'', $value); }, $signatures['style-src']) ); } diff --git a/src/ContentSecurityPolicy/ShaComputer.php b/src/ContentSecurityPolicy/ShaComputer.php index 7386549..51c5f9f 100644 --- a/src/ContentSecurityPolicy/ShaComputer.php +++ b/src/ContentSecurityPolicy/ShaComputer.php @@ -21,7 +21,7 @@ final class ShaComputer implements ShaComputerInterface public function __construct(string $type) { if (!\in_array($type, ['sha256', 'sha384', 'sha512'], true)) { - throw new \InvalidArgumentException(sprintf('Type "%s" is not supported', $type)); + throw new \InvalidArgumentException(\sprintf('Type "%s" is not supported', $type)); } $this->type = $type; @@ -76,7 +76,7 @@ private function getFavorite(): string private function compute(string $data): string { - return sprintf('%s-%s', $this->type, base64_encode($this->computeHash($data))); + return \sprintf('%s-%s', $this->type, base64_encode($this->computeHash($data))); } private function computeHash(string $data): string diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 85ce869..44a12f2 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -229,7 +229,7 @@ private function addReferrerPolicyNode(): ArrayNodeDefinition ->always(function (array $values): array { foreach ($values as $policy) { if (!\in_array($policy, $this->referrerPolicies, true)) { - throw new \InvalidArgumentException(sprintf('Unknown referrer policy "%s". Possible referrer policies are "%s".', $policy, implode('", "', $this->referrerPolicies))); + throw new \InvalidArgumentException(\sprintf('Unknown referrer policy "%s". Possible referrer policies are "%s".', $policy, implode('", "', $this->referrerPolicies))); } } diff --git a/src/ExternalRedirect/AllowListBasedTargetValidator.php b/src/ExternalRedirect/AllowListBasedTargetValidator.php index f6d6c36..12fa11d 100644 --- a/src/ExternalRedirect/AllowListBasedTargetValidator.php +++ b/src/ExternalRedirect/AllowListBasedTargetValidator.php @@ -45,7 +45,7 @@ public function isTargetAllowed(string $targetUrl): bool $host = parse_url($targetUrl, \PHP_URL_HOST); if (!\is_string($host)) { - throw new \InvalidArgumentException(sprintf('Url "%s" does not contain a host name.', $targetUrl)); + throw new \InvalidArgumentException(\sprintf('Url "%s" does not contain a host name.', $targetUrl)); } return preg_match('{^'.$this->allowList.'$}i', $host) > 0; diff --git a/src/Signer.php b/src/Signer.php index da605af..9d28849 100644 --- a/src/Signer.php +++ b/src/Signer.php @@ -37,11 +37,11 @@ public function __construct(string $secret, string $algo, ?string $legacyAlgo = $this->separator = $separator; if (!\in_array($this->algo, hash_algos(), true)) { - throw new \InvalidArgumentException(sprintf("The supplied hashing algorithm '%s' is not supported by this system.", $this->algo)); + throw new \InvalidArgumentException(\sprintf("The supplied hashing algorithm '%s' is not supported by this system.", $this->algo)); } if (null !== $this->legacyAlgo && !\in_array($this->legacyAlgo, hash_algos(), true)) { - throw new \InvalidArgumentException(sprintf("The supplied legacy hashing algorithm '%s' is not supported by this system.", $this->legacyAlgo)); + throw new \InvalidArgumentException(\sprintf("The supplied legacy hashing algorithm '%s' is not supported by this system.", $this->legacyAlgo)); } } @@ -78,7 +78,7 @@ public function verifySignedValue(string $signedValue): bool public function getVerifiedRawValue(string $signedValue): string { if (!$this->verifySignedValue($signedValue)) { - throw new \InvalidArgumentException(sprintf("The signature for '%s' was invalid.", $signedValue)); + throw new \InvalidArgumentException(\sprintf("The signature for '%s' was invalid.", $signedValue)); } $valueSignatureTuple = $this->splitSignatureFromSignedValue($signedValue); diff --git a/src/Twig/Node/CSPNode.php b/src/Twig/Node/CSPNode.php index 840f9d3..c33bc11 100644 --- a/src/Twig/Node/CSPNode.php +++ b/src/Twig/Node/CSPNode.php @@ -22,6 +22,7 @@ * file that was distributed with this source code. */ +use Nelmio\SecurityBundle\Twig\Version as TwigVersion; use Twig\Attribute\YieldReady; use Twig\Compiler; use Twig\Node\CaptureNode; @@ -36,11 +37,19 @@ final class CSPNode extends Node public function __construct(Node $body, int $lineno, string $tag, string $directive, ?string $sha = null) { if (class_exists(CaptureNode::class)) { - $body = new CaptureNode($body, $lineno, $tag); + if (TwigVersion::needsNodeTag()) { + $body = new CaptureNode($body, $lineno, $tag); + } else { + $body = new CaptureNode($body, $lineno); + } $body->setAttribute('raw', true); } - parent::__construct(['body' => $body], [], $lineno, $tag); + if (TwigVersion::needsNodeTag()) { + parent::__construct(['body' => $body], [], $lineno, $tag); + } else { + parent::__construct(['body' => $body], [], $lineno); + } $this->sha = $sha; $this->directive = $directive; } @@ -74,7 +83,7 @@ public function compile(Compiler $compiler): void } elseif ('style-src' === $this->directive) { $compiler->write("\$this->env->getRuntime('Nelmio\SecurityBundle\Twig\CSPRuntime')->getListener()->addStyle(\$content);\n"); } else { - throw new \InvalidArgumentException(sprintf('Unable to compile for directive "%s"', $this->directive)); + throw new \InvalidArgumentException(\sprintf('Unable to compile for directive "%s"', $this->directive)); } if (class_exists(CaptureNode::class)) { diff --git a/src/Twig/Version.php b/src/Twig/Version.php new file mode 100644 index 0000000..d1307c5 --- /dev/null +++ b/src/Twig/Version.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\SecurityBundle\Twig; + +/** + * @internal + */ +final class Version +{ + public static function needsNodeTag(): bool + { + return \Twig\Environment::VERSION_ID < 301200; + } +} diff --git a/tests/App/AppKernel.php b/tests/App/AppKernel.php index 17a683d..89bd33d 100644 --- a/tests/App/AppKernel.php +++ b/tests/App/AppKernel.php @@ -42,12 +42,12 @@ public function registerBundles(): iterable public function getCacheDir(): string { - return sprintf('%scache', $this->getBaseDir()); + return \sprintf('%scache', $this->getBaseDir()); } public function getLogDir(): string { - return sprintf('%slog', $this->getBaseDir()); + return \sprintf('%slog', $this->getBaseDir()); } public function getProjectDir(): string @@ -62,16 +62,16 @@ public function getProjectDir(): string */ protected function configureRoutes($routes): void { - $routes->import(sprintf('%s/config/routes.yaml', $this->getProjectDir())); + $routes->import(\sprintf('%s/config/routes.yaml', $this->getProjectDir())); } protected function configureContainer(ContainerBuilder $containerBuilder, LoaderInterface $loader): void { - $loader->load(sprintf('%s/config/config.yaml', $this->getProjectDir())); + $loader->load(\sprintf('%s/config/config.yaml', $this->getProjectDir())); } private function getBaseDir(): string { - return sprintf('%s/nelmio-security-bundle/var/', sys_get_temp_dir()); + return \sprintf('%s/nelmio-security-bundle/var/', sys_get_temp_dir()); } } diff --git a/tests/Listener/ExternalRedirectListenerTest.php b/tests/Listener/ExternalRedirectListenerTest.php index a2b09e2..4e2246a 100644 --- a/tests/Listener/ExternalRedirectListenerTest.php +++ b/tests/Listener/ExternalRedirectListenerTest.php @@ -92,14 +92,14 @@ public function provideRedirectOverrides(): iterable '/override', 'redirect_to', $target, - sprintf('/override?redirect_to=%s', urlencode($target)), + \sprintf('/override?redirect_to=%s', urlencode($target)), ]; yield 'override with parameter and with forwardAs' => [ '/override?param=value', 'redirect_to', $target, - sprintf('/override?param=value&redirect_to=%s', urlencode($target)), + \sprintf('/override?param=value&redirect_to=%s', urlencode($target)), ]; }