-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
html/template: allow actions in JS template literals #61619
Comments
I would prefer this proposal, if it's feasible. :) I haven't tried them yet, but the three workarounds that have come up for multiline strings appear to be:
But this gets trickier (1) if you want to handle single and double quotes, (2) if you want to preserve newlines in JavaScript, I think you need add them to the string:
Regardless, I really appreciate the work and time on this issue. I use Go's templates because I much prefer them to JavaScript, trying to use the latter only when necessary. |
This proposal has been added to the active column of the proposals project |
This proposal has been added to the active column of the proposals project |
As long as we can do this securely, this sounds like a win for everyone. |
Based on the discussion above, this proposal seems like a likely accept. |
No change in consensus, so accepted. 🎉 |
Change https://go.dev/cl/507995 mentions this issue: |
Change https://go.dev/cl/532595 mentions this issue: |
The change that keeps on giving. Only track brace depth in tJS if we are already inside of a template literal. If we start tracking depth outside of nested literals it can cause the parser to think we're still in a JS context when we've actually closed the string interp. I believe this _mostly_ captures the expected parsing, but since the JS parser does not implement proper lexical goal symbols, it may not be entirely accurate. At some point in the future we may be able to significantly reduce the complexity of this implementation by implementing a lexical parser that more closely follows the ECMAScript specification, and structuring escaping rules based on which symbol an action appears in. This would also allow us to catch errors, which we currently cannot reasonable do (although perhaps this is beyond the scope of what html/template _should_ be doing). Updates #61619 Change-Id: I56e1dbc0d0705ef8fb7a5454ebe2421d4e162ef6 Reviewed-on: https://go-review.googlesource.com/c/go/+/532595 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]>
@rolandshoemaker sorry for not getting to this sooner; I've been on PTO. The current (already merged) implementation is broken and escaping fails in this template: <script>var foo = `${ foo({ a: { c: `${ {{.}} }` }, b: {{.}} })}`</script> The new change at https://go.dev/cl/532595 doesn't seem to fix this either even though it does fiddle with the brace depth logic. The problem is that brace depth gets reset to 0 in places where there's nesting, and that breaks brace depth tracking for the outer JS template literals. |
Oh bah, you are correct, I thought I'd fixed this based on a particular case I was fixating on, but I realize now we actually need to track brace depth per-nesting level in order to properly address this. |
Change https://go.dev/cl/532995 mentions this issue: |
@jupenur I think http://go.dev/cl/532995 captures the correct behavior now, but each time I do this I'm less and less convinced I've gotten it right (which, given this is the... third(?) attempt at it, I've not got great odds). Enumerating all of the cases here is painful. |
We need to track the brace depth for each individual nested expression, since a string interpolation expression may be nested inside of an object. e.g. `${ {1:`${}`}}` has brace depths [1, 0] when inside of the inner ${} expression. When we exit the inner expression, we need to reset to the previous brace depth (1) so that we know that the following } closes the object, but not the outer expression. Note that if you write a broken expression (i.e. `${ { }`) escaping will clearly not work as expected (or depending on your interpretation, since it is broken, it will work as expected). Since the JS parser doesn't catch syntax errors, it's up to the user to write a valid template. Updates #61619 Change-Id: I4c33723d12aff49facdcb1134d9ca82b7a0dffc4 Reviewed-on: https://go-review.googlesource.com/c/go/+/532995 Reviewed-by: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
We need to track the brace depth for each individual nested expression, since a string interpolation expression may be nested inside of an object. e.g. `${ {1:`${}`}}` has brace depths [1, 0] when inside of the inner ${} expression. When we exit the inner expression, we need to reset to the previous brace depth (1) so that we know that the following } closes the object, but not the outer expression. Note that if you write a broken expression (i.e. `${ { }`) escaping will clearly not work as expected (or depending on your interpretation, since it is broken, it will work as expected). Since the JS parser doesn't catch syntax errors, it's up to the user to write a valid template. Updates golang#61619 Change-Id: I4c33723d12aff49facdcb1134d9ca82b7a0dffc4 Reviewed-on: https://go-review.googlesource.com/c/go/+/532995 Reviewed-by: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
This proposal is mutually exclusive with the already accepted proposal in #60055, but I believe is worth considering.
While prototyping the implementation for #60055 (see http://go.dev/cl/507995), we realized that it is actually not incredibly complicated to manage the state changes between template literals and nested string interpolation contexts (i.e.
`${ ... }`
) that would be necessary to allow us to safely support actions within JS template literals.There are a handful of seemingly valid use cases for template literals which the current behavior (disallowing actions within template literals) breaks, namely it prevents using an action to construct a multiline string. With proper handling of template literals, we are in the position to possibly allow actions within them safely.
In order to prevent an action switching the context, strings inserted into the template literal context would need to have the characters
$, {, }
escaped. Actions in the string interpolation context would be treated the same as actions in the top-level JS context.If accepted, the following templates would become acceptable (reverting the restrictions added in http://go.dev/cl/482079, and closing the existing loopholes).
This would revert the restrictions added in http://go.dev/cl/482079, and deprecate
ErrJSTemplate
(which is, unfortunately, slated to be added in 1.21).cc @golang/security @jupenur
The text was updated successfully, but these errors were encountered: