From 8691e08fdf80b54012e6ed120815f091626d483a Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org> Date: Thu, 17 Sep 2015 14:47:16 +0100 Subject: [PATCH] Issue #2545972 by alexpott, joelpittet, ericjenkins, stefan.r, Wim Leers, Cottser: Remove all code usages SafeMarkup::checkPlain() and rely more on Twig autoescaping --- core/includes/schema.inc | 6 - .../Drupal/Component/Utility/UrlHelper.php | 2 +- core/lib/Drupal/Component/Utility/Xss.php | 2 +- .../Controller/TitleResolverInterface.php | 14 +- .../ExceptionLoggingSubscriber.php | 5 +- .../Drupal/Core/Extension/ThemeHandler.php | 3 +- .../Drupal/Core/Field/AllowedTagsXssTrait.php | 2 +- core/lib/Drupal/Core/Form/form.api.php | 4 +- core/lib/Drupal/Core/Menu/menu.api.php | 3 - .../Drupal/Core/Session/AccountInterface.php | 5 +- core/lib/Drupal/Core/Utility/Token.php | 8 +- .../block/src/Controller/BlockController.php | 3 +- .../CategoryAutocompleteController.php | 4 +- core/modules/block/src/Tests/BlockUiTest.php | 4 + .../src/Unit/CategoryAutocompleteTest.php | 4 +- core/modules/comment/comment.module | 3 +- .../src/Plugin/views/argument/UserUid.php | 3 +- .../comment/src/Tests/CommentPreviewTest.php | 25 +- .../field_ui/src/Form/FieldConfigEditForm.php | 3 +- .../field_ui/src/Tests/ManageFieldsTest.php | 5 +- .../filter/src/Tests/FilterUnitTest.php | 2 - .../src/Controller/NodePreviewController.php | 3 +- .../node/src/Plugin/views/argument/Type.php | 3 +- .../modules/node/src/Plugin/views/row/Rss.php | 3 +- .../node/src/Tests/PagePreviewTest.php | 6 +- .../src/Tests/Views/NodeIntegrationTest.php | 3 +- .../test_views/views.view.test_node_view.yml | 4 +- .../Plugin/views/argument/NumberListField.php | 3 +- .../src/Tests/Views/StyleSerializerTest.php | 4 +- .../simpletest/src/AssertContentTrait.php | 8 +- .../system/src/Tests/System/ThemeTest.php | 4 +- .../themes/test_theme/test_theme.info.yml | 2 +- .../Plugin/views/argument/IndexTidDepth.php | 3 +- .../src/Plugin/views/argument/Taxonomy.php | 3 +- .../Plugin/views/argument/VocabularyVid.php | 3 +- .../Plugin/views/field/TaxonomyIndexTid.php | 3 +- .../Plugin/views/filter/TaxonomyIndexTid.php | 3 +- .../Views/TaxonomyDefaultArgumentTest.php | 10 + .../Tests/Views/TaxonomyFieldAllTermsTest.php | 2 + .../Views/TaxonomyTermArgumentDepthTest.php | 64 +++++ ...ws.view.taxonomy_default_argument_test.yml | 7 + ...test_argument_taxonomy_index_tid_depth.yml | 227 ++++++++++++++++++ .../Plugin/Field/FieldType/TextItemBase.php | 1 - core/modules/text/src/TextProcessed.php | 3 +- .../tracker/src/Controller/TrackerUserTab.php | 3 +- .../modules/tracker/src/Tests/TrackerTest.php | 11 + .../user/src/Plugin/Condition/UserRole.php | 2 +- .../user/src/Plugin/views/access/Role.php | 2 +- .../user/src/Plugin/views/field/Roles.php | 3 +- .../src/Tests/Views/HandlerFieldRoleTest.php | 17 +- .../user_hooks_test/user_hooks_test.info.yml | 6 + .../user_hooks_test/user_hooks_test.module | 22 ++ core/modules/user/user.module | 8 +- .../views/src/Plugin/views/HandlerBase.php | 9 +- .../views/src/Plugin/views/PluginBase.php | 5 +- .../Plugin/views/ViewsHandlerInterface.php | 5 +- .../views/src/Plugin/views/area/Result.php | 4 +- .../views/argument/ArgumentPluginBase.php | 5 +- .../src/Plugin/views/argument/FieldList.php | 3 +- .../src/Plugin/views/display/Attachment.php | 5 +- .../views/src/Plugin/views/display/Feed.php | 5 +- .../Plugin/views/field/FieldPluginBase.php | 7 +- .../src/Plugin/views/field/MachineName.php | 2 +- .../src/Plugin/views/field/PrerenderList.php | 13 +- .../src/Plugin/views/field/Serialized.php | 5 +- core/modules/views/src/Views.php | 6 +- .../views.view.test_attachment_ui.yml | 2 +- .../views.view.test_display_feed.yml | 2 +- .../test_views/views.view.test_style_opml.yml | 2 +- core/modules/views/views.module | 4 +- .../src/Tests/DisplayAttachmentTest.php | 5 + .../views_ui/src/Tests/DisplayFeedTest.php | 8 +- .../Tests/Component/Utility/HtmlTest.php | 4 +- .../Drupal/Tests/Core/Render/RendererTest.php | 2 +- 74 files changed, 500 insertions(+), 159 deletions(-) create mode 100644 core/modules/taxonomy/src/Tests/Views/TaxonomyTermArgumentDepthTest.php create mode 100644 core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_argument_taxonomy_index_tid_depth.yml create mode 100644 core/modules/user/tests/modules/user_hooks_test/user_hooks_test.info.yml create mode 100644 core/modules/user/tests/modules/user_hooks_test/user_hooks_test.module diff --git a/core/includes/schema.inc b/core/includes/schema.inc index b74c2701289c..bba4eab46f07 100644 --- a/core/includes/schema.inc +++ b/core/includes/schema.inc @@ -130,12 +130,6 @@ function drupal_install_schema($module) { * * @param string $module * The module for which the tables will be removed. - * - * @return array - * An array of arrays with the following key/value pairs: - * - success: a boolean indicating whether the query succeeded. - * - query: the SQL query(s) executed, passed through - * \Drupal\Component\Utility\SafeMarkup::checkPlain(). */ function drupal_uninstall_schema($module) { $schema = drupal_get_module_schema($module); diff --git a/core/lib/Drupal/Component/Utility/UrlHelper.php b/core/lib/Drupal/Component/Utility/UrlHelper.php index b442c57352fe..2f26b26b5ea4 100644 --- a/core/lib/Drupal/Component/Utility/UrlHelper.php +++ b/core/lib/Drupal/Component/Utility/UrlHelper.php @@ -304,7 +304,7 @@ public static function setAllowedProtocols(array $protocols = array()) { * \Drupal\Component\Utility\Xss::filter(), but those functions return an * HTML-encoded string, so this function can be called independently when the * output needs to be a plain-text string for passing to functions that will - * call \Drupal\Component\Utility\SafeMarkup::checkPlain() separately. + * call \Drupal\Component\Utility\Html::escape() separately. * * @param string $uri * A plain-text URI that might contain dangerous protocols. diff --git a/core/lib/Drupal/Component/Utility/Xss.php b/core/lib/Drupal/Component/Utility/Xss.php index d61d82119a65..423bde43d31b 100644 --- a/core/lib/Drupal/Component/Utility/Xss.php +++ b/core/lib/Drupal/Component/Utility/Xss.php @@ -106,7 +106,7 @@ public static function filter($string, array $html_tags = NULL) { * * Use only for fields where it is impractical to use the * whole filter system, but where some (mainly inline) mark-up - * is desired (so \Drupal\Component\Utility\SafeMarkup::checkPlain() is + * is desired (so \Drupal\Component\Utility\Html::escape() is * not acceptable). * * Allows all tags that can be used inside an HTML body, save diff --git a/core/lib/Drupal/Core/Controller/TitleResolverInterface.php b/core/lib/Drupal/Core/Controller/TitleResolverInterface.php index bedfd1781de0..fa72e1141a02 100644 --- a/core/lib/Drupal/Core/Controller/TitleResolverInterface.php +++ b/core/lib/Drupal/Core/Controller/TitleResolverInterface.php @@ -17,18 +17,20 @@ interface TitleResolverInterface { /** * Returns a static or dynamic title for the route. * - * The returned title string must be safe to output in HTML. For example, an - * implementation should call \Drupal\Component\Utility\SafeMarkup::checkPlain() - * or \Drupal\Component\Utility\Xss::filterAdmin() on the string, or use - * appropriate placeholders to sanitize dynamic content inside a localized - * string before returning it. The title may contain HTML such as EM tags. + * If the returned title can contain HTML that should not be escaped it should + * return a render array, for example: + * @code + * ['#markup' => 'title', '#allowed_tags' => ['em']] + * @endcode + * If the method returns a string and it is not marked safe then it will be + * auto-escaped. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object passed to the title callback. * @param \Symfony\Component\Routing\Route $route * The route information of the route to fetch the title. * - * @return string|null + * @return array|string|null * The title for the route. */ public function getTitle(Request $request, Route $route); diff --git a/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php index 6a2bd6c9dd35..9e3f3c7e86fb 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ExceptionLoggingSubscriber.php @@ -7,7 +7,6 @@ namespace Drupal\Core\EventSubscriber; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\Utility\Error; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -45,7 +44,7 @@ public function __construct(LoggerChannelFactoryInterface $logger) { */ public function on403(GetResponseForExceptionEvent $event) { $request = $event->getRequest(); - $this->logger->get('access denied')->warning(SafeMarkup::checkPlain($request->getRequestUri())); + $this->logger->get('access denied')->warning('@uri', ['@uri' => $request->getRequestUri()]); } /** @@ -56,7 +55,7 @@ public function on403(GetResponseForExceptionEvent $event) { */ public function on404(GetResponseForExceptionEvent $event) { $request = $event->getRequest(); - $this->logger->get('page not found')->warning(SafeMarkup::checkPlain($request->getRequestUri())); + $this->logger->get('page not found')->warning('@uri', ['@uri' => $request->getRequestUri()]); } /** diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php index 6dfb99abf929..a7230875f9d1 100644 --- a/core/lib/Drupal/Core/Extension/ThemeHandler.php +++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php @@ -7,7 +7,6 @@ namespace Drupal\Core\Extension; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\State\StateInterface; @@ -428,7 +427,7 @@ public function getName($theme) { if (!isset($themes[$theme])) { throw new \InvalidArgumentException("Requested the name of a non-existing theme $theme"); } - return SafeMarkup::checkPlain($themes[$theme]->info['name']); + return $themes[$theme]->info['name']; } /** diff --git a/core/lib/Drupal/Core/Field/AllowedTagsXssTrait.php b/core/lib/Drupal/Core/Field/AllowedTagsXssTrait.php index 95b18648ab06..c58096a1779f 100644 --- a/core/lib/Drupal/Core/Field/AllowedTagsXssTrait.php +++ b/core/lib/Drupal/Core/Field/AllowedTagsXssTrait.php @@ -24,7 +24,7 @@ trait AllowedTagsXssTrait { * * Used for items entered by administrators, like field descriptions, allowed * values, where some (mainly inline) mark-up may be desired (so - * \Drupal\Component\Utility\SafeMarkup::checkPlain() is not acceptable). + * \Drupal\Component\Utility\Html::escape() is not acceptable). * * @param string $string * The string with raw HTML in it. diff --git a/core/lib/Drupal/Core/Form/form.api.php b/core/lib/Drupal/Core/Form/form.api.php index 917323111dc6..12ce8d15d363 100644 --- a/core/lib/Drupal/Core/Form/form.api.php +++ b/core/lib/Drupal/Core/Form/form.api.php @@ -5,8 +5,6 @@ * Callbacks and hooks related to form system. */ -use Drupal\Component\Utility\SafeMarkup; - /** * @addtogroup callbacks * @{ @@ -79,7 +77,7 @@ function callback_batch_operation($MULTIPLE_PARAMS, &$context) { node_save($node); // Store some result for post-processing in the finished callback. - $context['results'][] = SafeMarkup::checkPlain($node->title); + $context['results'][] = $node->title; // Update our progress information. $context['sandbox']['progress']++; diff --git a/core/lib/Drupal/Core/Menu/menu.api.php b/core/lib/Drupal/Core/Menu/menu.api.php index 3569b24ffc4e..0ae528f90e03 100644 --- a/core/lib/Drupal/Core/Menu/menu.api.php +++ b/core/lib/Drupal/Core/Menu/menu.api.php @@ -461,9 +461,6 @@ function hook_system_breadcrumb_alter(\Drupal\Core\Breadcrumb\Breadcrumb &$bread * must be a string; other elements are more flexible, as they just need * to work as an argument for the constructor of the class * Drupal\Core\Template\Attribute($options['attributes']). - * - html: Whether or not HTML should be allowed as the link text. If FALSE, - * the text will be run through - * \Drupal\Component\Utility\SafeMarkup::checkPlain() before being output. * * @see \Drupal\Core\Routing\UrlGenerator::generateFromPath() * @see \Drupal\Core\Routing\UrlGenerator::generateFromRoute() diff --git a/core/lib/Drupal/Core/Session/AccountInterface.php b/core/lib/Drupal/Core/Session/AccountInterface.php index fa437c0205c6..96aeb2d4a3aa 100644 --- a/core/lib/Drupal/Core/Session/AccountInterface.php +++ b/core/lib/Drupal/Core/Session/AccountInterface.php @@ -116,10 +116,7 @@ public function getPreferredAdminLangcode($fallback_to_default = TRUE); * @see hook_user_format_name_alter() * * @return - * An unsanitized string with the username to display. The code receiving - * this result must ensure that \Drupal\Component\Utility\SafeMarkup::checkPlain() - * is called on it before it is - * printed to the page. + * An unsanitized string with the username to display. */ public function getUsername(); diff --git a/core/lib/Drupal/Core/Utility/Token.php b/core/lib/Drupal/Core/Utility/Token.php index 9966726e5079..f1f80cc8697a 100644 --- a/core/lib/Drupal/Core/Utility/Token.php +++ b/core/lib/Drupal/Core/Utility/Token.php @@ -164,8 +164,8 @@ public function __construct(ModuleHandlerInterface $module_handler, CacheBackend * display to a web browser. Defaults to TRUE. Developers who set this * option to FALSE assume responsibility for running * \Drupal\Component\Utility\Xss::filter(), - * \Drupal\Component\Utility\SafeMarkup::checkPlain() or other appropriate - * scrubbing functions before displaying data to users. + * \Drupal\Component\Utility\Html::escape() or other appropriate scrubbing + * functions before displaying data to users. * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata|null * (optional) An object to which static::generate() and the hooks and * functions that it invokes will add their required bubbleable metadata. @@ -285,8 +285,8 @@ public function scan($text) { * - sanitize: A boolean flag indicating that tokens should be sanitized for * display to a web browser. Developers who set this option to FALSE assume * responsibility for running \Drupal\Component\Utility\Xss::filter(), - * \Drupal\Component\Utility\SafeMarkup::checkPlain() or other appropriate - * scrubbing functions before displaying data to users. + * \Drupal\Component\Utility\Html::escape() or other appropriate scrubbing + * functions before displaying data to users. * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata * The bubbleable metadata. This is passed to the token replacement * implementations so that they can attach their metadata. diff --git a/core/modules/block/src/Controller/BlockController.php b/core/modules/block/src/Controller/BlockController.php index 66ecbbd0767d..32a662668303 100644 --- a/core/modules/block/src/Controller/BlockController.php +++ b/core/modules/block/src/Controller/BlockController.php @@ -7,6 +7,7 @@ namespace Drupal\block\Controller; +use Drupal\Component\Utility\Html; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Extension\ThemeHandler; use Drupal\Core\Extension\ThemeHandlerInterface; @@ -55,7 +56,7 @@ public static function create(ContainerInterface $container) { */ public function demo($theme) { $page = [ - '#title' => $this->themeHandler->getName($theme), + '#title' => Html::escape($this->themeHandler->getName($theme)), '#type' => 'page', '#attached' => array( 'drupalSettings' => [ diff --git a/core/modules/block/src/Controller/CategoryAutocompleteController.php b/core/modules/block/src/Controller/CategoryAutocompleteController.php index 0f6a011e91b4..6d6842cc8961 100644 --- a/core/modules/block/src/Controller/CategoryAutocompleteController.php +++ b/core/modules/block/src/Controller/CategoryAutocompleteController.php @@ -7,8 +7,8 @@ namespace Drupal\block\Controller; +use Drupal\Component\Utility\Html; use Drupal\Core\Block\BlockManagerInterface; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\JsonResponse; @@ -59,7 +59,7 @@ public function autocomplete(Request $request) { $matches = array(); foreach ($this->blockManager->getCategories() as $category) { if (stripos($category, $typed_category) === 0) { - $matches[] = array('value' => $category, 'label' => SafeMarkup::checkPlain($category)); + $matches[] = array('value' => $category, 'label' => Html::escape($category)); } } return new JsonResponse($matches); diff --git a/core/modules/block/src/Tests/BlockUiTest.php b/core/modules/block/src/Tests/BlockUiTest.php index 37fce6e60ae8..721a7e2e518c 100644 --- a/core/modules/block/src/Tests/BlockUiTest.php +++ b/core/modules/block/src/Tests/BlockUiTest.php @@ -86,6 +86,10 @@ public function testBlockDemoUiPage() { $this->clickLink(t('Demonstrate block regions (@theme)', array('@theme' => 'Classy'))); $elements = $this->xpath('//div[contains(@class, "region-highlighted")]/div[contains(@class, "block-region") and contains(text(), :title)]', array(':title' => 'Highlighted')); $this->assertTrue(!empty($elements), 'Block demo regions are shown.'); + + \Drupal::service('theme_handler')->install(array('test_theme')); + $this->drupalGet('admin/structure/block/demo/test_theme'); + $this->assertEscaped('<strong>Test theme</strong>'); } /** diff --git a/core/modules/block/tests/src/Unit/CategoryAutocompleteTest.php b/core/modules/block/tests/src/Unit/CategoryAutocompleteTest.php index 065a25b352e6..812c68a595ca 100644 --- a/core/modules/block/tests/src/Unit/CategoryAutocompleteTest.php +++ b/core/modules/block/tests/src/Unit/CategoryAutocompleteTest.php @@ -7,8 +7,8 @@ namespace Drupal\Tests\block\Unit; +use Drupal\Component\Utility\Html; use Drupal\block\Controller\CategoryAutocompleteController; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Tests\UnitTestCase; use Symfony\Component\HttpFoundation\Request; @@ -48,7 +48,7 @@ protected function setUp() { */ public function testAutocompleteSuggestions($string, $suggestions) { $suggestions = array_map(function ($suggestion) { - return array('value' => $suggestion, 'label' => SafeMarkup::checkPlain($suggestion)); + return array('value' => $suggestion, 'label' => Html::escape($suggestion)); }, $suggestions); $result = $this->autocompleteController->autocomplete(new Request(array('q' => $string))); $this->assertSame($suggestions, json_decode($result->getContent(), TRUE)); diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index edd20a05d0b2..9240ce6ef36f 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -16,7 +16,6 @@ use Drupal\comment\Entity\CommentType; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; @@ -579,7 +578,7 @@ function comment_preview(CommentInterface $comment, FormStateInterface $form_sta if (!empty($account) && $account->isAuthenticated()) { $comment->setOwner($account); - $comment->setAuthorName(SafeMarkup::checkPlain($account->getUsername())); + $comment->setAuthorName($account->getUsername()); } elseif (empty($author_name)) { $comment->setAuthorName(\Drupal::config('user.settings')->get('anonymous')); diff --git a/core/modules/comment/src/Plugin/views/argument/UserUid.php b/core/modules/comment/src/Plugin/views/argument/UserUid.php index 5195a7a0a803..c408f31ebea7 100644 --- a/core/modules/comment/src/Plugin/views/argument/UserUid.php +++ b/core/modules/comment/src/Plugin/views/argument/UserUid.php @@ -7,7 +7,6 @@ namespace Drupal\comment\Plugin\views\argument; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Database\Connection; use Drupal\views\Plugin\views\argument\ArgumentPluginBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -65,7 +64,7 @@ function title() { return $this->t('No user'); } - return SafeMarkup::checkPlain($title); + return $title; } protected function defaultActions($which = NULL) { diff --git a/core/modules/comment/src/Tests/CommentPreviewTest.php b/core/modules/comment/src/Tests/CommentPreviewTest.php index a1d0804eac39..ae92de083a28 100644 --- a/core/modules/comment/src/Tests/CommentPreviewTest.php +++ b/core/modules/comment/src/Tests/CommentPreviewTest.php @@ -8,6 +8,7 @@ namespace Drupal\comment\Tests; use Drupal\comment\CommentManagerInterface; +use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\comment\Entity\Comment; @@ -39,17 +40,31 @@ function testCommentPreview() { $this->setCommentSettings('default_mode', CommentManagerInterface::COMMENT_MODE_THREADED, 'Comment paging changed.'); $this->drupalLogout(); - // Login as web user and add a user picture. + // Login as web user. $this->drupalLogin($this->webUser); - $image = current($this->drupalGetTestFiles('image')); - $edit['files[user_picture_0]'] = drupal_realpath($image->uri); - $this->drupalPostForm('user/' . $this->webUser->id() . '/edit', $edit, t('Save')); - // As the web user, fill in the comment form and preview the comment. + // Test escaping of the username on the preview form. + \Drupal::service('module_installer')->install(['user_hooks_test']); + \Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE); $edit = array(); $edit['subject[0][value]'] = $this->randomMachineName(8); $edit['comment_body[0][value]'] = $this->randomMachineName(16); $this->drupalPostForm('node/' . $this->node->id(), $edit, t('Preview')); + $this->assertEscaped('<em>' . $this->webUser->id() . '</em>'); + + \Drupal::state()->set('user_hooks_test_user_format_name_alter_safe', TRUE); + $this->drupalPostForm('node/' . $this->node->id(), $edit, t('Preview')); + $this->assertTrue(SafeMarkup::isSafe($this->webUser->getUsername()), 'Username is marked safe'); + $this->assertNoEscaped('<em>' . $this->webUser->id() . '</em>'); + $this->assertRaw('<em>' . $this->webUser->id() . '</em>'); + + // Add a user picture. + $image = current($this->drupalGetTestFiles('image')); + $user_edit['files[user_picture_0]'] = drupal_realpath($image->uri); + $this->drupalPostForm('user/' . $this->webUser->id() . '/edit', $user_edit, t('Save')); + + // As the web user, fill in the comment form and preview the comment. + $this->drupalPostForm('node/' . $this->node->id(), $edit, t('Preview')); // Check that the preview is displaying the title and body. $this->assertTitle(t('Preview comment | Drupal'), 'Page title is "Preview comment".'); diff --git a/core/modules/field_ui/src/Form/FieldConfigEditForm.php b/core/modules/field_ui/src/Form/FieldConfigEditForm.php index 2bbd68e3366a..ba972a9f9976 100644 --- a/core/modules/field_ui/src/Form/FieldConfigEditForm.php +++ b/core/modules/field_ui/src/Form/FieldConfigEditForm.php @@ -7,7 +7,6 @@ namespace Drupal\field_ui\Form; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Entity\EntityForm; use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Field\FieldFilteredString; @@ -203,7 +202,7 @@ public function save(array $form, FormStateInterface $form_state) { * The label of the field. */ public function getTitle(FieldConfigInterface $field_config) { - return SafeMarkup::checkPlain($field_config->label()); + return $field_config->label(); } } diff --git a/core/modules/field_ui/src/Tests/ManageFieldsTest.php b/core/modules/field_ui/src/Tests/ManageFieldsTest.php index 1f3d1916ffdd..f1db4d4afe35 100644 --- a/core/modules/field_ui/src/Tests/ManageFieldsTest.php +++ b/core/modules/field_ui/src/Tests/ManageFieldsTest.php @@ -80,8 +80,8 @@ protected function setUp() { $type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name)); $this->contentType = $type->id(); - // Create random field name. - $this->fieldLabel = $this->randomMachineName(8); + // Create random field name with markup to test escaping. + $this->fieldLabel = '<em>' . $this->randomMachineName(8) . '</em>'; $this->fieldNameInput = strtolower($this->randomMachineName(8)); $this->fieldName = 'field_'. $this->fieldNameInput; @@ -194,6 +194,7 @@ function updateField() { $field_id = 'node.' . $this->contentType . '.' . $this->fieldName; // Go to the field edit page. $this->drupalGet('admin/structure/types/manage/' . $this->contentType . '/fields/' . $field_id . '/storage'); + $this->assertEscaped($this->fieldLabel); // Populate the field settings with new settings. $string = 'updated dummy test string'; diff --git a/core/modules/filter/src/Tests/FilterUnitTest.php b/core/modules/filter/src/Tests/FilterUnitTest.php index cc9da598d150..f441342dff42 100644 --- a/core/modules/filter/src/Tests/FilterUnitTest.php +++ b/core/modules/filter/src/Tests/FilterUnitTest.php @@ -479,8 +479,6 @@ function testNoFollowFilter() { /** * Tests the HTML escaping filter. - * - * \Drupal\Component\Utility\SafeMarkup::checkPlain() is not tested here. */ function testHtmlEscapeFilter() { // Get FilterHtmlEscape object. diff --git a/core/modules/node/src/Controller/NodePreviewController.php b/core/modules/node/src/Controller/NodePreviewController.php index 96b65b5bc0a0..b1009be10fa3 100644 --- a/core/modules/node/src/Controller/NodePreviewController.php +++ b/core/modules/node/src/Controller/NodePreviewController.php @@ -7,7 +7,6 @@ namespace Drupal\node\Controller; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\Controller\EntityViewController; @@ -61,7 +60,7 @@ public function view(EntityInterface $node_preview, $view_mode_id = 'full', $lan * The page title. */ public function title(EntityInterface $node_preview) { - return SafeMarkup::checkPlain($this->entityManager->getTranslationFromContext($node_preview)->label()); + return $this->entityManager->getTranslationFromContext($node_preview)->label(); } } diff --git a/core/modules/node/src/Plugin/views/argument/Type.php b/core/modules/node/src/Plugin/views/argument/Type.php index 26ab17afcb1f..62ab17dbbfaf 100644 --- a/core/modules/node/src/Plugin/views/argument/Type.php +++ b/core/modules/node/src/Plugin/views/argument/Type.php @@ -7,7 +7,6 @@ namespace Drupal\node\Plugin\views\argument; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\views\Plugin\views\argument\StringArgument; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -76,7 +75,7 @@ function title() { function node_type($type_name) { $type = $this->nodeTypeStorage->load($type_name); $output = $type ? $type->label() : $this->t('Unknown content type'); - return SafeMarkup::checkPlain($output); + return $output; } } diff --git a/core/modules/node/src/Plugin/views/row/Rss.php b/core/modules/node/src/Plugin/views/row/Rss.php index 098012f76e1e..e73d527285f3 100644 --- a/core/modules/node/src/Plugin/views/row/Rss.php +++ b/core/modules/node/src/Plugin/views/row/Rss.php @@ -7,7 +7,6 @@ namespace Drupal\node\Plugin\views\row; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\views\Plugin\views\row\RssPluginBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -78,7 +77,7 @@ public function buildOptionsForm_summary_options() { public function summaryTitle() { $options = $this->buildOptionsForm_summary_options(); - return SafeMarkup::checkPlain($options[$this->options['view_mode']]); + return $options[$this->options['view_mode']]; } public function preRender($values) { diff --git a/core/modules/node/src/Tests/PagePreviewTest.php b/core/modules/node/src/Tests/PagePreviewTest.php index 1c2d2259c0c2..6408e4d5cd49 100644 --- a/core/modules/node/src/Tests/PagePreviewTest.php +++ b/core/modules/node/src/Tests/PagePreviewTest.php @@ -139,7 +139,7 @@ function testPagePreview() { // Fill in node creation form and preview node. $edit = array(); - $edit[$title_key] = $this->randomMachineName(8); + $edit[$title_key] = '<em>' . $this->randomMachineName(8) . '</em>'; $edit[$body_key] = $this->randomMachineName(16); $edit[$term_key] = $this->term->getName(); @@ -153,7 +153,7 @@ function testPagePreview() { // Check that the preview is displaying the title, body and term. $this->assertTitle(t('@title | Drupal', array('@title' => $edit[$title_key])), 'Basic page title is preview.'); - $this->assertText($edit[$title_key], 'Title displayed.'); + $this->assertEscaped($edit[$title_key], 'Title displayed and escaped.'); $this->assertText($edit[$body_key], 'Body displayed.'); $this->assertText($edit[$term_key], 'Term displayed.'); $this->assertLink(t('Back to content editing')); @@ -185,7 +185,7 @@ function testPagePreview() { // Return to page preview to check everything is as expected. $this->drupalPostForm(NULL, array(), t('Preview')); $this->assertTitle(t('@title | Drupal', array('@title' => $edit[$title_key])), 'Basic page title is preview.'); - $this->assertText($edit[$title_key], 'Title displayed.'); + $this->assertEscaped($edit[$title_key], 'Title displayed and escaped.'); $this->assertText($edit[$body_key], 'Body displayed.'); $this->assertText($edit[$term_key], 'Term displayed.'); $this->assertLink(t('Back to content editing')); diff --git a/core/modules/node/src/Tests/Views/NodeIntegrationTest.php b/core/modules/node/src/Tests/Views/NodeIntegrationTest.php index b4188b705355..86daefa9508e 100644 --- a/core/modules/node/src/Tests/Views/NodeIntegrationTest.php +++ b/core/modules/node/src/Tests/Views/NodeIntegrationTest.php @@ -29,7 +29,7 @@ public function testNodeViewTypeArgument() { $types = array(); $all_nids = array(); for ($i = 0; $i < 2; $i++) { - $type = $this->drupalCreateContentType(); + $type = $this->drupalCreateContentType(['name' => '<em>' . $this->randomMachineName() . '</em>']); $types[] = $type; for ($j = 0; $j < 5; $j++) { @@ -49,6 +49,7 @@ public function testNodeViewTypeArgument() { foreach ($types as $type) { $this->drupalGet("test-node-view/{$type->id()}"); + $this->assertEscaped($type->label()); $this->assertNids(array_keys($nodes[$type->id()])); } } diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_view.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_view.yml index f9c2bdf1e674..c5cf7f65fbff 100644 --- a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_view.yml +++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_view.yml @@ -167,8 +167,8 @@ display: value: all title_enable: false title: All - title_enable: false - title: '' + title_enable: true + title: '{{ arguments.type }}' default_argument_type: fixed default_argument_options: argument: '' diff --git a/core/modules/options/src/Plugin/views/argument/NumberListField.php b/core/modules/options/src/Plugin/views/argument/NumberListField.php index 4e22f9c64000..a96f27ef71f9 100644 --- a/core/modules/options/src/Plugin/views/argument/NumberListField.php +++ b/core/modules/options/src/Plugin/views/argument/NumberListField.php @@ -7,7 +7,6 @@ namespace Drupal\options\Plugin\views\argument; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Field\FieldFilteredString; use Drupal\Core\Form\FormStateInterface; @@ -85,7 +84,7 @@ public function summaryName($data) { } // Else, fallback to the key. else { - return SafeMarkup::checkPlain($value); + return $value; } } diff --git a/core/modules/rest/src/Tests/Views/StyleSerializerTest.php b/core/modules/rest/src/Tests/Views/StyleSerializerTest.php index c96c275793f3..8fdbec46d7b5 100644 --- a/core/modules/rest/src/Tests/Views/StyleSerializerTest.php +++ b/core/modules/rest/src/Tests/Views/StyleSerializerTest.php @@ -395,7 +395,7 @@ public function testUIFieldAlias() { $expected[] = $expected_row; } - $this->assertIdentical($this->drupalGetJSON('test/serialize/field'), $expected); + $this->assertIdentical($this->drupalGetJSON('test/serialize/field'), $this->castSafeStrings($expected)); // Test a random aliases for fields, they should be replaced. $alias_map = array( @@ -430,7 +430,7 @@ public function testUIFieldAlias() { $expected[] = $expected_row; } - $this->assertIdentical($this->drupalGetJSON('test/serialize/field'), $expected); + $this->assertIdentical($this->drupalGetJSON('test/serialize/field'), $this->castSafeStrings($expected)); } /** diff --git a/core/modules/simpletest/src/AssertContentTrait.php b/core/modules/simpletest/src/AssertContentTrait.php index 87e888736635..eb1a80c66119 100644 --- a/core/modules/simpletest/src/AssertContentTrait.php +++ b/core/modules/simpletest/src/AssertContentTrait.php @@ -437,7 +437,7 @@ protected function assertNoLinkByHrefInMainRegion($href, $message = '', $group = */ protected function assertRaw($raw, $message = '', $group = 'Other') { if (!$message) { - $message = SafeMarkup::format('Raw "@raw" found', array('@raw' => $raw)); + $message = 'Raw "' . Html::escape($raw) . '" found'; } return $this->assert(strpos($this->getRawContent(), (string) $raw) !== FALSE, $message, $group); } @@ -465,7 +465,7 @@ protected function assertRaw($raw, $message = '', $group = 'Other') { */ protected function assertNoRaw($raw, $message = '', $group = 'Other') { if (!$message) { - $message = SafeMarkup::format('Raw "@raw" not found', array('@raw' => $raw)); + $message = 'Raw "' . Html::escape($raw) . '" not found'; } return $this->assert(strpos($this->getRawContent(), (string) $raw) === FALSE, $message, $group); } @@ -493,7 +493,7 @@ protected function assertNoRaw($raw, $message = '', $group = 'Other') { */ protected function assertEscaped($raw, $message = '', $group = 'Other') { if (!$message) { - $message = SafeMarkup::format('Escaped "@raw" found', array('@raw' => $raw)); + $message = 'Escaped "' . Html::escape($raw) . '" found'; } return $this->assert(strpos($this->getRawContent(), Html::escape($raw)) !== FALSE, $message, $group); } @@ -522,7 +522,7 @@ protected function assertEscaped($raw, $message = '', $group = 'Other') { */ protected function assertNoEscaped($raw, $message = '', $group = 'Other') { if (!$message) { - $message = SafeMarkup::format('Escaped "@raw" not found', array('@raw' => $raw)); + $message = 'Escaped "' . Html::escape($raw) . '" not found'; } return $this->assert(strpos($this->getRawContent(), Html::escape($raw)) === FALSE, $message, $group); } diff --git a/core/modules/system/src/Tests/System/ThemeTest.php b/core/modules/system/src/Tests/System/ThemeTest.php index c04560e8174c..cde72e06b26e 100644 --- a/core/modules/system/src/Tests/System/ThemeTest.php +++ b/core/modules/system/src/Tests/System/ThemeTest.php @@ -348,9 +348,9 @@ function testUninstallingThemes() { */ function testInstallAndSetAsDefault() { $this->drupalGet('admin/appearance'); - // Bartik is uninstalled in the test profile and has the second "Install and + // Bartik is uninstalled in the test profile and has the third "Install and // set as default" link. - $this->clickLink(t('Install and set as default'), 1); + $this->clickLink(t('Install and set as default'), 2); // Test the confirmation message. $this->assertText('Bartik is now the default theme.'); // Make sure Bartik is now set as the default theme in config. diff --git a/core/modules/system/tests/themes/test_theme/test_theme.info.yml b/core/modules/system/tests/themes/test_theme/test_theme.info.yml index e9d660253137..8f613bf2ccf6 100644 --- a/core/modules/system/tests/themes/test_theme/test_theme.info.yml +++ b/core/modules/system/tests/themes/test_theme/test_theme.info.yml @@ -8,7 +8,7 @@ # here in order for a test to ensure that this correctly prevents the module # version from being loaded, and that errors aren't caused by the lack of this # file within the theme folder. -name: 'Test theme' +name: '<strong>Test theme</strong>' type: theme description: 'Theme for testing the theme system' version: VERSION diff --git a/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepth.php b/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepth.php index f5bd524d75a9..e2df37fadb8f 100644 --- a/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepth.php +++ b/core/modules/taxonomy/src/Plugin/views/argument/IndexTidDepth.php @@ -11,7 +11,6 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\views\Plugin\views\argument\ArgumentPluginBase; -use Drupal\Component\Utility\SafeMarkup; use Drupal\taxonomy\Entity\Term; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -140,7 +139,7 @@ public function query($group_by = FALSE) { function title() { $term = $this->termStorage->load($this->argument); if (!empty($term)) { - return SafeMarkup::checkPlain($term->getName()); + return $term->getName(); } // TODO review text return $this->t('No name'); diff --git a/core/modules/taxonomy/src/Plugin/views/argument/Taxonomy.php b/core/modules/taxonomy/src/Plugin/views/argument/Taxonomy.php index ca365974f85d..ecf27f9d4269 100644 --- a/core/modules/taxonomy/src/Plugin/views/argument/Taxonomy.php +++ b/core/modules/taxonomy/src/Plugin/views/argument/Taxonomy.php @@ -10,7 +10,6 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\views\Plugin\views\argument\NumericArgument; -use Drupal\Component\Utility\SafeMarkup; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -56,7 +55,7 @@ function title() { if ($this->argument) { $term = $this->termStorage->load($this->argument); if (!empty($term)) { - return SafeMarkup::checkPlain($term->getName()); + return $term->getName(); } } // TODO review text diff --git a/core/modules/taxonomy/src/Plugin/views/argument/VocabularyVid.php b/core/modules/taxonomy/src/Plugin/views/argument/VocabularyVid.php index 7aedd518e082..80c27b8308c7 100644 --- a/core/modules/taxonomy/src/Plugin/views/argument/VocabularyVid.php +++ b/core/modules/taxonomy/src/Plugin/views/argument/VocabularyVid.php @@ -8,7 +8,6 @@ namespace Drupal\taxonomy\Plugin\views\argument; use Drupal\views\Plugin\views\argument\NumericArgument; -use Drupal\Component\Utility\SafeMarkup; use Drupal\taxonomy\VocabularyStorageInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -63,7 +62,7 @@ public static function create(ContainerInterface $container, array $configuratio function title() { $vocabulary = $this->vocabularyStorage->load($this->argument); if ($vocabulary) { - return SafeMarkup::checkPlain($vocabulary->label()); + return $vocabulary->label(); } return $this->t('No vocabulary'); diff --git a/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php index 3f40fc8f0b56..3049f6f7f20d 100644 --- a/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php +++ b/core/modules/taxonomy/src/Plugin/views/field/TaxonomyIndexTid.php @@ -11,7 +11,6 @@ use Drupal\views\ViewExecutable; use Drupal\views\Plugin\views\display\DisplayPluginBase; use Drupal\views\Plugin\views\field\PrerenderList; -use Drupal\Component\Utility\SafeMarkup; use Drupal\taxonomy\Entity\Vocabulary; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\taxonomy\VocabularyStorageInterface; @@ -153,7 +152,7 @@ public function preRender(&$values) { $this->items[$node_nid][$tid]['name'] = \Drupal::entityManager()->getTranslationFromContext($term)->label(); $this->items[$node_nid][$tid]['tid'] = $tid; $this->items[$node_nid][$tid]['vocabulary_vid'] = $term->getVocabularyId(); - $this->items[$node_nid][$tid]['vocabulary'] = SafeMarkup::checkPlain($vocabularies[$term->getVocabularyId()]->label()); + $this->items[$node_nid][$tid]['vocabulary'] = $vocabularies[$term->getVocabularyId()]->label(); if (!empty($this->options['link_to_taxonomy'])) { $this->items[$node_nid][$tid]['make_link'] = TRUE; diff --git a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php index 5c46a85129a5..01086b08b69e 100644 --- a/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php +++ b/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTid.php @@ -16,7 +16,6 @@ use Drupal\views\ViewExecutable; use Drupal\views\Plugin\views\display\DisplayPluginBase; use Drupal\views\Plugin\views\filter\ManyToOne; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\Tags; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -359,7 +358,7 @@ public function adminSummary() { $this->value = array_filter($this->value); $terms = Term::loadMultiple($this->value); foreach ($terms as $term) { - $this->valueOptions[$term->id()] = SafeMarkup::checkPlain(\Drupal::entityManager()->getTranslationFromContext($term)->label()); + $this->valueOptions[$term->id()] = \Drupal::entityManager()->getTranslationFromContext($term)->label(); } } return parent::adminSummary(); diff --git a/core/modules/taxonomy/src/Tests/Views/TaxonomyDefaultArgumentTest.php b/core/modules/taxonomy/src/Tests/Views/TaxonomyDefaultArgumentTest.php index aeae56719c83..fc9371ea5554 100644 --- a/core/modules/taxonomy/src/Tests/Views/TaxonomyDefaultArgumentTest.php +++ b/core/modules/taxonomy/src/Tests/Views/TaxonomyDefaultArgumentTest.php @@ -59,4 +59,14 @@ public function testTermPath() { $expected = $this->term1->id(); $this->assertEqual($expected, $view->argument['tid']->getDefaultArgument()); } + + /** + * Tests escaping of page title when the taxonomy plugin provides it. + */ + public function testTermTitleEscaping() { + $this->term1->setName('<em>Markup</em>')->save(); + $this->drupalGet('taxonomy_default_argument_test/'. $this->term1->id()); + $this->assertEscaped($this->term1->label()); + } + } diff --git a/core/modules/taxonomy/src/Tests/Views/TaxonomyFieldAllTermsTest.php b/core/modules/taxonomy/src/Tests/Views/TaxonomyFieldAllTermsTest.php index 8329d040362b..a913fa654435 100644 --- a/core/modules/taxonomy/src/Tests/Views/TaxonomyFieldAllTermsTest.php +++ b/core/modules/taxonomy/src/Tests/Views/TaxonomyFieldAllTermsTest.php @@ -28,6 +28,7 @@ class TaxonomyFieldAllTermsTest extends TaxonomyTestBase { * Tests the "all terms" field handler. */ public function testViewsHandlerAllTermsField() { + $this->term1->setName('<em>Markup</em>')->save(); $view = Views::getView('taxonomy_all_terms_test'); $this->executeView($view); $this->drupalGet('taxonomy_all_terms_test'); @@ -36,6 +37,7 @@ public function testViewsHandlerAllTermsField() { $this->assertEqual(count($actual), 2, 'Correct number of taxonomy term1 links'); $this->assertEqual($actual[0]->__toString(), $this->term1->label()); $this->assertEqual($actual[1]->__toString(), $this->term1->label()); + $this->assertEscaped($this->term1->label()); $actual = $this->xpath('//a[@href="' . $this->term2->url() . '"]'); $this->assertEqual(count($actual), 2, 'Correct number of taxonomy term2 links'); diff --git a/core/modules/taxonomy/src/Tests/Views/TaxonomyTermArgumentDepthTest.php b/core/modules/taxonomy/src/Tests/Views/TaxonomyTermArgumentDepthTest.php new file mode 100644 index 000000000000..e4f74a93ca61 --- /dev/null +++ b/core/modules/taxonomy/src/Tests/Views/TaxonomyTermArgumentDepthTest.php @@ -0,0 +1,64 @@ +<?php + +/** + * @file + * Contains \Drupal\taxonomy\Tests\Views\TaxonomyTermArgumentDepthTest. + */ + +namespace Drupal\taxonomy\Tests\Views; + +/** + * Tests the taxonomy term with depth argument. + * + * @group taxonomy + */ +class TaxonomyTermArgumentDepthTest extends TaxonomyTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = ['taxonomy', 'taxonomy_test_views', 'views', 'node']; + + /** + * {@inheritdoc} + */ + public static $testViews = ['test_argument_taxonomy_index_tid_depth']; + + /** + * @var \Drupal\taxonomy\TermInterface[] + */ + protected $terms = []; + + /** + * @var \Drupal\views\ViewExecutable + */ + protected $view; + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + + // Create a term with markup in the label. + $first = $this->createTerm(['name' => '<em>First</em>']); + + // Create a node w/o any terms. + $settings = ['type' => 'article']; + + // Create a node with linked to the term. + $settings['field_views_testing_tags'][0]['target_id'] = $first->id(); + $this->nodes[] = $this->drupalCreateNode($settings); + + $this->terms[0] = $first; + } + + /** + * Tests title escaping. + */ + public function testTermWithDepthArgumentTitleEscaping() { + $this->drupalGet('test_argument_taxonomy_index_tid_depth/' . $this->terms[0]->id()); + $this->assertEscaped($this->terms[0]->label()); + } + +} diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.taxonomy_default_argument_test.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.taxonomy_default_argument_test.yml index 615972b7380f..2f556af5a185 100644 --- a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.taxonomy_default_argument_test.yml +++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.taxonomy_default_argument_test.yml @@ -163,3 +163,10 @@ display: entity_type: taxonomy_term entity_field: tid rendering_language: '***LANGUAGE_entity_translation***' + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: null + display_options: + path: taxonomy_default_argument_test diff --git a/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_argument_taxonomy_index_tid_depth.yml b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_argument_taxonomy_index_tid_depth.yml new file mode 100644 index 000000000000..103f4f75e0b9 --- /dev/null +++ b/core/modules/taxonomy/tests/modules/taxonomy_test_views/test_views/views.view.test_argument_taxonomy_index_tid_depth.yml @@ -0,0 +1,227 @@ +langcode: en +status: true +dependencies: + module: + - node + - taxonomy + - user +id: test_argument_taxonomy_index_tid_depth +label: test_argument_taxonomy_index_tid_depth +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access content' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: full + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: '‹ previous' + next: 'next ›' + first: '« first' + last: 'last »' + quantity: 9 + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + uses_fields: false + row: + type: fields + options: + inline: { } + separator: '' + hide_empty: false + default_field_elements: true + fields: + title: + id: title + table: node_field_data + field: title + entity_type: node + entity_field: title + label: '' + alter: + alter_text: false + make_link: false + absolute: false + trim: false + word_boundary: false + ellipsis: false + strip_tags: false + html: false + hide_empty: false + empty_zero: false + settings: + link_to_entity: true + plugin_id: field + relationship: none + group_type: group + admin_label: '' + exclude: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_alter_empty: true + click_sort_column: value + type: string + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + filters: + status: + value: true + table: node_field_data + field: status + plugin_id: boolean + entity_type: node + entity_field: status + id: status + expose: + operator: '' + group: 1 + sorts: + created: + id: created + table: node_field_data + field: created + order: DESC + entity_type: node + entity_field: created + plugin_id: date + relationship: none + group_type: group + admin_label: '' + exposed: false + expose: + label: '' + granularity: second + header: { } + footer: { } + empty: { } + relationships: { } + arguments: + term_node_tid_depth: + id: term_node_tid_depth + table: node_field_data + field: term_node_tid_depth + relationship: none + group_type: group + admin_label: '' + default_action: ignore + exception: + value: all + title_enable: false + title: All + title_enable: true + title: '{{ arguments.term_node_tid_depth }}' + default_argument_type: fixed + default_argument_options: + argument: '' + default_argument_skip_url: false + summary_options: + base_path: '' + count: true + items_per_page: 25 + override: false + summary: + sort_order: asc + number_of_records: 0 + format: default_summary + specify_validation: false + validate: + type: none + fail: 'not found' + validate_options: { } + depth: 0 + break_phrase: false + use_taxonomy_term_path: false + entity_type: node + plugin_id: taxonomy_index_tid_depth + display_extenders: { } + cache_metadata: + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - 'user.node_grants:view' + - user.permissions + cacheable: false + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: test_argument_taxonomy_index_tid_depth + cache_metadata: + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - 'user.node_grants:view' + - user.permissions + cacheable: false diff --git a/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php b/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php index 13d15c925473..a3697e8cee54 100644 --- a/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php +++ b/core/modules/text/src/Plugin/Field/FieldType/TextItemBase.php @@ -43,7 +43,6 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel * {@inheritdoc} */ public function applyDefaultValue($notify = TRUE) { - // Default to a simple \Drupal\Component\Utility\SafeMarkup::checkPlain(). // @todo: Add in the filter default format here. $this->setValue(array('format' => NULL), $notify); return $this; diff --git a/core/modules/text/src/TextProcessed.php b/core/modules/text/src/TextProcessed.php index 364937b52f5c..d41cb92b89a2 100644 --- a/core/modules/text/src/TextProcessed.php +++ b/core/modules/text/src/TextProcessed.php @@ -49,8 +49,7 @@ public function getValue($langcode = NULL) { $item = $this->getParent(); $text = $item->{($this->definition->getSetting('text source'))}; - // Avoid running check_markup() or - // \Drupal\Component\Utility\SafeMarkup::checkPlain() on empty strings. + // Avoid running check_markup() on empty strings. if (!isset($text) || $text === '') { $this->processed = ''; } diff --git a/core/modules/tracker/src/Controller/TrackerUserTab.php b/core/modules/tracker/src/Controller/TrackerUserTab.php index ae215487a504..3aca4c07b833 100644 --- a/core/modules/tracker/src/Controller/TrackerUserTab.php +++ b/core/modules/tracker/src/Controller/TrackerUserTab.php @@ -9,7 +9,6 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\user\UserInterface; -use Drupal\Component\Utility\SafeMarkup; /** * Controller for tracker.user_tab route. @@ -28,6 +27,6 @@ public function getContent(UserInterface $user) { * Title callback for the tracker.user_tab route. */ public function getTitle(UserInterface $user) { - return SafeMarkup::checkPlain($user->getUsername()); + return $user->getUsername(); } } diff --git a/core/modules/tracker/src/Tests/TrackerTest.php b/core/modules/tracker/src/Tests/TrackerTest.php index 7450ba9732cc..0b0a91ece93b 100644 --- a/core/modules/tracker/src/Tests/TrackerTest.php +++ b/core/modules/tracker/src/Tests/TrackerTest.php @@ -198,6 +198,17 @@ function testTrackerUser() { $this->drupalPostForm('comment/1/edit', array('status' => CommentInterface::NOT_PUBLISHED), t('Save')); $this->drupalGet('user/' . $this->user->id() . '/activity'); $this->assertNoText($other_published_my_comment->label(), 'Unpublished comments are not counted on the tracker listing.'); + + // Test escaping of title on user's tracker tab. + \Drupal::service('module_installer')->install(['user_hooks_test']); + \Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE); + $this->drupalGet('user/' . $this->user->id() . '/activity'); + $this->assertEscaped('<em>' . $this->user->id() . '</em>'); + + \Drupal::state()->set('user_hooks_test_user_format_name_alter_safe', TRUE); + $this->drupalGet('user/' . $this->user->id() . '/activity'); + $this->assertNoEscaped('<em>' . $this->user->id() . '</em>'); + $this->assertRaw('<em>' . $this->user->id() . '</em>'); } /** diff --git a/core/modules/user/src/Plugin/Condition/UserRole.php b/core/modules/user/src/Plugin/Condition/UserRole.php index 3316cbc7b90b..f6ddb87d44f9 100644 --- a/core/modules/user/src/Plugin/Condition/UserRole.php +++ b/core/modules/user/src/Plugin/Condition/UserRole.php @@ -33,7 +33,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#type' => 'checkboxes', '#title' => $this->t('When the user has the following roles'), '#default_value' => $this->configuration['roles'], - '#options' => array_map('\Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names()), + '#options' => array_map('\Drupal\Component\Utility\Html::escape', user_role_names()), '#description' => $this->t('If you select no roles, the condition will evaluate to TRUE for all users.'), ); return parent::buildConfigurationForm($form, $form_state); diff --git a/core/modules/user/src/Plugin/views/access/Role.php b/core/modules/user/src/Plugin/views/access/Role.php index cd3a32233b2e..42404cea5043 100644 --- a/core/modules/user/src/Plugin/views/access/Role.php +++ b/core/modules/user/src/Plugin/views/access/Role.php @@ -97,7 +97,7 @@ public function summaryTitle() { else { $rids = user_role_names(); $rid = reset($this->options['role']); - return SafeMarkup::checkPlain($rids[$rid]); + return $rids[$rid]; } } diff --git a/core/modules/user/src/Plugin/views/field/Roles.php b/core/modules/user/src/Plugin/views/field/Roles.php index 00a1918c19be..e00da614fc6d 100644 --- a/core/modules/user/src/Plugin/views/field/Roles.php +++ b/core/modules/user/src/Plugin/views/field/Roles.php @@ -7,7 +7,6 @@ namespace Drupal\user\Plugin\views\field; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Database\Connection; use Drupal\views\Plugin\views\display\DisplayPluginBase; use Drupal\views\ViewExecutable; @@ -81,7 +80,7 @@ public function preRender(&$values) { $roles = user_roles(); $result = $this->database->query('SELECT u.entity_id as uid, u.roles_target_id as rid FROM {user__roles} u WHERE u.entity_id IN ( :uids[] ) AND u.roles_target_id IN ( :rids[] )', array(':uids[]' => $uids, ':rids[]' => array_keys($roles))); foreach ($result as $role) { - $this->items[$role->uid][$role->rid]['role'] = SafeMarkup::checkPlain($roles[$role->rid]->label()); + $this->items[$role->uid][$role->rid]['role'] = $roles[$role->rid]->label(); $this->items[$role->uid][$role->rid]['rid'] = $role->rid; } // Sort the roles for each user by role weight. diff --git a/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php b/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php index 0072d678f61c..9434925d552f 100644 --- a/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php +++ b/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php @@ -7,6 +7,7 @@ namespace Drupal\user\Tests\Views; +use Drupal\Component\Utility\Html; use Drupal\views\Views; use Drupal\user\Entity\User; @@ -28,7 +29,7 @@ class HandlerFieldRoleTest extends UserTestBase { public function testRole() { // Create a couple of roles for the view. $rolename_a = 'a' . $this->randomMachineName(8); - $this->drupalCreateRole(array('access content'), $rolename_a, $rolename_a, 9); + $this->drupalCreateRole(array('access content'), $rolename_a, '<em>' . $rolename_a . '</em>', 9); $rolename_b = 'b' . $this->randomMachineName(8); $this->drupalCreateRole(array('access content'), $rolename_b, $rolename_b, 8); @@ -42,16 +43,10 @@ public function testRole() { $user->addRole($rolename_b); $user->save(); - debug(db_query('SELECT * FROM {user__roles}')->fetchAll()); - - $view = Views::getView('test_views_handler_field_role'); - $this->executeView($view); - // The role field is populated during preRender. - $view->field['roles_target_id']->preRender($view->result); - $render = $view->field['roles_target_id']->advancedRender($view->result[0]); - - $this->assertEqual($rolename_b . $rolename_a, $render, 'View test_views_handler_field_role renders role assigned to user in the correct order.'); - $this->assertFalse(strpos($render, $rolename_not_assigned), 'View test_views_handler_field_role does not render a role not assigned to a user.'); + $this->drupalLogin($this->createUser(['access user profiles'])); + $this->drupalGet('/test-views-handler-field-role'); + $this->assertText($rolename_b . Html::escape('<em>' . $rolename_a . '</em>'), 'View test_views_handler_field_role renders role assigned to user in the correct order and markup in role names is escaped.'); + $this->assertNoText($rolename_not_assigned, 'View test_views_handler_field_role does not render a role not assigned to a user.'); } } diff --git a/core/modules/user/tests/modules/user_hooks_test/user_hooks_test.info.yml b/core/modules/user/tests/modules/user_hooks_test/user_hooks_test.info.yml new file mode 100644 index 000000000000..2e56f1736d67 --- /dev/null +++ b/core/modules/user/tests/modules/user_hooks_test/user_hooks_test.info.yml @@ -0,0 +1,6 @@ +name: 'User module hooks tests' +type: module +description: 'Support module for user hooks testing.' +package: Testing +version: VERSION +core: 8.x diff --git a/core/modules/user/tests/modules/user_hooks_test/user_hooks_test.module b/core/modules/user/tests/modules/user_hooks_test/user_hooks_test.module new file mode 100644 index 000000000000..a036c65c6b0f --- /dev/null +++ b/core/modules/user/tests/modules/user_hooks_test/user_hooks_test.module @@ -0,0 +1,22 @@ +<?php + +/** + * @file + * Support module for user hooks testing. + */ + +use Drupal\Component\Utility\SafeMarkup; + +/** + * Implements hook_user_format_name_alter(). + */ +function user_hooks_test_user_format_name_alter(&$name, $account) { + if (\Drupal::state()->get('user_hooks_test_user_format_name_alter', FALSE)) { + if (\Drupal::state()->get('user_hooks_test_user_format_name_alter_safe', FALSE)) { + $name = SafeMarkup::format('<em>@uid</em>', array('@uid' => $account->id())); + } + else { + $name = '<em>' . $account->id() . '</em>'; + } + } +} diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 4f8289b381ce..70e4a0c00b3e 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -413,9 +413,7 @@ function user_preprocess_block(&$variables) { * The account object for the user whose name is to be formatted. * * @return string - * An unsanitized string with the username to display. The code receiving - * this result must ensure that \Drupal\Component\Utility\SafeMarkup::checkPlain() - * is called on it before it is printed to the page. + * An unsanitized string with the username to display. * * @deprecated in Drupal 8.0.x-dev, will be removed before Drupal 9.0.0. * Use \Drupal\Core\Session\AccountInterface::getUsername(). @@ -453,9 +451,7 @@ function user_template_preprocess_default_variables_alter(&$variables) { * - account: The user account (\Drupal\Core\Session\AccountInterface). * * Modules that make any changes to variables like 'name' or 'extra' must ensure - * that the final string is safe to include directly in the output by using - * \Drupal\Component\Utility\SafeMarkup::checkPlain() or - * \Drupal\Component\Utility\Xss::filter(). + * that the final string is safe. */ function template_preprocess_username(&$variables) { $account = $variables['account'] ?: new AnonymousUserSession(); diff --git a/core/modules/views/src/Plugin/views/HandlerBase.php b/core/modules/views/src/Plugin/views/HandlerBase.php index 2bf57afb47ae..7b5fe3aa780c 100644 --- a/core/modules/views/src/Plugin/views/HandlerBase.php +++ b/core/modules/views/src/Plugin/views/HandlerBase.php @@ -7,7 +7,7 @@ namespace Drupal\views\Plugin\views; -use Drupal\Component\Utility\SafeMarkup; +use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\UrlHelper; use Drupal\Component\Utility\Xss; @@ -16,6 +16,7 @@ use Drupal\Core\Render\Element; use Drupal\Core\Session\AccountInterface; use Drupal\views\Plugin\views\display\DisplayPluginBase; +use Drupal\views\Render\ViewsRenderPipelineSafeString; use Drupal\views\ViewExecutable; use Drupal\Core\Database\Database; use Drupal\views\Views; @@ -229,13 +230,13 @@ public function sanitizeValue($value, $type = NULL) { $value = Xss::filterAdmin($value); break; case 'url': - $value = SafeMarkup::checkPlain(UrlHelper::stripDangerousProtocols($value)); + $value = Html::escape(UrlHelper::stripDangerousProtocols($value)); break; default: - $value = SafeMarkup::checkPlain($value); + $value = Html::escape($value); break; } - return $value; + return ViewsRenderPipelineSafeString::create($value); } /** diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php index 4dff979a3764..b8b7a30ed828 100644 --- a/core/modules/views/src/Plugin/views/PluginBase.php +++ b/core/modules/views/src/Plugin/views/PluginBase.php @@ -8,7 +8,6 @@ namespace Drupal\views\Plugin\views; use Drupal\Component\Plugin\DependentPluginInterface; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\Xss; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Language\LanguageInterface; @@ -314,9 +313,9 @@ public function summaryTitle() { public function pluginTitle() { // Short_title is optional so its defaults to an empty string. if (!empty($this->definition['short_title'])) { - return SafeMarkup::checkPlain($this->definition['short_title']); + return $this->definition['short_title']; } - return SafeMarkup::checkPlain($this->definition['title']); + return $this->definition['title']; } /** diff --git a/core/modules/views/src/Plugin/views/ViewsHandlerInterface.php b/core/modules/views/src/Plugin/views/ViewsHandlerInterface.php index 1775d99885ed..8a230863b98c 100644 --- a/core/modules/views/src/Plugin/views/ViewsHandlerInterface.php +++ b/core/modules/views/src/Plugin/views/ViewsHandlerInterface.php @@ -72,9 +72,10 @@ public function getJoin(); * @param $value * The value being rendered. * @param $type - * The type of sanitization needed. If not provided, SafeMarkup::checkPlain() is used. + * The type of sanitization needed. If not provided, + * \Drupal\Component\Utility\Html::escape() is used. * - * @return string + * @return \Drupal\views\Render\ViewsRenderPipelineSafeString * Returns the safe value. */ public function sanitizeValue($value, $type = NULL); diff --git a/core/modules/views/src/Plugin/views/area/Result.php b/core/modules/views/src/Plugin/views/area/Result.php index 02017e3a4c07..3079f0da9cd3 100644 --- a/core/modules/views/src/Plugin/views/area/Result.php +++ b/core/modules/views/src/Plugin/views/area/Result.php @@ -7,7 +7,7 @@ namespace Drupal\views\Plugin\views\area; -use Drupal\Component\Utility\SafeMarkup; +use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Xss; use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\views\style\DefaultSummary; @@ -87,7 +87,7 @@ public function render($empty = FALSE) { // @TODO: Maybe use a possible is views empty functionality. // Not every view has total_rows set, use view->result instead. $total = isset($this->view->total_rows) ? $this->view->total_rows : count($this->view->result); - $label = SafeMarkup::checkPlain($this->view->storage->label()); + $label = Html::escape($this->view->storage->label()); if ($per_page === 0) { $page_count = 1; $start = 1; diff --git a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php index b179245e5ab0..0a9fec7be01b 100644 --- a/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php +++ b/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php @@ -10,7 +10,6 @@ use Drupal\Component\Plugin\DependentPluginInterface; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\NestedArray; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; use Drupal\views\Plugin\CacheablePluginInterface; @@ -938,7 +937,7 @@ public function summaryName($data) { if (empty($value) && !empty($this->definition['empty field name'])) { $value = $this->definition['empty field name']; } - return SafeMarkup::checkPlain($value); + return $value; } /** @@ -957,7 +956,7 @@ public function query($group_by = FALSE) { * This usually needs to be overridden to provide a proper title. */ function title() { - return SafeMarkup::checkPlain($this->argument); + return $this->argument; } /** diff --git a/core/modules/views/src/Plugin/views/argument/FieldList.php b/core/modules/views/src/Plugin/views/argument/FieldList.php index 36c50ac5f78e..54b7883d95bd 100644 --- a/core/modules/views/src/Plugin/views/argument/FieldList.php +++ b/core/modules/views/src/Plugin/views/argument/FieldList.php @@ -7,7 +7,6 @@ namespace Drupal\views\Plugin\views\argument; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Field\FieldFilteredString; use Drupal\Core\Form\FormStateInterface; @@ -75,7 +74,7 @@ public function summaryName($data) { } // else fallback to the key. else { - return SafeMarkup::checkPlain($value); + return $value; } } diff --git a/core/modules/views/src/Plugin/views/display/Attachment.php b/core/modules/views/src/Plugin/views/display/Attachment.php index dcc4282e4006..ef691bec54ca 100644 --- a/core/modules/views/src/Plugin/views/display/Attachment.php +++ b/core/modules/views/src/Plugin/views/display/Attachment.php @@ -7,7 +7,6 @@ namespace Drupal\views\Plugin\views\display; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Form\FormStateInterface; use Drupal\views\ViewExecutable; @@ -92,7 +91,7 @@ public function optionsSummary(&$categories, &$options) { elseif (count($displays) == 1) { $display = array_shift($displays); if ($display = $this->view->storage->getDisplay($display)) { - $attach_to = SafeMarkup::checkPlain($display['display_title']); + $attach_to = $display['display_title']; } } @@ -204,7 +203,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { '#title' => $this->t('Displays'), '#type' => 'checkboxes', '#description' => $this->t('Select which display or displays this should attach to.'), - '#options' => $displays, + '#options' => array_map('\Drupal\Component\Utility\Html::escape', $displays), '#default_value' => $this->getOption('displays'), ); break; diff --git a/core/modules/views/src/Plugin/views/display/Feed.php b/core/modules/views/src/Plugin/views/display/Feed.php index 216a67592231..c78d23bcd6d7 100644 --- a/core/modules/views/src/Plugin/views/display/Feed.php +++ b/core/modules/views/src/Plugin/views/display/Feed.php @@ -7,7 +7,6 @@ namespace Drupal\views\Plugin\views\display; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheableResponse; use Drupal\Core\Form\FormStateInterface; @@ -204,7 +203,7 @@ public function optionsSummary(&$categories, &$options) { $display = array_shift($displays); $displays = $this->view->storage->get('display'); if (!empty($displays[$display])) { - $attach_to = SafeMarkup::checkPlain($displays[$display]['display_title']); + $attach_to = $displays[$display]['display_title']; } } @@ -256,7 +255,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { '#title' => $this->t('Displays'), '#type' => 'checkboxes', '#description' => $this->t('The feed icon will be available only to the selected displays.'), - '#options' => $displays, + '#options' => array_map('\Drupal\Component\Utility\Html::escape', $displays), '#default_value' => $this->getOption('displays'), ); break; diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php index 7ed1033d66d3..29abf887c300 100644 --- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php +++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php @@ -1396,8 +1396,8 @@ protected function renderAsLink($alter, $text, $tokens) { $path = preg_replace(['/(\%7B){2}(\%20)*/', '/(\%20)*(\%7D){2}/'], ['{{','}}'], $path); // Use strip tags as there should never be HTML in the path. - // However, we need to preserve special characters like " that - // were removed by SafeMarkup::checkPlain(). + // However, we need to preserve special characters like " that are escaped + // by \Drupal\Component\Utility\Html::escape(). $path = strip_tags(Html::decodeEntities($this->viewsTokenReplace($path, $tokens))); if (!empty($alter['path_case']) && $alter['path_case'] != 'none' && !$alter['url']->isRouted()) { @@ -1483,8 +1483,7 @@ protected function renderAsLink($alter, $text, $tokens) { $options['attributes']['rel'] = $rel; } - // Not sure if this SafeMarkup::checkPlain() is needed here? - $target = SafeMarkup::checkPlain(trim($this->viewsTokenReplace($alter['target'], $tokens))); + $target = trim($this->viewsTokenReplace($alter['target'], $tokens)); if (!empty($target)) { $options['attributes']['target'] = $target; } diff --git a/core/modules/views/src/Plugin/views/field/MachineName.php b/core/modules/views/src/Plugin/views/field/MachineName.php index 0c289cddce57..a31d7f25544c 100644 --- a/core/modules/views/src/Plugin/views/field/MachineName.php +++ b/core/modules/views/src/Plugin/views/field/MachineName.php @@ -83,7 +83,7 @@ public function preRender(&$values) { public function render(ResultRow $values) { $value = $values->{$this->field_alias}; if (!empty($this->options['machine_name']) || !isset($this->valueOptions[$value])) { - $result = SafeMarkup::checkPlain($value); + $result = $this->sanitizeValue($value); } else { $result = $this->valueOptions[$value]; diff --git a/core/modules/views/src/Plugin/views/field/PrerenderList.php b/core/modules/views/src/Plugin/views/field/PrerenderList.php index ce0caee45d96..4a1caeade1bf 100644 --- a/core/modules/views/src/Plugin/views/field/PrerenderList.php +++ b/core/modules/views/src/Plugin/views/field/PrerenderList.php @@ -78,17 +78,24 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { public function renderItems($items) { if (!empty($items)) { if ($this->options['type'] == 'separator') { - return implode($this->sanitizeValue($this->options['separator'], 'xss_admin'), $items); + $render = [ + '#type' => 'inline_template', + '#template' => '{{ items|safe_join(separator) }}', + '#context' => [ + 'items' => $items, + 'separator' => $this->sanitizeValue($this->options['separator'], 'xss_admin') + ] + ]; } else { - $item_list = array( + $render = array( '#theme' => 'item_list', '#items' => $items, '#title' => NULL, '#list_type' => $this->options['type'], ); - return drupal_render($item_list); } + return drupal_render($render); } } diff --git a/core/modules/views/src/Plugin/views/field/Serialized.php b/core/modules/views/src/Plugin/views/field/Serialized.php index f7f5a222842f..b2fd7443a3a8 100644 --- a/core/modules/views/src/Plugin/views/field/Serialized.php +++ b/core/modules/views/src/Plugin/views/field/Serialized.php @@ -7,7 +7,6 @@ namespace Drupal\views\Plugin\views\field; -use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Form\FormStateInterface; use Drupal\views\ResultRow; @@ -76,11 +75,11 @@ public function render(ResultRow $values) { $value = $values->{$this->field_alias}; if ($this->options['format'] == 'unserialized') { - return SafeMarkup::checkPlain(print_r(unserialize($value), TRUE)); + return $this->sanitizeValue(print_r(unserialize($value), TRUE)); } elseif ($this->options['format'] == 'key' && !empty($this->options['key'])) { $value = (array) unserialize($value); - return SafeMarkup::checkPlain($value[$this->options['key']]); + return $this->sanitizeValue($value[$this->options['key']]); } return $value; diff --git a/core/modules/views/src/Views.php b/core/modules/views/src/Views.php index 33570ae96da7..6f11b4add1fa 100644 --- a/core/modules/views/src/Views.php +++ b/core/modules/views/src/Views.php @@ -7,8 +7,6 @@ namespace Drupal\views; -use Drupal\Component\Utility\SafeMarkup; - /** * Static service container wrapper for views. */ @@ -398,8 +396,8 @@ public static function pluginList() { if (!isset($plugins[$key])) { $plugins[$key] = array( 'type' => $type, - 'title' => SafeMarkup::checkPlain($info[$name]['title']), - 'provider' => SafeMarkup::checkPlain($info[$name]['provider']), + 'title' => $info[$name]['title'], + 'provider' => $info[$name]['provider'], 'views' => array(), ); } diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_attachment_ui.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_attachment_ui.yml index 17bcdb7d4e39..529ea0a3977f 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_attachment_ui.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_attachment_ui.yml @@ -67,7 +67,7 @@ display: path: test_attachment_ui_feed page_1: display_plugin: page - display_title: Page + display_title: <em>Page</em> display_options: path: test_attachment_ui id: page_1 diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_feed.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_feed.yml index 452d9347bb8a..2c35726c6077 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_feed.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_display_feed.yml @@ -123,6 +123,6 @@ display: display_options: path: test-feed-display display_plugin: page - display_title: Page + display_title: <em>Page</em> id: page position: 0 diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_style_opml.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_style_opml.yml index 1342c70a86d7..bb856ce938a0 100644 --- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_style_opml.yml +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_style_opml.yml @@ -295,7 +295,7 @@ display: page: display_plugin: page id: page_1 - display_title: Page + display_title: <em>Page</em> position: 1 display_options: path: test-opml-style diff --git a/core/modules/views/views.module b/core/modules/views/views.module index 22424a124ac4..19af30df9254 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -67,8 +67,8 @@ function views_views_pre_render($view) { 'views_dom_id:' . $view->dom_id => array( 'view_name' => $view->storage->id(), 'view_display_id' => $view->current_display, - 'view_args' => SafeMarkup::checkPlain(implode('/', $view->args)), - 'view_path' => SafeMarkup::checkPlain(Url::fromRoute('<current>')->toString()), + 'view_args' => Html::escape(implode('/', $view->args)), + 'view_path' => Html::escape(Url::fromRoute('<current>')->toString()), 'view_base_path' => $view->getPath(), 'view_dom_id' => $view->dom_id, // To fit multiple views on a page, the programmer may have diff --git a/core/modules/views_ui/src/Tests/DisplayAttachmentTest.php b/core/modules/views_ui/src/Tests/DisplayAttachmentTest.php index 68fa2b3d7501..455ae9fc8fe4 100644 --- a/core/modules/views_ui/src/Tests/DisplayAttachmentTest.php +++ b/core/modules/views_ui/src/Tests/DisplayAttachmentTest.php @@ -33,6 +33,8 @@ public function testAttachmentUI() { $attachment_display_url = 'admin/structure/views/nojs/display/test_attachment_ui/attachment_1/displays'; $this->drupalGet($attachment_display_url); + // Display labels should be escaped. + $this->assertEscaped('<em>Page</em>'); foreach (array('default', 'page-1') as $display_id) { $this->assertNoFieldChecked("edit-displays-$display_id", format_string('Make sure the @display_id can be marked as attached', array('@display_id' => $display_id))); @@ -40,6 +42,9 @@ public function testAttachmentUI() { // Save the attachments and test the value on the view. $this->drupalPostForm($attachment_display_url, array('displays[page_1]' => 1), t('Apply')); + // Options summary should be escaped. + $this->assertEscaped('<em>Page</em>'); + $this->assertNoRaw('<em>Page</em>'); $result = $this->xpath('//a[@id = :id]', array(':id' => 'views-attachment-1-displays')); $this->assertEqual($result[0]->attributes()->title, t('Page')); $this->drupalPostForm(NULL, array(), t('Save')); diff --git a/core/modules/views_ui/src/Tests/DisplayFeedTest.php b/core/modules/views_ui/src/Tests/DisplayFeedTest.php index 78a3fdcfa9c0..cc52ca5bca01 100644 --- a/core/modules/views_ui/src/Tests/DisplayFeedTest.php +++ b/core/modules/views_ui/src/Tests/DisplayFeedTest.php @@ -55,6 +55,8 @@ protected function checkFeedViewUi($view_name) { // Check the attach TO interface. $this->drupalGet('admin/structure/views/nojs/display/' . $view_name . '/feed_1/displays'); + // Display labels should be escaped. + $this->assertEscaped('<em>Page</em>'); // Load all the options of the checkbox. $result = $this->xpath('//div[@id="edit-displays"]/div'); @@ -71,8 +73,12 @@ protected function checkFeedViewUi($view_name) { // Post and save this and check the output. $this->drupalPostForm('admin/structure/views/nojs/display/' . $view_name . '/feed_1/displays', array('displays[page]' => 'page'), t('Apply')); + // Options summary should be escaped. + $this->assertEscaped('<em>Page</em>'); + $this->assertNoRaw('<em>Page</em>'); + $this->drupalGet('admin/structure/views/view/' . $view_name . '/edit/feed_1'); - $this->assertFieldByXpath('//*[@id="views-feed-1-displays"]', 'Page'); + $this->assertFieldByXpath('//*[@id="views-feed-1-displays"]', '<em>Page</em>'); // Add the default display, so there should now be multiple displays. $this->drupalPostForm('admin/structure/views/nojs/display/' . $view_name . '/feed_1/displays', array('displays[default]' => 'default'), t('Apply')); diff --git a/core/tests/Drupal/Tests/Component/Utility/HtmlTest.php b/core/tests/Drupal/Tests/Component/Utility/HtmlTest.php index 178a66256848..28a2846032cf 100644 --- a/core/tests/Drupal/Tests/Component/Utility/HtmlTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/HtmlTest.php @@ -231,7 +231,7 @@ public function testDecodeEntities($text, $expected) { /** * Data provider for testDecodeEntities(). * - * @see testCheckPlain() + * @see testDecodeEntities() */ public function providerDecodeEntities() { return array( @@ -272,7 +272,7 @@ public function testEscape($expected, $text) { /** * Data provider for testEscape(). * - * @see testCheckPlain() + * @see testEscape() */ public function providerEscape() { return array( diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTest.php b/core/tests/Drupal/Tests/Core/Render/RendererTest.php index 3d7263337b51..4d0dec5f2f8e 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererTest.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererTest.php @@ -740,7 +740,7 @@ public function testRenderCacheProperties(array $expected_results) { 'child1' => ['#markup' => SafeString::create('1')], 'child2' => ['#markup' => SafeString::create('2')], // Mark the value as safe. - '#custom_property' => SafeMarkup::checkPlain('custom_value'), + '#custom_property' => SafeString::create('custom_value'), '#custom_property_array' => ['custom value'], ]; -- GitLab