Issue #3278636 by nod_, Wim Leers, mrinalini9, bnjmnm: HTMLRestrictions::fromString() bug: multiple occurrences of same tag results in only last one being respected

(cherry picked from commit f7ef84514c)
merge-requests/2643/merge
Alex Pott 2022-08-22 09:11:19 -07:00
parent fe19730b23
commit 3682bd2927
No known key found for this signature in database
GPG Key ID: BDA67E7EE836E5CE
5 changed files with 87 additions and 13 deletions

View File

@ -629,7 +629,8 @@ media_media:
class: Drupal\ckeditor5\Plugin\CKEditor5Plugin\Media
elements:
- <drupal-media>
- <drupal-media data-entity-type data-entity-uuid alt data-view-mode>
- <drupal-media data-entity-type data-entity-uuid alt>
- <drupal-media data-view-mode>
conditions:
filter: media_embed

View File

@ -16,7 +16,6 @@ use Drupal\media\Entity\MediaType;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\ckeditor5\Plugin\CKEditor5PluginDefinition;
use Drupal\ckeditor5\HTMLRestrictions;
/**
* CKEditor 5 Media plugin.
@ -194,14 +193,12 @@ class Media extends CKEditor5PluginDefault implements ContainerFactoryPluginInte
* {@inheritdoc}
*/
public function getElementsSubset(): array {
$all_elements = $this->getPluginDefinition()->getElements();
$subset = HTMLRestrictions::fromString(implode($all_elements));
$subset = $this->getPluginDefinition()->getElements();
$view_mode_override_enabled = $this->getConfiguration()['allow_view_mode_override'];
if (!$view_mode_override_enabled) {
$subset = $subset->diff(HTMLRestrictions::fromString('<drupal-media data-view-mode>'));
$subset = array_diff($subset, ['<drupal-media data-view-mode>']);
}
// @todo Simplify in https://www.drupal.org/project/drupal/issues/3278636, that will allow removing all uses of HTMLRestrictions in this class.
return array_merge(['<drupal-media>'], $subset->toCKEditor5ElementsArray());
return $subset;
}
/**

View File

@ -302,6 +302,26 @@ class HTMLRestrictionsTest extends UnitTestCase {
'<ol type="I A 1">',
['ol' => ['type' => ['I' => TRUE, 'A' => TRUE, 1 => TRUE]]],
];
yield 'tag with two attributes, spread across declarations' => [
'<a target> <a class>',
['a' => ['target' => TRUE, 'class' => TRUE]],
];
yield 'tag with conflicting attribute config, allow one attribute and forbid all attributes' => [
'<a target> <a>',
['a' => ['target' => TRUE]],
];
yield 'tag with conflicting attribute config, allow one attribute and allow all attributes' => [
'<a *> <a target>',
['a' => TRUE],
];
yield 'tag attribute configuration spread across declarations' => [
'<a target="_blank"> <a target="_self"> <a target="_*">',
['a' => ['target' => ['_blank' => TRUE, '_self' => TRUE, '_*' => TRUE]]],
];
yield 'tag attribute configuration spread across declarations, allow all attributes values' => [
'<a target> <a target="_blank"> <a target="_self"> <a target="_*">',
['a' => ['target' => TRUE]],
];
// Multiple tag cases.
yield 'two tags' => [
@ -309,8 +329,8 @@ class HTMLRestrictionsTest extends UnitTestCase {
['a' => FALSE, 'p' => FALSE],
];
yield 'two tags (reverse order)' => [
'<a> <p>',
['a' => FALSE, 'p' => FALSE],
'<p> <a>',
['p' => FALSE, 'a' => FALSE],
];
// Wildcard tag, attribute and attribute value.
@ -328,6 +348,20 @@ class HTMLRestrictionsTest extends UnitTestCase {
],
],
];
yield '$text-container, with attribute values spread across declarations' => [
'<$text-container class="text-align-left"> <$text-container class="text-align-center"> <$text-container class="text-align-right"> <$text-container class="text-align-justify">',
[],
[
'$text-container' => [
'class' => [
'text-align-left' => TRUE,
'text-align-center' => TRUE,
'text-align-right' => TRUE,
'text-align-justify' => TRUE,
],
],
],
];
yield '$text-container + one concrete tag to resolve into' => [
'<p> <$text-container class="text-align-left text-align-center text-align-right text-align-justify">',
[

View File

@ -135,6 +135,18 @@ class SourceEditingPluginTest extends UnitTestCase {
[
'name' => 'foo2',
'attributes' => [
[
'key' => [
'regexp' => [
'pattern' => '/^bar-.*$/',
],
],
'value' => [
'regexp' => [
'pattern' => '/^(baz)$/',
],
],
],
[
'key' => 'bar',
'value' => [
@ -148,6 +160,18 @@ class SourceEditingPluginTest extends UnitTestCase {
[
'name' => 'foo3',
'attributes' => [
[
'key' => [
'regexp' => [
'pattern' => '/^bar-.*$/',
],
],
'value' => [
'regexp' => [
'pattern' => '/^(baz|qux-.*)$/',
],
],
],
[
'key' => 'bar',
'value' => [

View File

@ -266,12 +266,29 @@ class FilterHtml extends FilterBase {
continue;
}
$tag = $node->tagName;
// All attributes are already allowed on this tag, this is the most
// permissive configuration, no additional processing is required.
if (isset($restrictions['allowed'][$tag]) && $restrictions['allowed'][$tag] === TRUE) {
continue;
}
if ($node->hasAttributes()) {
// Mark the tag as allowed, assigning TRUE for each attribute name if
// all values are allowed, or an array of specific allowed values.
$restrictions['allowed'][$tag] = [];
// If the tag is not yet present, prepare to add attribute restrictions.
// Otherwise, check if a more restrictive configuration (FALSE, meaning
// no attributes were allowed) is present: then override the existing
// value to prepare to add attribute restrictions.
if (!isset($restrictions['allowed'][$tag]) || $restrictions['allowed'][$tag] === FALSE) {
$restrictions['allowed'][$tag] = [];
}
// Iterate over any attributes, and mark them as allowed.
foreach ($node->attributes as $name => $attribute) {
// Only add specific attribute values if all values are not already
// allowed.
if (isset($restrictions['allowed'][$tag][$name]) && $restrictions['allowed'][$tag][$name] === TRUE) {
continue;
}
// Put back any trailing * on wildcard attribute name.
$name = str_replace($star_protector, '*', $name);
@ -302,7 +319,8 @@ class FilterHtml extends FilterBase {
}
}
}
else {
if (empty($restrictions['allowed'][$tag])) {
// Mark the tag as allowed, but with no attributes allowed.
$restrictions['allowed'][$tag] = FALSE;
}