Riot: Cannot use Riot in Chrome App due to Content Security Policy

Created on 3 Aug 2015  路  43Comments  路  Source: riot/riot

I'm trying to make a Chrome App using Riot. When I try to print variable in a tag I get following error

Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "default-src 'self' chrome-extension-resource:".

on riot.js line 269: https://github.com/riot/riot/blob/master/riot.js#L269

You can sandbox the page and Riot will work, but you'll lose most of the APIs to access outside of your app.

There is this old issue which I think is related https://github.com/riot/riot/issues/103 I tried Riot 2.0.0 but it didn't work either.

Here's a minimal Chrome App that highlights the issue https://github.com/JariInc/riot-minimal-chrome-app. More about Chrome App's CSP can be found at https://developer.chrome.com/apps/contentSecurityPolicy

enhancement feature request fixed

Most helpful comment

This issue was fixed, we will provide a special riot version riot.csp.js and riot+compiler.csp.js for all the users that want to avoid the Content Security Policy problem on chrome. This particular version of riot is much slower than the default one because it evaluates all the javascript expressions using https://github.com/mmckegg/notevil trying to emulate the Function() method used in our template engine. I guess that not all the possible javascript expressions can be covered but that's the only way it's possible to solve this issue

All 43 comments

Had same problem. Until a safer solution provided, it is possible to allow using eval by adding this line to manifest.json

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

Source: https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing-eval

Sadly that does work only for extensions AFAIK, the link points to extension documentation. I tried to add that to my minimal example, but got following errors:

csp-errors

Oops! Sorry about that, I am developing an extension now and I was found this while searching a solution. I can confirm it works with extensions but I wasn't tested with apps.

We are already working on a solution using precompiled expressions.

Good point and thank you @aMarCruz for finding a clever idea to solve this.

:+1: I have the same problem. Actually need a solution with CSP for Chrome Apps.

Same issue here. Any update for a version that can work?

Any updates here?

Hi all, I'm pushing the beta version of the compiler and tmpl.
Unfortunately, I was unable to integrate support for precompiled expressions (not using eval), due to the difficulty in implementing, at compile time, the spec "in templates, falsy values returns the empty string, except zero."

Unlike ASP, using the equal sign to indicate text (<%=), riot is using the same syntax for both templates and expressions, the only difference is the precense of text _outside_ the brackets:

'{ null }'     // <-- expression, here { null } returns null
'{ null } '    // <-- template, here { null } returns ""

I need parse the html body of custom tags to know when the expression is inside template. In runtime, the browser does the parging for us.

Anyway, upon termination of the new compiler, I start working on a solution for this issue.

@aMarCruz this means that we can release riot 2.3.0 without implementing this feature. Take your time and let's focus on the next release. Please close the issues in this repo that you have solved with the new compiler release

Is there any workaround to getting riot working in a chrome app?

@richarddavenport Is this option not working?

I'm using Chrome 46 and added this to my manifest:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

But it still isn't working.

@aMarCruz looks like there is a new Function construct on the runtime code that throws a security error. Any chance to generate the runtime functions on the compilation phase?

@tipiirai , It is the same, the D parameter is gone 'cause I'm using this. The E parameter is an internal error handler in tmpl, wich calls to the user error handler, is any, setted through the tmpl.errorHandler property (Function instances runs in the tag and global context). I'm preparing docs on this. Please see https://github.com/riot/tmpl/blob/master/doc/CHANGES.md#handling-evaluation-errors.

Precompiled expressions requires minor changes to riot code base, the complication is in the distinction of the return value (raw vs text), this is based only in the context from the expression, and I have to do some parsing of nested tags. I'm working in an alternate version for testing this.

Not sure I need to understand everything you just said :)

Does that mean that you can get rid of the Content Security Policy error?

@tipiirai , yes, but it is neccesary parse the body of a custom tag at compile time. Actually, we know the expression is a template because tmpl receive text mixed with the expression. e.g. if my-tag.innerHTML is "{ null } ", then tmpl returns " ", i.e. the browser does the parsing. With precompiled expressions we need get the innerHTML without the browser in order to know if the function must return a raw null or the empty string. (ASP has the <%= %> instead <%%> for this).

Also, mixing normal with precompiled expressions need adjusts in other riot parts, riot.tag2 is a first step.

I think once the new riot is stable, we can 1) make the changes to the code base (maybe without mixing expression modes), or 2) implement this feature with a separate preprocessor (post-compiler) and a special runtime version of riot.

Sorry, I hope you undestand my poor english.

Thank you!

The english is not the issue. I read your text perfectly well. It's my limited brain capacity to understand JavaScript from time to time.

@tipiirai , I'm sure yor brain capacity is high :) anyway, next week I will create a new branch to include a mini-parser. Maybe can solve this and other issues, but will grow the code and slow the compiler. I think about 15%

Which size will be increased? The resulting tags or the compiler? Compiler size isn't so critical.

@tipiirai both. Code generated by the compiler needs include function definitions:

riot.tag2('my-tag', '<p>{#0123456712345678}</p>', '', '', function(opts) {
}, {'#0123456712345678': function(E, data){ return "Hello World" } });

but tmpl can be lighter in runtime, the most important.
I will think about brackets usage, the raw html problem and other issues. This weekend I will working on this.

+1
Any progress on this?
Would really love to run my riot.js powered packaged app outside of the severely disabled sandbox mode.

+1
.......

riot-compiler v2.3.x becomes more stable, I will publish a beta with this capability soon (3-4 weeks).

