aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/grunt/utils.js2
-rw-r--r--src/Angular.js7
-rwxr-xr-xsrc/AngularPublic.js6
-rw-r--r--src/ng/directive/ngCsp.js24
-rw-r--r--src/ng/sniffer.js2
-rw-r--r--test/AngularSpec.js40
-rw-r--r--test/ng/directive/ngCspSpec.js10
-rw-r--r--test/ng/snifferSpec.js13
8 files changed, 64 insertions, 40 deletions
diff --git a/lib/grunt/utils.js b/lib/grunt/utils.js
index 764f481f..c7d4431b 100644
--- a/lib/grunt/utils.js
+++ b/lib/grunt/utils.js
@@ -91,7 +91,7 @@ module.exports = {
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(/\r?\n/g, '\\n');
- return "angular.element(document).find('head').prepend('<style type=\"text/css\">" + css + "</style>');";
+ return "!angular.$$csp() && angular.element(document).find('head').prepend('<style type=\"text/css\">" + css + "</style>');";
}
},
diff --git a/src/Angular.js b/src/Angular.js
index 305f1321..085e062d 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -760,6 +760,13 @@ function equals(o1, o2) {
}
+function csp() {
+ return (document.securityPolicy && document.securityPolicy.isActive) ||
+ (document.querySelector &&
+ !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
+}
+
+
function concat(array1, array2, index) {
return array1.concat(slice.call(array2, index));
}
diff --git a/src/AngularPublic.js b/src/AngularPublic.js
index f7f78ae5..09361079 100755
--- a/src/AngularPublic.js
+++ b/src/AngularPublic.js
@@ -44,12 +44,13 @@ function publishExternalAPI(angular){
'isNumber': isNumber,
'isElement': isElement,
'isArray': isArray,
- '$$minErr': minErr,
'version': version,
'isDate': isDate,
'lowercase': lowercase,
'uppercase': uppercase,
- 'callbacks': {counter: 0}
+ 'callbacks': {counter: 0},
+ '$$minErr': minErr,
+ '$$csp': csp
});
angularModule = setupModuleLoader(window);
@@ -77,7 +78,6 @@ function publishExternalAPI(angular){
ngClass: ngClassDirective,
ngClassEven: ngClassEvenDirective,
ngClassOdd: ngClassOddDirective,
- ngCsp: ngCspDirective,
ngCloak: ngCloakDirective,
ngController: ngControllerDirective,
ngForm: ngFormDirective,
diff --git a/src/ng/directive/ngCsp.js b/src/ng/directive/ngCsp.js
index 174e4c58..1a099f59 100644
--- a/src/ng/directive/ngCsp.js
+++ b/src/ng/directive/ngCsp.js
@@ -3,25 +3,26 @@
/**
* @ngdoc directive
* @name ng.directive:ngCsp
- * @priority 1000
*
* @element html
* @description
* Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
- *
+ *
* This is necessary when developing things like Google Chrome Extensions.
- *
+ *
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
* any of these restrictions.
- *
+ *
* 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.
- *
+ *
* In order to use this feature put the `ngCsp` directive on the root element of the application.
- *
+ *
+ * *Note: This directive is only available in the ng-csp and data-ng-csp attribute form.*
+ *
* @example
* This example shows how to apply the `ngCsp` directive to the `html` tag.
<pre>
@@ -33,11 +34,6 @@
</pre>
*/
-var ngCspDirective = ['$sniffer', function($sniffer) {
- return {
- priority: 1000,
- compile: function() {
- $sniffer.csp = true;
- }
- };
-}];
+// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
+// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
+// anywhere in the current doc
diff --git a/src/ng/sniffer.js b/src/ng/sniffer.js
index 7f26e312..9a7447cb 100644
--- a/src/ng/sniffer.js
+++ b/src/ng/sniffer.js
@@ -76,7 +76,7 @@ function $SnifferProvider() {
return eventSupport[event];
},
- csp: document.securityPolicy ? document.securityPolicy.isActive : false,
+ csp: csp(),
vendorPrefix: vendorPrefix,
transitions : transitions,
animations : animations
diff --git a/test/AngularSpec.js b/test/AngularSpec.js
index c1914947..1b08a18e 100644
--- a/test/AngularSpec.js
+++ b/test/AngularSpec.js
@@ -348,6 +348,46 @@ describe('angular', function() {
});
+ describe('csp', function() {
+ var originalSecurityPolicy;
+
+ beforeEach(function() {
+ originalSecurityPolicy = document.securityPolicy;
+ });
+
+ afterEach(function() {
+ document.securityPolicy = originalSecurityPolicy;
+ });
+
+
+ it('should return the false when CSP is not enabled (the default)', function() {
+ expect(csp()).toBe(false);
+ });
+
+
+ it('should return true if CSP is autodetected via CSP v1.1 securityPolicy.isActive property', function() {
+ document.securityPolicy = {isActive: true};
+ expect(csp()).toBe(true);
+ });
+
+ it('should return the true when CSP is enabled manually via [ng-csp]', function() {
+ spyOn(document, 'querySelector').andCallFake(function(selector) {
+ if (selector == '[ng-csp]') return {};
+ });
+ expect(csp()).toBe(true);
+ });
+
+
+ it('should return the true when CSP is enabled manually via [data-ng-csp]', function() {
+ spyOn(document, 'querySelector').andCallFake(function(selector) {
+ if (selector == '[data-ng-csp]') return {};
+ });
+ expect(csp()).toBe(true);
+ expect(document.querySelector).toHaveBeenCalledWith('[data-ng-csp]');
+ });
+ });
+
+
describe('parseKeyValue', function() {
it('should parse a string into key-value pairs', function() {
expect(parseKeyValue('')).toEqual({});
diff --git a/test/ng/directive/ngCspSpec.js b/test/ng/directive/ngCspSpec.js
deleted file mode 100644
index 7a21b587..00000000
--- a/test/ng/directive/ngCspSpec.js
+++ /dev/null
@@ -1,10 +0,0 @@
-'use strict';
-
-describe('ngCsp', function() {
-
- it('it should turn on CSP mode in $sniffer', inject(function($sniffer, $compile) {
- expect($sniffer.csp).toBe(false);
- $compile('<div ng-csp></div>');
- expect($sniffer.csp).toBe(true);
- }));
-});
diff --git a/test/ng/snifferSpec.js b/test/ng/snifferSpec.js
index 6edf9f61..6e9dc830 100644
--- a/test/ng/snifferSpec.js
+++ b/test/ng/snifferSpec.js
@@ -85,21 +85,12 @@ describe('$sniffer', function() {
describe('csp', function() {
- it('should be false if document.securityPolicy.isActive not available', function() {
+ it('should be false by default', function() {
expect(sniffer({}).csp).toBe(false);
});
-
-
- it('should use document.securityPolicy.isActive if available', function() {
- var createDocumentWithCSP = function(csp) {
- return {securityPolicy: {isActive: csp}};
- };
-
- expect(sniffer({}, createDocumentWithCSP(false)).csp).toBe(false);
- expect(sniffer({}, createDocumentWithCSP(true)).csp).toBe(true);
- });
});
+
describe('vendorPrefix', function() {
it('should return the correct vendor prefix based on the browser', function() {