-
Notifications
You must be signed in to change notification settings - Fork 11.9k
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
Serving the CSS definitions in a CSP-compliant manner, while remaining compatible with v2.0 #6015
Conversation
@simonbrunel I hope I saw everything involved with the build process. But please have another look, as I am not familiar with yours 😃 |
I think I like this approach more than all other suggestions trying to "workaround" CSP issues, though I don't think I would promote it as the recommended one in the next major release since it makes the library integration a bit more complex. Users who don't care about CSP shouldn't care about linking against the extra (almost empty) CSS. Anyway, that's another topic we will have time to figure out and maybe we will find a way to get rid of this stylesheet in v3 instead. About the TODO, I agree that the two last points can be done separately but I would like the first one (documentation) part of this PR once we all agree about the public API. However, I'm quite sure that it doesn't solve the CSP issues, so in order to review it, can you build a minimal test case that links against |
@benmccann Thanks for the Review 👍 , added all of your changes. @simonbrunel Sounds good. Could you list the parts about the public API that need to be agreed on? This way, I could already prepare some documentation. I can also understand your scepticism regarding whether or not this solves the CSP issue, after a few failed attempts. To clearly demonstrate that it works with only setting However, I am not really sure how a unit test (maybe with puppeteer? Will it check CSP in headless mode?) would look like, so is a simple Github.io webpage fine? I could do this a lot quicker 😅 |
It's not skepticism but I don't think your PR fixes the remaining CSP issue but only anticipates CSP implementation of
No, unit tests should simply make sure that the chart still work against the external style sheet. Let's not make the test process more complicated by trying to check CSP issues. |
Ah, I see. I also just stumbled over the While searching for other functions adding
Ok, I will add this in a moment. The demo page is also on its way. |
@simonbrunel While building the demo page, I think I understood what you meant. If I got it correctly, Chart.js is already injecting the CSS the moment the library is loaded and not just before a Chart needs to be rendered, if missing. Before, I assumed the later case, that the library is not affecting the DOM without explicitly calling its API. This way,
would have worked fine. But it seems as of now, it requires
To prevent a system wide global variable, this (at least for the css injection part) needs to be changed. Am I correct in assuming that this is what you are refactoring or want to refactor?
Just my personal thought, I would like to add to this discussion (feel free to ignore it 😉, I am happy either way, because Chart.js is doing an awesome job 👍 and it's just my opinion): I think this whole security and implementation issue arose because of the non-standard static CSS-injection via JS. In case we cannot get rid of the CSS information, I would suggest to provide it as a file, which is
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about the API, shouldn't it be specific to DOM?
I also feel useExternalStylesheet
is better name for the export.
style.setAttribute('type', 'text/css'); | ||
document.getElementsByTagName('head')[0].appendChild(style); | ||
} | ||
if (!useExternalStylesheet) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd move this check to initialize
, where injectCSS
is called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I also do this for createDiv
and its invocations?
@@ -325,6 +331,13 @@ module.exports = { | |||
*/ | |||
_enabled: typeof window !== 'undefined' && typeof document !== 'undefined', | |||
|
|||
get useSecureCSS() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use Object.defineProperty
instead, to be consistent with other parts of library.
For example: core.animation.js
(might want to wait for other comments, before changing)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on https://caniuse.com/#search=ECMAScript%205, Getter and Setter (introduced by ECMAScript 5), are supported at least by IE 10+, Edge, Firefox, Chrome, Safari, Opera (and their mobile variants).
Which ECMAScript version/browser should it support (so I know this for other changes 😃 )? I can also adjust it just for the sake of doing it in a consistent way.
Do you mean the line in |
Yes, you got it correctly. I started this work when exploring how to fix CSP issues but have been busy on other tasks since. I should be able to submit a PR next week with these changes (I'm currently traveling). The idea is that all the CSS rules will be injected when needed (i.e. when creating the first resize listener) which will impact when the I'm also investigating how to store the CSS rules in a separate file ( I think my upcoming PR will invalidate most of these changes. If that makes sense, I can integrate the remaining work in my branch to avoid more iterations here (moving the |
Sounds good to me. If It makes sense, I will gladly help to finish open work in your branch / PR. However, I don't want to steal you further time to explain how everything is planned to work to me, if it will already be finished in a few days by your own.
A simple approach (assuming the build process runs in a NodeJS environment) could be to either inject the CSS information directly into the JS file at build time const fs = require('fs');
fs.appendFileSync('src/platforms/platform.dom.js', `
const CSS = '${fs.readFileSync('src/platforms/platform.dom.css').replace(\'\g, '\'')}'
`); or to prepare an empty dummy file ( const fs = require('fs');
fs.writeFileSync('src/platforms/platform.dom.css.js', `
module.exports = {
CSS: '${fs.readFileSync('src/platforms/platform.dom.css').replace(\'\g, '\'')}',
}`); Personally, I would prefer the later one, as it remains compatible with the linter (as it requires the constant Beware, I did not tested this explicit code (might have some syntax errors), but I believe you got the idea. This is also how similar problems are solves in https://github.com/vuejs/vuepress, where they need to create the router component based on which files are found at build time. |
I didn't test yet but I think this rollup plugin can do the job (with minification support built-in), so would be: var style = require('./platform.dom.css');
// ...
injectCSS(style); |
Thanks, I will ping you as soon as I create the PR. In the meantime, if you feel to write the documentation about CSP issues and how to use the external CSS file, you can update that PR then I will grab it from here. I'm not sure where it should reside, maybe in "integration"? |
Sure, I will add some documentation over the weekend. I also feel that "integration" could be a good place for this. |
@@ -34,3 +34,23 @@ require(['path/to/chartjs/dist/Chart.js'], function(Chart){ | |||
``` | |||
|
|||
> **Important:** RequireJS [can **not** load CommonJS module as is](http://www.requirejs.org/docs/commonjs.html#intro), so be sure to require one of the built UMD files instead (i.e. `dist/Chart.js`, `dist/Chart.min.js`, etc.). | |||
|
|||
## Content Security Policy (CSP) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might make sense to add an extra #
in the four headers above this. They're all about including the JS and this one is about including the CSS, so it may make sense to differentiate somehow
Implements the solution proposed in #5208 (comment)
/src/platforms/platform.dom.js
chartjs.css
Fixes #5208
TODO:
Chart.platform.useSecureCSS = true;
<style src="chartjs/chartjs.css"></style>
Regarding the todos, I would suggest to merge this MR first (in case it is accepted), together with an explanation within the release notes, to quickly address the security concerns for fast adopters/peers in need of this. Afterwards, it could then be documented on https://chartjs.org and improved by adding a linting process and a minified version.