hoplon

The :hoplon: ClojureScript Web Framework - http://hoplon.io/
dave 2020-04-10T12:15:26.057Z

has anyone experienced hoplon's prerendering turning < in inline scripts into <? i'm running into trouble with my app's content security policy because the prerender step is changing the content of an inline script that contains < so that it contains < instead

dave 2020-04-10T12:32:32.058100Z

which seems like a bug. the content of script tags should not be html-escaped

micha 2020-04-10T12:34:40.058900Z

the prerenderer specifically skips scripts

micha 2020-04-10T12:34:46.059200Z

in both the head and the body

dave 2020-04-10T12:34:51.059400Z

in this case, the scripts have :prerender-keep

micha 2020-04-10T12:35:46.060200Z

yeah but that code doesn't look like it knows about :prerender-keep

micha 2020-04-10T12:36:12.060600Z

it's suspicious that it broke all of a sudden

micha 2020-04-10T12:36:20.061100Z

in the middle of changing all the tooling

dave 2020-04-10T12:36:45.061600Z

i think it's been broken the whole time, we just didn't notice in this particular project because the existing scripts we had with :prerender-keep happened not to contain &, <, or >

dave 2020-04-10T12:36:56.061900Z

the new one we're adding wants to do a less-than comparison

micha 2020-04-10T12:37:11.062200Z

can you make a minimal repro case?

dave 2020-04-10T12:37:38.062600Z

to be clear, i've put the debooted branch aside

dave 2020-04-10T12:37:45.063Z

this is all using the existing boot pipeline for geir

micha 2020-04-10T12:37:47.063100Z

like a helloworld that exhibits the problem

dave 2020-04-10T12:38:10.063300Z

i'll see if i can take a stab at that when i have time

dave 2020-04-10T12:38:28.064Z

for now, i think i might need to add a postprocessing step that re-encodes &lt; as &lt;

micha 2020-04-10T12:38:30.064100Z

i don't see how it can possibly be including those scripts

dave 2020-04-10T12:38:36.064300Z

i guess inside of script tags only

micha 2020-04-10T12:38:59.064800Z

there are better ways, you can use the baackslash hex encoding if you need to

micha 2020-04-10T12:39:04.065Z

in the js

dave 2020-04-10T12:39:13.065400Z

ah! i was wondering if there were another way to encode it in the JS

micha 2020-04-10T12:39:26.065800Z

like \x12 or whatever

micha 2020-04-10T12:39:43.066100Z

but link me to the script tag in the cljs code

micha 2020-04-10T12:39:53.066300Z

the problematic one

micha 2020-04-10T12:40:08.066600Z

and also have you tried with prerendering off?

dave 2020-04-10T12:40:24.066800Z

sending it to you on adzerk slack

dave 2020-04-10T12:40:50.067200Z

i've actually been wondering if we really need prerendering

dave 2020-04-10T12:41:20.067900Z

since we're getting caching via cloudfront, i'm not sure if prerendering is helping much beyond that

micha 2020-04-10T12:41:40.068200Z

prerendering helps with the flash of unstyled content

micha 2020-04-10T12:41:53.068500Z

have you built it with prerendering off though?

micha 2020-04-10T12:42:06.068900Z

to eliminate other issues unrelated to prerendering that may be causing it

dave 2020-04-10T12:43:08.069200Z

yeah, without prerendering the problem goes away

dave 2020-04-10T12:43:20.069700Z

my first thought was that it might be an advanced optimizations issue, but that wasn't it

dave 2020-04-10T12:49:03.070700Z

hmm, it looks like \x3C is the escape sequence for &lt;, but it doesn't seem to work outside of javascript string literals

dave 2020-04-10T12:49:19.071200Z

i've only experimented in the JS console, though. not sure if it behaves differently in an inline script tag

dave 2020-04-10T12:49:48.071600Z

in the JS console you can do escape("&lt;"), which returns "%3C"

dave 2020-04-10T12:50:06.072Z

then you can do "\x3C", and that returns "&lt;"

micha 2020-04-10T12:50:18.072300Z

you should be able to put that in the js source, no?

dave 2020-04-10T12:50:24.072500Z

i'll give it a try

micha 2020-04-10T12:51:00.072900Z

you need to escape the backslash because clojure strings interpret it

micha 2020-04-10T12:51:20.073400Z

like (script "foo \\3C ...")

dave 2020-04-10T12:51:44.073600Z

makes sense

dave 2020-04-10T12:57:50.073800Z

that doesn't appear to work

micha 2020-04-10T12:58:29.074700Z

what does it look like when you do "show source" (not the elements pane of the devtools)

dave 2020-04-10T12:58:35.074900Z

i changed the offending part of the code to for(w=0,x=v.length;w\\x3Cx;++w) whereas the \\x3C used to be &lt;

dave 2020-04-10T12:58:54.075500Z

i haven't tried prerendering yet, so show source doesn't include the script tag

dave 2020-04-10T12:59:21.075900Z

i suspect the result would be the same

micha 2020-04-10T13:01:00.076Z

micha 2020-04-10T13:01:41.076500Z

what does the script tag look like in the elements pane

micha 2020-04-10T13:02:31.077Z

the easiest thing to do really is to make your own html file and then mount the app in a div inside there

micha 2020-04-10T13:03:21.077500Z

then you don't need prerendering because you can pull out the things you want to have prerendered into the html file

dave 2020-04-10T14:39:13.078Z

dave 2020-04-10T14:39:43.078600Z

looks like what i expected: w\x3Cx intsead of w&lt;x

dave 2020-04-10T14:42:21.079100Z

making our own html file is a good suggestion. i've been thinking about that in the back of my mind

dave 2020-04-10T14:42:41.079500Z

i would just need to do some post-processing to insert the right cache keys for cache busting

dave 2020-04-10T14:44:46.080200Z

could another solution be to put the inline JS into a file instead? or would that potentially screw up the load order?

dave 2020-04-10T15:14:54.080600Z

putting the JS into a file got me un-stuck

2020-04-10T15:15:17.081100Z

just catching up,was the problem literla JS inside a script tag in a cljs file?

dave 2020-04-10T15:15:23.081300Z

yes

dave 2020-04-10T15:15:26.081500Z

with :prerender-keep

dave 2020-04-10T15:15:45.081800Z

although i guess i'm not 100% sure if :prerender-keep was related

2020-04-10T15:16:38.082500Z

i think i've run into that before,with google analytics or something

2020-04-10T15:17:02.082800Z

i wonder about using js* to inline JS strategically

2020-04-10T15:17:23.083Z

that would roll it into the cljs source

2020-04-10T15:17:39.083300Z

i guess sometimes you need JS to run before the cljs kicks in tho

dave 2020-04-10T15:18:26.083600Z

does it need to be inline for that to be the case?

dave 2020-04-10T15:20:16.085300Z

like is the load order for this:

&lt;script&gt;alert("lol");&lt;/script&gt;
&lt;script src="index.cachekeygoeshere.html.js"&gt;&lt;/script&gt;
any different than the load order for this?
&lt;script src="alert_lol.js"&gt;&lt;/script&gt;
&lt;script src="index.cachekeygoeshere.html.js"&gt;&lt;/script&gt;

2020-04-10T15:21:41.085600Z

should be no different

2020-04-10T15:22:31.086100Z

i was suggesting using js* to put alert("lol") in index.cachekeygoeshere.html.js

dave 2020-04-10T15:22:43.086300Z

ah, i see

dave 2020-04-10T15:22:49.086600Z

we're actually doing that for google analytics in geir

dave 2020-04-10T15:23:09.087100Z

it's just that it only works because the inline JS doesn't include &, <, or > which hoplon's prerenderer would escape

2020-04-10T15:25:33.089100Z

seems to me like the prerender shouldn't escape script tag innards

2020-04-10T15:26:14.089900Z

from a pure xml sense it make sense, and is a good default. maybe a bug in prerender?

dave 2020-04-10T15:26:43.090200Z

i'm thinking it's a bug, too

dave 2020-04-10T15:27:03.090600Z

like if the type of the DOM node is "script," then the escaping shouldn't happen

2020-04-10T15:27:24.091Z

absolut nyet

2020-04-10T15:27:50.091600Z

anothre option is golf that code to not use any escaped chars like goog did

2020-04-10T15:28:17.092200Z

partially as entertainment 😆

dave 2020-04-10T15:28:29.092500Z

haha, nothing like a rousing game of code golf 😄

dave 2020-04-10T15:28:47.092900Z

i'm sure there is some too-clever way to get "less-than" semantics without using &lt;

2020-04-10T15:32:59.093100Z

function lt(x, y) { var z = (y - x); return z != "0" && z.toString()[0] !== "-"; }

2020-04-10T15:33:15.093300Z

crap,ampersand

dave 2020-04-10T15:34:17.093500Z

lol

dave 2020-04-10T15:36:20.094200Z

function lt(x, y) { return (x - y).toString()[0] == "-"; }
would this work?

2020-04-10T15:36:52.094800Z

that would be <= because if x == y, [0] !== "-"

2020-04-10T15:37:22.095Z

close but no banana

dave 2020-04-10T15:37:34.095400Z

hmm, i tried that in my browser and lt(2, 2) is false like i expected

2020-04-10T15:38:20.095800Z

oh i see, yes, it should work

2020-04-10T15:38:36.096Z

my thing was lte, yours is lt

2020-04-10T15:39:17.096500Z

x is < y iff (y - x) < 0, e.g. its string rep. has a leading dash

2020-04-10T15:39:51.096900Z

i bet google did that intentionally man

2020-04-10T15:40:10.097400Z

i wonder if a tool of theirs does this kind of rewriting even

dave 2020-04-10T15:40:25.097800Z

lt=(x,y)=&gt;(x-y).toString()[0]=="-"
golfed a bit further 😄

2020-04-10T15:40:39.098100Z

aha that =&gt; tho

2020-04-10T15:40:45.098400Z

gotta keep it es3

dave 2020-04-10T15:40:56.098700Z

i keep forgetting that JS has had that for like 5-10 years lol

2020-04-10T15:41:07.098900Z

ha yeah

2020-04-10T15:41:20.099300Z

a few years ago at my new job i spent a few weeks relearning JS starting from 2012 or something

2020-04-10T15:41:23.099500Z

it has all the things now pretty much

2020-04-10T15:41:53.099900Z

in addition to all the crazy things it always had

2020-04-10T15:42:45.100700Z

you know, i guess you can't make a real short-circuting &amp;&amp; as a function, because the real one delays evaluation

2020-04-10T15:42:51.101Z

the best you could do is wrap every argument in a function at the call site

dave 2020-04-10T15:43:15.101500Z

for the purposes of <= and >=, you could just implement < and > and then call it with !

2020-04-10T15:43:25.101800Z

lol this is unfolding into a great big tech company interview question

dave 2020-04-10T15:43:31.102Z

haha

dave 2020-04-10T15:43:54.102700Z

"please sort this linked list in JS, and you can't use &, <, or >"

2020-04-10T15:43:58.102900Z

oh sweet, yes good point

2020-04-10T15:44:49.103500Z

you could even say it's not a contrived question, it actually came up in the course of work haha

dave 2020-04-10T15:45:03.103700Z

hahah