Cannot use Riot in Chrome App due to Content Security Policy #1076

Closed
JariInc opened this Issue Aug 3, 2015 · 41 comments

Projects

None yet
@JariInc
JariInc commented Aug 3, 2015

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 #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

@aMarCruz aMarCruz self-assigned this Aug 4, 2015
@codetorex

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

@JariInc
JariInc commented Aug 29, 2015

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

@codetorex

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.

@aMarCruz
Member

We are already working on a solution using precompiled expressions.

@tipiirai
Member
tipiirai commented Sep 1, 2015

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

@klen
klen commented Sep 8, 2015

👍 I have the same problem. Actually need a solution with CSP for Chrome Apps.

@ipeisong

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

@klen
klen commented Oct 7, 2015

Any updates here?

@aMarCruz
Member
aMarCruz commented Oct 8, 2015

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.

@GianlucaGuarini
Member

@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

@richarddavenport

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

@GianlucaGuarini
Member

@richarddavenport Is this option not working?

@richarddavenport

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.

@tipiirai
Member
tipiirai commented Nov 6, 2015

@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?

@aMarCruz
Member
aMarCruz commented Nov 6, 2015

@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.

@tipiirai
Member
tipiirai commented Nov 9, 2015

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

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

@aMarCruz
Member

@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.

@tipiirai
Member

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.

@aMarCruz
Member

@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%

@tipiirai
Member

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

@aMarCruz
Member

@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.

@thomfoolery

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

@naivefun

+1
.......

@aMarCruz
Member

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

@thomfoolery

@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

@aMarCruz
Member

@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.

@klen
klen commented Mar 22, 2016

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

@GianlucaGuarini
Member

Wow there are many of you doing chrome extenstions?

@thomfoolery

@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.

@GianlucaGuarini
Member

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

@thomfoolery

@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.

@GianlucaGuarini
Member

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?

@thomfoolery

@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.

@GianlucaGuarini
Member

@thomfoolery I totally understand.. @aMarCruz any chance to get a version of the riot-compiler@3.0.0-alpha to let our user testing whether this issue can be easily avoided?

@klen
klen commented Apr 7, 2016

@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.

@GianlucaGuarini
Member

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

@GianlucaGuarini GianlucaGuarini referenced this issue in riot/tmpl Apr 9, 2016
Closed

Safe eval #15

@GianlucaGuarini
Member

I think I can solve the issue soon riot/tmpl#15 (comment)

@GianlucaGuarini GianlucaGuarini added a commit to riot/tmpl that referenced this issue Apr 24, 2016
@GianlucaGuarini GianlucaGuarini closes #15 and riot/riot#1076 29ee39e
@GianlucaGuarini
Member
GianlucaGuarini commented Apr 24, 2016 edited

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

@richarddavenport

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 GianlucaGuarini added a commit to riot/tmpl that referenced this issue May 7, 2016
@GianlucaGuarini GianlucaGuarini closes #15 and riot/riot#1076 108fd01
@GianlucaGuarini GianlucaGuarini added a commit that closed this issue May 7, 2016
@GianlucaGuarini GianlucaGuarini closes #1076 be6ef3e
@chandermani
chandermani commented Jun 10, 2016 edited

@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

@GianlucaGuarini
Member

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment