Loading core/modules/link/tests/src/Kernel/LinkFormatterTest.php 0 → 100644 +132 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Tests\link\Kernel; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; /** * Tests the Field Formatter for the link field type. * * @group link */ class LinkFormatterTest extends EntityKernelTestBase { /** * Modules to enable. * * @var array */ protected static $modules = ['link']; /** * The entity type used in this test. * * @var string */ protected string $entityType = 'entity_test'; /** * The bundle used in this test. * * @var string */ protected string $bundle = 'entity_test'; /** * The name of the field used in this test. * * @var string */ protected string $fieldName = 'field_test'; /** * The entity to be tested. * * @var \Drupal\Core\Entity\EntityInterface */ protected $entity; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); // Use Stark theme for testing markup output. \Drupal::service('theme_installer')->install(['stark']); $this->config('system.theme')->set('default', 'stark')->save(); $this->installEntitySchema('entity_test'); // Grant the 'view test entity' permission. $this->installConfig(['user']); Role::load(RoleInterface::ANONYMOUS_ID) ->grantPermission('view test entity') ->save(); FieldStorageConfig::create([ 'field_name' => $this->fieldName, 'type' => 'link', 'entity_type' => $this->entityType, 'cardinality' => 1, ])->save(); FieldConfig::create([ 'field_name' => $this->fieldName, 'entity_type' => $this->entityType, 'bundle' => $this->bundle, 'label' => 'Field test', ])->save(); } /** * Tests the link formatters. * * @param string $formatter * The name of the link formatter to test. * * @dataProvider providerLinkFormatter */ public function testLinkFormatter(string $formatter): void { $entity = $this->container->get('entity_type.manager') ->getStorage($this->entityType) ->create([ 'name' => $this->randomMachineName(), $this->fieldName => [ 'uri' => 'https://www.drupal.org/', 'title' => 'Hello world', 'options' => [ 'attributes' => [ 'class' => 'classy', 'onmouseover' => 'alert(document.cookie)', ], ], ], ]); $entity->save(); $build = $entity->get($this->fieldName)->view(['type' => $formatter]); $renderer = $this->container->get('renderer'); $renderer->renderRoot($build[0]); $output = (string) $build[0]['#markup']; $this->assertStringContainsString('<a href="https://www.drupal.org/" class="classy">', $output); $this->assertStringNotContainsString('onmouseover=', $output); } /** * Data provider for ::testLinkFormatter. */ public static function providerLinkFormatter(): array { return [ 'default formatter' => ['link'], 'separate link text and URL' => ['link_separate'], ]; } } core/modules/link/tests/src/Unit/AttributeXssTest.php 0 → 100644 +126 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Tests\link\Unit; use Drupal\link\AttributeXss; use Drupal\Tests\UnitTestCase; /** * Tests AttributeXss. * * @group link * @covers \Drupal\link\AttributeXss */ final class AttributeXssTest extends UnitTestCase { /** * Covers ::sanitizeAttributes. * * @dataProvider providerSanitizeAttributes */ public function testSanitizeAttributes(array $attributes, array $expected): void { self::assertSame($expected, AttributeXss::sanitizeAttributes($attributes)); } /** * Data provider for ::testSanitizeAttributes. * * @return \Generator * Test cases. */ public static function providerSanitizeAttributes(): \Generator { yield 'safe' => [ ['class' => ['foo', 'bar'], 'data-biscuit' => TRUE], ['class' => ['foo', 'bar'], 'data-biscuit' => TRUE], ]; yield 'valueless' => [ ['class' => ['foo', 'bar'], 'selected' => ''], ['class' => ['foo', 'bar'], 'selected' => ''], ]; yield 'empty names' => [ ['class' => ['foo', 'bar'], '' => 'live', ' ' => TRUE], ['class' => ['foo', 'bar']], ]; yield 'only empty names' => [ ['' => 'live', ' ' => TRUE], [], ]; yield 'valueless, mangled with a space' => [ ['class' => ['foo', 'bar'], 'selected href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'valueless, mangled with a space, blocked' => [ ['class' => ['foo', 'bar'], 'selected onclick href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'with encoding' => [ ['class' => ['foo', 'bar'], 'data-how-good' => "It's the bee's knees"], ['class' => ['foo', 'bar'], 'data-how-good' => "It's the bee's knees"], ]; yield 'valueless, mangled with multiple spaces, blocked' => [ ['class' => ['foo', 'bar'], 'selected onclick href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'valueless, mangled with multiple spaces, blocked, mangled first' => [ ['selected onclick href' => 'http://example.com', 'class' => ['foo', 'bar']], ['selected' => 'selected', 'href' => 'http://example.com', 'class' => ['foo', 'bar']], ]; yield 'valueless but with value' => [ ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'valueless but with value, bad protocol' => [ ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'javascript:alert()'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'alert()'], ]; yield 'valueless, mangled with a space and bad protocol' => [ ['class' => ['foo', 'bar'], 'selected href' => 'javascript:alert()'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'alert()'], ]; yield 'valueless, mangled with a space and bad protocol, repeated' => [ ['class' => ['foo', 'bar'], 'selected href' => 'javascript:alert()', 'href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'alert()'], ]; yield 'with a space' => [ ['class' => ['foo', 'bar'], 'href' => \urlencode('some file.pdf')], ['class' => ['foo', 'bar'], 'href' => 'some+file.pdf'], ]; yield 'with an unencoded space' => [ ['class' => ['foo', 'bar'], 'href' => 'some file.pdf'], ['class' => ['foo', 'bar'], 'href' => 'some file.pdf'], ]; yield 'xss onclick' => [ ['class' => ['foo', 'bar'], 'onclick' => 'alert("whoop");'], ['class' => ['foo', 'bar']], ]; yield 'xss onclick, valueless, mangled with a space' => [ ['class' => ['foo', 'bar'], 'selected onclick href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'xss protocol' => [ ['class' => ['foo', 'bar'], 'src' => 'javascript:alert("whoop");'], ['class' => ['foo', 'bar'], 'src' => 'alert("whoop");'], ]; } } core/modules/menu_link_content/tests/src/Kernel/MenuLinksTest.php +29 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ namespace Drupal\Tests\menu_link_content\Kernel; use Drupal\Core\Link; use Drupal\Core\Menu\MenuTreeParameters; use Drupal\entity_test\Entity\EntityTestExternal; use Drupal\KernelTests\KernelTestBase; Loading Loading @@ -477,4 +478,32 @@ public function testMenuLinkContentFormInvalidParentMenu(): void { static::assertIsArray($build); } /** * Assert that attributes are filtered. */ public function testXssFiltering(): void { $options = [ 'menu_name' => 'menu-test', 'bundle' => 'menu_link_content', 'link' => [ [ 'uri' => 'https://www.drupal.org/', 'options' => [ 'attributes' => [ 'class' => 'classy', 'onmouseover' => 'alert(document.cookie)', ], ], ], ], 'title' => 'Link test', ]; $link = MenuLinkContent::create($options); $link->save(); assert($link instanceof MenuLinkContent); $output = Link::fromTextAndUrl($link->getTitle(), $link->getUrlObject())->toString()->getGeneratedLink(); $this->assertStringContainsString('<a href="https://www.drupal.org/" class="classy">', $output); $this->assertStringNotContainsString('onmouseover=', $output); } } Loading
core/modules/link/tests/src/Kernel/LinkFormatterTest.php 0 → 100644 +132 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Tests\link\Kernel; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; /** * Tests the Field Formatter for the link field type. * * @group link */ class LinkFormatterTest extends EntityKernelTestBase { /** * Modules to enable. * * @var array */ protected static $modules = ['link']; /** * The entity type used in this test. * * @var string */ protected string $entityType = 'entity_test'; /** * The bundle used in this test. * * @var string */ protected string $bundle = 'entity_test'; /** * The name of the field used in this test. * * @var string */ protected string $fieldName = 'field_test'; /** * The entity to be tested. * * @var \Drupal\Core\Entity\EntityInterface */ protected $entity; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); // Use Stark theme for testing markup output. \Drupal::service('theme_installer')->install(['stark']); $this->config('system.theme')->set('default', 'stark')->save(); $this->installEntitySchema('entity_test'); // Grant the 'view test entity' permission. $this->installConfig(['user']); Role::load(RoleInterface::ANONYMOUS_ID) ->grantPermission('view test entity') ->save(); FieldStorageConfig::create([ 'field_name' => $this->fieldName, 'type' => 'link', 'entity_type' => $this->entityType, 'cardinality' => 1, ])->save(); FieldConfig::create([ 'field_name' => $this->fieldName, 'entity_type' => $this->entityType, 'bundle' => $this->bundle, 'label' => 'Field test', ])->save(); } /** * Tests the link formatters. * * @param string $formatter * The name of the link formatter to test. * * @dataProvider providerLinkFormatter */ public function testLinkFormatter(string $formatter): void { $entity = $this->container->get('entity_type.manager') ->getStorage($this->entityType) ->create([ 'name' => $this->randomMachineName(), $this->fieldName => [ 'uri' => 'https://www.drupal.org/', 'title' => 'Hello world', 'options' => [ 'attributes' => [ 'class' => 'classy', 'onmouseover' => 'alert(document.cookie)', ], ], ], ]); $entity->save(); $build = $entity->get($this->fieldName)->view(['type' => $formatter]); $renderer = $this->container->get('renderer'); $renderer->renderRoot($build[0]); $output = (string) $build[0]['#markup']; $this->assertStringContainsString('<a href="https://www.drupal.org/" class="classy">', $output); $this->assertStringNotContainsString('onmouseover=', $output); } /** * Data provider for ::testLinkFormatter. */ public static function providerLinkFormatter(): array { return [ 'default formatter' => ['link'], 'separate link text and URL' => ['link_separate'], ]; } }
core/modules/link/tests/src/Unit/AttributeXssTest.php 0 → 100644 +126 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Tests\link\Unit; use Drupal\link\AttributeXss; use Drupal\Tests\UnitTestCase; /** * Tests AttributeXss. * * @group link * @covers \Drupal\link\AttributeXss */ final class AttributeXssTest extends UnitTestCase { /** * Covers ::sanitizeAttributes. * * @dataProvider providerSanitizeAttributes */ public function testSanitizeAttributes(array $attributes, array $expected): void { self::assertSame($expected, AttributeXss::sanitizeAttributes($attributes)); } /** * Data provider for ::testSanitizeAttributes. * * @return \Generator * Test cases. */ public static function providerSanitizeAttributes(): \Generator { yield 'safe' => [ ['class' => ['foo', 'bar'], 'data-biscuit' => TRUE], ['class' => ['foo', 'bar'], 'data-biscuit' => TRUE], ]; yield 'valueless' => [ ['class' => ['foo', 'bar'], 'selected' => ''], ['class' => ['foo', 'bar'], 'selected' => ''], ]; yield 'empty names' => [ ['class' => ['foo', 'bar'], '' => 'live', ' ' => TRUE], ['class' => ['foo', 'bar']], ]; yield 'only empty names' => [ ['' => 'live', ' ' => TRUE], [], ]; yield 'valueless, mangled with a space' => [ ['class' => ['foo', 'bar'], 'selected href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'valueless, mangled with a space, blocked' => [ ['class' => ['foo', 'bar'], 'selected onclick href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'with encoding' => [ ['class' => ['foo', 'bar'], 'data-how-good' => "It's the bee's knees"], ['class' => ['foo', 'bar'], 'data-how-good' => "It's the bee's knees"], ]; yield 'valueless, mangled with multiple spaces, blocked' => [ ['class' => ['foo', 'bar'], 'selected onclick href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'valueless, mangled with multiple spaces, blocked, mangled first' => [ ['selected onclick href' => 'http://example.com', 'class' => ['foo', 'bar']], ['selected' => 'selected', 'href' => 'http://example.com', 'class' => ['foo', 'bar']], ]; yield 'valueless but with value' => [ ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'valueless but with value, bad protocol' => [ ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'javascript:alert()'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'alert()'], ]; yield 'valueless, mangled with a space and bad protocol' => [ ['class' => ['foo', 'bar'], 'selected href' => 'javascript:alert()'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'alert()'], ]; yield 'valueless, mangled with a space and bad protocol, repeated' => [ ['class' => ['foo', 'bar'], 'selected href' => 'javascript:alert()', 'href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'alert()'], ]; yield 'with a space' => [ ['class' => ['foo', 'bar'], 'href' => \urlencode('some file.pdf')], ['class' => ['foo', 'bar'], 'href' => 'some+file.pdf'], ]; yield 'with an unencoded space' => [ ['class' => ['foo', 'bar'], 'href' => 'some file.pdf'], ['class' => ['foo', 'bar'], 'href' => 'some file.pdf'], ]; yield 'xss onclick' => [ ['class' => ['foo', 'bar'], 'onclick' => 'alert("whoop");'], ['class' => ['foo', 'bar']], ]; yield 'xss onclick, valueless, mangled with a space' => [ ['class' => ['foo', 'bar'], 'selected onclick href' => 'http://example.com'], ['class' => ['foo', 'bar'], 'selected' => 'selected', 'href' => 'http://example.com'], ]; yield 'xss protocol' => [ ['class' => ['foo', 'bar'], 'src' => 'javascript:alert("whoop");'], ['class' => ['foo', 'bar'], 'src' => 'alert("whoop");'], ]; } }
core/modules/menu_link_content/tests/src/Kernel/MenuLinksTest.php +29 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ namespace Drupal\Tests\menu_link_content\Kernel; use Drupal\Core\Link; use Drupal\Core\Menu\MenuTreeParameters; use Drupal\entity_test\Entity\EntityTestExternal; use Drupal\KernelTests\KernelTestBase; Loading Loading @@ -477,4 +478,32 @@ public function testMenuLinkContentFormInvalidParentMenu(): void { static::assertIsArray($build); } /** * Assert that attributes are filtered. */ public function testXssFiltering(): void { $options = [ 'menu_name' => 'menu-test', 'bundle' => 'menu_link_content', 'link' => [ [ 'uri' => 'https://www.drupal.org/', 'options' => [ 'attributes' => [ 'class' => 'classy', 'onmouseover' => 'alert(document.cookie)', ], ], ], ], 'title' => 'Link test', ]; $link = MenuLinkContent::create($options); $link->save(); assert($link instanceof MenuLinkContent); $output = Link::fromTextAndUrl($link->getTitle(), $link->getUrlObject())->toString()->getGeneratedLink(); $this->assertStringContainsString('<a href="https://www.drupal.org/" class="classy">', $output); $this->assertStringNotContainsString('onmouseover=', $output); } }