Problem/Motivation
We do not use the static safe list anymore therefore SafeMarkup::setMultiple() and SafeMarkup::getMultiple() are not needed and the storage of safe strings in the batch and forms is not necessary.
However SafeMarkup::checkPlain() still stores strings in the safe strings - but it has no usages in core.
Proposed resolution
Introduce HtmlEscapedText and change SafeMarkup::checkPlain() deprecation to Drupal 9 so that contrib and custom are not broken.
Remaining tasks
(done) Review
(done) Update CR https://www.drupal.org/node/2549395
User interface changes
None
API changes
SafeMarkup::setMultiple() and SafeMarkup::getMultiple() removed
SafeMarkup::checkPlain() returns an EscapedString string object.
Data model changes
None
| Comment | File | Size | Author |
|---|---|---|---|
| #68 | 2575615-tng-68.patch | 38.73 KB | alexpott |
| #68 | 66-68-interdiff.txt | 4.7 KB | alexpott |
| #66 | 2575615-tng-66.patch | 36.62 KB | alexpott |
| #66 | 65-66-interdiff.txt | 572 bytes | alexpott |
| #65 | 2575615-tng-65.patch | 36.61 KB | alexpott |
Comments
Comment #2
alexpottComment #5
alexpottComment #6
novitsh commentedThis patch also concludes #2569699-41: Remove SafeMarkup::checkPlain() for Drupal 9.0.x and seems to be OK. Do we need an update on the docs at https://api.drupal.org/api/drupal/core!lib!Drupal!Component!Utility!SafeMarkup.php/class/SafeMarkup/8?
Comment #7
dawehnerGreat idea, let's don't break even more contrib modules. Removing checkPlain doens't add additional security.
Comment #8
alexpottComment #9
imiksuComment #42 in issue #2569699
Comment #10
xjmThe CR also needs to be updated to include these.
Comment #11
pwolanin commentedfix title
Comment #12
pwolanin commentedI made a first pass at updating the CR.
Do we need an is_object() check here? It seems it's ok for scalar variables but not sure if there is any edge case.
Comment #13
stefan.r commentedAh so less double escaping with EscapedString now :)
"Escapes a string for HTML display." is pretty clear, and I think we already document on the interface where *not* to use it, but should we do so here as well?
Comment #14
alexpott@stefan.r
EscapedStringis deprecated.Comment #15
pwolanin commentedNitpicks:
Should we more literally say this?
Remove the "mark" terminology here?
Comment #16
alexpottThanks @pwolanin
Comment #17
pwolanin commenteddon't use this trait or the ::create() method will return any object implementing SafeStringInterface unchanged instead of escaping it.
Working on a fix for this now.
Comment #18
pwolanin commentedinline the methods including a valid ::create() and 2 little test cases.
Comment #19
alexpottLet's just not provide a create
Comment #21
pwolanin commentedok, great
Comment #26
pwolanin commentedoops - missing method. need a constructor instead.
per @alexpott also directly test the class to make sure it behaves the same and simplfy the data provider.
Also, need to use the Component test class, not the core class in the test.
Comment #27
dawehnerThis should not be deprecated, for 9.0.0 given that tokens will use it
{@inheritdoc}Not a nitpick at all: we need a new line
beatiful
It is not 100% obvious why we need to reset the build info, given that we almost doesn't change
$build_infoOMG
Form.inc: has a reference to -safe_strings still
Comment #28
alexpottAddressing all of @dawehner's feedback in #27 - thank you for the review.
Comment #29
pwolanin commentedlooks great
Comment #30
effulgentsia commentedAnd yet, core still calls this from a bunch of places, such as from TwigExtension::escapeFilter(), theme_render_and_autoescape(), PlaceholderTrait::placeholderEscape(), views_pre_render_views_form_views_form(), and more.
Do we want to change all those usages here or in a follow-up? If in a follow-up, is that issue created already? If not, can someone create it?
Comment #31
alexpott@effulgentsia
SafeMarkup::isSafe()is deprecated for Drupal 9 - I think that we can remove usages at any point in the Drupal 8 cycle - we certainly don't have to do it in this issue or quickly before the rc.Comment #32
yesct commentedhttps://www.drupal.org/node/2549395 has been updated, removing tag.
Comment #33
yesct commentedupdating remaining tasks in the issue summary
Comment #34
dawehnerNote: This issue would also help a lot with #2567257: hook_tokens() $sanitize option incompatible with Html sanitisation requirements
Comment #35
catchHow does this interact with the SafeString behaviour we added to https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Template%... ?
Looks like we'd:
- escape in EscapedString::__toString()
- convert to plain text with PlainTextOutput::renderFromHtml() (because it was detected as a SafeString)
- escape in AttributeString
at the moment.
Comment #36
catchRegardless of the answer to that, it would be documented best with explicit test coverage of that interaction.
Comment #37
lauriiiSad that we won't get rid of SafeMarkup::checkPlain() but yay for getting rid of the safe list!
Comment #38
alexpott@catch this interaction with the return of
SafeMarkup::checkPlain()is not new or changed by this patch - are you sure that we need to add additional test coverage here?I agree that there is a possible optimisation here since we know that the output of EscapedString is always escaped - but can't that be left to followups and API additions?
Comment #39
alexpottComment #40
catchSo it isn't changed because SafeMarkup::isSafe() will return TRUE for something returned from SafeMarkup::checkPlain() both before and after this patch.
I guess that is fine. However my other question here is whether we should add EscapedStringInterface so we can type hint/instanceof for that in places like this.
Comment #41
alexpottAdding
EscapedStringInterface- I'll open a followup to check this inAttributeand then not use thePlainTextOutput::renderFromHtml().Comment #42
alexpottCreated #2576523: Add an EscapedStringInterface and use it in Attribute
Comment #43
dawehnerNitpick for the commit, two dots.
I'm curious whether for API similarity we should provide a ::create() method much like SafeStringTrait provides.
Comment #45
novitsh commentedStrangely enough in my local this patch is not applying even after pulling from 8.0.x.
Testbot however is applying with no issues.
+++ b/core/lib/Drupal/Component/Utility/EscapedStringInterface.php<br>@@ -0,0 +1,27 @@<br>+ * Returns an escaped string..#43: agreed. Please remove 1 dot. I would write the patch if my local was not misbehaving :-)
Comment #46
alexpottBefore we proceed with this we should get a decision on #2576533: Rename SafeStringInterface to MarkupInterface and move related classes. Therefore postponing
Comment #47
alexpottSo in #2576533: Rename SafeStringInterface to MarkupInterface and move related classes @effulgentsia and @xjm pointed out that
EscapedMarkupcould be considered a bad name. I'm not certain I see it that way but I'm open to suggestions about what it should be. Patch attached is a reroll on top of #2576533: Rename SafeStringInterface to MarkupInterface and move related classes plus a move into Drupal/Component/Render. I also useEscapedMarkupin theTokenutility. Fixed #45 too.Comment #48
alexpottWe have to get this done before rc to get the full benefit of not having a static safe list.
Comment #49
catchIssue title still says escapedstring - that seems fine especially if it implements markupinterface
Comment #50
stefan.r commentedAre we expecting to add this to the API after all, i.e. does Token still need this? If we just mark it @internal, then it doesn't really matter what we call it :)
So in this case the input can be either plain text or markup, but the output will always be HTML-escaped HTML text. So it seems this can be used for two purposes:
EscapedString is confusing but I can't really come up with a better name due to the nature of the thing. I'd still prefer it if this had the word Markup in it somehow, EscapedMarkup at least hints that it implements MarkupInterface and that the __toString outputs HTML-escaped text.
Comment #51
stefan.r commentedWell I guess as long as they're @internal EscapedString or EscapableString work despite the ugliness.
Comment #52
alexpottComment #53
alexpottEscapableStringit is! Added a test for EscapableString too.Comment #54
stefan.r commentedReviewed this and I think this looks great! It is great to finally get rid of the safe list, which seemed impossible only a month ago.
Comment #55
alexpottThanks for the review @stefan.r
This class can be used to provide theme engine-like late escaping functionality.Comment #56
stefan.r commentedRTBC assuming this will come back green
Comment #57
alexpott@xjm asked if we have test coverage of the safe list removal. I'm not 100% convinced it is necessary since I'm certain many many things would be broken if this was not working - I think existing coverage in
Drupal\system\Tests\Batch\ProcessingTestproves this is working. However there is no harm in a few more assertions.Comment #58
xjm@alexpott, FWIW, no batch nor multiform tests failed that I could see in #1825952-139: Turn on twig autoescape by default when the safe list was first added (or the sandbox results earlier). But I may have missed an implicit fail.
Comment #59
David_Rothstein commentedI think this needs to be critical actually. The patch committed in #2570431: Document that certain (non-"href") attribute values in t() and SafeMarkup::format() are not supported and may be insecure assumed the patch here is already in core. Without it, the advice it gives in the documentation is currently wrong/insecure. For example:
Comment #60
David_Rothstein commentedMinor (and could be fixed on commit):
The code comment is wrong now and could just be removed.
Comment #61
effulgentsia commentedWould it be ok to not add
EscapableStringInterfacehere if nothing in this patch uses it? HEAD doesn't have any other sub-interfaces of MarkupInterface, and I'm not 100% convinced we want one. If we decide on it being useful in #2576523: Add an EscapedStringInterface and use it in Attribute, can we add it in that issue?As far as naming EscapableString, what about
HtmlEscapedTextinstead? I don't quite follow the nuances in #50. As far as I understand it, if it's "html escaped", then it is text: in the sense of it would all become a single text node within an HTML DOM. Whether the unescaped version of the string has "<" and ">" characters in it doesn't matter, or does it?Comment #62
effulgentsia commented"needs review" for #61. If the answer to #61 is no, then this can be re-RTBC'd.
Comment #63
pwolanin commentedI agree that EscapableString is a not a great name. HtmlEscapedText or HtmlEscapedString would be better.
I also agree with effulgentsia that this MarkupInterface interface seems a bit weird, and really does it make any sense to have other implementations?
Comment #64
alexpottWrt to the name EscapableString or HtmlEscapedText or HtmlEscapedString I think they are all fine - to me even EscapedMarkup is fine. Because the important thing is communicated by MarkupInterface + the word escape - which to means means that when represented in markup the string content will be escaped.
I've removed EscapableStringInterface as I only introduced it due to #40. And we can add it back when we need it.
Fixed #60 too.
Comment #65
alexpottDiscussed with @catch and @effulgentsia - decided to change EscapableString to HtmlEscapedText.
Comment #66
alexpott@xjm and @effulgentsia suggested some improvements to the class docblock.
Comment #67
stefan.r commentedLiking that last class docs improvement and the name works for me as well. As opposed to some of our other string value objects the name refers to the __toString output, but in a way that's still clearer than "EscapableString" :)
Back to RTBC considering #64 is green and #66 looks to have renamed them all, so this should come back green as well.
Comment #68
alexpottMove removal of "SafeString" in test comments and assertion messages.
Comment #69
alexpottI've ticked all the credit boxes for people that have discussed this issue at length with me or worked on #2569699: Remove SafeMarkup::checkPlain() for Drupal 9.0.x
Comment #70
alexpottSuggested commit message:
Comment #72
effulgentsia commentedPushed to 8.0.x!
I'm assuming there are CRs that need updating, but if I'm wrong about that, then please untag and mark fixed.
Comment #73
plachhttps://www.drupal.org/node/2549395 is already mentioning this issue and looks more or less up-to-date, at least as far as this issue is concerned.
Comment #75
effulgentsia commentedhttps://www.drupal.org/node/2549395 is great, but I think the intro of the "Escaping markup (or, how to check_plain() in Drupal 8)" section and its option #3 could be improved a bit. For example,
With this issue, the most direct replacement is now
new HtmlEscapedText()and that does mark the string as safe. And actually the "mark as safe" terminology might now be wrong as well, since MarkupInterface now has a slightly different semantics than "safe".Those aren't symmetrical options, because the output of SafeMarkup::format() is a MarkupInterface object, but the output of Html::escape() is not. Should we change this recommendation to
new HtmlEscapedTextandnew FormattableMarkupinstead? Do we want a section on when to useHtml::escape()vs. when to usenew HtmlEscapedText?The answers to the above questions aren't obvious (at least not to me), so that's why I'm asking them here instead of updating the CR myself. In fact, should we open a new issue for figuring this out, or does it make sense to keep using this one?
Additionally, it would be great if someone read through all the CRs in https://www.drupal.org/list-changes/published/drupal?keywords_descriptio... and flagged either in this issue or some other one things that are no longer accurate or recommended.
Comment #78
yesct commentedI'm familiar with wording changes in this area, so I will start on #75. but i dont know all the answers, so ping to collaborate. :)
Comment #79
yesct commentedI didn't answer/make a change for the "Those aren't symmetrical options..." concern. I'm leaning toward opening up another issue for that (normal task?)
for easier reviewing, here are changes
https://www.drupal.org/node/2549395/revisions/view/8949021/8949983
and going through the list https://www.drupal.org/list-changes/published/drupal?keywords_descriptio... from @effulgentsia
(no change to https://www.drupal.org/node/2575573 )
(no change to https://www.drupal.org/node/2574697 )
https://www.drupal.org/node/2571689/revisions/view/8928627/8949999
https://www.drupal.org/node/2560027/revisions/view/8924353/8950021
https://www.drupal.org/node/2549107/revisions/view/8838371/8950037
(no change to https://www.drupal.org/node/2559263 )
https://www.drupal.org/node/2506757/revisions/view/8838455/8950069
(no change to https://www.drupal.org/node/2457593 )
https://www.drupal.org/node/2392803/revisions/view/8838279/8950075 <- not sure what to change the new recommendation to
https://www.drupal.org/node/2445441/revisions/view/8865509/8950101 <- might need more old stuff like examples using SafeMarkup::format() updated
https://www.drupal.org/node/2296163/revisions/view/8928695/8950169 <- a main change record that could use review, and I think a better example of "simple concatenations"
https://www.drupal.org/node/2302363/revisions/view/8838291/8950187
https://www.drupal.org/node/2153775/revisions/view/8844725/8950197
https://www.drupal.org/node/2067859/revisions/view/8844663/8950205
https://www.drupal.org/node/1312890/revisions/view/8837809/8950209
Comment #80
yesct commentededited the previous comments to have links to all the revisions. They need review.
Also, created #2579655: Document when to use Html::escape() vs. when to use new HtmlEscapedText
Comment #81
chx commented1. The example linked for SafeMarkup::replace() , views_pre_render_views_form_views_form() uses SafeMarkup::isSafe which it shouldn't. At least a () note or find another example.
2. Alternatively, it is possible to escape output in JavaScript instead. has no code example.
Now on to https://www.drupal.org/node/2296163
3. renderPlain is an extremely poor name and we should open a new issue and add a much better name! Anyone sane would expect *plain text* to come out of it but it renders HTML? WTF!
4. ['list_style' => 'comma-list'], is it possible to specify the delimiter or is it hardwired comma
5. FormattableMarkup "will return an object" should mention "implementing MarkupInterface" just to reinforce it's MarkupInterface as mentioned in the SafeMarkup::isSafe replacement
6. If you have a genuine use-case for script tags or other markup stripped by Xss::filerAdmin(), you will need to use proper templates or other APIs such as the Library API. <= example? Isn't library api for attaching libraries? how is this relevant? I am baffled.
Comment #82
yesct commented1.
opened #2579691: Remove usages of SafeMarkup::isSafe()
and #2579697: Remove usages of SafeMarkup::checkPlain() in documentation
and #2579701: remove SafeMarkup class
and added a note about the example using a deprecated method https://www.drupal.org/node/2549395/revisions/view/8949983/8950651
3.
opened #2579709: rename renderPlain to something by making renderPlain a wrapper and adding another better named method
4.
core/modules/system/templates/item-list.html.twig
puts the value of the list type in the css, (so it is not hardcoded)
but, comma is the only list type core uses,
and we have some css for it in
core/themes/bartik/css/components/item-list.css
core/themes/classy/css/components/item-list.css
core/themes/seven/css/components/menus-and-lists.css
5.
and added the object Interface type for clarification
https://www.drupal.org/node/2296163/revisions/view/8950169/8950449
Comment #83
yesct commented2.
https://www.drupal.org/node/2549395/revisions/view/8950651/8950667
added a javascript Drupal.formatString example, but
I’m not sure if the javascript note is general or part of “4. Non-HTML responses" drupal.org/node/2549395
and looking at the issue that was linked, I'm not sure if that is appropriate,
or if
return '<span class="field">' + Drupal.checkPlain(settings.fieldLabel) + '</span>' + Drupal.checkPlain(settings.entityLabel);in Drupal.theme.quickeditEntityToolbarLabel in core/modules/quickedit/js/theme.js
would be better.
I will try and find something for 6. next, ping to help. :) I'm not sure how successful I will be.
[edit:]
#2273925: Ensure #markup is XSS escaped in Renderer::doRender() might have a clue.
core/lib/Drupal/Core/Render/theme.api.php
Comment #84
corbacho commentedAbout 2.
formatString example (now in the CR), maybe is not best example. Because formatString not always escapes the text, depends on the arguments as you see here:
http://cgit.drupalcode.org/drupal/tree/core/misc/drupal.js#n296
I would go for your example of .checkPlain
Comment #85
corbacho commentedAbout #83 question. I would consider the JavaScript note to be part of 4. Non HTML responses. It's where it has more sense.
If you are delivering non-escaped HTML from the server to be escaped only in JavaScript (via AJAX), you are doing it wrong
Comment #86
corbacho commentedIf you are on it, Cathy.. this text needs fix " There are three possibilities:" (Now there are actually 4 possibilities)
Comment #87
pwolanin commented@corbacho - we should remove the ! placeholder in the JS api also. I think that was overlooked.
Comment #88
yesct commentedI'm away for a few hours. CR improvements open to anyone. :) edit away! (post revisions links and questions here please)
Comment #89
pwolanin commentedGreat work by yesCT fixing up the CR and opening follow-up issues. I think may be ready to called this fixed assuming the CR update is all that remained?
I fixed "three possibilities" -> "four possibilities"
For JS turns out we already have #2570101: Remove !placeholder support from Drupal.formatString
Comment #90
corbacho commentedGreat!
I replaced the JavaScript example to use Drupal.checkPlain() in the CR, I find it more suitable.
Comment #92
pwolanin commentedHa, the bot chokes on the patch already being applied. Let's call this fixed then?
Comment #93
yesct commentedthanks!
https://www.drupal.org/node/2296163/revisions/view/8950449/8950977 is my best guess right now at addressing 6.
(note, bot is setting to needs work, cause it is trying to apply the patch that was already committed. not sure how to trick it. maybe an empty patch file?) [edit: cross post]
Comment #94
dawehnerThanks a lot yesct!
Comment #95
novitsh commentedGood enough for me to have this fixed. Who can update https://api.drupal.org/api/drupal/core!lib!Drupal!Component!Utility!Safe... pages ?
Comment #96
chx commented@Novitsh, you need to file core patches for that.