diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index d5137dc2ba805..930e0faaeaaee 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -26,6 +26,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\Form\Form; +use Symfony\Component\HtmlSanitizer\HtmlSanitizerAction; use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpFoundation\Cookie; @@ -2382,6 +2383,10 @@ private function addHtmlSanitizerSection(ArrayNodeDefinition $rootNode, callable ->fixXmlConfig('with_attribute_sanitizer') ->fixXmlConfig('without_attribute_sanitizer') ->children() + ->enumNode('default_action') + ->info('Defines how the sanitizer must behave by default.') + ->values(array_map(static fn (HtmlSanitizerAction $action): string => $action->value, HtmlSanitizerAction::cases())) + ->end() ->booleanNode('allow_safe_elements') ->info('Allows "safe" elements and attributes.') ->defaultFalse() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 7cc67725ec461..5cc7ee8fc9c9c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -80,6 +80,7 @@ use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\HtmlSanitizer\HtmlSanitizer; +use Symfony\Component\HtmlSanitizer\HtmlSanitizerAction; use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig; use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface; use Symfony\Component\HttpClient\Messenger\PingWebhookMessageHandler; @@ -3006,6 +3007,17 @@ private function registerHtmlSanitizerConfiguration(array $config, ContainerBuil $def = $container->register($configId, HtmlSanitizerConfig::class); // Base + if ($sanitizerConfig['default_action'] ?? false) { + if (!class_exists(HtmlSanitizerAction::class)) { + throw new LogicException(\sprintf( + 'Default action requires the HtmlSanitizer component to be installed in version >=7.2 (%s currently installed). Try running "composer require symfony/html-sanitizer".', + InstalledVersions::getVersion('symfony/html-sanitizer') + )); + } + + $def->addMethodCall('defaultAction', [HtmlSanitizerAction::from($sanitizerConfig['default_action'])], true); + } + if ($sanitizerConfig['allow_safe_elements']) { $def->addMethodCall('allowSafeElements', [], true); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index d8d23168d1887..55935d2d5fbbd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -918,6 +918,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php index 1b64cd1b3e21e..81ae3c337cec0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer.php @@ -8,6 +8,7 @@ 'html_sanitizer' => [ 'sanitizers' => [ 'custom' => [ + 'default_action' => 'allow', 'allow_safe_elements' => true, 'allow_static_elements' => true, 'allow_elements' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer_without_default_action.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer_without_default_action.php new file mode 100644 index 0000000000000..1b64cd1b3e21e --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/html_sanitizer_without_default_action.php @@ -0,0 +1,50 @@ +loadFromExtension('framework', [ + 'annotations' => false, + 'http_method_override' => false, + 'handle_all_throwables' => true, + 'php_errors' => ['log' => true], + 'html_sanitizer' => [ + 'sanitizers' => [ + 'custom' => [ + 'allow_safe_elements' => true, + 'allow_static_elements' => true, + 'allow_elements' => [ + 'iframe' => 'src', + 'custom-tag' => ['data-attr', 'data-attr-1'], + 'custom-tag-2' => '*', + ], + 'block_elements' => ['section'], + 'drop_elements' => ['video'], + 'allow_attributes' => [ + 'src' => ['iframe'], + 'data-attr' => '*', + ], + 'drop_attributes' => [ + 'data-attr' => ['custom-tag'], + 'data-attr-1' => [], + 'data-attr-2' => '*', + ], + 'force_attributes' => [ + 'a' => ['rel' => 'noopener noreferrer'], + 'h1' => ['class' => 'bp4-heading'], + ], + 'force_https_urls' => true, + 'allowed_link_schemes' => ['http', 'https', 'mailto'], + 'allowed_link_hosts' => ['symfony.com'], + 'allow_relative_links' => true, + 'allowed_media_schemes' => ['http', 'https', 'data'], + 'allowed_media_hosts' => ['symfony.com'], + 'allow_relative_medias' => true, + 'with_attribute_sanitizers' => [ + 'App\\Sanitizer\\CustomAttributeSanitizer', + ], + 'without_attribute_sanitizers' => [ + 'App\\Sanitizer\\OtherCustomAttributeSanitizer', + ], + ], + 'all.sanitizer' => null, + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml index 7cb6758d93bfe..ce97226fc3fd3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/html_sanitizer.xml @@ -10,6 +10,7 @@ + + + + + + + + + + src + + + data-attr + data-attr-1 + + + * + + section + video + + iframe + + + * + + + custom-tag + + + + * + + + noopener noreferrer + + + bp4-heading + + http + https + mailto + symfony.com + http + https + data + symfony.com + App\Sanitizer\CustomAttributeSanitizer + App\Sanitizer\OtherCustomAttributeSanitizer + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer.yml index f0d515e418d86..77aae692a03fc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer.yml @@ -7,6 +7,7 @@ framework: html_sanitizer: sanitizers: custom: + default_action: 'allow' allow_safe_elements: true allow_static_elements: true allow_elements: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer_without_default_action.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer_without_default_action.yml new file mode 100644 index 0000000000000..f0d515e418d86 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/html_sanitizer_without_default_action.yml @@ -0,0 +1,44 @@ +framework: + annotations: false + http_method_override: false + handle_all_throwables: true + php_errors: + log: true + html_sanitizer: + sanitizers: + custom: + allow_safe_elements: true + allow_static_elements: true + allow_elements: + iframe: 'src' + custom-tag: ['data-attr', 'data-attr-1'] + custom-tag-2: '*' + block_elements: + - section + drop_elements: + - video + allow_attributes: + src: ['iframe'] + data-attr: '*' + drop_attributes: + data-attr: [custom-tag] + data-attr-1: [] + data-attr-2: '*' + force_attributes: + a: + rel: noopener noreferrer + h1: + class: bp4-heading + force_https_urls: true + allowed_link_schemes: ['http', 'https', 'mailto'] + allowed_link_hosts: ['symfony.com'] + allow_relative_links: true + allowed_media_schemes: ['http', 'https', 'data'] + allowed_media_hosts: ['symfony.com'] + allow_relative_medias: true + with_attribute_sanitizers: + - App\Sanitizer\CustomAttributeSanitizer + without_attribute_sanitizers: + - App\Sanitizer\OtherCustomAttributeSanitizer + + all.sanitizer: null diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index b37d2e910ec45..72a8bbf0b0508 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -47,6 +47,7 @@ use Symfony\Component\Finder\Finder; use Symfony\Component\Form\Form; use Symfony\Component\HtmlSanitizer\HtmlSanitizer; +use Symfony\Component\HtmlSanitizer\HtmlSanitizerAction; use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig; use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface; use Symfony\Component\HttpClient\MockHttpClient; @@ -2219,8 +2220,74 @@ public function testLocaleSwitcherServiceRegistered() $this->assertNotContains('translation.locale_switcher', $localeAwareServices); } + public function testHtmlSanitizerBefore72() + { + if (class_exists(HtmlSanitizerAction::class)) { + $this->markTestSkipped('HtmlSanitizer version is <7.2'); + } + + $container = $this->createContainerFromFile('html_sanitizer_without_default_action'); + + // html_sanitizer service + $this->assertSame(HtmlSanitizer::class, $container->getDefinition('html_sanitizer.sanitizer.custom')->getClass()); + $this->assertCount(1, $args = $container->getDefinition('html_sanitizer.sanitizer.custom')->getArguments()); + $this->assertSame('html_sanitizer.config.custom', (string) $args[0]); + + // config + $this->assertTrue($container->hasDefinition('html_sanitizer.config.custom'), '->registerHtmlSanitizerConfiguration() loads custom sanitizer'); + $this->assertSame(HtmlSanitizerConfig::class, $container->getDefinition('html_sanitizer.config.custom')->getClass()); + $this->assertCount(23, $calls = $container->getDefinition('html_sanitizer.config.custom')->getMethodCalls()); + $this->assertSame( + [ + ['allowSafeElements', [], true], + ['allowStaticElements', [], true], + ['allowElement', ['iframe', 'src'], true], + ['allowElement', ['custom-tag', ['data-attr', 'data-attr-1']], true], + ['allowElement', ['custom-tag-2', '*'], true], + ['blockElement', ['section'], true], + ['dropElement', ['video'], true], + ['allowAttribute', ['src', $this instanceof XmlFrameworkExtensionTest ? 'iframe' : ['iframe']], true], + ['allowAttribute', ['data-attr', '*'], true], + ['dropAttribute', ['data-attr', $this instanceof XmlFrameworkExtensionTest ? 'custom-tag' : ['custom-tag']], true], + ['dropAttribute', ['data-attr-1', []], true], + ['dropAttribute', ['data-attr-2', '*'], true], + ['forceAttribute', ['a', 'rel', 'noopener noreferrer'], true], + ['forceAttribute', ['h1', 'class', 'bp4-heading'], true], + ['forceHttpsUrls', [true], true], + ['allowLinkSchemes', [['http', 'https', 'mailto']], true], + ['allowLinkHosts', [['symfony.com']], true], + ['allowRelativeLinks', [true], true], + ['allowMediaSchemes', [['http', 'https', 'data']], true], + ['allowMediaHosts', [['symfony.com']], true], + ['allowRelativeMedias', [true], true], + ['withAttributeSanitizer', ['@App\\Sanitizer\\CustomAttributeSanitizer'], true], + ['withoutAttributeSanitizer', ['@App\\Sanitizer\\OtherCustomAttributeSanitizer'], true], + ], + + // Convert references to their names for easier assertion + array_map( + static function ($call) { + foreach ($call[1] as $k => $arg) { + $call[1][$k] = $arg instanceof Reference ? '@'.$arg : $arg; + } + + return $call; + }, + $calls + ) + ); + + // Named alias + $this->assertSame('html_sanitizer.sanitizer.all.sanitizer', (string) $container->getAlias(HtmlSanitizerInterface::class.' $allSanitizer')); + $this->assertFalse($container->hasAlias(HtmlSanitizerInterface::class.' $default')); + } + public function testHtmlSanitizer() { + if (!class_exists(HtmlSanitizerAction::class)) { + $this->markTestSkipped('HtmlSanitizer version must be >=7.2'); + } + $container = $this->createContainerFromFile('html_sanitizer'); // html_sanitizer service @@ -2231,9 +2298,10 @@ public function testHtmlSanitizer() // config $this->assertTrue($container->hasDefinition('html_sanitizer.config.custom'), '->registerHtmlSanitizerConfiguration() loads custom sanitizer'); $this->assertSame(HtmlSanitizerConfig::class, $container->getDefinition('html_sanitizer.config.custom')->getClass()); - $this->assertCount(23, $calls = $container->getDefinition('html_sanitizer.config.custom')->getMethodCalls()); + $this->assertCount(24, $calls = $container->getDefinition('html_sanitizer.config.custom')->getMethodCalls()); $this->assertSame( [ + ['defaultAction', [HtmlSanitizerAction::Allow], true], ['allowSafeElements', [], true], ['allowStaticElements', [], true], ['allowElement', ['iframe', 'src'], true], pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy