Commit 5de9e407 authored by alexpott's avatar alexpott

Issue #2199637 by Berdir, sun, swentel: Replace "required" flag of Field...

Issue #2199637 by Berdir, sun, swentel: Replace "required" flag of Field module with proper dependencies.
parent 6a6e528b
<?php
/**
* @file
* Contains \Drupal\Core\Field\AllowedTagsXssTrait.
*/
namespace Drupal\Core\Field;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
/**
* Useful methods when dealing with displaying allowed tags.
*/
trait AllowedTagsXssTrait {
/**
* Filters an HTML string to prevent 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\Component\Utility\String::checkPlain() is not acceptable).
*
* @param string $string
* The string with raw HTML in it.
*
* @return \Drupal\Component\Utility\SafeMarkup
* An XSS safe version of $string, or an empty string if $string is not
* valid UTF-8.
*/
public function fieldFilterXss($string) {
return SafeMarkup::set(Html::normalize(Xss::filter($string, $this->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()) . '>';
}
}
......@@ -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 @@
*/
abstract class NumericFormatterBase extends FormatterBase {
use AllowedTagsXssTrait;
/**
* {@inheritdoc}
*/
......@@ -72,8 +75,8 @@ public function viewElements(FieldItemListInterface $items) {
// 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;
......
......@@ -101,11 +101,11 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
// 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);
......
......@@ -21,6 +21,8 @@
*/
abstract class WidgetBase extends PluginSettingsBase implements WidgetInterface {
use AllowedTagsXssTrait;
/**
* The field definition.
*
......@@ -82,7 +84,7 @@ public function form(FieldItemListInterface $items, array &$form, FormStateInter
$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 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
}
$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 @@ public static function isApplicable(FieldDefinitionInterface $field_definition)
return TRUE;
}
}
......@@ -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
......@@ -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".
*/
......
......@@ -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 @@
*/
class FieldList extends Numeric {
use AllowedTagsXssTrait;
/**
* Stores the allowed values of this field.
*
......@@ -67,7 +70,7 @@ public function summaryName($data) {
$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 {
......
......@@ -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 @@
*/
class ListString extends String {
use AllowedTagsXssTrait;
/**
* Stores the allowed values of this field.
*
......@@ -69,7 +72,7 @@ public function summaryName($data) {
$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 {
......
......@@ -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 @@
*/
class FieldInstanceEditForm extends FormBase {
use AllowedTagsXssTrait;
/**
* The field instance being edited.
*
......@@ -124,7 +127,7 @@ public function buildForm(array $form, FormStateInterface $form_state, FieldInst
'#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.<br />Allowed HTML tags: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '<br />' . $this->t('This field supports tokens.'),
'#description' => $this->t('Instructions to present to the user below this field on the editing form.<br />Allowed HTML tags: @tags', array('@tags' => $this->displayAllowedTags())) . '<br />' . $this->t('This field supports tokens.'),
'#weight' => -10,
);
......
......@@ -97,7 +97,7 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
}
$title = String::checkPlain($this->fieldDefinition->getLabel());
$description = field_filter_xss($this->fieldDefinition->getDescription());
$description = $this->fieldFilterXss($this->fieldDefinition->getDescription());
$elements = array();
......
......@@ -96,7 +96,7 @@ protected function formMultipleElements(FieldItemListInterface $items, array &$f
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);
}
}
......
......@@ -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.
......
......@@ -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 @@
*/
class OptionsDefaultFormatter extends FormatterBase {
use AllowedTagsXssTrait;
/**
* {@inheritdoc}
*/
......@@ -36,11 +39,11 @@ public function viewElements(FieldItemListInterface $items) {
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);
}
......
......@@ -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 @@
*/
class OptionsKeyFormatter extends FormatterBase {
use AllowedTagsXssTrait;
/**
* {@inheritdoc}
*/
......@@ -32,7 +35,7 @@ public function viewElements(FieldItemListInterface $items) {
$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;
......
......@@ -59,7 +59,7 @@ protected function allowedValuesDescription() {
$description .= '<br/>' . t('The label is optional: if a line contains a single number, it will be used as key and label.');
$description .= '<br/>' . 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 .= '</p>';
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '</p>';
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '</p>';
return $description;
}
......
......@@ -59,7 +59,7 @@ protected function allowedValuesDescription() {
$description .= '<br/>' . t('The label is optional: if a line contains a single number, it will be used as key and label.');
$description .= '<br/>' . 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 .= '</p>';
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '</p>';
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '</p>';
return $description;
}
......
......@@ -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 @@
*/
abstract class ListItemBase extends FieldItemBase implements AllowedValuesInterface {
use AllowedTagsXssTrait;
/**
* {@inheritdoc}
*/
......
......@@ -60,7 +60,7 @@ protected function allowedValuesDescription() {
$description .= '<br/>' . t('The key is the stored value. The label will be used in displayed values and edit forms.');
$description .= '<br/>' . t('The label is optional: if a line contains a single string, it will be used as key and label.');
$description .= '</p>';
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => _field_filter_xss_display_allowed_tags())) . '</p>';
$description .= '<p>' . t('Allowed HTML tags in labels: @tags', array('@tags' => $this->displayAllowedTags())) . '</p>';
return $description;
}
......
......@@ -219,9 +219,9 @@ protected function supportsGroups() {
* @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);
}
/**
......
......@@ -47,7 +47,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
/**
* {@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));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment