diff --git a/core/lib/Drupal/Core/Field/AllowedTagsXssTrait.php b/core/lib/Drupal/Core/Field/AllowedTagsXssTrait.php new file mode 100644 index 00000000000..270d92386f8 --- /dev/null +++ b/core/lib/Drupal/Core/Field/AllowedTagsXssTrait.php @@ -0,0 +1,53 @@ +allowedTags()))); + } + + /** + * Returns a list of tags allowed by AllowedTagsXssTrait::fieldFilterXss(). + */ + public function allowedTags() { + return array('a', 'b', 'big', 'code', 'del', 'em', 'i', 'ins', 'pre', 'q', 'small', 'span', 'strong', 'sub', 'sup', 'tt', 'ol', 'ul', 'li', 'p', 'br', 'img'); + } + + /** + * Returns a human-readable list of allowed tags for display in help texts. + */ + public function displayAllowedTags() { + return '<' . implode('> <', $this->allowedTags()) . '>'; + } + +} diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php index ef3cec6dc51..d261dedc57c 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Field\Plugin\Field\FieldFormatter; +use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Field\FormatterBase; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; @@ -16,6 +17,8 @@ use Drupal\Core\Form\FormStateInterface; */ abstract class NumericFormatterBase extends FormatterBase { + use AllowedTagsXssTrait; + /** * {@inheritdoc} */ @@ -72,8 +75,8 @@ abstract class NumericFormatterBase extends FormatterBase { // Account for prefix and suffix. if ($this->getSetting('prefix_suffix')) { - $prefixes = isset($settings['prefix']) ? array_map('field_filter_xss', explode('|', $settings['prefix'])) : array(''); - $suffixes = isset($settings['suffix']) ? array_map('field_filter_xss', explode('|', $settings['suffix'])) : array(''); + $prefixes = isset($settings['prefix']) ? array_map(array($this, 'fieldFilterXss'), explode('|', $settings['prefix'])) : array(''); + $suffixes = isset($settings['suffix']) ? array_map(array($this, 'fieldFilterXss'), explode('|', $settings['suffix'])) : array(''); $prefix = (count($prefixes) > 1) ? format_plural($item->value, $prefixes[0], $prefixes[1]) : $prefixes[0]; $suffix = (count($suffixes) > 1) ? format_plural($item->value, $suffixes[0], $suffixes[1]) : $suffixes[0]; $output = $prefix . $output . $suffix; diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php index 0f5020c027b..50f80062d40 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php @@ -101,11 +101,11 @@ class NumberWidget extends WidgetBase { // Add prefix and suffix. if ($field_settings['prefix']) { $prefixes = explode('|', $field_settings['prefix']); - $element['#field_prefix'] = field_filter_xss(array_pop($prefixes)); + $element['#field_prefix'] = $this->fieldFilterXss(array_pop($prefixes)); } if ($field_settings['suffix']) { $suffixes = explode('|', $field_settings['suffix']); - $element['#field_suffix'] = field_filter_xss(array_pop($suffixes)); + $element['#field_suffix'] = $this->fieldFilterXss(array_pop($suffixes)); } return array('value' => $element); diff --git a/core/lib/Drupal/Core/Field/WidgetBase.php b/core/lib/Drupal/Core/Field/WidgetBase.php index 44fe57afcd3..11663406d3a 100644 --- a/core/lib/Drupal/Core/Field/WidgetBase.php +++ b/core/lib/Drupal/Core/Field/WidgetBase.php @@ -21,6 +21,8 @@ use Symfony\Component\Validator\ConstraintViolationListInterface; */ abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface { + use AllowedTagsXssTrait; + /** * The field definition. * @@ -82,7 +84,7 @@ abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface $delta = isset($get_delta) ? $get_delta : 0; $element = array( '#title' => String::checkPlain($this->fieldDefinition->getLabel()), - '#description' => field_filter_xss(\Drupal::token()->replace($this->fieldDefinition->getDescription())), + '#description' => $this->fieldFilterXss(\Drupal::token()->replace($this->fieldDefinition->getDescription())), ); $element = $this->formSingleElement($items, $delta, $element, $form, $form_state); @@ -161,7 +163,7 @@ abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface } $title = String::checkPlain($this->fieldDefinition->getLabel()); - $description = field_filter_xss(\Drupal::token()->replace($this->fieldDefinition->getDescription())); + $description = $this->fieldFilterXss(\Drupal::token()->replace($this->fieldDefinition->getDescription())); $elements = array(); @@ -537,5 +539,4 @@ abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface return TRUE; } - } diff --git a/core/modules/field/field.info.yml b/core/modules/field/field.info.yml index f30ba864149..13b5da0054b 100644 --- a/core/modules/field/field.info.yml +++ b/core/modules/field/field.info.yml @@ -4,4 +4,3 @@ description: 'Field API to add fields to entities like nodes and users.' package: Core version: VERSION core: 8.x -required: true diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 4207d28747b..ec8d2b77f3b 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -4,9 +4,6 @@ * Attach custom data fields to Drupal entities. */ -use Drupal\Component\Utility\Html; -use Drupal\Component\Utility\SafeMarkup; -use Drupal\Component\Utility\Xss; use Drupal\Core\Config\ConfigImporter; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Extension\Extension; @@ -243,41 +240,6 @@ function field_entity_bundle_delete($entity_type, $bundle) { } } -/** - * Filters an HTML string to prevent cross-site-scripting (XSS) vulnerabilities. - * - * Like \Drupal\Component\Utility\Xss::filterAdmin(), but with a shorter list - * of allowed tags. - * - * Used for items entered by administrators, like field descriptions, allowed - * values, where some (mainly inline) mark-up may be desired (so - * drupal_htmlspecialchars() is not acceptable). - * - * @param $string - * The string with raw HTML in it. - * - * @return - * An XSS safe version of $string, or an empty string if $string is not valid - * UTF-8. - */ -function field_filter_xss($string) { - return SafeMarkup::set(Html::normalize(Xss::filter($string, _field_filter_xss_allowed_tags()))); -} - -/** - * Returns a list of tags allowed by field_filter_xss(). - */ -function _field_filter_xss_allowed_tags() { - return array('a', 'b', 'big', 'code', 'del', 'em', 'i', 'ins', 'pre', 'q', 'small', 'span', 'strong', 'sub', 'sup', 'tt', 'ol', 'ul', 'li', 'p', 'br', 'img'); -} - -/** - * Returns a human-readable list of allowed tags for display in help texts. - */ -function _field_filter_xss_display_allowed_tags() { - return '<' . implode('> <', _field_filter_xss_allowed_tags()) . '>'; -} - /** * @} End of "defgroup field". */ diff --git a/core/modules/field/src/Plugin/views/argument/FieldList.php b/core/modules/field/src/Plugin/views/argument/FieldList.php index 08c7756eed3..14e82191188 100644 --- a/core/modules/field/src/Plugin/views/argument/FieldList.php +++ b/core/modules/field/src/Plugin/views/argument/FieldList.php @@ -8,6 +8,7 @@ namespace Drupal\field\Plugin\views\argument; use Drupal\Component\Utility\String; +use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Form\FormStateInterface; use Drupal\views\ViewExecutable; use Drupal\views\Plugin\views\display\DisplayPluginBase; @@ -23,6 +24,8 @@ use Drupal\views\Plugin\views\argument\Numeric; */ class FieldList extends Numeric { + use AllowedTagsXssTrait; + /** * Stores the allowed values of this field. * @@ -67,7 +70,7 @@ class FieldList extends Numeric { $value = $data->{$this->name_alias}; // If the list element has a human readable name show it, if (isset($this->allowed_values[$value]) && !empty($this->options['summary']['human'])) { - return field_filter_xss($this->allowed_values[$value]); + return $this->fieldFilterXss($this->allowed_values[$value]); } // else fallback to the key. else { diff --git a/core/modules/field/src/Plugin/views/argument/ListString.php b/core/modules/field/src/Plugin/views/argument/ListString.php index eee75e2d4a5..e78a9f71d90 100644 --- a/core/modules/field/src/Plugin/views/argument/ListString.php +++ b/core/modules/field/src/Plugin/views/argument/ListString.php @@ -8,6 +8,7 @@ namespace Drupal\field\Plugin\views\argument; use Drupal\Component\Utility\String as UtilityString; +use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Form\FormStateInterface; use Drupal\views\ViewExecutable; use Drupal\views\Plugin\views\display\DisplayPluginBase; @@ -23,6 +24,8 @@ use Drupal\views\Plugin\views\argument\String; */ class ListString extends String { + use AllowedTagsXssTrait; + /** * Stores the allowed values of this field. * @@ -69,7 +72,7 @@ class ListString extends String { $value = $data->{$this->name_alias}; // If the list element has a human readable name show it, if (isset($this->allowed_values[$value]) && !empty($this->options['summary']['human'])) { - return $this->caseTransform(field_filter_xss($this->allowed_values[$value]), $this->options['case']); + return $this->caseTransform($this->fieldfilterXss($this->allowed_values[$value]), $this->options['case']); } // else fallback to the key. else { diff --git a/core/modules/field_ui/src/Form/FieldInstanceEditForm.php b/core/modules/field_ui/src/Form/FieldInstanceEditForm.php index a6703992d46..14330fd2d6d 100644 --- a/core/modules/field_ui/src/Form/FieldInstanceEditForm.php +++ b/core/modules/field_ui/src/Form/FieldInstanceEditForm.php @@ -8,6 +8,7 @@ namespace Drupal\field_ui\Form; use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Form\FormBase; use Drupal\Component\Utility\String; use Drupal\Core\Form\FormStateInterface; @@ -20,6 +21,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; */ class FieldInstanceEditForm extends FormBase { + use AllowedTagsXssTrait; + /** * The field instance being edited. * @@ -124,7 +127,7 @@ class FieldInstanceEditForm extends FormBase { '#title' => $this->t('Help text'), '#default_value' => $this->instance->getDescription(), '#rows' => 5, - '#description' => $this->t('Instructions to present to the user below this field on the editing form.
Allowed HTML tags: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '
' . $this->t('This field supports tokens.'), + '#description' => $this->t('Instructions to present to the user below this field on the editing form.
Allowed HTML tags: @tags', array('@tags' => $this->displayAllowedTags())) . '
' . $this->t('This field supports tokens.'), '#weight' => -10, ); diff --git a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php index 0a8ea88e76b..f9becf457a8 100644 --- a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php +++ b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php @@ -97,7 +97,7 @@ class FileWidget extends WidgetBase { } $title = String::checkPlain($this->fieldDefinition->getLabel()); - $description = field_filter_xss($this->fieldDefinition->getDescription()); + $description = $this->fieldFilterXss($this->fieldDefinition->getDescription()); $elements = array(); diff --git a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php index b0a2914a027..ab72de5df29 100644 --- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php +++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php @@ -96,7 +96,7 @@ class ImageWidget extends FileWidget { if ($cardinality == 1) { // If there's only one field, return it as delta 0. if (empty($elements[0]['#default_value']['fids'])) { - $file_upload_help['#description'] = field_filter_xss($this->fieldDefinition->getDescription()); + $file_upload_help['#description'] = $this->fieldFilterXss($this->fieldDefinition->getDescription()); $elements[0]['#description'] = drupal_render($file_upload_help); } } diff --git a/core/modules/options/options.module b/core/modules/options/options.module index 90ddc5a963f..2d1115404b9 100644 --- a/core/modules/options/options.module +++ b/core/modules/options/options.module @@ -51,7 +51,8 @@ function options_field_storage_config_delete(FieldStorageConfigInterface $field_ * Returns the array of allowed values for a list field. * * The strings are not safe for output. Keys and values of the array should be - * sanitized through field_filter_xss() before being displayed. + * sanitized through \Drupal\Core\Field\AllowedTagsXssTrait::fieldFilterXss() + * before being displayed. * * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The field definition. diff --git a/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php b/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php index 5118e5f69ca..42df92069bb 100644 --- a/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php +++ b/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsDefaultFormatter.php @@ -7,6 +7,7 @@ namespace Drupal\options\Plugin\Field\FieldFormatter; +use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Field\FormatterBase; use Drupal\Core\Field\FieldItemListInterface; @@ -25,6 +26,8 @@ use Drupal\Core\Field\FieldItemListInterface; */ class OptionsDefaultFormatter extends FormatterBase { + use AllowedTagsXssTrait; + /** * {@inheritdoc} */ @@ -36,11 +39,11 @@ class OptionsDefaultFormatter extends FormatterBase { foreach ($items as $delta => $item) { if (isset($allowed_values[$item->value])) { - $output = field_filter_xss($allowed_values[$item->value]); + $output = $this->fieldFilterXss($allowed_values[$item->value]); } else { // If no match was found in allowed values, fall back to the key. - $output = field_filter_xss($item->value); + $output = $this->fieldFilterXss($item->value); } $elements[$delta] = array('#markup' => $output); } diff --git a/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsKeyFormatter.php b/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsKeyFormatter.php index dbe1f118598..89f3eb0d2b7 100644 --- a/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsKeyFormatter.php +++ b/core/modules/options/src/Plugin/Field/FieldFormatter/OptionsKeyFormatter.php @@ -7,6 +7,7 @@ namespace Drupal\options\Plugin\Field\FieldFormatter; +use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Field\FormatterBase; use Drupal\Core\Field\FieldItemListInterface; @@ -25,6 +26,8 @@ use Drupal\Core\Field\FieldItemListInterface; */ class OptionsKeyFormatter extends FormatterBase { + use AllowedTagsXssTrait; + /** * {@inheritdoc} */ @@ -32,7 +35,7 @@ class OptionsKeyFormatter extends FormatterBase { $elements = array(); foreach ($items as $delta => $item) { - $elements[$delta] = array('#markup' => field_filter_xss($item->value)); + $elements[$delta] = array('#markup' => $this->fieldFilterXss($item->value)); } return $elements; diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php index e0ba02d7162..6fa8fbe2199 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListFloatItem.php @@ -59,7 +59,7 @@ class ListFloatItem extends ListItemBase { $description .= '
' . t('The label is optional: if a line contains a single number, it will be used as key and label.'); $description .= '
' . t('Lists of labels are also accepted (one label per line), only if the field does not hold any values yet. Numeric keys will be automatically generated from the positions in the list.'); $description .= '

'; - $description .= '

' . t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '

'; + $description .= '

' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '

'; return $description; } diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php index c0498780777..8a0b297971e 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListIntegerItem.php @@ -59,7 +59,7 @@ class ListIntegerItem extends ListItemBase { $description .= '
' . t('The label is optional: if a line contains a single number, it will be used as key and label.'); $description .= '
' . t('Lists of labels are also accepted (one label per line), only if the field does not hold any values yet. Numeric keys will be automatically generated from the positions in the list.'); $description .= '

'; - $description .= '

' . t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '

'; + $description .= '

' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '

'; return $description; } diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php index 74e3d450a77..af854ebbaae 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListItemBase.php @@ -7,6 +7,7 @@ namespace Drupal\options\Plugin\Field\FieldType; +use Drupal\Core\Field\AllowedTagsXssTrait; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemBase; use Drupal\Core\Form\FormStateInterface; @@ -19,6 +20,8 @@ use Drupal\Core\TypedData\AllowedValuesInterface; */ abstract class ListItemBase extends FieldItemBase implements AllowedValuesInterface { + use AllowedTagsXssTrait; + /** * {@inheritdoc} */ diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListTextItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListTextItem.php index 1cf34b42195..43848e8d856 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListTextItem.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListTextItem.php @@ -60,7 +60,7 @@ class ListTextItem extends ListItemBase { $description .= '
' . t('The key is the stored value. The label will be used in displayed values and edit forms.'); $description .= '
' . t('The label is optional: if a line contains a single string, it will be used as key and label.'); $description .= '

'; - $description .= '

' . t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '

'; + $description .= '

' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '

'; return $description; } diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php b/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php index aa42e812b7b..49f2d817fea 100644 --- a/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php +++ b/core/modules/options/src/Plugin/Field/FieldWidget/OptionsWidgetBase.php @@ -219,9 +219,9 @@ abstract class OptionsWidgetBase extends WidgetBase { * @param string $label * The label to sanitize. */ - static protected function sanitizeLabel(&$label) { + protected function sanitizeLabel(&$label) { // Allow a limited set of HTML tags. - $label = field_filter_xss($label); + $label = $this->fieldFilterXss($label); } /** diff --git a/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php b/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php index 093e06c3c9b..28a75d2c2cd 100644 --- a/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php +++ b/core/modules/options/src/Plugin/Field/FieldWidget/SelectWidget.php @@ -47,7 +47,7 @@ class SelectWidget extends OptionsWidgetBase { /** * {@inheritdoc} */ - static protected function sanitizeLabel(&$label) { + protected function sanitizeLabel(&$label) { // Select form inputs allow unencoded HTML entities, but no HTML tags. $label = decode_entities(strip_tags($label)); }