aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChirayu Krishnappa2013-05-14 14:51:39 -0700
committerChirayu Krishnappa2013-07-25 13:00:35 -0700
commitbea9422ebfc8e80ee28ad81afc62d2e432c85cbb (patch)
tree718e35908d9a017e51041b080276826f6595c8d2 /src
parentfb7d891dacdcb9f799061d5fbb96cdd2dd912196 (diff)
downloadangular.js-bea9422ebfc8e80ee28ad81afc62d2e432c85cbb.tar.bz2
feat($sce): new $sce service for Strict Contextual Escaping.
$sce is a service that provides Strict Contextual Escaping services to AngularJS. Strict Contextual Escaping -------------------------- Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain contexts to result in a value that is marked as safe to use for that context One example of such a context is binding arbitrary html controlled by the user via ng-bind-html-unsafe. We refer to these contexts as privileged or SCE contexts. As of version 1.2, Angular ships with SCE enabled by default. Note: When enabled (the default), IE8 in quirks mode is not supported. In this mode, IE8 allows one to execute arbitrary javascript by the use of the expression() syntax. Refer http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx to learn more about them. You can ensure your document is in standards mode and not quirks mode by adding <!doctype html> to the top of your HTML document. SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for security vulnerabilities such as XSS, clickjacking, etc. a lot easier. Here's an example of a binding in a privileged context: <input ng-model="userHtml"> <div ng-bind-html-unsafe="{{userHtml}}"> Notice that ng-bind-html-unsafe is bound to {{userHtml}} controlled by the user. With SCE disabled, this application allows the user to render arbitrary HTML into the DIV. In a more realistic example, one may be rendering user comments, blog articles, etc. via bindings. (HTML is just one example of a context where rendering user controlled input creates security vulnerabilities.) For the case of HTML, you might use a library, either on the client side, or on the server side, to sanitize unsafe HTML before binding to the value and rendering it in the document. How would you ensure that every place that used these types of bindings was bound to a value that was sanitized by your library (or returned as safe for rendering by your server?) How can you ensure that you didn't accidentally delete the line that sanitized the value, or renamed some properties/fields and forgot to update the binding to the sanitized value? To be secure by default, you want to ensure that any such bindings are disallowed unless you can determine that something explicitly says it's safe to use a value for binding in that context. You can then audit your code (a simple grep would do) to ensure that this is only done for those values that you can easily tell are safe - because they were received from your server, sanitized by your library, etc. You can organize your codebase to help with this - perhaps allowing only the files in a specific directory to do this. Ensuring that the internal API exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task. In the case of AngularJS' SCE service, one uses $sce.trustAs (and shorthand methods such as $sce.trustAsHtml, etc.) to obtain values that will be accepted by SCE / privileged contexts. In privileged contexts, directives and code will bind to the result of $sce.getTrusted(context, value) rather than to the value directly. Directives use $sce.parseAs rather than $parse to watch attribute bindings, which performs the $sce.getTrusted behind the scenes on non-constant literals. As an example, ngBindHtmlUnsafe uses $sce.parseAsHtml(binding expression). Here's the actual code (slightly simplified): var ngBindHtmlUnsafeDirective = ['$sce', function($sce) { return function(scope, element, attr) { scope.$watch($sce.parseAsHtml(attr.ngBindHtmlUnsafe), function(value) { element.html(value || ''); }); }; }]; Impact on loading templates --------------------------- This applies both to the ng-include directive as well as templateUrl's specified by directives. By default, Angular only loads templates from the same domain and protocol as the application document. This is done by calling $sce.getTrustedResourceUrl on the template URL. To load templates from other domains and/or protocols, you may either either whitelist them or wrap it into a trusted value. *Please note*: The browser's Same Origin Policy and Cross-Origin Resource Sharing (CORS) policy apply in addition to this and may further restrict whether the template is successfully loaded. This means that without the right CORS policy, loading templates from a different domain won't work on all browsers. Also, loading templates from file:// URL does not work on some browsers. This feels like too much overhead for the developer? ---------------------------------------------------- It's important to remember that SCE only applies to interpolation expressions. If your expressions are constant literals, they're automatically trusted and you don't need to call $sce.trustAs on them. e.g. <div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div> just works. Additionally, a[href] and img[src] automatically sanitize their URLs and do not pass them through $sce.getTrusted. SCE doesn't play a role here. The included $sceDelegate comes with sane defaults to allow you to load templates in ng-include from your application's domain without having to even know about SCE. It blocks loading templates from other domains or loading templates over http from an https served document. You can change these by setting your own custom whitelists and blacklists for matching such URLs. This significantly reduces the overhead. It is far easier to pay the small overhead and have an application that's secure and can be audited to verify that with much more ease than bolting security onto an application later.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/AngularPublic.js2
-rw-r--r--src/ng/compile.js12
-rw-r--r--src/ng/directive/ngBind.js4
-rw-r--r--src/ng/directive/ngInclude.js23
-rw-r--r--src/ng/interpolate.js27
-rw-r--r--src/ng/sce.js959
-rw-r--r--src/ng/urlUtils.js5
-rw-r--r--src/ngRoute/route.js25
-rw-r--r--src/ngSanitize/sanitize.js14
9 files changed, 1027 insertions, 44 deletions
diff --git a/src/AngularPublic.js b/src/AngularPublic.js
index 99f6cdbd..25e21b2c 100755
--- a/src/AngularPublic.js
+++ b/src/AngularPublic.js
@@ -122,6 +122,8 @@ function publishExternalAPI(angular){
$parse: $ParseProvider,
$rootScope: $RootScopeProvider,
$q: $QProvider,
+ $sce: $SceProvider,
+ $sceDelegate: $SceDelegateProvider,
$sniffer: $SnifferProvider,
$templateCache: $TemplateCacheProvider,
$timeout: $TimeoutProvider,
diff --git a/src/ng/compile.js b/src/ng/compile.js
index c059af47..82976822 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -274,9 +274,9 @@ function $CompileProvider($provide) {
this.$get = [
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
- '$controller', '$rootScope', '$document', '$$urlUtils',
+ '$controller', '$rootScope', '$document', '$sce', '$$urlUtils',
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
- $controller, $rootScope, $document, $$urlUtils) {
+ $controller, $rootScope, $document, $sce, $$urlUtils) {
var Attributes = function(element, attr) {
this.$$element = element;
@@ -1095,7 +1095,7 @@ function $CompileProvider($provide) {
$compileNode.html('');
- $http.get(templateUrl, {cache: $templateCache}).
+ $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
success(function(content) {
var compileNode, tempTemplateAttrs, $template;
@@ -1203,12 +1203,12 @@ function $CompileProvider($provide) {
}
- function isTrustedContext(node, attrNormalizedName) {
+ function getTrustedContext(node, attrNormalizedName) {
// maction[xlink:href] can source SVG. It's not limited to <maction>.
if (attrNormalizedName == "xlinkHref" ||
(nodeName_(node) != "IMG" && (attrNormalizedName == "src" ||
attrNormalizedName == "ngSrc"))) {
- return true;
+ return $sce.RESOURCE_URL;
}
}
@@ -1238,7 +1238,7 @@ function $CompileProvider($provide) {
// we need to interpolate again, in case the attribute value has been updated
// (e.g. by another directive's compile function)
- interpolateFn = $interpolate(attr[name], true, isTrustedContext(node, name));
+ interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
// if attribute was updated so that there is no interpolation going on we don't want to
// register any observers
diff --git a/src/ng/directive/ngBind.js b/src/ng/directive/ngBind.js
index f1cf4c70..fc54adcf 100644
--- a/src/ng/directive/ngBind.js
+++ b/src/ng/directive/ngBind.js
@@ -129,10 +129,10 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
* @element ANY
* @param {expression} ngBindHtmlUnsafe {@link guide/expression Expression} to evaluate.
*/
-var ngBindHtmlUnsafeDirective = [function() {
+var ngBindHtmlUnsafeDirective = ['$sce', function($sce) {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
- scope.$watch(attr.ngBindHtmlUnsafe, function ngBindHtmlUnsafeWatchAction(value) {
+ scope.$watch($sce.parseAsHtml(attr.ngBindHtmlUnsafe), function ngBindHtmlUnsafeWatchAction(value) {
element.html(value || '');
});
};
diff --git a/src/ng/directive/ngInclude.js b/src/ng/directive/ngInclude.js
index adcc46e5..72b5af08 100644
--- a/src/ng/directive/ngInclude.js
+++ b/src/ng/directive/ngInclude.js
@@ -8,9 +8,20 @@
* @description
* Fetches, compiles and includes an external HTML fragment.
*
- * Keep in mind that Same Origin Policy applies to included resources
- * (e.g. ngInclude won't work for cross-domain requests on all browsers and for
- * file:// access on some browsers).
+ * Keep in mind that:
+ *
+ * - by default, the template URL is restricted to the same domain and protocol as the
+ * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
+ * $sce.getTrustedResourceUrl} on it. To load templates from other domains and/or protocols,
+ * you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
+ * {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value. Refer Angular's {@link
+ * ng.$sce Strict Contextual Escaping}.
+ * - in addition, the browser's
+ * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
+ * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing
+ * (CORS)} policy apply that may further restrict whether the template is successfully loaded.
+ * (e.g. ngInclude won't work for cross-domain requests on all browsers and for `file://`
+ * access on some browsers)
*
* Additionally, you can also provide animations via the ngAnimate attribute to animate the **enter**
* and **leave** effects.
@@ -132,8 +143,8 @@
* @description
* Emitted every time the ngInclude content is reloaded.
*/
-var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animator',
- function($http, $templateCache, $anchorScroll, $compile, $animator) {
+var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animator', '$sce',
+ function($http, $templateCache, $anchorScroll, $compile, $animator, $sce) {
return {
restrict: 'ECA',
terminal: true,
@@ -155,7 +166,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
animate.leave(element.contents(), element);
};
- scope.$watch(srcExp, function ngIncludeWatchAction(src) {
+ scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
var thisChangeId = ++changeCounter;
if (src) {
diff --git a/src/ng/interpolate.js b/src/ng/interpolate.js
index 8e94fe24..ade5ce69 100644
--- a/src/ng/interpolate.js
+++ b/src/ng/interpolate.js
@@ -54,7 +54,7 @@ function $InterpolateProvider() {
};
- this.$get = ['$parse', '$exceptionHandler', function($parse, $exceptionHandler) {
+ this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
var startSymbolLength = startSymbol.length,
endSymbolLength = endSymbol.length;
@@ -64,6 +64,7 @@ function $InterpolateProvider() {
* @function
*
* @requires $parse
+ * @requires $sce
*
* @description
*
@@ -84,12 +85,10 @@ function $InterpolateProvider() {
* @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
* embedded expression in order to return an interpolation function. Strings with no
* embedded expression will return null for the interpolation function.
- * @param {boolean=} isTrustedContext when true, requires that the interpolation string does not
- * contain any concatenations - i.e. the interpolation string is a single expression.
- * Interpolations for *[src] and *[ng-src] (except IMG, since itwhich sanitizes its value)
- * pass true for this parameter. This helps avoid hunting through the template code to
- * figure out of some iframe[src], object[src], etc. was interpolated with a concatenation
- * that ended up introducing a XSS.
+ * @param {string=} trustedContext when provided, the returned function passes the interpolated
+ * result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
+ * trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that
+ * provides Strict Contextual Escaping for details.
* @returns {function(context)} an interpolation function which is used to compute the interpolated
* string. The function has these parameters:
*
@@ -97,7 +96,7 @@ function $InterpolateProvider() {
* against.
*
*/
- function $interpolate(text, mustHaveExpression, isTrustedContext) {
+ function $interpolate(text, mustHaveExpression, trustedContext) {
var startIndex,
endIndex,
index = 0,
@@ -135,10 +134,11 @@ function $InterpolateProvider() {
// is assigned or constructed by some JS code somewhere that is more testable or make it
// obvious that you bound the value to some user controlled value. This helps reduce the load
// when auditing for XSS issues.
- if (isTrustedContext && parts.length > 1) {
+ if (trustedContext && parts.length > 1) {
throw $interpolateMinErr('noconcat',
- "Error while interpolating: {0}\nYou may not use multiple expressions when " +
- "interpolating this expression.", text);
+ "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
+ "interpolations that concatenate multiple expressions when a trusted value is " +
+ "required. See http://docs.angularjs.org/api/ng.$sce", text);
}
if (!mustHaveExpression || hasInterpolation) {
@@ -148,6 +148,11 @@ function $InterpolateProvider() {
for(var i = 0, ii = length, part; i<ii; i++) {
if (typeof (part = parts[i]) == 'function') {
part = part(context);
+ if (trustedContext) {
+ part = $sce.getTrusted(trustedContext, part);
+ } else {
+ part = $sce.valueOf(part);
+ }
if (part == null || part == undefined) {
part = '';
} else if (typeof part != 'string') {
diff --git a/src/ng/sce.js b/src/ng/sce.js
new file mode 100644
index 00000000..ab3d2208
--- /dev/null
+++ b/src/ng/sce.js
@@ -0,0 +1,959 @@
+'use strict';
+
+var $sceMinErr = minErr('$sce');
+
+var SCE_CONTEXTS = {
+ HTML: 'html',
+ CSS: 'css',
+ URL: 'url',
+ // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
+ // url. (e.g. ng-include, script src, templateUrl)
+ RESOURCE_URL: 'resourceUrl',
+ JS: 'js'
+};
+
+
+/**
+ * @ngdoc service
+ * @name ng.$sceDelegate
+ * @function
+ *
+ * @description
+ *
+ * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
+ * Contextual Escaping (SCE)} services to AngularJS.
+ *
+ * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
+ * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is
+ * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
+ * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
+ * work because `$sce` delegates to `$sceDelegate` for these operations.
+ *
+ * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
+ *
+ * The default instance of `$sceDelegate` should work out of the box with little pain. While you
+ * can override it completely to change the behavior of `$sce`, the common case would
+ * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
+ * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
+ * templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
+ * $sceDelegateProvider.resourceUrlWhitelist} and {@link
+ * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
+ */
+
+/**
+ * @ngdoc object
+ * @name ng.$sceDelegateProvider
+ * @description
+ *
+ * The $sceDelegateProvider provider allows developers to configure the {@link ng.$sceDelegate
+ * $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure
+ * that URLs used for sourcing Angular templates are safe. Refer {@link
+ * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
+ * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
+ *
+ * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
+ */
+
+function $SceDelegateProvider() {
+ this.SCE_CONTEXTS = SCE_CONTEXTS;
+
+ // Resource URLs can also be trusted by policy.
+ var resourceUrlWhitelist = ['self'],
+ resourceUrlBlacklist = [];
+
+ /**
+ * @ngdoc function
+ * @name ng.sceDelegateProvider#resourceUrlWhitelist
+ * @methodOf ng.$sceDelegateProvider
+ * @function
+ *
+ * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
+ * provided. This must be an array.
+ *
+ * Each element of this array must either be a regex or the special string `'self'`.
+ *
+ * When a regex is used, it is matched against the normalized / absolute URL of the resource
+ * being tested.
+ *
+ * The **special string** `'self'` can be used to match against all URLs of the same domain as the
+ * application document with the same protocol (allows sourcing https resources from http documents.)
+ *
+ * Please note that **an empty whitelist array will block all URLs**!
+ *
+ * @return {Array} the currently set whitelist array.
+ *
+ * The **default value** when no whitelist has been explicitly set is `['self']`.
+ *
+ * @description
+ * Sets/Gets the whitelist of trusted resource URLs.
+ */
+ this.resourceUrlWhitelist = function (value) {
+ if (arguments.length) {
+ resourceUrlWhitelist = value;
+ }
+ return resourceUrlWhitelist;
+ };
+
+ /**
+ * @ngdoc function
+ * @name ng.sceDelegateProvider#resourceUrlBlacklist
+ * @methodOf ng.$sceDelegateProvider
+ * @function
+ *
+ * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
+ * provided. This must be an array.
+ *
+ * Each element of this array must either be a regex or the special string `'self'` (see
+ * `resourceUrlWhitelist` for meaning - it's only really useful there.)
+ *
+ * When a regex is used, it is matched against the normalized / absolute URL of the resource
+ * being tested.
+ *
+ * The typical usage for the blacklist is to **block [open redirects](http://cwe.mitre.org/data/definitions/601.html)**
+ * served by your domain as these would otherwise be trusted but actually return content from the redirected
+ * domain.
+ *
+ * Finally, **the blacklist overrides the whitelist** and has the final say.
+ *
+ * @return {Array} the currently set blacklist array.
+ *
+ * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there is
+ * no blacklist.)
+ *
+ * @description
+ * Sets/Gets the blacklist of trusted resource URLs.
+ */
+
+ this.resourceUrlBlacklist = function (value) {
+ if (arguments.length) {
+ resourceUrlBlacklist = value;
+ }
+ return resourceUrlBlacklist;
+ };
+
+ // Helper functions for matching resource urls by policy.
+ function isCompatibleProtocol(documentProtocol, resourceProtocol) {
+ return ((documentProtocol === resourceProtocol) ||
+ (documentProtocol === "http:" && resourceProtocol === "https:"));
+ }
+
+ this.$get = ['$log', '$document', '$$urlUtils', function(
+ $log, $document, $$urlUtils) {
+
+ function matchUrl(matcher, parsedUrl) {
+ if (matcher === 'self') {
+ return $$urlUtils.isSameOrigin(parsedUrl);
+ } else {
+ return !!parsedUrl.href.match(matcher);
+ }
+ }
+
+ function isResourceUrlAllowedByPolicy(url) {
+ var parsedUrl = $$urlUtils.resolve(url.toString(), true);
+ var i, n, allowed = false;
+ // Ensure that at least one item from the whitelist allows this url.
+ for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
+ if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
+ allowed = true;
+ break;
+ }
+ }
+ if (allowed) {
+ // Ensure that no item from the blacklist blocked this url.
+ for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
+ if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
+ allowed = false;
+ break;
+ }
+ }
+ }
+ return allowed;
+ }
+
+ function generateHolderType(base) {
+ var holderType = function TrustedValueHolderType(trustedValue) {
+ this.$$unwrapTrustedValue = function() {
+ return trustedValue;
+ };
+ };
+ if (base) {
+ holderType.prototype = new base();
+ }
+ holderType.prototype.valueOf = function sceValueOf() {
+ return this.$$unwrapTrustedValue();
+ }
+ holderType.prototype.toString = function sceToString() {
+ return this.$$unwrapTrustedValue().toString();
+ }
+ return holderType;
+ }
+
+ var trustedValueHolderBase = generateHolderType(),
+ byType = {};
+
+ byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
+ byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
+ byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
+ byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
+ byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
+
+ /**
+ * @ngdoc method
+ * @name ng.$sceDelegate#trustAs
+ * @methodOf ng.$sceDelegate
+ *
+ * @description
+ * Returns an object that is trusted by angular for use in specified strict
+ * contextual escaping contexts (such as ng-html-bind-unsafe, ng-include, any src
+ * attribute interpolation, any dom event binding attribute interpolation
+ * such as for onclick, etc.) that uses the provided value.
+ * See {@link ng.$sce $sce} for enabling strict contextual escaping.
+ *
+ * @param {string} type The kind of context in which this value is safe for use. e.g. url,
+ * resourceUrl, html, js and css.
+ * @param {*} value The value that that should be considered trusted/safe.
+ * @returns {*} A value that can be used to stand in for the provided `value` in places
+ * where Angular expects a $sce.trustAs() return value.
+ */
+ function trustAs(type, trustedValue) {
+ var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
+ if (!constructor) {
+ throw $sceMinErr('icontext', 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
+ type, trustedValue);
+ }
+ if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
+ return trustedValue;
+ }
+ // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting
+ // mutable objects, we ensure here that the value passed in is actually a string.
+ if (typeof trustedValue !== 'string') {
+ throw $sceMinErr('itype',
+ 'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
+ type);
+ }
+ return new constructor(trustedValue);
+ }
+
+ /**
+ * @ngdoc method
+ * @name ng.$sceDelegate#valueOf
+ * @methodOf ng.$sceDelegate
+ *
+ * @description
+ * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
+ * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
+ * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
+ *
+ * If the passed parameter is not a value that had been returned by {@link
+ * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
+ *
+ * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
+ * call or anything else.
+ * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
+ * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns `value`
+ * unchanged.
+ */
+ function valueOf(maybeTrusted) {
+ if (maybeTrusted instanceof trustedValueHolderBase) {
+ return maybeTrusted.$$unwrapTrustedValue();
+ } else {
+ return maybeTrusted;
+ }
+ }
+
+ /**
+ * @ngdoc method
+ * @name ng.$sceDelegate#getTrusted
+ * @methodOf ng.$sceDelegate
+ *
+ * @description
+ * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and returns the
+ * originally supplied value if the queried context type is a supertype of the created type. If
+ * this condition isn't satisfied, throws an exception.
+ *
+ * @param {string} type The kind of context in which this value is to be used.
+ * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
+ * `$sceDelegate.trustAs`} call.
+ * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
+ * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception.
+ */
+ function getTrusted(type, maybeTrusted) {
+ if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
+ return maybeTrusted;
+ }
+ var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
+ if (constructor && maybeTrusted instanceof constructor) {
+ return maybeTrusted.$$unwrapTrustedValue();
+ }
+ if (type === SCE_CONTEXTS.RESOURCE_URL) {
+ if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
+ return maybeTrusted;
+ } else {
+ throw $sceMinErr('isecrurl',
+ 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}', maybeTrusted.toString());
+ return;
+ }
+ }
+ throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
+ }
+
+ return { trustAs: trustAs,
+ getTrusted: getTrusted,
+ valueOf: valueOf };
+ }];
+}
+
+
+/**
+ * @ngdoc object
+ * @name ng.$sceProvider
+ * @description
+ *
+ * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
+ * - enable/disable Strict Contextual Escaping (SCE) in a module
+ * - override the default implementation with a custom delegate
+ *
+ * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
+ */
+
+/**
+ * @ngdoc service
+ * @name ng.$sce
+ * @function
+ *
+ * @description
+ *
+ * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
+ *
+ * # Strict Contextual Escaping
+ *
+ * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
+ * contexts to result in a value that is marked as safe to use for that context One example of such
+ * a context is binding arbitrary html controlled by the user via `ng-bind-html-unsafe`. We refer
+ * to these contexts as privileged or SCE contexts.
+ *
+ * As of version 1.2, Angular ships with SCE enabled by default.
+ *
+ * Note: When enabled (the default), IE8 in quirks mode is not supported. In this mode, IE8 allows
+ * one to execute arbitrary javascript by the use of the expression() syntax. Refer
+ * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
+ * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
+ * to the top of your HTML document.
+ *
+ * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
+ * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
+ *
+ * Here's an example of a binding in a privileged context:
+ *
+ * <pre class="prettyprint">
+ * <input ng-model="userHtml">
+ * <div ng-bind-html-unsafe="{{userHtml}}">
+ * </pre>
+ *
+ * Notice that `ng-bind-html-unsafe` is bound to `{{userHtml}}` controlled by the user. With SCE
+ * disabled, this application allows the user to render arbitrary HTML into the DIV.
+ * In a more realistic example, one may be rendering user comments, blog articles, etc. via
+ * bindings. (HTML is just one example of a context where rendering user controlled input creates
+ * security vulnerabilities.)
+ *
+ * For the case of HTML, you might use a library, either on the client side, or on the server side,
+ * to sanitize unsafe HTML before binding to the value and rendering it in the document.
+ *
+ * How would you ensure that every place that used these types of bindings was bound to a value that
+ * was sanitized by your library (or returned as safe for rendering by your server?) How can you
+ * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
+ * properties/fields and forgot to update the binding to the sanitized value?
+ *
+ * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
+ * determine that something explicitly says it's safe to use a value for binding in that
+ * context. You can then audit your code (a simple grep would do) to ensure that this is only done
+ * for those values that you can easily tell are safe - because they were received from your server,
+ * sanitized by your library, etc. You can organize your codebase to help with this - perhaps
+ * allowing only the files in a specific directory to do this. Ensuring that the internal API
+ * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
+ *
+ * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} (and shorthand
+ * methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to obtain values that will be
+ * accepted by SCE / privileged contexts.
+ *
+ *
+ * ## How does it work?
+ *
+ * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
+ * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link
+ * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
+ * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
+ *
+ * As an example, {@link ng.directive:ngBindHtmlUnsafe ngBindHtmlUnsafe} uses {@link
+ * ng.$sce#parseHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly
+ * simplified):
+ *
+ * <pre class="prettyprint">
+ * var ngBindHtmlUnsafeDirective = ['$sce', function($sce) {
+ * return function(scope, element, attr) {
+ * scope.$watch($sce.parseAsHtml(attr.ngBindHtmlUnsafe), function(value) {
+ * element.html(value || '');
+ * });
+ * };
+ * }];
+ * </pre>
+ *
+ * ## Impact on loading templates
+ *
+ * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
+ * `templateUrl`'s specified by {@link guide/directive directives}.
+ *
+ * By default, Angular only loads templates from the same domain and protocol as the application
+ * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
+ * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or
+ * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
+ * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
+ *
+ * *Please note*:
+ * The browser's
+ * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
+ * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)}
+ * policy apply in addition to this and may further restrict whether the template is successfully
+ * loaded. This means that without the right CORS policy, loading templates from a different domain
+ * won't work on all browsers. Also, loading templates from `file://` URL does not work on some
+ * browsers.
+ *
+ * ## This feels like too much overhead for the developer?
+ *
+ * It's important to remember that SCE only applies to interpolation expressions.
+ *
+ * If your expressions are constant literals, they're automatically trusted and you don't need to
+ * call `$sce.trustAs` on them. (e.g.
+ * `<div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div>`) just works.
+ *
+ * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
+ * through {@link ng.$sce#getTrusted $sce.getTrusted}. SCE doesn't play a role here.
+ *
+ * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
+ * templates in `ng-include` from your application's domain without having to even know about SCE.
+ * It blocks loading templates from other domains or loading templates over http from an https
+ * served document. You can change these by setting your own custom {@link
+ * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
+ * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
+ *
+ * This significantly reduces the overhead. It is far easier to pay the small overhead and have an
+ * application that's secure and can be audited to verify that with much more ease than bolting
+ * security onto an application later.
+ *
+ * ## What trusted context types are supported?<a name="contexts"></a>
+ *
+ * | Context | Notes |
+ * |=====================|================|
+ * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtmlUnsafe ngBindHtmlUnsafe} directive uses this context for bindings. |
+ * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. |
+ * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`<a href=` and `<img src=` sanitize their urls and don't consititute an SCE context. |
+ * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contens are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
+ * | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. |
+ *
+ * ## Show me an example.
+ *
+ *
+ *
+ * @example
+ <example module="mySceApp">
+ <file name="index.html">
+ <div ng-controller="myAppController as myCtrl">
+ <button ng-click="myCtrl.fetchUserComments()" id="fetchBtn">Fetch Comments</button>
+ <div ng-show="myCtrl.errorMsg">Error: {{myCtrl.errorMsg}}</div>
+ <div ng-repeat="userComment in myCtrl.userComments">
+ <hr>
+ <b>{{userComment.name}}</b>:
+ <span ng-bind-html-unsafe="userComment.htmlComment" class="htmlComment"></span>
+ </div>
+ <div ng-bind-html-unsafe="myCtrl.someHtml" id="someHtml"></div>
+ </div>
+ </file>
+
+ <file name="script.js">
+ // These types of functions would be in the data access layer of your application code.
+ function fetchUserCommentsFromServer($http, $q, $templateCache, $sce) {
+ var deferred = $q.defer();
+ $http({method: "GET", url: "test_data.json", cache: $templateCache}).
+ success(function(userComments, status) {
+ // The comments coming from the server have been sanitized by the server and can be
+ // trusted.
+ angular.forEach(userComments, function(userComment) {
+ userComment.htmlComment = $sce.trustAsHtml(userComment.htmlComment);
+ });
+ deferred.resolve(userComments);
+ }).
+ error(function (data, status) {
+ deferred.reject("HTTP status code " + status + ": " + data);
+ });
+ return deferred.promise;
+ };
+
+ var mySceApp = angular.module('mySceApp', []);
+
+ mySceApp.controller("myAppController", function myAppController($injector) {
+ var self = this;
+
+ self.someHtml = "This might have been any binding including an input element " +
+ "controlled by the user.";
+
+ self.fetchUserComments = function() {
+ $injector.invoke(fetchUserCommentsFromServer).then(
+ function onSuccess(userComments) {
+ self.errorMsg = null;
+ self.userComments = userComments;
+ },
+ function onFailure(errorMsg) {
+ self.errorMsg = errorMsg;
+ });
+ }
+ });
+ </file>
+
+ <file name="test_data.json">
+ [
+ { "name": "Alice",
+ "htmlComment": "Is <i>anyone</i> reading this?"
+ },
+ { "name": "Bob",
+ "htmlComment": "<i>Yes!</i> Am I the only other one?"
+ }
+ ]
+ </file>
+
+ <file name="scenario.js">
+ describe('SCE doc demo', function() {
+ it('should bind trusted values', function() {
+ element('#fetchBtn').click();
+ expect(element('.htmlComment').html()).toBe('Is <i>anyone</i> reading this?');
+ });
+ it('should NOT bind arbitrary values', function() {
+ expect(element('#someHtml').html()).toBe('');
+ });
+ });
+ </file>
+ </example>
+ *
+ *
+ *
+ * ## Can I disable SCE completely?
+ *
+ * Yes, you can. However, this is strongly discouraged. SCE gives you a lot of security benefits
+ * for little coding overhead. It will be much harder to take an SCE disabled application and
+ * either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE
+ * for cases where you have a lot of existing code that was written before SCE was introduced and
+ * you're migrating them a module at a time.
+ *
+ * That said, here's how you can completely disable SCE:
+ *
+ * <pre class="prettyprint">
+ * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
+ * // Completely disable SCE. For demonstration purposes only!
+ * // Do not use in new projects.
+ * $sceProvider.enabled(false);
+ * });
+ * </pre>
+ *
+ */
+
+function $SceProvider() {
+ var enabled = true;
+
+ /**
+ * @ngdoc function
+ * @name ng.sceProvider#enabled
+ * @methodOf ng.$sceProvider
+ * @function
+ *
+ * @param {boolean=} value If provided, then enables/disables SCE.
+ * @return {boolean} true if SCE is enabled, false otherwise.
+ *
+ * @description
+ * Enables/disables SCE and returns the current value.
+ */
+ this.enabled = function (value) {
+ if (arguments.length) {
+ enabled = !!value;
+ }
+ return enabled;
+ };
+
+
+ /* Design notes on the default implementation for SCE.
+ *
+ * The API contract for the SCE delegate
+ * -------------------------------------
+ * The SCE delegate object must provide the following 3 methods:
+ *
+ * - trustAs(contextEnum, value)
+ * This method is used to tell the SCE service that the provided value is OK to use in the
+ * contexts specified by contextEnum. It must return an object that will be accepted by
+ * getTrusted() for a compatible contextEnum and return this value.
+ *
+ * - valueOf(value)
+ * For values that were not produced by trustAs(), return them as is. For values that were
+ * produced by trustAs(), return the corresponding input value to trustAs. Basically, if
+ * trustAs is wrapping the given values into some type, this operation unwraps it when given
+ * such a value.
+ *
+ * - getTrusted(contextEnum, value)
+ * This function should return the a value that is safe to use in the context specified by
+ * contextEnum or throw and exception otherwise.
+ *
+ * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be opaque
+ * or wrapped in some holder object. That happens to be an implementation detail. For instance,
+ * an implementation could maintain a registry of all trusted objects by context. In such a case,
+ * trustAs() would return the same object that was passed in. getTrusted() would return the same
+ * object passed in if it was found in the registry under a compatible context or throw an
+ * exception otherwise. An implementation might only wrap values some of the time based on
+ * some criteria. getTrusted() might return a value and not throw an exception for special
+ * constants or objects even if not wrapped. All such implementations fulfill this contract.
+ *
+ *
+ * A note on the inheritance model for SCE contexts
+ * ------------------------------------------------
+ * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types. This
+ * is purely an implementation details.
+ *
+ * The contract is simply this:
+ *
+ * getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
+ * will also succeed.
+ *
+ * Inheritance happens to capture this in a natural way. In some future, we
+ * may not use inheritance anymore. That is OK because no code outside of
+ * sce.js and sceSpecs.js would need to be aware of this detail.
+ */
+
+ this.$get = ['$parse', '$document', '$sceDelegate', function(
+ $parse, $document, $sceDelegate) {
+ // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows
+ // the "expression(javascript expression)" syntax which is insecure.
+ if (enabled && msie) {
+ var documentMode = $document[0].documentMode;
+ if (documentMode !== undefined && documentMode < 8) {
+ throw $sceMinErr('iequirks',
+ 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
+ 'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
+ 'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
+ }
+ }
+
+ var sce = copy(SCE_CONTEXTS);
+
+ /**
+ * @ngdoc function
+ * @name ng.sce#isEnabled
+ * @methodOf ng.$sce
+ * @function
+ *
+ * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you
+ * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
+ *
+ * @description
+ * Returns a boolean indicating if SCE is enabled.
+ */
+ sce.isEnabled = function () {
+ return enabled;
+ };
+ sce.trustAs = $sceDelegate.trustAs;
+ sce.getTrusted = $sceDelegate.getTrusted;
+ sce.valueOf = $sceDelegate.valueOf;
+
+ if (!enabled) {
+ sce.trustAs = sce.getTrusted = function(type, value) { return value; },
+ sce.valueOf = identity
+ }
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#parse
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Converts Angular {@link guide/expression expression} into a function. This is like {@link
+ * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it
+ * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
+ * *result*)}
+ *
+ * @param {string} type The kind of SCE context in which this result will be used.
+ * @param {string} expression String expression to compile.
+ * @returns {function(context, locals)} a function which represents the compiled expression:
+ *
+ * * `context` – `{object}` – an object against which any expressions embedded in the strings
+ * are evaluated against (typically a scope object).
+ * * `locals` – `{object=}` – local variables context object, useful for overriding values in
+ * `context`.
+ */
+ sce.parseAs = function sceParseAs(type, expr) {
+ var parsed = $parse(expr);
+ if (parsed.literal && parsed.constant) {
+ return parsed;
+ } else {
+ return function sceParseAsTrusted(self, locals) {
+ return sce.getTrusted(type, parsed(self, locals));
+ }
+ }
+ };
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#trustAs
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, returns an object
+ * that is trusted by angular for use in specified strict contextual escaping contexts (such as
+ * ng-html-bind-unsafe, ng-include, any src attribute interpolation, any dom event binding
+ * attribute interpolation such as for onclick, etc.) that uses the provided value. See *
+ * {@link ng.$sce $sce} for enabling strict contextual escaping.
+ *
+ * @param {string} type The kind of context in which this value is safe for use. e.g. url,
+ * resource_url, html, js and css.
+ * @param {*} value The value that that should be considered trusted/safe.
+ * @returns {*} A value that can be used to stand in for the provided `value` in places
+ * where Angular expects a $sce.trustAs() return value.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#trustAsHtml
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.trustAsHtml(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
+ *
+ * @param {*} value The value to trustAs.
+ * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
+ * $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives
+ * only accept expressions that are either literal constants or are the
+ * return value of {@link ng.$sce#trustAs $sce.trustAs}.)
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#trustAsUrl
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.trustAsUrl(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
+ *
+ * @param {*} value The value to trustAs.
+ * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
+ * $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives
+ * only accept expressions that are either literal constants or are the
+ * return value of {@link ng.$sce#trustAs $sce.trustAs}.)
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#trustAsResourceUrl
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.trustAsResourceUrl(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
+ *
+ * @param {*} value The value to trustAs.
+ * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
+ * $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives
+ * only accept expressions that are either literal constants or are the return
+ * value of {@link ng.$sce#trustAs $sce.trustAs}.)
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#trustAsJs
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.trustAsJs(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
+ *
+ * @param {*} value The value to trustAs.
+ * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
+ * $sce.getTrustedJs(value)} to obtain the original value. (privileged directives
+ * only accept expressions that are either literal constants or are the
+ * return value of {@link ng.$sce#trustAs $sce.trustAs}.)
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#getTrusted
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such, takes
+ * the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the originally supplied
+ * value if the queried context type is a supertype of the created type. If this condition
+ * isn't satisfied, throws an exception.
+ *
+ * @param {string} type The kind of context in which this value is to be used.
+ * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`} call.
+ * @returns {*} The value the was originally provided to {@link ng.$sce#trustAs `$sce.trustAs`} if
+ * valid in this context. Otherwise, throws an exception.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#getTrustedHtml
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.getTrustedHtml(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
+ *
+ * @param {*} value The value to pass to `$sce.getTrusted`.
+ * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#getTrustedCss
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.getTrustedCss(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
+ *
+ * @param {*} value The value to pass to `$sce.getTrusted`.
+ * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#getTrustedUrl
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.getTrustedUrl(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
+ *
+ * @param {*} value The value to pass to `$sce.getTrusted`.
+ * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#getTrustedResourceUrl
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.getTrustedResourceUrl(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
+ *
+ * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
+ * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#getTrustedJs
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.getTrustedJs(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
+ *
+ * @param {*} value The value to pass to `$sce.getTrusted`.
+ * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#parseAsHtml
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.parseAsHtml(expression string)` → {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
+ *
+ * @param {string} expression String expression to compile.
+ * @returns {function(context, locals)} a function which represents the compiled expression:
+ *
+ * * `context` – `{object}` – an object against which any expressions embedded in the strings
+ * are evaluated against (typically a scope object).
+ * * `locals` – `{object=}` – local variables context object, useful for overriding values in
+ * `context`.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#parseAsCss
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.parseAsCss(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
+ *
+ * @param {string} expression String expression to compile.
+ * @returns {function(context, locals)} a function which represents the compiled expression:
+ *
+ * * `context` – `{object}` – an object against which any expressions embedded in the strings
+ * are evaluated against (typically a scope object).
+ * * `locals` – `{object=}` – local variables context object, useful for overriding values in
+ * `context`.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#parseAsUrl
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.parseAsUrl(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
+ *
+ * @param {string} expression String expression to compile.
+ * @returns {function(context, locals)} a function which represents the compiled expression:
+ *
+ * * `context` – `{object}` – an object against which any expressions embedded in the strings
+ * are evaluated against (typically a scope object).
+ * * `locals` – `{object=}` – local variables context object, useful for overriding values in
+ * `context`.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#parseAsResourceUrl
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.parseAsResourceUrl(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
+ *
+ * @param {string} expression String expression to compile.
+ * @returns {function(context, locals)} a function which represents the compiled expression:
+ *
+ * * `context` – `{object}` – an object against which any expressions embedded in the strings
+ * are evaluated against (typically a scope object).
+ * * `locals` – `{object=}` – local variables context object, useful for overriding values in
+ * `context`.
+ */
+
+ /**
+ * @ngdoc method
+ * @name ng.$sce#parseAsJs
+ * @methodOf ng.$sce
+ *
+ * @description
+ * Shorthand method. `$sce.parseAsJs(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
+ *
+ * @param {string} expression String expression to compile.
+ * @returns {function(context, locals)} a function which represents the compiled expression:
+ *
+ * * `context` – `{object}` – an object against which any expressions embedded in the strings
+ * are evaluated against (typically a scope object).
+ * * `locals` – `{object=}` – local variables context object, useful for overriding values in
+ * `context`.
+ */
+
+ // Shorthand delegations.
+ var parse = sce.parseAs,
+ getTrusted = sce.getTrusted,
+ trustAs = sce.trustAs;
+
+ angular.forEach(SCE_CONTEXTS, function (enumValue, name) {
+ var lName = lowercase(name);
+ sce[camelCase("parse_as_" + lName)] = function (expr) {
+ return parse(enumValue, expr);
+ }
+ sce[camelCase("get_trusted_" + lName)] = function (value) {
+ return getTrusted(enumValue, value);
+ }
+ sce[camelCase("trust_as_" + lName)] = function (value) {
+ return trustAs(enumValue, value);
+ }
+ });
+
+ return sce;
+ }];
+}
diff --git a/src/ng/urlUtils.js b/src/ng/urlUtils.js
index 5402b500..af2d913f 100644
--- a/src/ng/urlUtils.js
+++ b/src/ng/urlUtils.js
@@ -105,11 +105,12 @@ function $$UrlUtilsProvider() {
/**
* Parse a request URL and determine whether this is a same-origin request as the application document.
*
- * @param {string} requestUrl The url of the request.
+ * @param {string|object} requestUrl The url of the request as a string that will be resolved
+ * or a parsed URL object.
* @returns {boolean} Whether the request is for the same origin as the application document.
*/
isSameOrigin: function isSameOrigin(requestUrl) {
- var parsed = resolve(requestUrl, true);
+ var parsed = (typeof requestUrl === 'string') ? resolve(requestUrl, true) : requestUrl;
return (parsed.protocol === originUrl.protocol &&
parsed.host === originUrl.host);
}
diff --git a/src/ngRoute/route.js b/src/ngRoute/route.js
index de0d9016..743897d6 100644
--- a/src/ngRoute/route.js
+++ b/src/ngRoute/route.js
@@ -56,9 +56,9 @@ function $RouteProvider(){
* if passed as a string.
* - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
* published to scope under the `controllerAs` name.
- * - `template` – `{string=|function()=}` – html template as a string or function that returns
- * an html template as a string which should be used by {@link ngRoute.directive:ngView ngView} or
- * {@link ng.directive:ngInclude ngInclude} directives.
+ * - `template` – `{string=|function()=}` – html template as a string or a function that
+ * returns an html template as a string which should be used by {@link
+ * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
* This property takes precedence over `templateUrl`.
*
* If `template` is a function, it will be called with the following parameters:
@@ -149,8 +149,8 @@ function $RouteProvider(){
};
- this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$http', '$templateCache',
- function( $rootScope, $location, $routeParams, $q, $injector, $http, $templateCache) {
+ this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$http', '$templateCache', '$sce',
+ function( $rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
/**
* @ngdoc object
@@ -437,7 +437,7 @@ function $RouteProvider(){
then(function() {
if (next) {
var locals = extend({}, next.resolve),
- template;
+ template, templateUrl;
forEach(locals, function(value, key) {
locals[key] = isString(value) ? $injector.get(value) : $injector.invoke(value);
@@ -447,13 +447,14 @@ function $RouteProvider(){
if (isFunction(template)) {
template = template(next.params);
}
- } else if (isDefined(template = next.templateUrl)) {
- if (isFunction(template)) {
- template = template(next.params);
+ } else if (isDefined(templateUrl = next.templateUrl)) {
+ if (isFunction(templateUrl)) {
+ templateUrl = templateUrl(next.params);
}
- if (isDefined(template)) {
- next.loadedTemplateUrl = template;
- template = $http.get(template, {cache: $templateCache}).
+ templateUrl = $sce.getTrustedResourceUrl(templateUrl);
+ if (isDefined(templateUrl)) {
+ next.loadedTemplateUrl = templateUrl;
+ template = $http.get(templateUrl, {cache: $templateCache}).
then(function(response) { return response.data; });
}
}
diff --git a/src/ngSanitize/sanitize.js b/src/ngSanitize/sanitize.js
index 049a6821..110b3a64 100644
--- a/src/ngSanitize/sanitize.js
+++ b/src/ngSanitize/sanitize.js
@@ -63,11 +63,15 @@ var ngSanitizeMinErr = angular.$$minErr('ngSanitize');
<doc:example module="ngSanitize">
<doc:source>
<script>
- function Ctrl($scope) {
+ function Ctrl($scope, $sce) {
$scope.snippet =
'<p style="color:blue">an html\n' +
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
'snippet</p>';
+ // ng-bind-html-unsafe requires a $sce trusted value of type $sce.HTML.
+ $scope.getSceSnippet = function() {
+ return $sce.trustAsHtml($scope.snippet);
+ };
}
</script>
<div ng-controller="Ctrl">
@@ -94,8 +98,8 @@ var ngSanitizeMinErr = angular.$$minErr('ngSanitize');
</tr>
<tr id="html-unsafe-filter">
<td>unsafe html filter</td>
- <td><pre>&lt;div ng-bind-html-unsafe="snippet"&gt;<br/>&lt;/div&gt;</pre></td>
- <td><div ng-bind-html-unsafe="snippet"></div></td>
+ <td><pre>&lt;div ng-bind-html-unsafe="getSceSnippet()"&gt;<br/>&lt;/div&gt;</pre></td>
+ <td><div ng-bind-html-unsafe="getSceSnippet()"></div></td>
</tr>
</table>
</div>
@@ -120,11 +124,11 @@ var ngSanitizeMinErr = angular.$$minErr('ngSanitize');
"snippet</p>");
});
- it('should update', function() {
+ it('should update', function($sce) {
input('snippet').enter('new <b>text</b>');
expect(using('#html-filter').binding('snippet')).toBe('new <b>text</b>');
expect(using('#escaped-html').element('div').html()).toBe("new &lt;b&gt;text&lt;/b&gt;");
- expect(using('#html-unsafe-filter').binding("snippet")).toBe('new <b>text</b>');
+ expect(using('#html-unsafe-filter').element('div').html()).toBe('new <b>text</b>');
});
</doc:scenario>
</doc:example>