From cb2db07bc7a37875dead7e4d9d814f280fabd5a8 Mon Sep 17 00:00:00 2001 From: Jeldrik Hanschke Date: Wed, 2 Jan 2019 10:22:13 +0100 Subject: [PATCH] fix CSP by injecting styles using CSSOM This uses CSS Object Model (CSSOM) to modify stylesheets. Changing stylesheets via CSSOM does not violate Content-Security-Policy style-src 'none'. CSSOM is still a working draft but the features been used should be supported by all target browsers: https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/styleSheets#Browser_compatibility https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule#Browser_compatibility Creating an empty style element does not violate CSP. -webkit- prefix is not needed anymore for keyframe. Inserting CSS rule @-webkit-keyframews throws a SyntaxError in IE11. Done basic manual testing using samples in recent versions of: - Chrome (Desktop & Mobile) - Firefox - Microsoft Edge - IE 11 Fixes #5208 together with #5909 Live example: https://codepen.io/jelhan/pen/jXYymO Please note the CSP meta tag definied in settings. You need to update SHA hashes if you change any JavaScript in this Codepen as it violates CSP otherwise. --- src/platforms/platform.dom.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/platforms/platform.dom.js b/src/platforms/platform.dom.js index c70d73963aa..3f41c5bbfee 100644 --- a/src/platforms/platform.dom.js +++ b/src/platforms/platform.dom.js @@ -304,17 +304,19 @@ function removeResizeListener(node) { } } -function injectCSS(platform, css) { - // https://stackoverflow.com/q/3922139 - var style = platform._style || document.createElement('style'); - if (!platform._style) { - platform._style = style; - css = '/* Chart.js */\n' + css; - style.setAttribute('type', 'text/css'); - document.getElementsByTagName('head')[0].appendChild(style); +function injectCSS(platform, cssRules) { + if (!platform._stylesheet) { + var styleElement = document.createElement('style'); + styleElement.setAttribute('type', 'text/css'); + document.getElementsByTagName('head')[0].appendChild(styleElement); + + platform._stylesheet = styleElement.sheet; } - style.appendChild(document.createTextNode(css)); + cssRules.forEach(function(cssRule) { + // index is required for IE11 + platform._stylesheet.insertRule(cssRule, 0); + }); } module.exports = { @@ -328,16 +330,15 @@ module.exports = { initialize: function() { var keyframes = 'from{opacity:0.99}to{opacity:1}'; - injectCSS(this, + injectCSS(this, [ // DOM rendering detection // https://davidwalsh.name/detect-node-insertion - '@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' + - '@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' + + '@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}', '.' + CSS_RENDER_MONITOR + '{' + '-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' + 'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' + '}' - ); + ]); }, acquireContext: function(item, config) {