Commit cc574ff2 authored by catch's avatar catch

Issue #2560863 by alexpott, stefan.r, lauriii: #options for radios and...

Issue #2560863 by alexpott, stefan.r, lauriii: #options for radios and checkboxes uses SafeMarkup::checkPlain() to escape - use Html::escape() instead
parent 53b28208
......@@ -27,7 +27,7 @@ interface SelectionInterface extends PluginFormInterface {
*
* @return array
* A nested array of entities, the first level is keyed by the
* entity bundle, which contains an array of entity labels (safe HTML),
* entity bundle, which contains an array of entity labels (escaped),
* keyed by the entity ID.
*/
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0);
......
......@@ -7,7 +7,7 @@
namespace Drupal\Core\Entity\Plugin\EntityReferenceSelection;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityManagerInterface;
......@@ -235,7 +235,7 @@ public function getReferenceableEntities($match = NULL, $match_operator = 'CONTA
$entities = entity_load_multiple($target_type, $result);
foreach ($entities as $entity_id => $entity) {
$bundle = $entity->bundle();
$options[$bundle][$entity_id] = SafeMarkup::checkPlain($entity->label());
$options[$bundle][$entity_id] = Html::escape($entity->label());
}
return $options;
......
......@@ -7,7 +7,7 @@
namespace Drupal\entity_reference;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Core\Field\PreconfiguredFieldUiOptionsInterface;
......@@ -80,7 +80,9 @@ public function getSettableOptions(AccountInterface $account = NULL) {
$return = array();
foreach ($options as $bundle => $entity_ids) {
$bundle_label = SafeMarkup::checkPlain($bundles[$bundle]['label']);
// The label does not need sanitizing since it is used as an optgroup
// which is only supported by select elements and auto-escaped.
$bundle_label = $bundles[$bundle]['label'];
$return[$bundle_label] = $entity_ids;
}
......@@ -135,11 +137,11 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
// entity type specific plugins (e.g., 'default:node', 'default:user',
// etc.).
if (array_key_exists($selection_group_id, $selection_plugins[$selection_group_id])) {
$handlers_options[$selection_group_id] = SafeMarkup::checkPlain($selection_plugins[$selection_group_id][$selection_group_id]['label']);
$handlers_options[$selection_group_id] = Html::escape($selection_plugins[$selection_group_id][$selection_group_id]['label']);
}
elseif (array_key_exists($selection_group_id . ':' . $this->getSetting('target_type'), $selection_plugins[$selection_group_id])) {
$selection_group_plugin = $selection_group_id . ':' . $this->getSetting('target_type');
$handlers_options[$selection_group_plugin] = SafeMarkup::checkPlain($selection_plugins[$selection_group_id][$selection_group_plugin]['base_plugin_label']);
$handlers_options[$selection_group_plugin] = Html::escape($selection_plugins[$selection_group_id][$selection_group_plugin]['base_plugin_label']);
}
}
......
<?php
/**
* @file
* Contains \Drupal\entity_reference\Tests\EntityReferenceXSSTest.
*/
namespace Drupal\entity_reference\Tests;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\simpletest\WebTestBase;
/**
* Tests possible XSS security issues in entity references.
*
* @group entity_reference
*/
class EntityReferenceXSSTest extends WebTestBase {
use EntityReferenceTestTrait;
/**
* Modules to enable.
*
* @var array
*/
protected static $modules = ['node', 'entity_reference'];
/**
* Tests markup is escaped in the entity reference select and label formatter.
*/
public function testEntityReferenceXSS() {
$this->drupalCreateContentType(['type' => 'article']);
// Create a node with markup in the title.
$node_type_one = $this->drupalCreateContentType();
$node = [
'type' => $node_type_one->id(),
'title' => '<em>I am kitten</em>',
];
$referenced_node = $this->drupalCreateNode($node);
$node_type_two = $this->drupalCreateContentType(['name' => '<em>bundle with markup</em>']);
$this->drupalCreateNode([
'type' => $node_type_two->id(),
'title' => 'My bundle has markup',
]);
$this->createEntityReferenceField('node', 'article', 'entity_reference_test', 'Entity Reference test', 'node', 'default', ['target_bundles' => [$node_type_one->id(), $node_type_two->id()]]);
EntityFormDisplay::load('node.article.default')
->setComponent('entity_reference_test', ['type' => 'options_select'])
->save();
EntityViewDisplay::load('node.article.default')
->setComponent('entity_reference_test', ['type' => 'entity_reference_label'])
->save();
// Create a node and reference the node with markup in the title.
$this->drupalLogin($this->rootUser);
$this->drupalGet('node/add/article');
$this->assertEscaped($referenced_node->getTitle());
$this->assertEscaped($node_type_two->label());
$edit = [
'title[0][value]' => $this->randomString(),
'entity_reference_test' => $referenced_node->id()
];
$this->drupalPostForm(NULL, $edit, 'Save and publish');
$this->assertEscaped($referenced_node->getTitle());
// Test the options_buttons type.
EntityFormDisplay::load('node.article.default')
->setComponent('entity_reference_test', ['type' => 'options_buttons'])
->save();
$this->drupalGet('node/add/article');
$this->assertEscaped($referenced_node->getTitle());
// options_buttons does not support optgroups.
$this->assertNoText('bundle with markup');
}
}
......@@ -79,7 +79,7 @@ public function form(array $form, FormStateInterface $form_state) {
$form['roles'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('Roles'),
'#options' => array_map('\Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names()),
'#options' => array_map('\Drupal\Component\Utility\Html::escape', user_role_names()),
'#disabled' => $is_fallback,
'#weight' => -10,
);
......
......@@ -554,7 +554,7 @@ public function searchFormAlter(array &$form, FormStateInterface $form_state) {
);
// Add node types.
$types = array_map(array('\Drupal\Component\Utility\SafeMarkup', 'checkPlain'), node_type_get_names());
$types = array_map(array('\Drupal\Component\Utility\Html', 'escape'), node_type_get_names());
$form['advanced']['types-fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('Types'),
......
......@@ -57,8 +57,8 @@ function testEntityReferenceAutocompletion() {
$entity_2 = entity_create($this->entityType, array('name' => '10/17/2011'));
$entity_2->save();
// Add another entity that has both a comma and a slash character.
$entity_3 = entity_create($this->entityType, array('name' => 'label with, and / test'));
// Add another entity that has both a comma, a slash and markup.
$entity_3 = entity_create($this->entityType, array('name' => 'label with, and / <em>test</em>'));
$entity_3->save();
// Try to autocomplete a entity label that matches both entities.
......@@ -84,8 +84,8 @@ function testEntityReferenceAutocompletion() {
$data = $this->getAutocompleteResult($input);
$this->assertIdentical($data[0]['label'], Html::escape($entity_2->name->value), 'Autocomplete returned the second matching entity');
// Try to autocomplete a entity label with both a comma and a slash.
$input = '"label with, and / t';
// Try to autocomplete a entity label with both a comma, a slash and markup.
$input = '"label with, and / <em>';
$data = $this->getAutocompleteResult($input);
$n = $entity_3->name->value . ' (3)';
// Entity labels containing commas or quotes must be wrapped in quotes.
......
......@@ -62,6 +62,12 @@ function testOptions() {
}
}
// Verify that the choices are admin filtered as expected.
$this->assertRaw("<em>Special Char</em>alert('checkboxes');");
$this->assertRaw("<em>Special Char</em>alert('radios');");
$this->assertRaw('<em>Bar - checkboxes</em>');
$this->assertRaw('<em>Bar - radios</em>');
// Enable customized option sub-elements.
$this->drupalGet('form-test/checkboxes-radios/customize');
......
......@@ -363,6 +363,10 @@ function testSelect() {
$form = \Drupal::formBuilder()->getForm('Drupal\form_test\Form\FormTestSelectForm');
$this->drupalGet('form-test/select');
// Verify that the options are escaped as expected.
$this->assertEscaped('<strong>four</strong>');
$this->assertNoRaw('<strong>four</strong>');
// Posting without any values should throw validation errors.
$this->drupalPostForm(NULL, array(), 'Submit');
$no_errors = array(
......
......@@ -36,8 +36,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $customiz
0 => 'Zero',
'foo' => 'Foo',
1 => 'One',
'bar' => 'Bar',
'>' => 'Special Char',
'bar' => $this->t('<em>Bar - checkboxes</em>'),
'>' => "<em>Special Char</em><script>alert('checkboxes');</script>",
),
);
if ($customize) {
......@@ -60,8 +60,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $customiz
0 => 'Zero',
'foo' => 'Foo',
1 => 'One',
'bar' => 'Bar',
'>' => 'Special Char',
'bar' => '<em>Bar - radios</em>',
'>' => "<em>Special Char</em><script>alert('radios');</script>",
),
);
if ($customize) {
......
......@@ -29,7 +29,7 @@ public function getFormId() {
public function buildForm(array $form, FormStateInterface $form_state) {
$base = array(
'#type' => 'select',
'#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
'#options' => array('one' => 'one', 'two' => 'two', 'three' => 'three', 'four' => '<strong>four</strong>'),
);
$form['select'] = $base + array(
......
......@@ -7,7 +7,7 @@
namespace Drupal\taxonomy\Plugin\EntityReferenceSelection;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase;
use Drupal\Core\Form\FormStateInterface;
......@@ -73,7 +73,7 @@ public function getReferenceableEntities($match = NULL, $match_operator = 'CONTA
if ($vocabulary = Vocabulary::load($bundle)) {
if ($terms = $this->entityManager->getStorage('taxonomy_term')->loadTree($vocabulary->id(), 0, NULL, TRUE)) {
foreach ($terms as $term) {
$options[$vocabulary->id()][$term->id()] = str_repeat('-', $term->depth) . SafeMarkup::checkPlain($term->getName());
$options[$vocabulary->id()][$term->id()] = str_repeat('-', $term->depth) . Html::escape($term->getName());
}
}
}
......
......@@ -183,7 +183,7 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
if ($tree) {
foreach ($tree as $term) {
$choice = new \stdClass();
$choice->option = array($term->id() => str_repeat('-', $term->depth) . SafeMarkup::checkPlain(\Drupal::entityManager()->getTranslationFromContext($term)->label()));
$choice->option = array($term->id() => str_repeat('-', $term->depth) . \Drupal::entityManager()->getTranslationFromContext($term)->label());
$options[] = $choice;
}
}
......@@ -201,7 +201,7 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
}
$terms = Term::loadMultiple($query->execute());
foreach ($terms as $term) {
$options[$term->id()] = SafeMarkup::checkPlain(\Drupal::entityManager()->getTranslationFromContext($term)->label());
$options[$term->id()] = \Drupal::entityManager()->getTranslationFromContext($term)->label();
}
}
......
......@@ -205,7 +205,7 @@ public function form(array $form, FormStateInterface $form_state) {
'#access' => $admin,
);
$roles = array_map(array('\Drupal\Component\Utility\SafeMarkup', 'checkPlain'), user_role_names(TRUE));
$roles = array_map(array('\Drupal\Component\Utility\Html', 'escape'), user_role_names(TRUE));
$form['account']['roles'] = array(
'#type' => 'checkboxes',
......
......@@ -115,7 +115,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
'#type' => 'checkboxes',
'#title' => $this->t('Role'),
'#default_value' => $this->options['role'],
'#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('Only the checked roles will be able to access this display.'),
);
}
......
......@@ -65,7 +65,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
$form['roles'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('Restrict to the selected roles'),
'#options' => array_map(array('\Drupal\Component\Utility\SafeMarkup', 'checkPlain'), user_role_names(TRUE)),
'#options' => array_map(array('\Drupal\Component\Utility\Html', 'escape'), user_role_names(TRUE)),
'#default_value' => $this->options['roles'],
'#description' => $this->t('If no roles are selected, users from any role will be allowed.'),
'#states' => array(
......
......@@ -7,7 +7,7 @@
namespace Drupal\user\Plugin\views\filter;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\user\PermissionHandlerInterface;
use Drupal\views\Plugin\views\filter\ManyToOne;
......@@ -76,7 +76,7 @@ public function getValueOptions() {
foreach ($permissions as $perm => $perm_item) {
$provider = $perm_item['provider'];
$display_name = $this->moduleHandler->getName($provider);
$this->valueOptions[$display_name][$perm] = SafeMarkup::checkPlain(strip_tags($perm_item['title']));
$this->valueOptions[$display_name][$perm] = Html::escape(strip_tags($perm_item['title']));
}
}
else {
......
......@@ -7,7 +7,7 @@
namespace Drupal\views\Plugin\views\exposed_form;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Form\ViewsExposedForm;
......@@ -211,7 +211,7 @@ public function exposedFormAlter(&$form, FormStateInterface $form_state) {
$exposed_sorts = array();
foreach ($this->view->sort as $id => $handler) {
if ($handler->canExpose() && $handler->isExposed()) {
$exposed_sorts[$id] = SafeMarkup::checkPlain($handler->options['expose']['label']);
$exposed_sorts[$id] = Html::escape($handler->options['expose']['label']);
}
}
......
......@@ -594,7 +594,7 @@ public function buildExposeForm(&$form, FormStateInterface $form_state) {
'#default_value' => $this->options['expose']['remember'],
);
$role_options = array_map('\Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names());
$role_options = array_map('\Drupal\Component\Utility\Html::escape', user_role_names());
$form['expose']['remember_roles'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('User roles'),
......
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