From 7cd3961387412c4801096053af24bb64e3b263ab 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 | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/platforms/platform.dom.js b/src/platforms/platform.dom.js index c70d73963aa..88a71f8e410 100644 --- a/src/platforms/platform.dom.js +++ b/src/platforms/platform.dom.js @@ -304,17 +304,17 @@ function removeResizeListener(node) { } } -function injectCSS(platform, css) { - // https://stackoverflow.com/q/3922139 +function injectCSS(platform, rules) { 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); } - style.appendChild(document.createTextNode(css)); + rules.forEach(function(rule) { + style.sheet.insertRule(rule, style.sheet.cssRules.length); + }); } module.exports = { @@ -328,16 +328,14 @@ 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) {