diff --git a/src/ngSanitize/sanitize.js b/src/ngSanitize/sanitize.js index 89073037cc7a..f916e1b58455 100644 --- a/src/ngSanitize/sanitize.js +++ b/src/ngSanitize/sanitize.js @@ -40,16 +40,16 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); * @kind function * * @description - * The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are + * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are * then serialized back to properly escaped html string. This means that no unsafe input can make * it into the returned string, however, since our parser is more strict than a typical browser * 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. + * browser, won't make it through the sanitizer. The input may also contain SVG markup. * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}. * - * @param {string} html Html input. - * @returns {string} Sanitized html. + * @param {string} html HTML input. + * @returns {string} Sanitized HTML. * * @example @@ -193,6 +193,12 @@ var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + "samp,small,span,strike,strong,sub,sup,time,tt,u,var")); +// SVG Elements +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements +var svgElements = makeMap("animate,animateColor,animateMotion,animateTransform,circle,defs," + + "desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient," + + "line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,set," + + "stop,svg,switch,text,title,tspan,use"); // Special Elements (can contain anything) var specialElements = makeMap("script,style"); @@ -201,16 +207,41 @@ var validElements = angular.extend({}, voidElements, blockElements, inlineElements, - optionalEndTagElements); + optionalEndTagElements, + svgElements); //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( - 'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+ +var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xmlns:href"); + +var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+ 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+ 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+ 'scope,scrolling,shape,size,span,start,summary,target,title,type,'+ - 'valign,value,vspace,width')); + 'valign,value,vspace,width'); + +// SVG attributes (without "id" and "name" attributes) +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes +var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,'+ + 'attributeName,attributeType,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,'+ + 'color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,'+ + 'font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,'+ + 'gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,'+ + 'keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,'+ + 'markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,'+ + 'overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,'+ + 'repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,'+ + 'stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,'+ + 'stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,'+ + 'stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,'+ + 'underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,'+ + 'viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,'+ + 'xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,'+ + 'zoomAndPan'); + +var validAttrs = angular.extend({}, + uriAttrs, + svgAttrs, + htmlAttrs); function makeMap(str) { var obj = {}, items = str.split(','), i; diff --git a/test/ngSanitize/sanitizeSpec.js b/test/ngSanitize/sanitizeSpec.js index ca2dc4270e2c..cfbd23947b94 100644 --- a/test/ngSanitize/sanitizeSpec.js +++ b/test/ngSanitize/sanitizeSpec.js @@ -238,6 +238,16 @@ describe('HTML', function() { expectHTML(false).toBe('false'); }); + it('should accept SVG tags', function() { + expectHTML('') + .toEqual(''); + }); + + it('should sanitize SVG xmlns:xlink attribute values', function() { + expectHTML('') + .toEqual(''); + }); + describe('htmlSanitizerWriter', function() { /* global htmlSanitizeWriter: false */ if (angular.isUndefined(window.htmlSanitizeWriter)) return;