Commit d8a3d5d4 authored by catch's avatar catch

Issue #2549791 by alexpott, Wim Leers: Remove SafeMarkup::xssFilter() and...

Issue #2549791 by alexpott, Wim Leers: Remove SafeMarkup::xssFilter() and provide ability to define #markup escaping strategy and what tags to filter
parent a3542ee7
......@@ -1254,6 +1254,10 @@ function template_preprocess_html(&$variables) {
$site_config = \Drupal::config('system.site');
// Construct page title.
if (isset($variables['page']['#title']) && is_array($variables['page']['#title'])) {
// Do an early render if the title is a render array.
$variables['page']['#title'] = (string) \Drupal::service('renderer')->render($variables['page']['#title']);
}
if (!empty($variables['page']['#title'])) {
$head_title = array(
'title' => trim(strip_tags($variables['page']['#title'])),
......
......@@ -15,9 +15,9 @@
* provides a store for known safe strings and methods to manage them
* throughout the page request.
*
* Strings sanitized by self::checkPlain() and self::escape() or
* self::xssFilter() are automatically marked safe, as are markup strings
* created from @link theme_render render arrays @endlink via drupal_render().
* Strings sanitized by self::checkPlain() and self::escape() are automatically
* marked safe, as are markup strings created from @link theme_render render
* arrays @endlink via drupal_render().
*
* This class should be limited to internal use only. Module developers should
* instead use the appropriate
......@@ -138,60 +138,6 @@ public static function escape($string) {
return static::isSafe($string) ? $string : static::checkPlain($string);
}
/**
* Filters HTML for XSS vulnerabilities and marks the result as safe.
*
* Calling this method unnecessarily will result in bloating the safe string
* list and increases the chance of unintended side effects.
*
* If Twig receives a value that is not marked as safe then it will
* automatically encode special characters in a plain-text string for display
* as HTML. Therefore, SafeMarkup::xssFilter() should only be used when the
* string might contain HTML that needs to be rendered properly by the
* browser.
*
* If you need to filter for admin use, like Xss::filterAdmin(), then:
* - If the string is used as part of a @link theme_render render array @endlink,
* use #markup to allow the render system to filter by the admin tag list
* automatically.
* - Otherwise, use the SafeMarkup::xssFilter() with tag list provided by
* Xss::getAdminTagList() instead.
*
* This method should only be used instead of Xss::filter() when the result is
* being added to a render array that is constructed before rendering begins.
*
* In the rare instance that the caller does not want to filter strings that
* are marked safe already, it needs to check SafeMarkup::isSafe() itself.
*
* @param $string
* The string with raw HTML in it. It will be stripped of everything that
* can cause an XSS attack. The string provided will always be escaped
* regardless of whether the string is already marked as safe.
* @param array $html_tags
* (optional) An array of HTML tags. If omitted, it uses the default tag
* list defined by \Drupal\Component\Utility\Xss::filter().
*
* @return string
* An XSS-safe version of $string, or an empty string if $string is not
* valid UTF-8. The string is marked as safe.
*
* @ingroup sanitization
*
* @see \Drupal\Component\Utility\Xss::filter()
* @see \Drupal\Component\Utility\Xss::filterAdmin()
* @see \Drupal\Component\Utility\Xss::getAdminTagList()
* @see \Drupal\Component\Utility\SafeMarkup::isSafe()
*/
public static function xssFilter($string, $html_tags = NULL) {
if (is_null($html_tags)) {
$string = Xss::filter($string);
}
else {
$string = Xss::filter($string, $html_tags);
}
return static::set($string);
}
/**
* Gets all strings currently marked as safe.
*
......
......@@ -15,7 +15,7 @@
class Xss {
/**
* The list of html tags allowed by filterAdmin().
* The list of HTML tags allowed by filterAdmin().
*
* @var array
*
......@@ -23,19 +23,21 @@ class Xss {
*/
protected static $adminTags = array('a', 'abbr', 'acronym', 'address', 'article', 'aside', 'b', 'bdi', 'bdo', 'big', 'blockquote', 'br', 'caption', 'cite', 'code', 'col', 'colgroup', 'command', 'dd', 'del', 'details', 'dfn', 'div', 'dl', 'dt', 'em', 'figcaption', 'figure', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'i', 'img', 'ins', 'kbd', 'li', 'mark', 'menu', 'meter', 'nav', 'ol', 'output', 'p', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'small', 'span', 'strong', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'time', 'tr', 'tt', 'u', 'ul', 'var', 'wbr');
/**
* The default list of HTML tags allowed by filter().
*
* @var array
*
* @see \Drupal\Component\Utility\Xss::filter()
*/
protected static $htmlTags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd');
/**
* Filters HTML to prevent cross-site-scripting (XSS) vulnerabilities.
*
* Based on kses by Ulf Harnhammar, see http://sourceforge.net/projects/kses.
* For examples of various XSS attacks, see: http://ha.ckers.org/xss.html.
*
* This method is preferred to
* \Drupal\Component\Utility\SafeMarkup::xssFilter() when the result is not
* being used directly in the rendering system (for example, when its result
* is being combined with other strings before rendering). This avoids
* bloating the safe string list with partial strings if the whole result will
* be marked safe.
*
* This code does four things:
* - Removes characters and constructs that can trick browsers.
* - Makes sure all HTML entities are well-formed.
......@@ -54,11 +56,13 @@ class Xss {
* valid UTF-8.
*
* @see \Drupal\Component\Utility\Unicode::validateUtf8()
* @see \Drupal\Component\Utility\SafeMarkup::xssFilter()
*
* @ingroup sanitization
*/
public static function filter($string, $html_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd')) {
public static function filter($string, array $html_tags = NULL) {
if (is_null($html_tags)) {
$html_tags = static::$htmlTags;
}
// Only operate on valid UTF-8 strings. This is necessary to prevent cross
// site scripting issues on Internet Explorer 6.
if (!Unicode::validateUtf8($string)) {
......@@ -108,13 +112,6 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
* is desired (so \Drupal\Component\Utility\SafeMarkup::checkPlain() is
* not acceptable).
*
* This method is preferred to
* \Drupal\Component\Utility\SafeMarkup::xssFilter() when the result is
* not being used directly in the rendering system (for example, when its
* result is being combined with other strings before rendering). This avoids
* bloating the safe string list with partial strings if the whole result will
* be marked safe.
*
* Allows all tags that can be used inside an HTML body, save
* for scripts and styles.
*
......@@ -126,7 +123,6 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
*
* @ingroup sanitization
*
* @see \Drupal\Component\Utility\SafeMarkup::xssFilter()
* @see \Drupal\Component\Utility\Xss::getAdminTagList()
*
*/
......@@ -338,13 +334,22 @@ protected static function needsRemoval($html_tags, $elem) {
}
/**
* Gets the list of html tags allowed by Xss::filterAdmin().
* Gets the list of HTML tags allowed by Xss::filterAdmin().
*
* @return array
* The list of html tags allowed by filterAdmin().
* The list of HTML tags allowed by filterAdmin().
*/
public static function getAdminTagList() {
return static::$adminTags;
}
/**
* Gets the standard list of HTML tags allowed by Xss::filter().
*
* @return array
* The list of HTML tags allowed by Xss::filter().
*/
public static function getHtmlTagList() {
return static::$htmlTags;
}
}
<?php
/**
* @file
* Contains \Drupal\Core\Render\Element\Markup.
*/
namespace Drupal\Core\Render\Element;
use Drupal\Component\Utility\Html as HtmlUtility;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Render\SafeString;
/**
* Provides a render element for HTML as a string, with sanitization.
*
* Properties:
* - #markup: Specifies that the array provides HTML markup directly. Unless
* the markup is very simple, such as an explanation in a paragraph tag, it
* is normally preferable to use #theme or #type instead, so that the theme
* can customize the markup. Note that the value is passed through
* \Drupal\Component\Utility\Xss::filterAdmin(), which strips known XSS
* vectors while allowing a permissive list of HTML tags that are not XSS
* vectors. (I.e, <script> and <style> are not allowed.) See
* \Drupal\Component\Utility\Xss::$adminTags for the list of tags that will
* be allowed. If your markup needs any of the tags that are not in this
* whitelist, then you can implement a theme hook and template file and/or
* an asset library. Alternatively, you can use the render array keys
* #safe_strategy and #allowed_tags to alter how #markup is made safe.
* - #safe_strategy: If #markup is supplied this can be used to change
* how the string is made safe for render. By default, all #markup is filtered
* using Xss::adminFilter(). However, if the string should be escaped using
* Html::escape() then this should be set to Markup::SAFE_STRATEGY_ESCAPE.
* - #allowed_tags: If #markup is supplied this can be used to change which tags
* are using to filter the markup. The value should be an array of tags that
* Xss::filter() would accept. If #safe_strategy is set to
* Markup::SAFE_STRATEGY_ESCAPE this value is ignored.
*
* Usage example:
* @code
* $output['admin_filtered_string'] = array(
* '#type' => 'markup',
* '#markup' => '<em>This is filtered using the admin tag list</em>',
* );
* $output['filtered_string'] = array(
* '#type' => 'markup',
* '#markup' => '<em>This is filtered</em>',
* '#allowed_tags' => ['strong'],
* );
* $output['escaped_string'] = array(
* '#type' => 'markup',
* '#markup' => '<em>This is escaped</em>',
* '#safe_strategy' => Markup::SAFE_STRATEGY_ESCAPE,
* );
* @endcode
*
* @see theme_render
*
* @ingroup sanitization
*
* @RenderElement("markup")
*/
class Markup extends RenderElement {
/**
* #safe_strategy indicating #markup should be filtered.
*
* @see ::ensureMarkupIsSafe()
* @see \Drupal\Component\Utility\Xss::filter()
*/
const SAFE_STRATEGY_FILTER = 'xss';
/**
* #safe_strategy indicating #markup should be escaped.
*
* @see ::ensureMarkupIsSafe()
* @see \Drupal\Component\Utility\Html::escape()
*/
const SAFE_STRATEGY_ESCAPE = 'escape';
/**
* {@inheritdoc}
*/
public function getInfo() {
return [
'#pre_render' => [
[static::class, 'ensureMarkupIsSafe'],
],
];
}
/**
* Escapes or filters #markup as required.
*
* Drupal uses Twig's auto-escape feature to improve security. This feature
* automatically escapes any HTML that is not known to be safe. Due to this
* the render system needs to ensure that all markup it generates is marked
* safe so that Twig does not do any additional escaping.
*
* By default all #markup is filtered to protect against XSS using the admin
* tag list. Render arrays can alter the list of tags allowed by the filter
* using the #allowed_tags property. This value should be an array of tags
* that Xss::filter() would accept. Render arrays can escape #markup instead
* of XSS filtering by setting the #safe_strategy property to
* Markup:SAFE_STRATEGY_ESCAPE. If the escaping strategy is used #allowed_tags
* is ignored.
*
* @param array $elements
* A render array with #markup set.
*
* @return \Drupal\Component\Utility\SafeStringInterface|string
* The escaped markup wrapped in a SafeString object. If
* SafeMarkup::isSafe($elements['#markup']) returns TRUE, it won't be
* escaped or filtered again.
*
* @see \Drupal\Component\Utility\Html::escape()
* @see \Drupal\Component\Utility\Xss::filter()
* @see \Drupal\Component\Utility\Xss::adminFilter()
* @see \Drupal\Core\Render\Element\Markup::SAFE_STRATEGY_FILTER
* @see \Drupal\Core\Render\Element\Markup::SAFE_STRATEGY_ESCAPE
*/
public static function ensureMarkupIsSafe(array $elements) {
if (empty($elements['#markup'])) {
return $elements;
}
$strategy = isset($elements['#safe_strategy']) ? $elements['#safe_strategy'] : static::SAFE_STRATEGY_FILTER;
if (SafeMarkup::isSafe($elements['#markup'])) {
// Nothing to do as #markup is already marked as safe.
return $elements;
}
elseif ($strategy == static::SAFE_STRATEGY_ESCAPE) {
$markup = HtmlUtility::escape($elements['#markup']);
}
else {
// The default behaviour is to XSS filter using the admin tag list.
$tags = isset($elements['#allowed_tags']) ? $elements['#allowed_tags'] : Xss::getAdminTagList();
$markup = Xss::filter($elements['#markup'], $tags);
}
$elements['#markup'] = SafeString::create($markup);
return $elements;
}
}
......@@ -301,6 +301,12 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
$pre_bubbling_elements = [];
$pre_bubbling_elements['#cache'] = isset($elements['#cache']) ? $elements['#cache'] : [];
// If #markup is set, ensure #type is set. This allows to specify just
// #markup on an element without setting #type.
if (isset($elements['#markup']) && !isset($elements['#type'])) {
$elements['#type'] = 'markup';
}
// If the default values for this element have not been loaded yet, populate
// them.
if (isset($elements['#type']) && empty($elements['#defaults_loaded'])) {
......@@ -412,12 +418,6 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
$elements['#children'] = '';
}
if (!empty($elements['#markup'])) {
// @todo Decide how to support non-HTML in the render API in
// https://www.drupal.org/node/2501313.
$elements['#markup'] = $this->xssFilterAdminIfUnsafe($elements['#markup']);
}
// Assume that if #theme is set it represents an implemented hook.
$theme_is_implemented = isset($elements['#theme']);
// Check the elements for insecure HTML and pass through sanitization.
......
......@@ -265,16 +265,11 @@
* - #markup: Specifies that the array provides HTML markup directly. Unless
* the markup is very simple, such as an explanation in a paragraph tag, it
* is normally preferable to use #theme or #type instead, so that the theme
* can customize the markup. Note that the value is passed through
* \Drupal\Component\Utility\Xss::filterAdmin(), which strips known XSS
* vectors while allowing a permissive list of HTML tags that are not XSS
* vectors. (I.e, <script> and <style> are not allowed.) See
* \Drupal\Component\Utility\Xss::$adminTags for the list of tags that will
* be allowed. If your markup needs any of the tags that are not in this
* whitelist, then you should implement a theme hook and template file and/or
* an asset library.
* can customize the markup. For additional options related to #markup see
* \Drupal\Core\Render\Element\Markup.
* @see core.libraries.yml
* @see hook_theme()
* @see \Drupal\Core\Render\Element\Markup
*
* JavaScript and CSS assets are specified in the render array using the
* #attached property (see @ref sec_attached).
......
......@@ -6,7 +6,6 @@
*/
use Drupal\aggregator\Entity\Feed;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Routing\RouteMatchInterface;
/**
......@@ -157,16 +156,15 @@ function aggregator_cron() {
}
/**
* Renders the HTML content safely, as allowed.
* Gets the list of allowed tags.
*
* @param string $value
* The content to be filtered.
* @return array
* The list of allowed tags.
*
* @return string
* The filtered content.
* @internal
*/
function aggregator_filter_xss($value) {
return SafeMarkup::xssFilter($value, preg_split('/\s+|<|>/', \Drupal::config('aggregator.settings')->get('items.allowed_html'), -1, PREG_SPLIT_NO_EMPTY));
function _aggregator_allowed_tags() {
return preg_split('/\s+|<|>/', \Drupal::config('aggregator.settings')->get('items.allowed_html'), -1, PREG_SPLIT_NO_EMPTY);
}
/**
......
......@@ -7,7 +7,7 @@
namespace Drupal\aggregator\Controller;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatter;
use Drupal\aggregator\FeedInterface;
......@@ -193,11 +193,11 @@ public function pageLast() {
* @param \Drupal\aggregator\FeedInterface $aggregator_feed
* The aggregator feed.
*
* @return string
* The feed label.
* @return array
* The feed label as a render array.
*/
public function feedTitle(FeedInterface $aggregator_feed) {
return SafeMarkup::xssFilter($aggregator_feed->label());
return ['#markup' => $aggregator_feed->label(), '#allowed_tags' => Xss::getHtmlTagList()];
}
}
......@@ -79,7 +79,8 @@ public function buildComponents(array &$build, array $entities, array $displays,
if ($display->getComponent('description')) {
$build[$id]['description'] = array(
'#markup' => aggregator_filter_xss($entity->getDescription()),
'#markup' => $entity->getDescription(),
'#allowed_tags' => _aggregator_allowed_tags(),
'#prefix' => '<div class="feed-description">',
'#suffix' => '</div>',
);
......
......@@ -26,7 +26,8 @@ public function buildComponents(array &$build, array $entities, array $displays,
if ($display->getComponent('description')) {
$build[$id]['description'] = array(
'#markup' => aggregator_filter_xss($entity->getDescription()),
'#markup' => $entity->getDescription(),
'#allowed_tags' => _aggregator_allowed_tags(),
'#prefix' => '<div class="item-description">',
'#suffix' => '</div>',
);
......
......@@ -36,7 +36,8 @@ public function viewElements(FieldItemListInterface $items) {
foreach ($items as $delta => $item) {
$elements[$delta] = [
'#type' => 'markup',
'#markup' => aggregator_filter_xss($item->value),
'#markup' => $item->value,
'#allowed_tags' => _aggregator_allowed_tags(),
];
}
return $elements;
......
......@@ -7,6 +7,7 @@
namespace Drupal\aggregator\Tests\Views;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Render\RenderContext;
use Drupal\Core\Url;
use Drupal\views\Views;
......@@ -121,13 +122,13 @@ public function testAggregatorItemView() {
});
$this->assertEqual($output, $expected_link, 'Ensure the right link is generated');
$expected_author = aggregator_filter_xss($items[$iid]->getAuthor());
$expected_author = Xss::filter($items[$iid]->getAuthor(), _aggregator_allowed_tags());
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
return $view->field['author']->advancedRender($row);
});
$this->assertEqual($output, $expected_author, 'Ensure the author got filtered');
$expected_description = aggregator_filter_xss($items[$iid]->getDescription());
$expected_description = Xss::filter($items[$iid]->getDescription(), _aggregator_allowed_tags());
$output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
return $view->field['description']->advancedRender($row);
});
......
......@@ -206,7 +206,7 @@ public function overview() {
$this->dateFormatter->format($dblog->timestamp, 'short'),
$message,
array('data' => $username),
SafeMarkup::xssFilter($dblog->link),
array('data' => array('#markup' => $dblog->link)),
),
// Attributes for table row.
'class' => array(Html::getClass('dblog-' . $dblog->type), $classes[$dblog->severity]),
......
......@@ -46,7 +46,7 @@ public function process($text, $langcode) {
// Sanitize caption: decode HTML encoding, limit allowed HTML tags; only
// allow inline tags that are allowed by default, plus <br>.
$caption = Html::decodeEntities($caption);
$caption = SafeMarkup::xssFilter($caption, array('a', 'em', 'strong', 'cite', 'code', 'br'));
$caption = FilteredString::create(Xss::filter($caption, array('a', 'em', 'strong', 'cite', 'code', 'br')));
// The caption must be non-empty.
if (Unicode::strlen($caption) === 0) {
......
......@@ -7,7 +7,7 @@
namespace Drupal\menu_ui\Controller;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Menu\MenuParentFormSelectorInterface;
use Drupal\system\MenuInterface;
......@@ -73,11 +73,11 @@ public function getParentOptions(Request $request) {
* @param \Drupal\system\MenuInterface $menu
* The menu entity.
*
* @return string
* The menu label.
* @return array
* The menu label as a render array.
*/
public function menuTitle(MenuInterface $menu) {
return SafeMarkup::xssFilter($menu->label());
return ['#markup' => $menu->label(), '#allowed_tags' => Xss::getHtmlTagList()];
}
}
......@@ -8,6 +8,7 @@
namespace Drupal\node\Controller;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatter;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
......@@ -194,7 +195,7 @@ public function revisionOverview(NodeInterface $node) {
'#context' => [
'date' => $link,
'username' => $this->renderer->renderPlain($username),
'message' => SafeMarkup::xssFilter($revision->revision_log->value),
'message' => ['#markup' => $revision->revision_log->value, '#allowed_tags' => Xss::getHtmlTagList()],
],
],
];
......
......@@ -10,6 +10,7 @@
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\Markup;
use Drupal\Core\Routing\RouteMatchInterface;
/**
......@@ -628,8 +629,8 @@ function search_mark_for_reindex($type = NULL, $sid = NULL, $langcode = NULL) {
* @param string|null $langcode
* Language code for the language of $text, if known.
*
* @return string
* A string containing HTML for the excerpt.
* @return array
* A render array containing HTML for the excerpt.
*/
function search_excerpt($keys, $text, $langcode = NULL) {
// We highlight around non-indexable or CJK characters.
......@@ -722,7 +723,10 @@ function search_excerpt($keys, $text, $langcode = NULL) {
// We didn't find any keyword matches, so just return the first part of the
// text. We also need to re-encode any HTML special characters that we
// entity-decoded above.
return SafeMarkup::checkPlain(Unicode::truncate($text, 256, TRUE, TRUE));
return [
'#markup' => Unicode::truncate($text, 256, TRUE, TRUE),
'#safe_strategy' => Markup::SAFE_STRATEGY_ESCAPE,
];
}
// Sort the text ranges by starting position.
......@@ -768,7 +772,10 @@ function search_excerpt($keys, $text, $langcode = NULL) {
// Highlight keywords. Must be done at once to prevent conflicts ('strong'
// and '<strong>').
$text = trim(preg_replace('/' . $boundary . '(?:' . implode('|', $keys) . ')' . $boundary . '/iu', '<strong>\0</strong>', ' ' . $text . ' '));
return SafeMarkup::xssFilter($text, ['strong']);
return [
'#markup' => $text,
'#allowed_tags' => ['strong']
];
}
/**
......
......@@ -9,12 +9,10 @@
* individual product (node) listed in the search results.
*/
use Drupal\Component\Utility\SafeMarkup;
/**
* Adds the test form to search results.
*/
function search_embedded_form_preprocess_search_result(&$variables) {
$form = \Drupal::formBuilder()->getForm('Drupal\search_embedded_form\Form\SearchEmbeddedForm');
$variables['snippet'] = ['#markup' => SafeMarkup::escape($variables['snippet']), $form];
$variables['snippet'] = array_merge($variables['snippet'], $form);
}
......@@ -7,7 +7,6 @@
namespace Drupal\taxonomy\Controller;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\taxonomy\TermInterface;
......@@ -49,13 +48,13 @@ public function addForm(VocabularyInterface $taxonomy_vocabulary) {
* Route title callback.
*
* @param \Drupal\taxonomy\VocabularyInterface $taxonomy_vocabulary
* The taxonomy term.
* The vocabulary.
*
* @return string
* The term label.
* The vocabulary label as a render array.
*/
public function vocabularyTitle(VocabularyInterface $taxonomy_vocabulary) {
return SafeMarkup::xssFilter($taxonomy_vocabulary->label());
return ['#markup' => $taxonomy_vocabulary->label(), '#allowed_tags' => Xss::getHtmlTagList()];
}
/**
......@@ -64,11 +63,11 @@ public function vocabularyTitle(VocabularyInterface $taxonomy_vocabulary) {
* @param \Drupal\taxonomy\TermInterface $taxonomy_term
* The taxonomy term.
*
* @return string
* The term label.
* @return array
* The term label as a render array.
*/
public function termTitle(TermInterface $taxonomy_term) {
return SafeMarkup::xssFilter($taxonomy_term->getName());
return ['#markup' => $taxonomy_term->getName(), '#allowed_tags' => Xss::getHtmlTagList()];
}
}
......@@ -7,7 +7,6 @@
namespace Drupal\user\Controller;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Datetime\DateFormatter;
......@@ -158,11 +157,12 @@ public function userPage() {
* @param \Drupal\user\UserInterface $user
* The user account.
*
* @return string
* The user account name.
* @return string|array
* The user account name as a render array or an empty string if $user is
* NULL.
*/
public function userTitle(UserInterface $user = NULL) {
return $user ? SafeMarkup::xssFilter($user->getUsername()) : '';
return $user ? ['#markup' => $user->getUsername(), '#allowed_tags' => Xss::getHtmlTagList()] : '';
}
/**
......
......@@ -7,7 +7,6 @@
namespace Drupal\views\Plugin\Block;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Config\Entity\Query\Query;
use Drupal\Core\Form\FormStateInterface;
......@@ -33,8 +32,7 @@ public function build() {
if ($output = $this->view->buildRenderable($this->displayID, [], FALSE)) {
// Override the label to the dynamic title configured in the view.
if (empty($this->configuration['views_label']) && $this->view->getTitle()) {
// @todo https://www.drupal.org/node/2527360 remove call to SafeMarkup.
$output['#title'] = SafeMarkup::xssFilter($this->view->getTitle(), Xss::getAdminTagList());
$output['#title'] = ['#markup' => $this->view->getTitle(), '#allowed_tags' => Xss::getHtmlTagList()];
}
// Before returning the block output, convert it to a renderable array
......
......@@ -7,7 +7,6 @@
namespace Drupal\views\Plugin\views\display;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
......@@ -182,8 +181,7 @@ public function execute() {
// it should be dropped.
if (is_array($render)) {
$render += array(
// @todo https://www.drupal.org/node/2527360 remove call to SafeMarkup.
'#title' => SafeMarkup::xssFilter($this->view->getTitle(), Xss::getAdminTagList()),
'#title' => ['#markup' => $this->view->getTitle(), '#allowed_tags' => Xss::getHtmlTagList()],