import {isDevMode} from '@angular/core'; import {DomAdapter, getDOM} from '../dom/dom_adapter'; import {sanitizeUrl} from './url_sanitizer'; /** A
element that can be safely used to parse untrusted HTML. Lazily initialized below. */ let inertElement: HTMLElement = null; /** Lazily initialized to make sure the DOM adapter gets set before use. */ let DOM: DomAdapter = null; /** Returns an HTML element that is guaranteed to not execute code when creating elements in it. */ function getInertElement() { if (inertElement) return inertElement; DOM = getDOM(); // Prefer using element if supported. let templateEl = DOM.createElement('template'); if ('content' in templateEl) return templateEl; let doc = DOM.createHtmlDocument(); inertElement = DOM.querySelector(doc, 'body'); if (inertElement == null) { // usually there should be only one body element in the document, but IE doesn't have any, so we // need to create one. let html = DOM.createElement('html', doc); inertElement = DOM.createElement('body', doc); DOM.appendChild(html, inertElement); DOM.appendChild(doc, html); } return inertElement; } function tagSet(tags: string): {[k: string]: boolean} { let res: {[k: string]: boolean} = {}; for (let t of tags.split(',')) res[t.toLowerCase()] = true; return res; } function merge(...sets: {[k: string]: boolean}[]): {[k: string]: boolean} { let res: {[k: string]: boolean} = {}; for (let s of sets) { for (let v in s) { if (s.hasOwnProperty(v)) res[v] = true; } } return res; } // Good source of info about elements and attributes // http://dev.w3.org/html5/spec/Overview.html#semantics // http://simon.html5.org/html-elements // Safe Void Elements - HTML5 // http://dev.w3.org/html5/spec/Overview.html#void-elements const VOID_ELEMENTS = tagSet('area,br,col,hr,img,wbr'); // Elements that you can, intentionally, leave open (and which close themselves) // http://dev.w3.org/html5/spec/Overview.html#optional-tags const OPTIONAL_END_TAG_BLOCK_ELEMENTS = tagSet('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'); const OPTIONAL_END_TAG_INLINE_ELEMENTS = tagSet('rp,rt'); const OPTIONAL_END_TAG_ELEMENTS = merge(OPTIONAL_END_TAG_INLINE_ELEMENTS, OPTIONAL_END_TAG_BLOCK_ELEMENTS); // Safe Block Elements - HTML5 const BLOCK_ELEMENTS = merge( OPTIONAL_END_TAG_BLOCK_ELEMENTS, tagSet( 'address,article,' + 'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' + 'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul')); // Inline Elements - HTML5 const INLINE_ELEMENTS = merge( OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet( 'a,abbr,acronym,b,' + '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')); const VALID_ELEMENTS = merge(VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, OPTIONAL_END_TAG_ELEMENTS); // Attributes that have href and hence need to be sanitized const URI_ATTRS = tagSet('background,cite,href,longdesc,src,xlink:href'); const HTML_ATTRS = tagSet( '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,tabindex,target,title,type,' + 'valign,value,vspace,width'); // NB: This currently conciously doesn't support SVG. SVG sanitization has had several security // issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via // innerHTML is required, SVG attributes should be added here. // NB: Sanitization does not allow