diff --git a/lib/grunt/utils.js b/lib/grunt/utils.js
index 5c194378bad2..204db413ecf2 100644
--- a/lib/grunt/utils.js
+++ b/lib/grunt/utils.js
@@ -116,7 +116,7 @@ module.exports = {
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(/\r?\n/g, '\\n');
- js = "!window.angular.$$csp() && window.angular.element(document.head).prepend('');";
+ js = "!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend('');";
state.js.push(js);
return state;
diff --git a/src/Angular.js b/src/Angular.js
index e66b9938a9a3..9d351a869bb0 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -984,22 +984,39 @@ function equals(o1, o2) {
}
var csp = function() {
- if (isDefined(csp.isActive_)) return csp.isActive_;
+ if (!isDefined(csp.rules)) {
- var active = !!(document.querySelector('[ng-csp]') ||
- document.querySelector('[data-ng-csp]'));
- if (!active) {
+ var ngCspElement = (document.querySelector('[ng-csp]') ||
+ document.querySelector('[data-ng-csp]'));
+
+ if (ngCspElement) {
+ var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
+ ngCspElement.getAttribute('data-ng-csp');
+ csp.rules = {
+ noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
+ noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
+ };
+ } else {
+ csp.rules = {
+ noUnsafeEval: noUnsafeEval(),
+ noInlineStyle: false
+ };
+ }
+ }
+
+ return csp.rules;
+
+ function noUnsafeEval() {
try {
/* jshint -W031, -W054 */
new Function('');
/* jshint +W031, +W054 */
+ return false;
} catch (e) {
- active = true;
+ return true;
}
}
-
- return (csp.isActive_ = active);
};
/**
diff --git a/src/AngularPublic.js b/src/AngularPublic.js
index dff1ce015ae1..9afb79c16d6a 100644
--- a/src/AngularPublic.js
+++ b/src/AngularPublic.js
@@ -20,7 +20,6 @@
ngClassDirective,
ngClassEvenDirective,
ngClassOddDirective,
- ngCspDirective,
ngCloakDirective,
ngControllerDirective,
ngFormDirective,
diff --git a/src/ng/directive/ngCsp.js b/src/ng/directive/ngCsp.js
index 974d2e9305fb..378333b4a854 100644
--- a/src/ng/directive/ngCsp.js
+++ b/src/ng/directive/ngCsp.js
@@ -6,27 +6,29 @@
*
* @element html
* @description
- * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
+ *
+ * Angular has some features that can break certain
+ * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
+ *
+ * If you intend to implement these rules then you must tell Angular not to use these features.
*
* This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
*
- * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
- * For Angular to be CSP compatible there are only two things that we need to do differently:
*
- * - don't use `Function` constructor to generate optimized value getters
- * - don't inject custom stylesheet into the document
+ * The following rules affect Angular:
*
- * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
- * 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.
+ * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
+ * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
+ * increase in the speed of evaluating Angular expressions.
*
- * 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.
+ * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
+ * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
+ * To make these directives work when a CSP rule is blocking inline styles, you must link to the
+ * `angular-csp.css` in your HTML manually.
*
- * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
- * autodetection however triggers a CSP error to be logged in the console:
+ * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
+ * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
+ * however, triggers a CSP error to be logged in the console:
*
* ```
* Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
@@ -35,11 +37,39 @@
* ```
*
* This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
- * directive on the root element of the application or on the `angular.js` script tag, whichever
- * appears first in the html document.
+ * directive on an element of the HTML document that appears before the `