Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Special characters in tags field saved escaped when selected using autocomplete #4043

Closed
silllli opened this issue Dec 14, 2021 · 8 comments · Fixed by #4624
Closed

Special characters in tags field saved escaped when selected using autocomplete #4043

silllli opened this issue Dec 14, 2021 · 8 comments · Fixed by #4624
Assignees
Labels
type: bug 🐛 Is a bug; fixes a bug type: regression 🚨 Is a regression between versions
Milestone

Comments

@silllli
Copy link
Contributor

silllli commented Dec 14, 2021

Description

I have a tags field that gets its options from a query:

fields:
  bikeManufacturer:
    type: tags
    max: 1
    options: query
    query: page.parent.childrenAndDrafts.pluck('bikeManufacturer', ',', true)
    required: true

When I save a tag featuring an ampersand (e. g. “Riese & Müller“) it gets saved correctly. But when I then go to a sibling page and select that same value from the autocomplete options, it’s getting saved and output as Riese & Müller.

Expected behavior
The value being saved just like the original.

To reproduce

  1. Create a blueprint using the YAML provided above.
  2. Add a page and save a value featuring an ampersand in the tags field.
  3. Create a second page and select the previously saved value from the autocomplete options.
  4. Create a third page and look at the provided autocomplete options or the value in the just saved txt file of the second page.

Your setup

Kirby Version

3.6.1.1

Console output

Your system (please complete the following information)

  • Device: MacBook Pro
  • OS: macOS 12.0.1
  • Browser: Google Chrome
  • Version: 96.0.4664.110

Maybe related to #4041.

@distantnative distantnative added the type: bug 🐛 Is a bug; fixes a bug label Dec 19, 2021
@silllli
Copy link
Contributor Author

silllli commented Dec 21, 2021

It also happens with select fields that access values of a structure field in their query.

@silllli
Copy link
Contributor Author

silllli commented Jan 11, 2022

Do you know when there will be a fix available? My client is filling their website with content and saving dozens of entries with wrong data. 🥴

@silllli
Copy link
Contributor Author

silllli commented Jan 18, 2022

This bug was introduced in version 3.6.0.

@lukasbestle lukasbestle added this to the 3.6.2 milestone Jan 23, 2022
@lukasbestle lukasbestle self-assigned this Jan 23, 2022
@lukasbestle lukasbestle removed this from the 3.6.2 milestone Jan 23, 2022
@lukasbestle
Copy link
Member

Issue summary

Status quo

This issue occurs because we use Str::safeTemplate() for both the display text and the value:

'text' => $this->template($alias, 'text', $data),
'value' => $this->template($alias, 'value', $data)
protected function template(string $object, string $field, array $data)
{
$value = $this->$field();
if (is_array($value) === true) {
if (isset($value[$object]) === false) {
throw new NotFoundException('Missing "' . $field . '" definition');
}
$value = $value[$object];
}
return Str::safeTemplate($value, $data);
}

Because the value is escaped, the stored value will also be escaped when the option is selected.

Rough solution draft

The issue can be solved by only using safeTemplate() for the text and template() for the value. Diff:

diff --git a/src/Form/OptionsQuery.php b/src/Form/OptionsQuery.php
index ba4660f7..be71cfb5 100644
--- a/src/Form/OptionsQuery.php
+++ b/src/Form/OptionsQuery.php
@@ -86,11 +86,10 @@ class OptionsQuery
     /**
      * @param string $object
      * @param string $field
-     * @param array $data
      * @return string
      * @throws \Kirby\Exception\NotFoundException
      */
-    protected function template(string $object, string $field, array $data)
+    protected function templateValue(string $object, string $field)
     {
         $value = $this->$field();

@@ -102,7 +101,7 @@ class OptionsQuery
             $value = $value[$object];
         }

-        return Str::safeTemplate($value, $data);
+        return $value;
     }

     /**
@@ -125,8 +124,8 @@ class OptionsQuery
             $data  = array_merge($data, [$alias => $item]);

             $options[] = [
-                'text'  => $this->template($alias, 'text', $data),
-                'value' => $this->template($alias, 'value', $data)
+                'text'  => Str::safeTemplate($this->templateValue($alias, 'text'), $data),
+                'value' => Str::template($this->templateValue($alias, 'value'), $data)
             ];
         }

This can be a possible temporary fix for you @silllli if you are not affected by the side effects below.

Side effects

  • This seems to break the select field for some reason. If an option with an escaped text is selected (= when text differs from value), the field is not considered valid and cannot be saved. That said, the select field display is currently broken as well because it does not use v-html for displaying the options, so the text is escaped twice.
  • The multiselect field displays both the text and the value in the dropdown (the value in parentheses). If we didn't escape the value in the backend, the field displays it unescaped (XSS attack vector!). So we also need to update the multiselect field to escape the value on display.

Summary

  • We need a refactoring of the Options classes that makes sure that all combinations of options fields and option settings (query, API, fixed list) work. It is not possible to fix this issue with an isolated change without breaking other option fields.
  • We need to ensure that all frontend components for all option fields consistently handle the text and value props, i.e. they should all escape the value on output for display but not the text.

@lukasbestle lukasbestle removed their assignment Jan 23, 2022
@lukasbestle lukasbestle added the type: regression 🚨 Is a regression between versions label Jan 23, 2022
@distantnative distantnative added this to the 3.6.3 milestone Jan 25, 2022
@distantnative distantnative self-assigned this Feb 3, 2022
@distantnative
Copy link
Member

distantnative commented Feb 3, 2022

@lukasbestle

the select field display is currently broken as well because it does not use v-html for displaying the options

We use the standard <option> tags which don't allow HTML inside - I don't really see a good forward that doesn't require to totally refactor the select input to something custom :/

Current state of refactoring the backend: develop...lab/nico/4043-options-escape

@lukasbestle
Copy link
Member

@distantnative

We use the standard <option> tags which don't allow HTML inside

Shouldn't the <option> just ignore the HTML though and render the text without formatting? Otherwise a simple solution could be to strip the HTML tags in the select field component before the text is printed to the <option>. In any case we must not double-escape here.

@iamwebrocker
Copy link

iamwebrocker commented Jul 18, 2022

Can confirm that this also exists in a 3.7 (3.7.0.1).
Just ran into this unexpected behavior on my site, which obviously if this exists since 3.6.x, I don't update too often, content-wise :-)
Since the content txt files may be used for other outlets, I think there shouldn't be an escaped char like "&amp;" for "&" in there, even if in my case I could fix my templates to work with the "&amp;"s instead.

@bastianallgeier
Copy link
Member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug 🐛 Is a bug; fixes a bug type: regression 🚨 Is a regression between versions
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants