Skip to content

Commit 7f1dec0

Browse files
rjametchristopherthielen
authored andcommitted
feat($templateFactory): refactor to a Provider to have a $http/$templateRequest switch
This creates a $TemplateFactoryProvider to be able to set a global config option that forces $templateFactory to use $http (which bypasses the security checks, hence the scary name). Added tests and doc for that too. This still defaults to $http on older Angulars as expected.
1 parent ad1f093 commit 7f1dec0

File tree

2 files changed

+78
-5
lines changed

2 files changed

+78
-5
lines changed

src/templateFactory.js

+55-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,54 @@
1+
2+
/**
3+
* @ngdoc object
4+
* @name ui.router.util.$templateFactoryProvider
5+
*
6+
* @description
7+
* Provider for $templateFactory. Manages which template-loading mechanism to
8+
* use, and will default to the most recent one ($templateRequest on Angular
9+
* versions starting from 1.3, $http otherwise).
10+
*/
11+
function $TemplateFactoryProvider() {
12+
var shouldUnsafelyUseHttp = angular.version.minor < 3;
13+
14+
/**
15+
* @ngdoc function
16+
* @name ui.router.util.$templateFactoryProvider#shouldUnsafelyUseHttp
17+
* @methodOf ui.router.util.$templateFactoryProvider
18+
*
19+
* @description
20+
* Forces $templateFactory to use $http instead of $templateRequest. This
21+
* might cause XSS, as $http doesn't enforce the regular security checks for
22+
* templates that have been introduced in Angular 1.3. Note that setting this
23+
* to false on Angular older than 1.3.x will crash, as the $templateRequest
24+
* service (and the security checks) are not implemented on these versions.
25+
*
26+
* See the $sce documentation, section
27+
* <a href="https://docs.angularjs.org/api/ng/service/$sce#impact-on-loading-templates">
28+
* Impact on loading templates</a> for more details about this mechanism.
29+
*
30+
* @param {boolean} value
31+
*/
32+
this.shouldUnsafelyUseHttp = function(value) {
33+
shouldUnsafelyUseHttp = !!value;
34+
};
35+
36+
/**
37+
* @ngdoc object
38+
* @name ui.router.util.$templateFactory
39+
*
40+
* @requires $http
41+
* @requires $templateCache
42+
* @requires $injector
43+
*
44+
* @description
45+
* Service. Manages loading of templates.
46+
*/
47+
this.$get = ['$http', '$templateCache', '$injector', function($http, $templateCache, $injector){
48+
return new $TemplateFactory($http, $templateCache, $injector, shouldUnsafelyUseHttp);}];
49+
}
50+
51+
152
/**
253
* @ngdoc object
354
* @name ui.router.util.$templateFactory
@@ -9,8 +60,7 @@
960
* @description
1061
* Service. Manages loading of templates.
1162
*/
12-
$TemplateFactory.$inject = ['$http', '$templateCache', '$injector'];
13-
function $TemplateFactory( $http, $templateCache, $injector) {
63+
function $TemplateFactory($http, $templateCache, $injector, shouldUnsafelyUseHttp) {
1464

1565
/**
1666
* @ngdoc function
@@ -83,7 +133,7 @@ function $TemplateFactory( $http, $templateCache, $injector) {
83133
if (isFunction(url)) url = url(params);
84134
if (url == null) return null;
85135
else {
86-
if($injector.has && $injector.has('$templateRequest')) {
136+
if(!shouldUnsafelyUseHttp) {
87137
return $injector.get('$templateRequest')(url);
88138
} else {
89139
return $http
@@ -111,6 +161,6 @@ function $TemplateFactory( $http, $templateCache, $injector) {
111161
this.fromProvider = function (provider, params, locals) {
112162
return $injector.invoke(provider, null, locals || { params: params });
113163
};
114-
}
164+
};
115165

116-
angular.module('ui.router.util').service('$templateFactory', $TemplateFactory);
166+
angular.module('ui.router.util').provider('$templateFactory', $TemplateFactoryProvider);

test/templateFactorySpec.js

+23
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,26 @@ describe('templateFactory', function () {
5555
}));
5656
}
5757
});
58+
59+
describe('templateFactory with $http use forced', function () {
60+
61+
beforeEach(function() {
62+
angular
63+
.module('forceHttpInTemplateFactory', [])
64+
.config(function($templateFactoryProvider) {
65+
$templateFactoryProvider.shouldUnsafelyUseHttp(true);
66+
});
67+
module('ui.router.util');
68+
module('forceHttpInTemplateFactory');
69+
});
70+
71+
it('does not restrict URL loading', inject(function($templateFactory, $httpBackend) {
72+
$httpBackend.expectGET('http://evil.com/views/view.html').respond(200, 'template!');
73+
$templateFactory.fromUrl('http://evil.com/views/view.html');
74+
$httpBackend.flush();
75+
76+
$httpBackend.expectGET('data:text/html,foo').respond(200, 'template!');
77+
$templateFactory.fromUrl('data:text/html,foo');
78+
$httpBackend.flush();
79+
}));
80+
});

0 commit comments

Comments
 (0)