Implement safe filter as SafeString and handle SafeString in filters, functions and expressions#385
Conversation
| return null; | ||
| } | ||
|
|
||
| if (!(var instanceof String)) { |
There was a problem hiding this comment.
perhaps the friendlier thing to do here is just to return the passed in object
|
@jboulter Would you mind taking a look over my changes here |
| throw new InvalidInputException(interpreter, this, InvalidReason.NUMBER_FORMAT, object.toString()); | ||
| } | ||
| } | ||
| if (object instanceof SafeString) { |
There was a problem hiding this comment.
Perhaps you could use a Delegate pattern here and implement SafeStringFilter which takes care of this rather than manually checking for SafeStrings in every filter?
You could have the default interface implement filter, then delegate to a safeFilter method in each of these classes, unwrapping and wrapping the SafeString around it.
| public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { | ||
| return StringUtils.trim(Objects.toString(var)); | ||
| if (var instanceof String) { | ||
| return safeFilter(StringUtils.trim(var.toString()), interpreter, args); |
There was a problem hiding this comment.
Should this be return StringUtils.trim(Objects.toString(var)); instead?
There was a problem hiding this comment.
Why? If we know its a string, whats the need to wrap it in the call. We know we can cast or do .toString
|
@boulter This is ready for review again. Sorry about the formatting changes but there was a lot of inconsistencies between the filters. My general approach here was to handle For the output, if a filter takes a SafeString and manipulates it eg. replace it should return a safe string. There is an extra case here is |
| String input = Objects.toString(objectToFilter, ""); | ||
| LengthLimitingStringBuilder builder = new LengthLimitingStringBuilder(jinjavaInterpreter.getConfig().getMaxOutputSize()); | ||
| if (objectToFilter instanceof String) { | ||
| String input = Objects.toString(objectToFilter, ""); |
| @@ -1,17 +1,17 @@ | |||
| /********************************************************************** | |||
| Copyright (c) 2014 HubSpot Inc. | |||
| Copyright (c) 2014 HubSpot Inc. | |||
There was a problem hiding this comment.
in general, it's nice to separate formatting changes like this out into a separate PR so make your PRs clean and easy to understand.
| @@ -0,0 +1,19 @@ | |||
| package com.hubspot.jinjava.objects; | |||
|
|
|||
| public class SafeString { | |||
There was a problem hiding this comment.
could you have this extend String? That might simplify all your instanceof checks.
There was a problem hiding this comment.
I wish! Unfortunately String is final so we can't. String with an extra property would have made this a lot more simple. I think if we were designing this from scratch we wouldn't use strings anywhere and instead always pass some sort of StringToken that could be safe/not safe and have some other properties.
| return calculateBigRoot(interpreter, new BigDecimal((BigInteger) object), root); | ||
| } | ||
| if (object instanceof String) { | ||
| if (object instanceof String || object instanceof SafeString) { |
There was a problem hiding this comment.
nit: extra space after object
| this.value = value; | ||
| } | ||
|
|
||
| public String getValue() { |
There was a problem hiding this comment.
Yes its needed to resolve the token to a string when rendering
There was a problem hiding this comment.
Never-mind. Its actually not. I got mixed up with tokens.
* First draft of deferring from tag including macros * Checkstyle * Add more tests * Remove incorrect assert * Add test that checks deferring macros in depth and update DeferredValue & MacroFunction * Checkstyle * Make constructor private and overload instance method * Fixes #159: Adds dict support for DefaultFilter * removes undesired code from Filter.java * removes whitespaces from DateTimeFormatFilter.java * Fixes Style Check Errors * Removes stringArgs from DateTimeFormatFilter * Revert "Fixes #159: Adds dict support for DefaultFilter" * Changes DefaultFilter to extend AdvancedFilter * adds PyList support to ForTag * adds tests for ForTag * removes escape filter from fortag test * Fix resoncstruct end to honor trim tags * Add reconstructImage to MacroFunction * Add test for reconstructing macro with no trim tags * Whitespace fix * Implement safe filter as SafeString and handle SafeString in filters, functions and expressions (#385) * Start implementing safe filter * Remove comment about pass-through implementation * Return var if it's not instance of string instead of throwing * Add test for pass-through * Add support for SafeString to all filters which handle Strings * Remove utils for string reverse filter * Handle SafeString in truncate function * Formatting fix * Add SafeStringFilter interface * Handle safe strings in filters * rm trailing space * Formatting fixes * Move safeFilter method to Filter IF and remove SafeFilter IF * rm space * Change behaviour of Urlize filter to not always return a SafeString * Code style changes * Remove unnecessary call to safeString * Style fix * Add tests to handle Urlize string being escaped and made safe * rm hardcoded string * rm uneeded getValue * Add SafeString type as str * Handle SafeString in expressions Co-authored-by: Joe <Joeoh@users.noreply.github.com> * Fix template error line numbers (#380) * Fix line numbers * add to some more places * two levels deep test * Fix case with child interpreter * Add deprecation * Add another test * Update error messages * Fix up error messages and tests * Fix case with scopes * Add check for inherit * Put everything on the path stack * always push parent * remove callstack crud * Set back path management * Fix extend lineNo/position and keep track for each block * cleanup * Add test for extends * Add more tests * Check parent call stack for emtpy and line numbers * Fix test * Reorient line numbers when evaluating macros, make sure to pop import path off of stack * Add test for imported macros * Reorient line numbers when resolving blocks * Reorient line numbers when processing extend parents * Add tests for extends + includes * Revert "Implement safe filter as SafeString and handle SafeString in filters, functions and expressions (#385)" This reverts commit a6bea47. * Implement safe filter as SafeString and handle SafeString in filters, functions and expressions (#394) * Start implementing safe filter * Remove comment about pass-through implementation * Return var if it's not instance of string instead of throwing * Add test for pass-through * Handle safestrings and call implementor * Add tests * Handle SafeString in filter using kwargs * Handle safe strings in most simple expressions * Handle SafeString in IsUpperExp * Handle SafeString in filters. Allow overriding from within filter * Formatting fixes Co-authored-by: jkollmann <48923512+jkollmann@users.noreply.github.com> * First draft of deferring from tag including macros * Checkstyle * Add more tests * Remove incorrect assert * Add test that checks deferring macros in depth and update DeferredValue & MacroFunction * Checkstyle * Make constructor private and overload instance method * Fix resoncstruct end to honor trim tags * Add reconstructImage to MacroFunction * Add test for reconstructing macro with no trim tags * Whitespace fix * rm duplicate statement after merge Co-authored-by: Manish Devgan <manish.nsit8@gmail.com> Co-authored-by: Jeff Boulter <jeff@boulter.com> Co-authored-by: Joe <Joeoh@users.noreply.github.com> Co-authored-by: Matt Coley <matthewjcoley@gmail.com>
Safe filter:
Documentation
Jinja docs: http://jinja.palletsprojects.com/en/2.10.x/templates/#working-with-automatic-escaping
Approach:
Wrap String with new class
SafeStringwhen the|safefilter is applied to the value. This way we can check the type inExpressionNodeand not escape it. I overwrotetoStringto make it work as expected here:jinjava/src/main/java/com/hubspot/jinjava/tree/ExpressionNode.java
Line 52 in 1667977
Considerations:
Since I introduce a new type here we might need to add some implementation for this in
ExpressionResolverorJinjavaInterpreterResolver. The implementation is currently only tested with|safebeing used at the end of an expression.