Skip to content
Snippets Groups Projects
Commit 1435fe26 authored by Michael Anello's avatar Michael Anello
Browse files

Issue #3378216 by ultimike, lostcarpark, cindy_codediaries, pilot3, h_kac:...

Issue #3378216 by ultimike, lostcarpark, cindy_codediaries, pilot3, h_kac: Improve validation on text format configuration
parent 9d03f75e
No related branches found
No related tags found
1 merge request!2Issue #3378216: Improve validation on text format configuration
Pipeline #17608 passed
......@@ -30,11 +30,16 @@ the text format will allow all HTML tags.
- IMPORTANT - Enable and configure the "Convert line breaks into HTML" filter
to run after the Markdown Easy filter and the "Limit allowed HTML tags and
correct faulty HTML" filter.
- For best results, at a minimum, text formats utilizing the Markdown Easy filter should
be configured as follows:
- For best results, at a minimum, text formats utilizing the Markdown Easy
- filter should be configured as follows:
![Screenshot of the suggested filter order](https://www.drupal.org/files/markdown-easy-filter-order.png)
- Markdown Easy requires (via validation) that it be configured with both the
"Convert line breaks into HTML" and "Limit allowed HTML tags and correct faulty
HTML" filters enabled to run after Markdown Easy. This can be overridden (at
your peril) by removing the validation handler. See
tests/modules/markdown_easy_test/markdown_easy_test.module for an example.
## Additional information
- The Markdown Easy text filter is configured to run with the following
......
......@@ -11,7 +11,28 @@ use Drupal\Core\Form\FormStateInterface;
* Implements hook_form_FORM_ID_alter().
*/
function markdown_easy_form_filter_format_add_form_alter(array &$form, FormStateInterface $form_state): void {
$form['#validate'][] = '_markdown_easy_filter_format_edit_form_validate';
$form['actions']['submit']['#submit'][] = '_markdown_easy_filter_format_form_submit';
// Fixes issue related to https://www.drupal.org/project/markdown_easy/issues/3378216#comment-15209538
// Remove if/when https://www.drupal.org/project/drupal/issues/3383891 is
// fixed.
$input = $form_state->getUserInput();
if (isset($input['filters'])) {
// Copy submitted weights to filter order.
foreach ($form['filters']['order'] as $name => $item) {
if (isset($input['filters'][$name]['weight'])) {
$form['filters']['order'][$name]['#weight'] = intval($input['filters'][$name]['weight']);
}
}
// Sort filters by weight.
uasort($form['filters']['order'], function ($a, $b) {
if (is_array($a) && is_array($b) && isset($a['#weight']) && isset($b['#weight'])) {
return $a['#weight'] - $b['#weight'];
}
return 0;
});
}
}
/**
......@@ -21,6 +42,73 @@ function markdown_easy_form_filter_format_edit_form_alter(array &$form, FormStat
markdown_easy_form_filter_format_add_form_alter($form, $form_state);
}
/**
* Custom validate handler for filter format add/edit form.
*
* Ensures that Markdown Easy filter is run before the "Limit allowed HTML tags
* and correct faulty HTML" filter. Code based on
* media_filter_format_edit_form_validate().
*/
function _markdown_easy_filter_format_edit_form_validate(array $form, FormStateInterface $form_state): void {
if ($form_state->getTriggeringElement()['#name'] !== 'op') {
return;
}
$markdown_easy_enabled = $form_state->getValue([
'filters',
'markdown_easy',
'status',
]);
if (!((bool) $markdown_easy_enabled)) {
return;
}
$get_filter_label = function ($filter_plugin_id) use ($form) {
return (string) $form['filters']['order'][$filter_plugin_id]['filter']['#markup'];
};
$filters = $form_state->getValue('filters');
// The "markdown_easy" filter must run before the following filters.
$subsequents = [
'filter_html',
'filter_autop',
];
$error_filters = [];
foreach ($subsequents as $filter_name) {
// A filter that should run after the markdown_easy filter.
$subsequent = $filters[$filter_name];
if (!isset($subsequent['status']) || !((bool) $subsequent['status']) || !isset($subsequent['weight']) || ($subsequent['weight'] <= $filters['markdown_easy']['weight'])) {
$error_filters[$filter_name] = $get_filter_label($filter_name);
}
}
if ((bool) count($error_filters)) {
$error_message = \Drupal::translation()->formatPlural(
count($error_filters),
'The %markdown-easy-filter-label filter needs to be placed before the %filter filter.',
'The %markdown-easy-filter-label filter needs to be placed before the following filters: %filters.',
[
'%markdown-easy-filter-label' => $get_filter_label('markdown_easy'),
'%filter' => reset($error_filters),
'%filters' => implode(', ', $error_filters),
]
);
$form_state->setErrorByName('filters', $error_message);
}
// Check that "Convert line breaks" filter runs after "Limit HTML".
if ((bool) $filters['filter_html']['status'] && (bool) $filters['filter_autop']['status']) {
if ($filters['filter_html']['weight'] >= $filters['filter_autop']['weight']) {
$error_message = t('The "Convert line breaks into HTML (i.e. &lt;br&gt; and &lt;p&gt;)" filter must run after the "Limit allowed HTML tags and correct faulty HTML" filter in order for the Markdown Easy filter to work properly.');
$form_state->setErrorByName('filters', $error_message);
}
}
}
/**
* Custom submit handler for filter format add/edit form.
*
......@@ -32,7 +120,7 @@ function markdown_easy_form_filter_format_edit_form_alter(array &$form, FormStat
function _markdown_easy_filter_format_form_submit(array $form, FormStateInterface &$form_state): void {
$filters = $form_state->getValue('filters');
/** @var Drupal\markdown_easy\MarkdownUtility */
/** @var Drupal\markdown_easy\MarkdownUtility $markdown_easy_utility_service */
$markdown_easy_utility_service = \Drupal::service('markdown_easy.utility');
$weights = $markdown_easy_utility_service->getFilterWeights($filters);
......
name: 'Markdown easy test'
type: module
description: 'Used to test various API options of the Markdown Easy module.'
package: Custom
core_version_requirement: ^9 || ^10
dependencies:
- markdown_easy:markdown_easy
<?php
/**
* @file
* Primary module hooks for Markdown easy test module.
*/
use Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_form_FORM_ID_alter().
*/
function markdown_easy_test_form_filter_format_form_alter(array &$form, FormStateInterface $form_state, $form_id): void {
// Disable the markdown_easy validation to allow potentially insecure
// configurations.
$key = array_search('_markdown_easy_filter_format_edit_form_validate', $form['#validate']);
if ($key !== FALSE) {
unset($form['#validate'][$key]);
}
}
......@@ -41,6 +41,9 @@ class AddEditFormatTest extends BrowserTestBase {
* Test various warning messages on format page when using Markdown Easy.
*
* @test
*
* @throws \Behat\Mink\Exception\ExpectationException
* @throws \Behat\Mink\Exception\ResponseTextException
*/
public function testAddEditFormat(): void {
// Start the browsing session.
......@@ -50,47 +53,90 @@ class AddEditFormatTest extends BrowserTestBase {
$this->drupalGet('/admin/config/content/formats/add');
$session->statusCodeEquals(200);
// Populate the new text format form.
// Populate the new text format form (tests "add" mode).
$edit = [
'name' => 'Markdown Easy format page test',
'format' => 'markdown_easy_format_page_test',
'filters[markdown_easy][status]' => 1,
'filters[markdown_easy][settings][flavor]' => 'standard',
];
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('The Markdown Easy filter needs to be placed before the following filters: Limit allowed HTML tags and correct faulty HTML, Convert line breaks into HTML (i.e. <code>&lt;br&gt;</code> and <code>&lt;p&gt;</code>).');
// Resubmit the text format with additional filters enabled, but in a
// potentially insecure order.
$edit = [
'name' => 'Markdown Easy format page test',
'format' => 'markdown_easy_format_page_test',
'filters[markdown_easy][status]' => 1,
'filters[markdown_easy][weight]' => 30,
'filters[markdown_easy][settings][flavor]' => 'standard',
'filters[filter_html][status]' => 1,
'filters[filter_html][weight]' => 20,
'filters[filter_autop][status]' => 1,
'filters[filter_autop][weight]' => 10,
];
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('The Markdown Easy filter needs to be placed before the following filters: Limit allowed HTML tags and correct faulty HTML, Convert line breaks into HTML (i.e. <code>&lt;br&gt;</code> and <code>&lt;p&gt;</code>).');
// Resubmit the text format with filters in a proper order.
$edit = [
'name' => 'Markdown Easy format page test',
'format' => 'markdown_easy_format_page_test',
'filters[markdown_easy][status]' => 1,
'filters[markdown_easy][weight]' => 10,
'filters[markdown_easy][settings][flavor]' => 'standard',
'filters[filter_html][status]' => 1,
'filters[filter_html][weight]' => 20,
'filters[filter_autop][status]' => 1,
'filters[filter_autop][weight]' => 30,
];
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('Added text format Markdown Easy format page test.');
$session->pageTextContainsOnce('The text format Markdown Easy format page test is potentially configured insecurely. The "Limit allowed HTML tags and correct faulty HTML" filter is strongly recommended and should be configured to run after the Markdown Easy filter.');
$session->pageTextContainsOnce('The text format Markdown Easy format page test is potentially configured incorrectly. The "Convert line breaks into HTML" filter is recommended and should be configured to run after the Markdown Easy filter.');
// Navigate back to the edit text format page.
// Navigate back to the edit text format page (tests "edit" mode).
$this->drupalGet('/admin/config/content/formats/manage/markdown_easy_format_page_test');
$session->statusCodeEquals(200);
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('The text format Markdown Easy format page test has been updated.');
$session->pageTextContainsOnce('The text format Markdown Easy format page test is potentially configured insecurely. The "Limit allowed HTML tags and correct faulty HTML" filter is strongly recommended and should be configured to run after the Markdown Easy filter.');
$session->pageTextContainsOnce('The text format Markdown Easy format page test is potentially configured incorrectly. The "Convert line breaks into HTML" filter is recommended and should be configured to run after the Markdown Easy filter.');
// Navigate back to the edit text format page.
$this->drupalGet('/admin/config/content/formats/manage/markdown_easy_format_page_test');
// Resubmit the text format with additional filters enabled, but in a
// potentially insecure order.
$edit = [
'name' => 'Markdown Easy format page test',
'format' => 'markdown_easy_format_page_test',
'filters[markdown_easy][status]' => 1,
'filters[markdown_easy][weight]' => 30,
'filters[markdown_easy][settings][flavor]' => 'standard',
'filters[filter_html][status]' => 1,
'filters[filter_html][weight]' => 20,
'filters[filter_autop][status]' => 1,
'filters[filter_autop][weight]' => 10,
];
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('The Markdown Easy filter needs to be placed before the following filters: Limit allowed HTML tags and correct faulty HTML, Convert line breaks into HTML (i.e. <code>&lt;br&gt;</code> and <code>&lt;p&gt;</code>).');
// Resubmit the text format with "Limit HTML" and "Convert line breaks" in
// the wrong order.
$edit = [
'name' => 'Markdown Easy format page test',
'format' => 'markdown_easy_format_page_test',
'filters[markdown_easy][status]' => 1,
'filters[markdown_easy][weight]' => 10,
'filters[markdown_easy][weight]' => 0,
'filters[markdown_easy][settings][flavor]' => 'standard',
'filters[filter_html][status]' => 1,
'filters[filter_html][weight]' => 20,
'filters[filter_autop][status]' => 1,
'filters[filter_autop][weight]' => 30,
'filters[filter_autop][weight]' => 10,
];
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('The text format Markdown Easy format page test has been updated.');
$session->pageTextNotContains('The text format Markdown Easy format page test is potentially configured insecurely. The "Limit allowed HTML tags and correct faulty HTML" filter is strongly recommended and should be configured to run after the Markdown Easy filter.');
$session->pageTextNotContains('The text format Markdown Easy format page test is potentially configured incorrectly. The "Convert line breaks into HTML" filter is recommended and should be configured to run after the Markdown Easy filter.');
$session->pageTextContainsOnce('The "Convert line breaks into HTML (i.e. <br> and <p>)" filter must run after the "Limit allowed HTML tags and correct faulty HTML" filter in order for the Markdown Easy filter to work properly.');
}
}
<?php
namespace Drupal\Tests\markdown_easy\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Test warnings when adding/editing a text format with no validation.
*
* @group markdown_easy
*/
class AddEditInsecureFormatTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = [
'markdown_easy_test',
'node',
'field',
'filter',
'text',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->drupalLogin($this->rootUser);
}
/**
* Test various warning messages on format page when using Markdown Easy.
*
* @test
*/
public function testAddEditFormat(): void {
// Start the browsing session.
$session = $this->assertSession();
// Navigate to the add text format page.
$this->drupalGet('/admin/config/content/formats/add');
$session->statusCodeEquals(200);
// Populate the new text format form.
$edit = [
'name' => 'Markdown Easy format page test',
'format' => 'markdown_easy_format_page_test',
'filters[markdown_easy][status]' => 1,
'filters[markdown_easy][settings][flavor]' => 'standard',
];
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('Added text format Markdown Easy format page test.');
$session->pageTextContainsOnce('The text format Markdown Easy format page test is potentially configured insecurely. The "Limit allowed HTML tags and correct faulty HTML" filter is strongly recommended and should be configured to run after the Markdown Easy filter.');
$session->pageTextContainsOnce('The text format Markdown Easy format page test is potentially configured incorrectly. The "Convert line breaks into HTML" filter is recommended and should be configured to run after the Markdown Easy filter.');
// Navigate back to the edit text format page.
$this->drupalGet('/admin/config/content/formats/manage/markdown_easy_format_page_test');
$session->statusCodeEquals(200);
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('The text format Markdown Easy format page test has been updated.');
$session->pageTextContainsOnce('The text format Markdown Easy format page test is potentially configured insecurely. The "Limit allowed HTML tags and correct faulty HTML" filter is strongly recommended and should be configured to run after the Markdown Easy filter.');
$session->pageTextContainsOnce('The text format Markdown Easy format page test is potentially configured incorrectly. The "Convert line breaks into HTML" filter is recommended and should be configured to run after the Markdown Easy filter.');
// Navigate back to the edit text format page.
$this->drupalGet('/admin/config/content/formats/manage/markdown_easy_format_page_test');
$session->statusCodeEquals(200);
$edit = [
'name' => 'Markdown Easy format page test',
'format' => 'markdown_easy_format_page_test',
'filters[markdown_easy][status]' => 1,
'filters[markdown_easy][weight]' => 10,
'filters[markdown_easy][settings][flavor]' => 'standard',
'filters[filter_html][status]' => 1,
'filters[filter_html][weight]' => 20,
'filters[filter_autop][status]' => 1,
'filters[filter_autop][weight]' => 30,
];
$this->submitForm($edit, 'Save configuration');
$session->statusCodeEquals(200);
$session->pageTextContainsOnce('The text format Markdown Easy format page test has been updated.');
$session->pageTextNotContains('The text format Markdown Easy format page test is potentially configured insecurely. The "Limit allowed HTML tags and correct faulty HTML" filter is strongly recommended and should be configured to run after the Markdown Easy filter.');
$session->pageTextNotContains('The text format Markdown Easy format page test is potentially configured incorrectly. The "Convert line breaks into HTML" filter is recommended and should be configured to run after the Markdown Easy filter.');
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment