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

Automatic output escaping #500

Closed
floofnoodlecode opened this issue Apr 20, 2022 · 5 comments
Closed

Automatic output escaping #500

floofnoodlecode opened this issue Apr 20, 2022 · 5 comments

Comments

@floofnoodlecode
Copy link

Hello,

As far as I understand, there is no auto-escape mechanism built into liquidjs. Would it be possible to provide an option that would enable auto-escaping of any output rendered by {{ value }}?

My use case is that users will write .liquid templates for rendering HTML, JSON, etc. Requiring the users to make sure that every single output is escaped properly (e.g. {{ x | escape}} for HTML, or {{ x | json}} for JSON) is tedious and confusing.

Would you be willing to add an option that takes a function which will be applied on every output? (e.g. {autoEscape: (val: any) => any})

@harttle
Copy link
Owner

harttle commented Apr 21, 2022

Makes sense. This option makes templates safer.

github-actions bot pushed a commit that referenced this issue Apr 21, 2022
# [9.37.0](v9.36.2...v9.37.0) (2022-04-21)

### Bug Fixes

* support integer arithmetic for `divided_by`, closes [#465](#465) ([e69a510](e69a510))

### Features

* automatic output escaping, closes [#500](#500) ([f88490c](f88490c))
@github-actions
Copy link

🎉 This issue has been resolved in version 9.37.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@harttle
Copy link
Owner

harttle commented Apr 21, 2022

Now it's supported on v9.37.0. I created some test cases here:

describe('LiquidOptions#*outputEscape*', function () {
it('when outputEscape is not set', async function () {
const engine = new Liquid()
const html = await engine.parseAndRender('{{"<"}}')
expect(html).to.equal('<')
})
it('should escape when outputEscape="escape"', async function () {
const engine = new Liquid({
outputEscape: 'escape'
})
const html = await engine.parseAndRender('{{"<"}}')
expect(html).to.equal('&lt;')
})
it('should json stringify when outputEscape="json"', async function () {
const engine = new Liquid({
outputEscape: 'json'
})
const html = await engine.parseAndRender('{{"<"}}')
expect(html).to.equal('"<"')
})
it('should support outputEscape=Function', async function () {
const engine = new Liquid({
outputEscape: (v: any) => `{${v}}`
})
const html = await engine.parseAndRender('{{"<"}}')
expect(html).to.equal('{<}')
})
it('should skip escape for output with filter "| raw"', async function () {
const engine = new Liquid({
outputEscape: 'escape'
})
const html = await engine.parseAndRender('{{"<" | raw}}')
expect(html).to.equal('<')
})
})

And you may also need this raw filter now: https://liquidjs.com/filters/raw.html

@floofnoodlecode
Copy link
Author

This is such great news. Thank you very much.

This will be so much cleaner than my hack. I wasn't expecting you to add this feature so soon so I registered a tag that would add the "| escape" filter to all output tokens. 😂

By the way, one observation regarding the docs: https://liquidjs.com/tutorials/parse-parameters.html

The docs instruct to create a new tokenizer like so: const tokenizer = new Tokenizer(tagToken.args).
However, typescript complains that 2-3 args are needed. I saw that in your code you actually use this: const tokenizer = new Tokenizer(token.args, this.liquid.options.operatorsTrie)

harttle added a commit that referenced this issue Nov 18, 2022
BREAKING CHANGE: use `operators` instead of `operatorsTrie` as Tokenizer constructor argument, #500
harttle added a commit that referenced this issue Nov 27, 2022
BREAKING CHANGE: use `operators` instead of `operatorsTrie` as Tokenizer constructor argument, #500
github-actions bot pushed a commit that referenced this issue Nov 27, 2022
# [10.0.0](v9.43.0...v10.0.0) (2022-11-27)

### chore

* rename filters to snake style, [#487](#487) ([ff112a4](ff112a4))

### Code Refactoring

* `_evalToken` renamed to `evalToken` ([4e1a30a](4e1a30a))
* change `ownPropertyOnly` default value to `true` ([7eb6216](7eb6216))
* delay creation of `operatorsTrie` and hide this implementation ([bb58d3e](bb58d3e))
* remove `toThenable` export ([ffefd91](ffefd91))
* remove use of internal `Context` class in `evalValue` argument ([b115077](b115077))

### Performance Improvements

* target Node.js 14 for cjs bundle (main entry) ([1f6ce7c](1f6ce7c))

### BREAKING CHANGES

* `evalToken` now returns a generator (LiquidJS async), which is different from `evalToken` in previous LiquidJS versions.
* main entry need Node.js>=14 to run, you can build LiquidJS by your own by using ESM entry.
* `ownPropertyOnly` default value changed to `true`
* `<liquidjs>.toThenable` is removed, use `<liquidjs>.toPromise` instead
* `evalValue` won't support `Context` as second argument anymore.
* use `operators` instead of `operatorsTrie` as Tokenizer constructor argument, #500
* keys in `<liquidjs>.filters` are now in snake case (instead of camel case), identical to that in Liquid template.
@rauschma
Copy link

rauschma commented Jan 24, 2024

Another option would be to do what Handlebars does:

  • {{expression}} escapes expression before inserting it.
    • By default, escaping is for HTML, but users can provide their own escape function.
  • {{{expression}}} inserts unescaped/raw.

Source: https://handlebarsjs.com/guide/expressions.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants