From a154fe871ecde437e50574929514005372ed936e Mon Sep 17 00:00:00 2001
From: quietone <quietone@2572884.no-reply.drupal.org>
Date: Mon, 28 Aug 2023 21:14:08 +1200
Subject: [PATCH] Issue #2944421 by sathish.redcrackle, ressa, Lendude,
 ankithashetty, udayraj123, smustgrave, DuaelFr, JeroenT, alexpott: Double
 exposed filter field when trying to use "q" as identifier

---
 .../Plugin/views/filter/FilterPluginBase.php  | 28 +++++++++++++---
 .../src/Functional/Plugin/ExposedFormTest.php | 32 +++++++++++++++++++
 2 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index f8d03e12b72c..c0fcde77ea36 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -46,6 +46,23 @@
  */
 abstract class FilterPluginBase extends HandlerBase implements CacheableDependencyInterface {
 
+  /**
+   * A list of restricted identifiers.
+   *
+   * This list contains strings that could cause clashes with other site
+   * operations when used as a filter identifier.
+   *
+   * @var array
+   */
+  const RESTRICTED_IDENTIFIERS = [
+    'value',
+    'q',
+    'destination',
+    '_format',
+    '_wrapper_format',
+    'token',
+  ];
+
   /**
    * The value.
    *
@@ -660,7 +677,8 @@ public function buildExposeForm(&$form, FormStateInterface $form_state) {
       '#default_value' => $this->options['expose']['identifier'],
       '#title' => $this->t('Filter identifier'),
       '#size' => 40,
-      '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank. Only letters, digits and the dot ("."), hyphen ("-"), underscore ("_"), and tilde ("~") characters are allowed.'),
+      '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank. Only letters, digits and the dot ("."), hyphen ("-"), underscore ("_"), and tilde ("~") characters are allowed. @reserved_identifiers are reserved words and cannot be used.',
+        ['@reserved_identifiers' => '"' . implode('", "', self::RESTRICTED_IDENTIFIERS) . '"']),
     ];
   }
 
@@ -771,7 +789,7 @@ protected function validateIdentifier($identifier, FormStateInterface $form_stat
     if (empty($identifier)) {
       $error = $this->t('The identifier is required if the filter is exposed.');
     }
-    elseif ($identifier == 'value') {
+    elseif (in_array($identifier, self::RESTRICTED_IDENTIFIERS)) {
       $error = $this->t('This identifier is not allowed.');
     }
     elseif (preg_match('/[^a-zA-Z0-9_~\.\-]+/', $identifier)) {
@@ -1029,7 +1047,8 @@ protected function buildExposedFiltersGroupForm(&$form, FormStateInterface $form
       '#default_value' => $identifier,
       '#title' => $this->t('Filter identifier'),
       '#size' => 40,
-      '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank. Only letters, digits and the dot ("."), hyphen ("-"), underscore ("_"), and tilde ("~") characters are allowed.'),
+      '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank. Only letters, digits and the dot ("."), hyphen ("-"), underscore ("_"), and tilde ("~") characters are allowed. @reserved_identifiers are reserved words and cannot be used.',
+        ['@reserved_identifiers' => '"' . implode('", "', self::RESTRICTED_IDENTIFIERS) . '"']),
     ];
     $form['group_info']['label'] = [
       '#type' => 'textfield',
@@ -1083,7 +1102,8 @@ protected function buildExposedFiltersGroupForm(&$form, FormStateInterface $form
       '#default_value' => $identifier,
       '#title' => $this->t('Filter identifier'),
       '#size' => 40,
-      '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank. Only letters, digits and the dot ("."), hyphen ("-"), underscore ("_"), and tilde ("~") characters are allowed.'),
+      '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank. Only letters, digits and the dot ("."), hyphen ("-"), underscore ("_"), and tilde ("~") characters are allowed. @reserved_identifiers are reserved words and cannot be used.',
+        ['@reserved_identifiers' => '"' . implode('", "', self::RESTRICTED_IDENTIFIERS) . '"']),
     ];
     $form['group_info']['label'] = [
       '#type' => 'textfield',
diff --git a/core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php b/core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php
index 4f6dd5b84460..99bfb6baabf5 100644
--- a/core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php
+++ b/core/modules/views/tests/src/Functional/Plugin/ExposedFormTest.php
@@ -9,6 +9,7 @@
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
 use Drupal\views\Entity\View;
+use Drupal\views\Plugin\views\filter\FilterPluginBase;
 
 /**
  * Tests exposed forms functionality.
@@ -161,6 +162,37 @@ public function testExposedIdentifier() {
       'page_1' => ['This identifier has illegal characters.'],
     ];
     $this->assertEquals($expected, $errors);
+
+    foreach (FilterPluginBase::RESTRICTED_IDENTIFIERS as $restricted_identifier) {
+      $view = Views::getView('test_exposed_form_buttons');
+      $view->setDisplay();
+      $view->displayHandlers->get('default')->overrideOption('filters', [
+        'type' => [
+          'exposed' => TRUE,
+          'field' => 'type',
+          'id' => 'type',
+          'table' => 'node_field_data',
+          'plugin_id' => 'in_operator',
+          'entity_type' => 'node',
+          'entity_field' => 'type',
+          'expose' => [
+            'identifier' => $restricted_identifier,
+            'label' => 'Content: Type',
+            'operator_id' => 'type_op',
+            'reduce' => FALSE,
+            'description' => 'Exposed overridden description',
+          ],
+        ],
+      ]);
+      $this->executeView($view);
+
+      $errors = $view->validate();
+      $expected = [
+        'default' => ['This identifier is not allowed.'],
+        'page_1' => ['This identifier is not allowed.'],
+      ];
+      $this->assertEquals($expected, $errors);
+    }
   }
 
   /**
-- 
GitLab