/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import {isDevMode} from '@angular/core'; import {DomAdapter, getDOM} from '../dom/dom_adapter'; import {DOCUMENT} from '../dom/dom_tokens'; import {sanitizeSrcset, 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. const templateEl = DOM.createElement('template'); if ('content' in templateEl) return templateEl; const 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. const 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} { const res: {[k: string]: boolean} = {}; for (const t of tags.split(',')) res[t] = true; return res; } function merge(...sets: {[k: string]: boolean}[]): {[k: string]: boolean} { const res: {[k: string]: boolean} = {}; for (const s of sets) { for (const 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,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' + 'h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul')); // Inline Elements - HTML5 const INLINE_ELEMENTS = merge( OPTIONAL_END_TAG_INLINE_ELEMENTS, tagSet( 'a,abbr,acronym,audio,b,' + 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,' + 'samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video')); 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,itemtype,longdesc,poster,src,xlink:href'); // Attributes that have special href set hence need to be sanitized const SRCSET_ATTRS = tagSet('srcset'); const HTML_ATTRS = tagSet( 'abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' + 'compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,' + 'ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,' + 'scope,scrolling,shape,size,sizes,span,srclang,start,summary,tabindex,target,title,translate,type,usemap,' + '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