Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

feat(ngSanitize): add $sanitizeExt factory #6252

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions src/ngSanitize/sanitize.js
Original file line number Diff line number Diff line change
@@ -46,7 +46,9 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
* parser, it's possible that some obscure input, which would be recognized as valid HTML by a
* browser, won't make it through the sanitizer.
* The whitelist is configured using the functions `aHrefSanitizationWhitelist` and
* `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}.
* `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}
* as well as the functions `addSafeElements` and `addSafeAttributes` of
* {@link ngSanitize.$sanitizeExt `$sanitizeExt`}.
*
* @param {string} html Html input.
* @returns {string} Sanitized html.
@@ -201,6 +203,12 @@ var validElements = angular.extend({},
inlineElements,
optionalEndTagElements);

//Unsupported elements:
// audio,base,body,button,canvas,command,data,datalist,details,dialog,embed,
// fieldset,form,head,html,iframe,input,keygen,legend,link,meta,meter,
// noscript,object,optgroup,option,output,param,progress,select,source,
// summary,textarea,title,track,video

//Attributes that have href and hence need to be sanitized
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
var validAttrs = angular.extend({}, uriAttrs, makeMap(
@@ -216,6 +224,43 @@ function makeMap(str) {
return obj;
}

/**
* @ngdoc object
* @name ngSanitize.$sanitizeExt
*
* @description
* Extends the safe token whitelists used by the {@link ngSanitize.$sanitize `$sanitize`} service.
*/
function $SanitizeExtFactory() {
return {
/**
* @ngdoc method
* @name ngSanitize.$sanitizeExt#addSafeElements
* @methodOf ngSanitize.$sanitizeExt
*
* @description
* Extends the default HTML element whitelist used during sanitization.
* @param {string} elements Comma-separated list of tag names to add to the whitelist.
*/
addSafeElements: function(elements) {
var map = makeMap(elements);
angular.extend(blockElements, map);
angular.extend(validElements, map);
},
/**
* @ngdoc method
* @name ngSanitize.$sanitizeExt#addSafeAttributes
* @methodOf ngSanitize.$sanitizeExt
*
* @description
* Extends the default attribute whitelist used during sanitization.
* @param {string} attrs Comma-separated list of attribute names to add to the whitelist.
*/
addSafeAttributes: function(attrs) {
angular.extend(validAttrs, makeMap(attrs));
}
};
}

/**
* @example
@@ -464,4 +509,6 @@ function htmlSanitizeWriter(buf, uriValidator){


// define ngSanitize module and register $sanitize service
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
angular.module('ngSanitize', [])
.provider('$sanitize', $SanitizeProvider)
.factory('$sanitizeExt', $SanitizeExtFactory);
21 changes: 21 additions & 0 deletions test/ngSanitize/sanitizeSpec.js
Original file line number Diff line number Diff line change
@@ -410,6 +410,27 @@ describe('HTML', function() {
expect(sanitizeText('a<div>&</div>c')).toEqual('a&lt;div&gt;&amp;&lt;/div&gt;c');
});
});

describe('sanitizeExt', function() {
beforeEach(function() {
var sanitizeExt;
inject(function($sanitizeExt) {
sanitizeExt = $sanitizeExt;
});
sanitizeExt.addSafeElements('audio,video,a:custom');
sanitizeExt.addSafeAttributes('autoplay,custom');
});

it('should extend valid tags', function() {
expectHTML('a<audio src="abc"></audio>c').toEqual('a<audio src="abc"></audio>c');
expectHTML('a<video src="abc"></video>c').toEqual('a<video src="abc"></video>c');
expectHTML('a<a:custom>b</a:custom>c').toEqual('a<a:custom>b</a:custom>c');
});
it('should extend valid attributes', function() {
expectHTML('a<div autoplay="true" custom="y" class="b" unknown="x"></div>c').toEqual('a<div autoplay="true" custom="y" class="b"></div>c');
});

});
});

describe('decodeEntities', function() {