@aMarCruz if you need any help with this I would love to contribute. I would like to understand how you are approaching this so we don't duplicate efforts

@thomfoolery , the output will be something like the code in my previous comment.
Currently, the compiler clean the expression and tmpl does the compilation at runtime.

Precompiling expressions is easy, but the hash function needs to be lightweight and 99.99% reliable :). riot.tag2 will register the pre-made functions in the internal cache of tmpl, but I think we need support the current runtime compilation inline with the precompiled expressions.
Also, it is needed changes to riot core and about 30% of the tests.

Still waiting.
Actually, the problem stops me using riot in many projects :disappointed:

Wow there are many of you doing chrome extenstions?

@GianlucaGuarini
I actually build a lot of productivity tools for my colleagues. Wrapping them up as chrome extensions makes it simple and easy to distribute without the necessity of setting up the infrastructure of hosting a web application. I love RiotJS because of how quickly I can build out complex UI's, but requiring me to run in sandbox mode severely limits the power of my applications.

Are there any performance issues? Are there any limitations? I am not a chrome extensions expert ( I use firefox btw )

@GianlucaGuarini
Basically, Sandbox mode "will not have access to extension or app APIs, or direct access to non-sandboxed pages (it may communicate with them via postMessage())"
-https://developer.chrome.com/apps/manifest/sandbox

Though communication to non sandboxed page through post message is possible. building a bridge to support all of the functionality I may require completely negates the efficiencies I gain through the use of RiotJS.

Riot JS is a great framework, and I still use it today for a lot of my UI prototypes, but this limitation of running in sandboxed mode has prevented me from taking some of my prototypes to the next stage of development.

Maybe I shouldn't say this shooting on my own feet! But still.. you are developing a chrome extension and this means:

  1. you got web components + shadow DOM natively supported
  2. no need to care about the javascript bundle size since all the assets are already on your device
  3. many es6 features/syntax sugar natively supported out of the box
  4. no specific hacks to let it work on several browsers

Why the heck should someone build them using riot instead of using plain javascript?

@GianlucaGuarini
The benefit of RiotJS for myself is the speed and simplicity. React JS is to heavy handed for the quick prototypes and tools i develop. RiotJS get's out of the way and allows me to just build things in a relatively straight forward manner.

It's a barebones framework that brings standardization into the process and requires less boilerplate code than writing everything from scratch. It also has great documentation for collaborating with other teams. Onboarding team members with little contemporary web development knowledge can wrap their heads around it in a few hours.

@thomfoolery I totally understand.. @aMarCruz any chance to get a version of the [email protected] to let our user testing whether this issue can be easily avoided?

@GianlucaGuarini It's not about Chrome extensions, It's mostly about Chrome Apps.

Chrome Apps will allow me to build desktop and mobile applications based on RiotJS. And I cannot do it now because the problem, so that the reason which stops me from using Riot (which I love so much) in many cases.

And again it's not about Chrome extensions, but desktop and mobile apps.

I was checking if vuejs has the same issue, and it seems that @yyx990803 has created a custom vue build just to address this issue https://github.com/vuejs/vue/blob/csp/lib/notevil.js

I think I can solve the issue soon https://github.com/riot/tmpl/issues/15#issuecomment-208388454

This issue was fixed, we will provide a special riot version riot.csp.js and riot+compiler.csp.js for all the users that want to avoid the Content Security Policy problem on chrome. This particular version of riot is much slower than the default one because it evaluates all the javascript expressions using https://github.com/mmckegg/notevil trying to emulate the Function() method used in our template engine. I guess that not all the possible javascript expressions can be covered but that's the only way it's possible to solve this issue

Thanks @GianlucaGuarini! I've been looking at Vue.js again since you mentioned it a couple of weeks ago. I like Vue.js, but I feel Riot is simpler and for me that's makes all the difference. I like the way a tag works in Riot vs a single component file using webpack in Vue.js. You're right that we can do a lot of things with a chrome extension given we know what the browser is capable of, but using Riot is so nice. I'd rather use Riot then implement all that Riot can do myself. @Thomfoolery is right about the barebones framework design. It's much nicer to work with. The CSP build may be slower now, but maybe in the future it will get better and having a slower, working build is better than no build at all. Thanks again!

@GianlucaGuarini do we still need to override the default content security policy for chrome, when using the csp build of riot?
Even with the csp build i continue to get the error Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed..., for the line return new Function('E', expr + ';'), riot.csp.js
I am building an chrome extension using riot. The riot version is 2.4.1

@chandermani thanks for reporting it will be fixed in the next release.. you can pick this build for now https://gist.github.com/GianlucaGuarini/98a121b1d0d4419c15a2aa9486dbc50f

This issue was fixed, we will provide a special riot version riot.csp.js and riot+compiler.csp.js for all the users that want to avoid the Content Security Policy problem on chrome.

Could this please be emphasized on the Riot.js documentation?

I have been reading the documentation, and was vaguely wondering why there is the csp build, and now that I bumped into the problem of not being able to use inline scripts, and after implementing a small library to add and remove events, and still not being able to handle forms, I finally found this explanation. Thank you for the effort to solve this issue!

@peterhil you could help improving that part of our doc by doing a PR here https://github.com/riot/riot.github.io Any contribute is really welcome

Was this page helpful?
0 / 5 - 0 ratings

Related issues

niutech picture niutech  路  25Comments

steelbrain picture steelbrain  路  21Comments

GianlucaGuarini picture GianlucaGuarini  路  125Comments

em-sghosh picture em-sghosh  路  33Comments

rsbondi picture rsbondi  路  41Comments