justpy icon indicating copy to clipboard operation
justpy copied to clipboard

inner_html containing script tag breaks page

Open falkoschindler opened this issue 3 years ago • 2 comments
trafficstars

The following example should insert a script tag into a div:

import justpy as jp

wp = jp.WebPage()
d = jp.Div()
d.inner_html = '<script>alert("Hello World!");</script>'
wp.add(d)

jp.justpy(lambda: wp)

But the result is a page full of JavaScript code. It looks like the closing </script> causes the the remaining code of the JustPy framework to be interpreted as HTML.

Although I'm aware of other possibilities to insert code into the HTML body (e.g. body_html), this smells like unsafe behavior. Besides, it would be handy to be able to just insert any HTML via inner_html.

falkoschindler avatar Jul 08 '22 06:07 falkoschindler

Something about "" that is introducing special character. If i change this to "<//script>" that seems to not break the parsing on the frontend.

sandeep-gh avatar Jul 12 '22 17:07 sandeep-gh

@sandeep-gh Interesting! That breaks the HTML and the alert is not executed, but at least that led me to a way to detect the issue and raise an exception in our library: https://github.com/zauberzeug/nicegui/commit/4b6cf36c15b900b1341bb322efaaf69ea5871b92

It still would be nice to be able to just add whatever HTML you want. Or maybe there is a way to close the

falkoschindler avatar Jul 29 '22 16:07 falkoschindler

In a nutshell, when JavaScript code within an HTML file contains "", the code block terminates and the remaining code is treated as HTML:

<html>
  <body>
    <script>
      console.log('<script>console.log("script");</script>');
    </script>
  </body>
</html>

Here is the line where this hiccup happens in JustPy:

var justpyComponents = {{ justpy_dict | safe }};

To avoid this problem, I'm thinking about either escaping the slash or splitting the string (as suggested here):

var justpyComponents = {{ justpy_dict.replace('</' + 'script>', '</" + "script>') | safe }};

This solves the rendering problem. But unfortunately I can't manage to actually execute the contained JavaScript code, even though the resulting DOM looks ok. Is there maybe a fundamental problem with running code as part of a JustPy component?

falkoschindler avatar Aug 25 '22 07:08 falkoschindler

@elimintz Do you have an idea, why JavaScript code contained in a jp.Div is not executed on the client?

I'm testing with this line in main.html to hide the closing script tag from the HTML parser

var justpyComponents = {{ justpy_dict.replace('</' + 'script>', '</" + "script>') | safe }};

and the following test.py:

import justpy as jp

wp = jp.WebPage()
d = jp.Div()
d.inner_html = '<script>console.log("Hello World!");</script>'
wp.add(d)

jp.justpy(lambda: wp)

I would expect to see "Hello World!" on the JavaScript console. At least the script is contained in the response from 127.0.0.1:8000 and in the rendered DOM.

falkoschindler avatar Aug 29 '22 17:08 falkoschindler

I think that since the html on the page is generated by a script (Vue) , the closes the main running script which creates unforeseen results. In this case, part of the dictionary describing the page is inserted as text.

elimintz avatar Aug 29 '22 19:08 elimintz

@elimintz That's what the line

var justpyComponents = {{ justpy_dict.replace('</' + 'script>', '</" + "script>') | safe }};

in my local copy of main.html is already taking care of. The script reaches the client correctly. I just thought you might know why the console.log is still not executed - maybe some Vue magic happening...

falkoschindler avatar Aug 29 '22 20:08 falkoschindler

This is interesting: https://www.danielcrabtree.com/blog/25/gotchas-with-dynamically-adding-script-tags-to-html Apparently htnl5 does not execute scripts inserted via innerHtml

Perhaps the solution is to wait for page_ready and then run a JavaScript script that inserts the wanted script not using inner html.

elimintz avatar Aug 29 '22 20:08 elimintz

Very interesting indeed! There doesn't seem to be an easy way to inject JavaScript via innerHtml. So I just replaced the closing script tag to make sure the whole app doesn't crash. But to actually run JavaScript code, you need to add it to the head_html.

falkoschindler avatar Aug 30 '22 05:08 falkoschindler

See #473 and #471 - i suggest we allow user specific java code to be explicitly loaded as part of the startup process. That will be way cleaner than having to fiddle with html as such. Especially debugging the java script code and setting break points will be way easier.

WolfgangFahl avatar Aug 30 '22 08:08 WolfgangFahl