From dca87c932df314531570e6be7fd206e5d09f8e77 Mon Sep 17 00:00:00 2001 From: tigbro Date: Mon, 14 Oct 2013 12:06:26 -0700 Subject: [PATCH] fix: don't inline css in csp mode. Also add `angular-csp.css` to the resulting build. --- Gruntfile.js | 1 + lib/grunt/utils.js | 41 ++++++++++++++++++++++++++-------- src/ng/directive/ngCloak.js | 3 ++- src/ng/directive/ngCsp.js | 4 ++++ src/ng/directive/ngShowHide.js | 2 ++ 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index c4d2bb219b51..8c957e630736 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -121,6 +121,7 @@ module.exports = function(grunt) { src: util.wrap([files['angularSrc']], 'angular'), styles: { css: ['css/angular.css'], + generateCspCssFile: true, minify: true } }, diff --git a/lib/grunt/utils.js b/lib/grunt/utils.js index 764f481fff00..1c9766c9acbd 100644 --- a/lib/grunt/utils.js +++ b/lib/grunt/utils.js @@ -3,6 +3,7 @@ var shell = require('shelljs'); var grunt = require('grunt'); var spawn = require('child_process').spawn; var version; +var CSP_CSS_HEADER = '/* Include this file in your html if you are using csp mode. */\n\n'; module.exports = { @@ -70,12 +71,20 @@ module.exports = { addStyle: function(src, styles, minify){ - styles = styles.map(processCSS.bind(this)).join('\n'); - src += styles; - return src; + styles = styles.reduce(processCSS.bind(this), { + js: [src], + css: [] + }); + return { + js: styles.js.join('\n'), + css: styles.css.join('\n') + }; + + function processCSS(state, file) { + var css = fs.readFileSync(file).toString(), + js; + state.css.push(css); - function processCSS(file){ - var css = fs.readFileSync(file).toString(); if(minify){ css = css .replace(/\r?\n/g, '') @@ -87,11 +96,14 @@ module.exports = { .replace(/\s*\;\s*/g, ';'); } //escape for js - css = css + js = css .replace(/\\/g, '\\\\') .replace(/'/g, "\\'") .replace(/\r?\n/g, '\\n'); - return "angular.element(document).find('head').prepend('');"; + js = "if (!document.securityPolicy || !document.securityPolicy.isActive) { angular.element(document).find('head').prepend(''); }"; + state.js.push(js); + + return state; } }, @@ -112,17 +124,28 @@ module.exports = { build: function(config, fn){ var files = grunt.file.expand(config.src); var styles = config.styles; + var processedStyles; //concat - var src = files.map(function(filepath){ + var src = files.map(function(filepath) { return grunt.file.read(filepath); }).join(grunt.util.normalizelf('\n')); //process var processed = this.process(src, grunt.config('NG_VERSION'), config.strict); - if (styles) processed = this.addStyle(processed, styles.css, styles.minify); + if (styles) { + processedStyles = this.addStyle(processed, styles.css, styles.minify); + processed = processedStyles.js; + if (config.styles.generateCspCssFile) { + grunt.file.write(removeSuffix(config.dest) + '-csp.css', CSP_CSS_HEADER + processedStyles.css); + } + } //write grunt.file.write(config.dest, processed); grunt.log.ok('File ' + config.dest + ' created.'); fn(); + + function removeSuffix(fileName) { + return fileName.replace(/\.js$/, ''); + } }, diff --git a/src/ng/directive/ngCloak.js b/src/ng/directive/ngCloak.js index 6e39bdfc2471..d430ae52120c 100644 --- a/src/ng/directive/ngCloak.js +++ b/src/ng/directive/ngCloak.js @@ -15,7 +15,8 @@ * of the browser view. * * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and - * `angular.min.js`: + * `angular.min.js`. + * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). * *
  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
diff --git a/src/ng/directive/ngCsp.js b/src/ng/directive/ngCsp.js
index 174e4c58f927..cf8d205e4cec 100644
--- a/src/ng/directive/ngCsp.js
+++ b/src/ng/directive/ngCsp.js
@@ -19,6 +19,10 @@
  * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
  * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
  * be raised.
+ *
+ * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
+ * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
+ * To make those directives work in CSP mode, include the `angular-csp.css` manually.
  * 
  * In order to use this feature put the `ngCsp` directive on the root element of the application.
  * 
diff --git a/src/ng/directive/ngShowHide.js b/src/ng/directive/ngShowHide.js
index cdfa060421ca..5b13a57bf428 100644
--- a/src/ng/directive/ngShowHide.js
+++ b/src/ng/directive/ngShowHide.js
@@ -9,6 +9,7 @@
  * provided to the ngShow attribute. The element is shown or hidden by removing or adding
  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
  * in AngularJS and sets the display style to none (using an !important flag).
+ * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
  *
  * 
  * 
@@ -161,6 +162,7 @@ var ngShowDirective = ['$animate', function($animate) {
  * provided to the ngHide attribute. The element is shown or hidden by removing or adding
  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
  * in AngularJS and sets the display style to none (using an !important flag).
+ * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
  *
  * 
  *