Problem/Motivation
Add validation for so called "global" attributes (see https://html.spec.whatwg.org/multipage/dom.html#global-attributes) allowed or forbidden on all elements to Drupal\ckeditor5\Plugin\Validation\Constraint\FundamentalCompatibilityConstraintValidator
.
FilterHtml
supports:
<* dir="ltr rtl">
- https://html.spec.whatwg.org/multipage/dom.html#attr-dir
<* lang>
- https://html.spec.whatwg.org/multipage/dom.html#attr-lang
As proven in #27 and further clarified in #29's refined test coverage (\Drupal\Tests\ckeditor5\FunctionalJavascript\CKEditor5Test::testFilterHtmlAllowedGlobalAttributes()
), this represents a data loss bug in HEAD.
Steps to reproduce
- Data loss: content like this would have its
lang
anddir
attributes stripped:
<p dir="ltr">Hello World</p><p dir="rtl">مرحبا بالعالم</p>
- Validation: no warning about not supporting these global attributes is provided.
Proposed resolution
- Add support for
<*>
to\Drupal\ckeditor5\HTMLRestrictions
as per\Drupal\filter\Plugin\Filter\FilterHtml::getHTMLRestrictions()
— and require that this tag has attributes listed for it, because this tag on its own is absolutely meaningless. - Fix the data loss bug by adding
ckeditor5_globalAttributeDir
+ckeditor5_globalAttributeLang
CKEditor 5 plugins that use GHS to prevent the data loss, and automatically enable them for text formats usingfilter_html
.
Remaining tasks
Reviews.
User interface changes
None.
API changes
None. \Drupal\ckeditor5\HTMLRestrictions
is entirely internal.
Data model changes
None.
Comment | File | Size | Author |
---|---|---|---|
#74 | 3231334-74-9.3.x.patch | 53.69 KB | Wim Leers |
#70 | 3231334-70.patch | 54.63 KB | Wim Leers |
| |||
#64 | 3231334-64.patch | 50.63 KB | Wim Leers |
| |||
#59 | 3231334-59.patch | 42.18 KB | Wim Leers |
#59 | interdiff.txt | 3.35 KB | Wim Leers |
Issue fork drupal-3231334
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
Wim LeersThis should wait for #3228334: Refactor HTMLRestrictionsUtilities to a HtmlRestrictions value object to finish; that will make this simpler.
Comment #4
Wim Leers#3228334: Refactor HTMLRestrictionsUtilities to a HtmlRestrictions value object is in!
This issue will have to make it possible to delete the current work-around in the 3 places where it occurs. I.e. it should make the attached patch pass tests.
Comment #6
Wim LeersThis now blocks #3228691: Restrict allowed additional attributes to prevent self XSS. See comments 14, 15 and 16 there.
Comment #7
Wim LeersAdd support for the
*
special case used byFilterHtml
.Comment #8
Wim LeersUpdate
FundamentalCompatibilityConstraintValidator
to be aware of the*
special case.Comment #10
Wim LeersTurns out that a few of the
@todo
s were wrongly pointing to this issue when they should've been pointing to #3231336: Simplify HtmlRestrictions and FundamentalCompatibilityConstraintValidator now that "forbidden tags" are deprecated.That means this is basically … done! The only thing that remains is adding some test coverage for operations.
Comment #11
Wim LeersComment #14
Wim LeersThis conflicted heavily with #3231328: SmartDefaultSettings should select the CKE5 plugin that minimizes creation of HTML restriction supersets. Rebased.
Comment #15
Wim LeersLet's run only CKE5 tests to make DrupalCI faster.
Comment #17
Wim LeersThis added validation, but we didn't have tests for it yet.
This adds those.
Comment #19
Wim LeersThis case fails. Because it's the first time we need to deal with "attribute values are forbidden".
Nothing in Drupal core can configure this, not even
FilterHtml
.Theoretically, there could be filters in custom/contrib modules that implement this. But we've yet to see this.
So I want to go ahead with just expecting this test failure and adding a
@todo
.Comment #21
Wim LeersThorough unit test coverage. I expect this to fail, hard. Because none of the logic in
\Drupal\ckeditor5\HTMLRestrictions
has been updated to support this special "joker wildcard tag" yet.Once these new unit tests pass, all tests should pass. 🤞
Comment #23
Wim LeersAdd support for operations involving the joker wildcard tag
*
.This will fix the
\Drupal\Tests\ckeditor5\Unit\HTMLRestrictionsTest::testOperations()
failures.Comment #24
Wim LeersWhat's special about the joker wildcard tag: it does not resolve into concrete tags. But it is a wildcard tag. Update the logic accordingly.
This will fix the
\Drupal\Tests\ckeditor5\Unit\HTMLRestrictionsTest::testSubsets()
failures.Comment #27
Wim LeersWhile working on this, I realized that this in
filter_html
is not actually supported by CKEditor 5 today:… which means that content in Drupal 8/9 with CKEditor 4 that uses the
lang
attribute, or sets thedir="rtl"
attribute, would be lost upon editing that content with CKEditor 5.Here's a failing test that proves it.
Comment #29
Wim LeersWhile #27 proved the bug, it mixes it with other test coverage. That's bad.
Furthermore, once the #3259555: Organize and rename CKEditor 5 tests and test classes test reorganization happens, it'll be even more confusing.
So let's get this test right the first time.
Comment #30
Wim LeersFix cspell + typo.
Comment #32
Wim LeersThe test coverage in #7 was wrong: it shouldn't have expected the
*
tag to be returned by::getAllowedElements()
, only by::getAllowedElements(FALSE)
— because only the latter returns wildcards.Comment #33
Wim Leers#3268307: $block wildcard resolves into a superset of the actual $block tags landed and conflicts. Rebased.
Comment #35
Wim LeersI've been working to get
SmartDefaultSettingsTest
to pass …😬 Only now I discovered https://html.spec.whatwg.org/multipage/dom.html#global-attributes, which in turn led me to find #2549077: Allow the "Limit allowed HTML tags" filter to also restrict HTML attributes, and only allow a small whitelist of attributes by default which introduced
😬 This made me realize that the approach in all of the patches above has been wrong on two counts:
<*>
"joker" tag is misnamed: it should be named the "global attributes" tag.Comment #36
Wim LeersAs a nice consequence, the solution becomes very elegant too, and the original scope of the issue easily gets solved:
FundamentalCompatibilityConstraintValidator
starts to complain about global attributes supported byfilter_html
but not by CKEditor 5! 🥳(This reverts #8's change to
FundamentalCompatibilityConstraintValidator
.)Comment #38
Wim LeersAs of #36, we should start to see concrete helpful failures. But … they're lacking a list of unsupported tags and attributes! That's because the violation constraint messages are using
::toFilterHtmlAllowedTagsString()
, but as of #35, that's been updated to not ever generate a<* something>
entry for theallowed_tags
setting ofFilterHtml
, because that is not supported by that plugin.So, we need to generate a list of unsupported tags/attributes slightly differently.
Now we should start to see
The following elements are not supported: <* lang dir="ltr rtl">
as expected 🤓Comment #39
Wim LeersSo now we've established that
<*>
is the global attribute `*` HTML tag. Great.… but
ckeditor5_sourceEditing
today has this in its plugin definition:… that is now problematic. And it sort of always was, but that's only become clear now 🙈
Let's refactor it to set
elements: []
by default.Comment #42
Wim LeersYay, #36 is showing a huge increase in the number of test failures! That proves that the original scope of this issue has been met: validation for attributes allowed/forbidden on all elements (aka global attributes that are allowed or forbidden).
Time to add the plugins that we need to solve the data loss bug!
Introducing:
ckeditor5_globalAttributeDir
<* dir="ltr rtl">
by using GHSckeditor5_globalAttributeLang
<* lang>
by using GHSThey're automatically enabled for text formats using
filter_html
.Comment #44
Wim LeersI think this should be the final thing — making sure that we do not treat CKEditor 5 not supporting forbidding global attributes a problem at all, because CKEditor 5 specifically requires everything to be explicitly supported. If it's not supported at all, there's also no need to then explicitly forbid it.
Hopefully this will be green 🤞
Comment #46
Wim LeersComment #48
Wim LeersThe
WildcardHtmlSupportTest
failures are simple to fix.Comment #50
Wim LeersOne particular edge case that is being tested in
\Drupal\Tests\ckeditor5\Kernel\ValidatorsTest::testPair()
needed to have an expectation updated — easy!Comment #52
Wim LeersLooks like the remaining failures are a genuine regression that this introduced. Will look into that tomorrow.
Comment #53
Wim LeersFirst, clean-up. Let's make this more consistent.
This way, reviews could already start without being too confusing 🤓
Comment #57
bnjmnmThe current test failures seem to be related to html restrictions no longer restricting as expected (for example, a not-allowed
<div>
is permitted by CKEditor 5 instead of being stripped/converted to something supported).I believe this is due to CKEditor 5's
htmlSupport
syntax behaving differently from Drupal's coreSo a rule like
Seems to be saying ANY tag is allowed, and those tags may have a dir attribute.
With the plugins added in this issue I'm able to add any tag when editing source and it remains there. The newly-allowed tags can only use the attributes specified in
ckeditor5_globalAttributeDir + ckeditor5_globalAttributeLang
.This could be addressed (I believe) by creating plugin classes that dynamically provide the GHS config, I'm not sure if there are aspects that should be handled upstream instead.
Comment #58
Wim Leers#57 is spot-on. The solution is very simple though: we just need to not pass this global attribute
*
HTML tag to CKEditor 5, because it's a Drupal-specific concept, not a CKEditor 5 one … and we can instruct CKEditor 5 exactly which tags it should allow these attributes on, because we know what the full list of supported HTML tags is!That idea is very simple, now to actually implement it 🤓
Comment #59
Wim LeersThis implements #58.
Comment #61
Wim LeersComment #62
Wim Leers100% unrelated test failures, from Quick Edit to Migrate 🤪
Comment #63
bnjmnmFeedback addressed, this is RTBC!
Comment #64
Wim Leers3759c178 in patch form!
Comment #65
lauriiiPosted some feedback on the MR.
Comment #66
Wim LeersAll feedback addressed 👍
Comment #67
Wim LeersThis makes no sense at all, because that line in this MR contains
return [$editor, $messages];
🤪🙃.There are only two possible ways that this only reason I could possibly understand this happening: GitLab is wildly broken and testing the wrong commit, or the branch needs to be rebased. Let's assume it's the latter.
Comment #68
Wim LeersAh, now it makes sense! #3261943: Confusing behavior after pressing "Apply changes to allowed tags" with invalid value just landed and it added code to
SmartDefaultSettings
, and that needs to be updated still. 👍Fixed now 😄
Comment #69
bnjmnmBack to RTBC. Leaving the method renaming thread open since that's a bit subjective, but I offered some feedback there.
Comment #70
Wim LeersCommit 5c0879dec73257c25762825bf8b4427cab0f3b71 in patch form, should apply to all 3 branches.
Comment #73
lauriiiCommitted 464291f and pushed to 10.0.x. Also cherry-picked to 9.4.x. Thanks!
Leaving open for 9.3.x but that requires another patch.
Comment #74
Wim LeersComment #75
Wim LeersThis unblocked #3228691: Restrict allowed additional attributes to prevent self XSS, unpostponed! 👍
Comment #77
lauriiiCommitted d65692c and pushed to 9.3.x. Thanks!
Comment #79
Wim LeersDiscovered an overlooked aspect: #3314478: Follow-up for #3231334: global attributes should result in HTMLRestrictions becoming simplified.