This bug was discovered by @Mark LaCroix in #2555973: Fatal error when editing content after disabling format with editor.

Problem/Motivation

When you disable a filter format, at admin/config/content/formats/manage/{format}/disable, it asks you for a confirmation, stating:

Disabled text formats are completely removed from the administrative interface, and any content stored with that format will not be displayed

This is not true. In fact the value of a field, formatted with this format, is still displayed in node view (as an example) and processed with the disabled format.

Proposed resolution

Fix the bug.

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

None.

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because introduces a regression.
Issue priority Critical because the content can be displayed to the user without being sanitized with an enabled filter format. A site builder might disable a format for security reasons but the content is still processed and displayed with that format.
Disruption No disruption.

Comments

claudiu.cristea created an issue. See original summary.

claudiu.cristea’s picture

Status: Active » Needs review
StatusFileSize
new4.38 KB

Let's see this.

claudiu.cristea’s picture

StatusFileSize
new773 bytes

Forgot the interdiff.

claudiu.cristea’s picture

StatusFileSize
new3.63 KB

The "test only" patch.

xjm’s picture

Issue tags: +Security
alexpott’s picture

Status: Needs review » Needs work

Nice find. And the test and fix is looking good.

+++ b/core/modules/filter/src/Element/ProcessedText.php
@@ -80,7 +80,7 @@ public static function preRenderText($element) {
       static::logger('filter')->alert('Missing text format: %format.', array('%format' => $format_id));

If it disabled it is not "missing".

The last submitted patch, 4: 2556617-4-test-only.patch, failed testing.

claudiu.cristea’s picture

Status: Needs work » Needs review
StatusFileSize
new4.8 KB
new1.8 KB

@alexpott, yes I noticed that but because of UI of formats, this is a little bit confusing for users because they cannot see disabled formats. For them "disabled" looks like "removed". But this is tackled in #2502637: Disabled text formats can't be seen in the GUI.

Added different message templates.

PS: IMO, that message doesn't help too much the site builder. There's no call-to-action there.

claudiu.cristea’s picture

A side note: Right now we set the $element['#markup'] to an empty string for such cases. That means the field surrounding markup (divs, etc.) is still outputted. And I think this is not OK. The correct way would be to set $element['#access'] = FALSE; but I think this is too late in this stage because the access check occurred in an early stage.

Status: Needs review » Needs work

The last submitted patch, 8: regression-2556617-8.patch, failed testing.

claudiu.cristea’s picture

Issue summary: View changes

Beta evaluation.

claudiu.cristea’s picture

Status: Needs work » Needs review
StatusFileSize
new4.81 KB
new1.02 KB

Ouch!

tim.plunkett’s picture

+++ b/core/modules/filter/src/Element/ProcessedText.php
@@ -78,10 +78,13 @@ public static function preRenderText($element) {
+      $message = !$format ? 'Missing text format: %format.' : 'Disabled text format: %format.';

If we're going to make this distinction, we should test it.

tim.plunkett’s picture

Issue tags: +Needs tests
StatusFileSize
new1.33 KB
new5.37 KB
+++ b/core/modules/filter/src/Element/ProcessedText.php
@@ -78,10 +78,13 @@ public static function preRenderText($element) {
+    if (!$format || !$format->get('status')) {

We have $format->status() available to us.

However, this doesn't take the fallback filter into account. Sure, in theory it can't be disabled, but still.

Thirdly, we have $format->access('use'), which for some reason does not check status.

We should get this right, this should never have been a bug.

---

Maybe something like this? Not sure how/if to fix FilterFormatAccessControlHandler.

claudiu.cristea’s picture

Issue tags: -Needs tests
StatusFileSize
new5.8 KB
new1.85 KB

Maybe something like this? Not sure how/if to fix FilterFormatAccessControlHandler.

@tim.plunkett, maybe we need to open a followup for that?

dawehner’s picture

+++ b/core/modules/filter/src/Entity/FilterFormat.php
@@ -150,6 +150,13 @@ public function filters($instance_id = NULL) {
+    return parent::status() || $this->isFallbackFormat();

We should explain this particular line with a comment.

alexpott’s picture

+++ b/core/modules/filter/src/Entity/FilterFormat.php
@@ -150,6 +150,13 @@ public function filters($instance_id = NULL) {
   /**
    * {@inheritdoc}
    */
+  public function status() {
+    return parent::status() || $this->isFallbackFormat();
+  }

Would it not be better to throw an exception in the disable() method if someone tries to disable the fallback format?

claudiu.cristea’s picture

@alexpott, I would do that inside ::disable() and keep the parent ::status().

EDIT: Ah, it's the same you proposed, sorry :)

alexpott’s picture

@claudiu.cristea yep and then there is no need to override status in FilterFormat

claudiu.cristea’s picture

StatusFileSize
new6.01 KB
new2.73 KB

@dawehner, @alexpott, moved the fallback issue in ::disable() as exception throwing.

@tim.plunkett,

Thirdly, we have $format->access('use'), which for some reason does not check status.

Researching this and found that it doesn't work. The 'use' access check is not for showing content to the end-users but to access that text format as a content editor. And here the case is that we have to decide to render content. So, it's a no.

claudiu.cristea’s picture

StatusFileSize
new1.39 KB

Added test coverage for disable() exception.

claudiu.cristea’s picture

StatusFileSize
new7.4 KB

Status: Needs review » Needs work

The last submitted patch, 22: regression-2556617-21.patch, failed testing.

claudiu.cristea’s picture

Status: Needs work » Needs review
StatusFileSize
new7.4 KB

I canceled the test because I forgot a sprintf() function inside. See the last interdiff — that is valid except I removed the useless function.

claudiu.cristea’s picture

StatusFileSize
new7.39 KB
new753 bytes

Fixing message. Thanks @stefan.r

alexpott’s picture

Status: Needs review » Needs work
+++ b/core/modules/filter/src/Tests/FilterCrudTest.php
@@ -74,6 +75,23 @@ function testTextFormatCrud() {
+      if ($e->getMessage() == "The fallback text format 'plain_text' cannot be disabled.") {
+        $this->pass($message);
+      }

This should just do an assertion against the message... doing an if means that a LogicException with a different message would produce a false positive.

claudiu.cristea’s picture

Status: Needs work » Needs review
StatusFileSize
new1.03 KB
new7.37 KB

Yep, forgot how to catch the exact exception.

geertvd’s picture

Status: Needs review » Needs work
+++ b/core/modules/filter/src/Element/ProcessedText.php
@@ -78,10 +78,13 @@ public static function preRenderText($element) {
+      $message = !$format ? 'Missing text format: %format.' : 'Disabled text format: %format.';

We still don't test the 'Missing text format' message. Shouldn't we?

geertvd’s picture

Status: Needs work » Needs review
StatusFileSize
new1.09 KB
new6.94 KB

Something like this maybe?

Status: Needs review » Needs work

The last submitted patch, 29: 2556617-29.patch, failed testing.

geertvd queued 27: 2556617-27.patch for re-testing.

claudiu.cristea’s picture

@geertvd, it's not in the scope of this issue. Let's not mess this issue with off-topic tests.

claudiu.cristea’s picture

Status: Needs work » Needs review
geertvd’s picture

@claudiu.cristea, sorry patch in #29 is missing the FilterStatic.php file, #27 should probably be re-uploaded then

claudiu.cristea’s picture

Patch for review is #27. Hiding others.

wim leers’s picture

Status: Needs review » Needs work

The actual changes look good, but the tests need a bit of work:

  1. +++ b/core/modules/filter/src/Element/ProcessedText.php
    @@ -78,10 +78,13 @@ public static function preRenderText($element) {
    +    // If the requested text format doesn't exist or it's disabled, the text
    

    Nit: s/it's/is/

  2. +++ b/core/modules/filter/src/Tests/FilterAdminTest.php
    @@ -386,4 +390,60 @@ function testFilterTipHtmlEscape() {
    +   * Tests whether a field having a disabled format is rendered.
    

    Nit: s/having/using/

  3. +++ b/core/modules/filter/src/Tests/FilterAdminTest.php
    @@ -386,4 +390,60 @@ function testFilterTipHtmlEscape() {
    +    // We test the interface as anonymous user.
    

    Why?

    And if we indeed want to keep this: s/as/as the/

  4. +++ b/core/modules/filter/src/Tests/FilterAdminTest.php
    @@ -386,4 +390,60 @@ function testFilterTipHtmlEscape() {
    +    // Create a new format and add a filter that replaces the text with a static
    +    // text every time.
    

    The wording here feels a bit off. What about: Create a text format with a filter that returns a static string.

  5. +++ b/core/modules/filter/src/Tests/FilterAdminTest.php
    @@ -386,4 +390,60 @@ function testFilterTipHtmlEscape() {
    +    /** @var \Drupal\filter\FilterFormatInterface $format */
    

    Unnecessary, can be deleted.

  6. +++ b/core/modules/filter/src/Tests/FilterAdminTest.php
    @@ -386,4 +390,60 @@ function testFilterTipHtmlEscape() {
    +    $format->save();
    +    $format->setFilterConfig('filter_static_text', ['status' => TRUE]);
    +    $format->save();
    

    This first $format->save() can be removed.

  7. +++ b/core/modules/filter/src/Tests/FilterAdminTest.php
    @@ -386,4 +390,60 @@ function testFilterTipHtmlEscape() {
    +    $body_value = 'body text &<';
    ...
    +    $this->assertNoRaw($body_value);
    +    $this->assertNoEscaped($body_value);
    

    Why this very special string if we are merely asserting the absence? Seems like it could simply be $body_value = $this->randomName().

  8. +++ b/core/modules/filter/tests/filter_test_plugin/src/Plugin/Filter/FilterStatic.php
    @@ -0,0 +1,33 @@
    +class FilterStatic extends FilterBase {
    

    s/FilterStatic/FilterTestStatic/

    (All other test-only filters are named FilterTestSOMETHING.)

    Also, why isn't FilterTestReplace already sufficient for the needs of the tests added in this patch?

dawehner’s picture

Looking into it.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new7.88 KB
new5.09 KB

Why?

And if we indeed want to keep this: s/as/as the/

The test passed, so I just removed it.

Why this very special string if we are merely asserting the absence? Seems like it could simply be $body_value = $this->randomName().

Yeah we add both & and < in the random string code.

Also, why isn't FilterTestReplace already sufficient for the needs of the tests added in this patch?

Well, the other one seems to do more, and we want to stay explicit here ...

wim leers’s picture

Status: Needs review » Reviewed & tested by the community
  1. +++ b/core/modules/filter/src/Entity/FilterFormat.php
    @@ -180,9 +180,10 @@ public function toArray() {
    -      throw new \LogicException(sprintf("The fallback text format '%s' cannot be disabled.", $this->id()));
    +      throw new \LogicException("The fallback text format '{$this->id()}' cannot be disabled.");
    

    Good call!

  2. +++ b/core/modules/filter/src/Tests/FilterAdminTest.php
    @@ -418,20 +412,20 @@ public function testDisabledFormat() {
    -    $this->drupalGet('node/' . $node->id());
    +    $this->drupalGet($node->urlInfo());
    

    Again good call :)

  3. +++ b/core/modules/filter/src/Entity/FilterFormat.php
    @@ -180,6 +180,12 @@ public function toArray() {
    +    // The fallback text format cannot be disabled, as we always have to be able
    +    // to run it, in case a different format is disabled.
    

    This could be improved by a native speaker on commit.

  4. +++ b/core/modules/filter/tests/filter_test_plugin/src/Plugin/Filter/FilterTestStatic.php
    @@ -0,0 +1,33 @@
    + * Provides a filter that returns the same static text, regardless of what input
    + * text he receives.
    

    I think the "regardless of what input text he receives" can simply be omitted. Can be fixed on commit.

wim leers’s picture

StatusFileSize
new7.69 KB
new1.48 KB

I quickly fixed #39.3 and 4 myself. In fact, the entire comment mentioned in 3 can be deleted, "fallback format" already says plenty.

Keeping at RTBC because these are just minor comment changes.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed bb39343 and pushed to 8.0.x. Thanks!

  • alexpott committed bb39343 on 8.0.x
    Issue #2556617 by claudiu.cristea, dawehner, geertvd, Wim Leers, tim....

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.