dompurify 2.2.4 → 2.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  DOMPurify is a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG.
8
8
 
9
- It's also very simple to use and get started with. DOMPurify was [started in February 2014](https://github.com/cure53/DOMPurify/commit/a630922616927373485e0e787ab19e73e3691b2b) and, meanwhile, has reached version 2.2.4.
9
+ It's also very simple to use and get started with. DOMPurify was [started in February 2014](https://github.com/cure53/DOMPurify/commit/a630922616927373485e0e787ab19e73e3691b2b) and, meanwhile, has reached version 2.2.8.
10
10
 
11
11
  DOMPurify is written in JavaScript and works in all modern browsers (Safari (10+), Opera (15+), Internet Explorer (10+), Edge, Firefox and Chrome - as well as almost anything else using Blink or WebKit). It doesn't break on MSIE6 or other legacy browsers. It either uses [a fall-back](#what-about-older-browsers-like-msie8) or simply does nothing.
12
12
 
@@ -160,6 +160,8 @@ var clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b']});
160
160
  var clean = DOMPurify.sanitize(dirty, {ALLOWED_TAGS: ['b', 'q'], ALLOWED_ATTR: ['style']});
161
161
 
162
162
  // allow all safe HTML elements but neither SVG nor MathML
163
+ // note that the USE_PROFILES setting will override the ALLOWED_TAGS setting
164
+ // so don't use them together
163
165
  var clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {html: true}});
164
166
 
165
167
  // allow all safe SVG elements and SVG Filters, no HTML or MathML
@@ -168,6 +170,9 @@ var clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {svg: true, svgFilters: tru
168
170
  // allow all safe MathML elements and SVG, but no SVG Filters
169
171
  var clean = DOMPurify.sanitize(dirty, {USE_PROFILES: {mathMl: true, svg: true}});
170
172
 
173
+ // change the default namespace from HTML to something different
174
+ var clean = DOMPurify.sanitize(dirty, {NAMESPACE: 'http://www.w3.org/2000/svg'});
175
+
171
176
  // leave all safe HTML as it is and add <style> elements to block-list
172
177
  var clean = DOMPurify.sanitize(dirty, {FORBID_TAGS: ['style']});
173
178
 
@@ -332,7 +337,7 @@ Feature releases will not be announced to this list.
332
337
 
333
338
  Many people helped and help DOMPurify become what it is and need to be acknowledged here!
334
339
 
335
- [granlem 💸](https://twitter.com/MaximeVeit), [oreoshake 💸](https://github.com/oreoshake), [dcramer 💸](https://github.com/dcramer),[tdeekens ❤️](https://github.com/tdeekens), [peernohell ❤️](https://github.com/peernohell), [neilj](https://github.com/neilj), [fhemberger](https://github.com/fhemberger), [Joris-van-der-Wel](https://github.com/Joris-van-der-Wel), [ydaniv](https://github.com/ydaniv), [terjanq](https://twitter.com/terjanq), [filedescriptor](https://github.com/filedescriptor), [ConradIrwin](https://github.com/ConradIrwin), [gibson042](https://github.com/gibson042), [choumx](https://github.com/choumx), [0xSobky](https://github.com/0xSobky), [styfle](https://github.com/styfle), [koto](https://github.com/koto), [tlau88](https://github.com/tlau88), [strugee](https://github.com/strugee), [oparoz](https://github.com/oparoz), [mathiasbynens](https://github.com/mathiasbynens), [edg2s](https://github.com/edg2s), [dnkolegov](https://github.com/dnkolegov), [dhardtke](https://github.com/dhardtke), [wirehead](https://github.com/wirehead), [thorn0](https://github.com/thorn0), [styu](https://github.com/styu), [mozfreddyb](https://github.com/mozfreddyb), [mikesamuel](https://github.com/mikesamuel), [jorangreef](https://github.com/jorangreef), [jimmyhchan](https://github.com/jimmyhchan), [jameydeorio](https://github.com/jameydeorio), [jameskraus](https://github.com/jameskraus), [hyderali](https://github.com/hyderali), [hansottowirtz](https://github.com/hansottowirtz), [hackvertor](https://github.com/hackvertor), [freddyb](https://github.com/freddyb), [flavorjones](https://github.com/flavorjones), [djfarrelly](https://github.com/djfarrelly), [devd](https://github.com/devd), [camerondunford](https://github.com/camerondunford), [buu700](https://github.com/buu700), [buildog](https://github.com/buildog), [alabiaga](https://github.com/alabiaga), [Vector919](https://github.com/Vector919), [Robbert](https://github.com/Robbert), [GreLI](https://github.com/GreLI), [FuzzySockets](https://github.com/FuzzySockets), [ArtemBernatskyy](https://github.com/ArtemBernatskyy), [@garethheyes](https://twitter.com/garethheyes), [@shafigullin](https://twitter.com/shafigullin), [@mmrupp](https://twitter.com/mmrupp), [@irsdl](https://twitter.com/irsdl),[ShikariSenpai](https://github.com/ShikariSenpai), [ansjdnakjdnajkd](https://github.com/ansjdnakjdnajkd), [@asutherland](https://twitter.com/asutherland), [@mathias](https://twitter.com/mathias), [@cgvwzq](https://twitter.com/cgvwzq), [@robbertatwork](https://twitter.com/robbertatwork), [@giutro](https://twitter.com/giutro) and especially [@securitymb ❤️](https://twitter.com/securitymb) & [@masatokinugawa ❤️](https://twitter.com/masatokinugawa)
340
+ [granlem 💸](https://twitter.com/MaximeVeit), [oreoshake 💸](https://github.com/oreoshake), [dcramer 💸](https://github.com/dcramer),[tdeekens ❤️](https://github.com/tdeekens), [peernohell ❤️](https://github.com/peernohell), [neilj](https://github.com/neilj), [fhemberger](https://github.com/fhemberger), [Joris-van-der-Wel](https://github.com/Joris-van-der-Wel), [ydaniv](https://github.com/ydaniv), [terjanq](https://twitter.com/terjanq), [filedescriptor](https://github.com/filedescriptor), [ConradIrwin](https://github.com/ConradIrwin), [gibson042](https://github.com/gibson042), [choumx](https://github.com/choumx), [0xSobky](https://github.com/0xSobky), [styfle](https://github.com/styfle), [koto](https://github.com/koto), [tlau88](https://github.com/tlau88), [strugee](https://github.com/strugee), [oparoz](https://github.com/oparoz), [mathiasbynens](https://github.com/mathiasbynens), [edg2s](https://github.com/edg2s), [dnkolegov](https://github.com/dnkolegov), [dhardtke](https://github.com/dhardtke), [wirehead](https://github.com/wirehead), [thorn0](https://github.com/thorn0), [styu](https://github.com/styu), [mozfreddyb](https://github.com/mozfreddyb), [mikesamuel](https://github.com/mikesamuel), [jorangreef](https://github.com/jorangreef), [jimmyhchan](https://github.com/jimmyhchan), [jameydeorio](https://github.com/jameydeorio), [jameskraus](https://github.com/jameskraus), [hyderali](https://github.com/hyderali), [hansottowirtz](https://github.com/hansottowirtz), [hackvertor](https://github.com/hackvertor), [freddyb](https://github.com/freddyb), [flavorjones](https://github.com/flavorjones), [djfarrelly](https://github.com/djfarrelly), [devd](https://github.com/devd), [camerondunford](https://github.com/camerondunford), [buu700](https://github.com/buu700), [buildog](https://github.com/buildog), [alabiaga](https://github.com/alabiaga), [Vector919](https://github.com/Vector919), [Robbert](https://github.com/Robbert), [GreLI](https://github.com/GreLI), [FuzzySockets](https://github.com/FuzzySockets), [ArtemBernatskyy](https://github.com/ArtemBernatskyy), [@garethheyes](https://twitter.com/garethheyes), [@shafigullin](https://twitter.com/shafigullin), [@mmrupp](https://twitter.com/mmrupp), [@irsdl](https://twitter.com/irsdl),[ShikariSenpai](https://github.com/ShikariSenpai), [ansjdnakjdnajkd](https://github.com/ansjdnakjdnajkd), [@asutherland](https://twitter.com/asutherland), [@mathias](https://twitter.com/mathias), [@cgvwzq](https://twitter.com/cgvwzq), [@robbertatwork](https://twitter.com/robbertatwork), [@giutro](https://twitter.com/giutro), [@CmdEngineer_](https://twitter.com/CmdEngineer_), [@avr4mit](https://twitter.com/avr4mit) and especially [@securitymb ❤️](https://twitter.com/securitymb) & [@masatokinugawa ❤️](https://twitter.com/masatokinugawa)
336
341
 
337
342
  ## Testing powered by
338
343
  <a target="_blank" href="https://www.browserstack.com/"><img width="200" src="https://www.browserstack.com/images/layout/browserstack-logo-600x315.png"></a><br>
@@ -6,7 +6,9 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
6
6
 
7
7
  var hasOwnProperty = Object.hasOwnProperty,
8
8
  setPrototypeOf = Object.setPrototypeOf,
9
- isFrozen = Object.isFrozen;
9
+ isFrozen = Object.isFrozen,
10
+ getPrototypeOf = Object.getPrototypeOf,
11
+ getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
10
12
  var freeze = Object.freeze,
11
13
  seal = Object.seal,
12
14
  create = Object.create; // eslint-disable-line import/no-mutable-exports
@@ -117,18 +119,56 @@ function clone(object) {
117
119
  return newObject;
118
120
  }
119
121
 
122
+ /* IE10 doesn't support __lookupGetter__ so lets'
123
+ * simulate it. It also automatically checks
124
+ * if the prop is function or getter and behaves
125
+ * accordingly. */
126
+ function lookupGetter(object, prop) {
127
+ while (object !== null) {
128
+ var desc = getOwnPropertyDescriptor(object, prop);
129
+ if (desc) {
130
+ if (desc.get) {
131
+ return unapply(desc.get);
132
+ }
133
+
134
+ if (typeof desc.value === 'function') {
135
+ return unapply(desc.value);
136
+ }
137
+ }
138
+
139
+ object = getPrototypeOf(object);
140
+ }
141
+
142
+ function fallbackValue(element) {
143
+ console.warn('fallback value for', element);
144
+ return null;
145
+ }
146
+
147
+ return fallbackValue;
148
+ }
149
+
120
150
  var html = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
121
151
 
122
152
  // SVG
123
- var svg = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'audio', 'canvas', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'video', 'view', 'vkern']);
153
+ var svg = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
124
154
 
125
155
  var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
126
156
 
157
+ // List of SVG elements that are disallowed by default.
158
+ // We still need to know them so that we can do namespace
159
+ // checks properly in case one wants to add them to
160
+ // allow-list.
161
+ var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', 'feimage', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
162
+
127
163
  var mathMl = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']);
128
164
 
165
+ // Similarly to SVG, we want to know all MathML elements,
166
+ // even those that we disallow by default.
167
+ var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
168
+
129
169
  var text = freeze(['#text']);
130
170
 
131
- var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns']);
171
+ var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
132
172
 
133
173
  var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
134
174
 
@@ -205,7 +245,7 @@ function createDOMPurify() {
205
245
  * Version label, exposed for easier checks
206
246
  * if DOMPurify is up to date or not
207
247
  */
208
- DOMPurify.version = '2.2.4';
248
+ DOMPurify.version = '2.2.8';
209
249
 
210
250
  /**
211
251
  * Array of elements that DOMPurify removed during sanitation.
@@ -227,6 +267,7 @@ function createDOMPurify() {
227
267
  var DocumentFragment = window.DocumentFragment,
228
268
  HTMLTemplateElement = window.HTMLTemplateElement,
229
269
  Node = window.Node,
270
+ Element = window.Element,
230
271
  NodeFilter = window.NodeFilter,
231
272
  _window$NamedNodeMap = window.NamedNodeMap,
232
273
  NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
@@ -235,13 +276,20 @@ function createDOMPurify() {
235
276
  DOMParser = window.DOMParser,
236
277
  trustedTypes = window.trustedTypes;
237
278
 
279
+
280
+ var ElementPrototype = Element.prototype;
281
+
282
+ var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
283
+ var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
284
+ var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
285
+ var getParentNode = lookupGetter(ElementPrototype, 'parentNode');
286
+
238
287
  // As per issue #47, the web-components registry is inherited by a
239
288
  // new document created via createHTMLDocument. As per the spec
240
289
  // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
241
290
  // a new empty registry is used when creating a template contents owner
242
291
  // document, so we use that as our parent document to ensure nothing
243
292
  // is inherited.
244
-
245
293
  if (typeof HTMLTemplateElement === 'function') {
246
294
  var template = document.createElement('template');
247
295
  if (template.content && template.content.ownerDocument) {
@@ -255,7 +303,6 @@ function createDOMPurify() {
255
303
  var _document = document,
256
304
  implementation = _document.implementation,
257
305
  createNodeIterator = _document.createNodeIterator,
258
- getElementsByTagName = _document.getElementsByTagName,
259
306
  createDocumentFragment = _document.createDocumentFragment;
260
307
  var importNode = originalDocument.importNode;
261
308
 
@@ -270,7 +317,7 @@ function createDOMPurify() {
270
317
  /**
271
318
  * Expose whether this browser supports running the full DOMPurify.
272
319
  */
273
- DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
320
+ DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
274
321
 
275
322
  var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,
276
323
  ERB_EXPR$$1 = ERB_EXPR,
@@ -363,7 +410,7 @@ function createDOMPurify() {
363
410
  var USE_PROFILES = {};
364
411
 
365
412
  /* Tags to ignore content of when KEEP_CONTENT is true */
366
- var FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
413
+ var FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
367
414
 
368
415
  /* Tags that are safe for data: URIs */
369
416
  var DATA_URI_TAGS = null;
@@ -373,6 +420,12 @@ function createDOMPurify() {
373
420
  var URI_SAFE_ATTRIBUTES = null;
374
421
  var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
375
422
 
423
+ var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
424
+ var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
425
+ var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
426
+ /* Document namespace */
427
+ var NAMESPACE = HTML_NAMESPACE;
428
+
376
429
  /* Keep a reference to config to pass to hooks */
377
430
  var CONFIG = null;
378
431
 
@@ -422,6 +475,7 @@ function createDOMPurify() {
422
475
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
423
476
  IN_PLACE = cfg.IN_PLACE || false; // Default false
424
477
  IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
478
+ NAMESPACE = cfg.NAMESPACE || NAMESPACE;
425
479
  if (SAFE_FOR_TEMPLATES) {
426
480
  ALLOW_DATA_ATTR = false;
427
481
  }
@@ -504,6 +558,111 @@ function createDOMPurify() {
504
558
  CONFIG = cfg;
505
559
  };
506
560
 
561
+ var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
562
+
563
+ var HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
564
+
565
+ /* Keep track of all possible SVG and MathML tags
566
+ * so that we can perform the namespace checks
567
+ * correctly. */
568
+ var ALL_SVG_TAGS = addToSet({}, svg);
569
+ addToSet(ALL_SVG_TAGS, svgFilters);
570
+ addToSet(ALL_SVG_TAGS, svgDisallowed);
571
+
572
+ var ALL_MATHML_TAGS = addToSet({}, mathMl);
573
+ addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
574
+
575
+ /**
576
+ *
577
+ *
578
+ * @param {Element} element a DOM element whose namespace is being checked
579
+ * @returns {boolean} Return false if the element has a
580
+ * namespace that a spec-compliant parser would never
581
+ * return. Return true otherwise.
582
+ */
583
+ var _checkValidNamespace = function _checkValidNamespace(element) {
584
+ var parent = getParentNode(element);
585
+
586
+ // In JSDOM, if we're inside shadow DOM, then parentNode
587
+ // can be null. We just simulate parent in this case.
588
+ if (!parent || !parent.tagName) {
589
+ parent = {
590
+ namespaceURI: HTML_NAMESPACE,
591
+ tagName: 'template'
592
+ };
593
+ }
594
+
595
+ var tagName = stringToLowerCase(element.tagName);
596
+ var parentTagName = stringToLowerCase(parent.tagName);
597
+
598
+ if (element.namespaceURI === SVG_NAMESPACE) {
599
+ // The only way to switch from HTML namespace to SVG
600
+ // is via <svg>. If it happens via any other tag, then
601
+ // it should be killed.
602
+ if (parent.namespaceURI === HTML_NAMESPACE) {
603
+ return tagName === 'svg';
604
+ }
605
+
606
+ // The only way to switch from MathML to SVG is via
607
+ // svg if parent is either <annotation-xml> or MathML
608
+ // text integration points.
609
+ if (parent.namespaceURI === MATHML_NAMESPACE) {
610
+ return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
611
+ }
612
+
613
+ // We only allow elements that are defined in SVG
614
+ // spec. All others are disallowed in SVG namespace.
615
+ return Boolean(ALL_SVG_TAGS[tagName]);
616
+ }
617
+
618
+ if (element.namespaceURI === MATHML_NAMESPACE) {
619
+ // The only way to switch from HTML namespace to MathML
620
+ // is via <math>. If it happens via any other tag, then
621
+ // it should be killed.
622
+ if (parent.namespaceURI === HTML_NAMESPACE) {
623
+ return tagName === 'math';
624
+ }
625
+
626
+ // The only way to switch from SVG to MathML is via
627
+ // <math> and HTML integration points
628
+ if (parent.namespaceURI === SVG_NAMESPACE) {
629
+ return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
630
+ }
631
+
632
+ // We only allow elements that are defined in MathML
633
+ // spec. All others are disallowed in MathML namespace.
634
+ return Boolean(ALL_MATHML_TAGS[tagName]);
635
+ }
636
+
637
+ if (element.namespaceURI === HTML_NAMESPACE) {
638
+ // The only way to switch from SVG to HTML is via
639
+ // HTML integration points, and from MathML to HTML
640
+ // is via MathML text integration points
641
+ if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
642
+ return false;
643
+ }
644
+
645
+ if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
646
+ return false;
647
+ }
648
+
649
+ // Certain elements are allowed in both SVG and HTML
650
+ // namespace. We need to specify them explicitly
651
+ // so that they don't get erronously deleted from
652
+ // HTML namespace.
653
+ var commonSvgAndHTMLElements = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
654
+
655
+ // We disallow tags that are specific for MathML
656
+ // or SVG and should never appear in HTML namespace
657
+ return !ALL_MATHML_TAGS[tagName] && (commonSvgAndHTMLElements[tagName] || !ALL_SVG_TAGS[tagName]);
658
+ }
659
+
660
+ // The code should never reach this place (this means
661
+ // that the element somehow got namespace that is not
662
+ // HTML, SVG or MathML). Return false just in case.
663
+ return false;
664
+ };
665
+
507
666
  /**
508
667
  * _forceRemove
509
668
  *
@@ -542,6 +701,19 @@ function createDOMPurify() {
542
701
  }
543
702
 
544
703
  node.removeAttribute(name);
704
+
705
+ // We void attribute values for unremovable "is"" attributes
706
+ if (name === 'is' && !ALLOWED_ATTR[name]) {
707
+ if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
708
+ try {
709
+ _forceRemove(node);
710
+ } catch (_) {}
711
+ } else {
712
+ try {
713
+ node.setAttribute(name, '');
714
+ } catch (_) {}
715
+ }
716
+ }
545
717
  };
546
718
 
547
719
  /**
@@ -564,27 +736,30 @@ function createDOMPurify() {
564
736
  }
565
737
 
566
738
  var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
567
- /* Use the DOMParser API by default, fallback later if needs be */
568
- try {
569
- doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
570
- } catch (_) {}
739
+ /*
740
+ * Use the DOMParser API by default, fallback later if needs be
741
+ * DOMParser not work for svg when has multiple root element.
742
+ */
743
+ if (NAMESPACE === HTML_NAMESPACE) {
744
+ try {
745
+ doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
746
+ } catch (_) {}
747
+ }
571
748
 
572
749
  /* Use createHTMLDocument in case DOMParser is not available */
573
750
  if (!doc || !doc.documentElement) {
574
- doc = implementation.createHTMLDocument('');
575
- var _doc = doc,
576
- body = _doc.body;
577
-
578
- body.parentNode.removeChild(body.parentNode.firstElementChild);
579
- body.outerHTML = dirtyPayload;
751
+ doc = implementation.createDocument(NAMESPACE, 'template', null);
752
+ doc.documentElement.innerHTML = dirtyPayload;
580
753
  }
581
754
 
755
+ var body = doc.body || doc.documentElement;
756
+
582
757
  if (dirty && leadingWhitespace) {
583
- doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
758
+ body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
584
759
  }
585
760
 
586
761
  /* Work on whole document or just its body */
587
- return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
762
+ return WHOLE_DOCUMENT ? doc.documentElement : body;
588
763
  };
589
764
 
590
765
  /**
@@ -610,7 +785,7 @@ function createDOMPurify() {
610
785
  return false;
611
786
  }
612
787
 
613
- if (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string') {
788
+ if (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function') {
614
789
  return true;
615
790
  }
616
791
 
@@ -691,29 +866,30 @@ function createDOMPurify() {
691
866
  /* Remove element if anything forbids its presence */
692
867
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
693
868
  /* Keep content except for bad-listed elements */
694
- if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] && typeof currentNode.insertAdjacentHTML === 'function') {
695
- try {
696
- var htmlToInsert = currentNode.innerHTML;
697
- currentNode.insertAdjacentHTML('AfterEnd', trustedTypesPolicy ? trustedTypesPolicy.createHTML(htmlToInsert) : htmlToInsert);
698
- } catch (_) {}
699
- }
869
+ if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
870
+ var parentNode = getParentNode(currentNode) || currentNode.parentNode;
871
+ var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
700
872
 
701
- _forceRemove(currentNode);
702
- return true;
703
- }
873
+ if (childNodes && parentNode) {
874
+ var childCount = childNodes.length;
875
+
876
+ for (var i = childCount - 1; i >= 0; --i) {
877
+ parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
878
+ }
879
+ }
880
+ }
704
881
 
705
- if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
706
882
  _forceRemove(currentNode);
707
883
  return true;
708
884
  }
709
885
 
710
- if (tagName === 'math' && _isNode(currentNode.firstElementChild) && currentNode.querySelectorAll(':not(' + mathMl.join('):not(') + ')').length > 0) {
886
+ /* Check whether element has a valid namespace */
887
+ if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
711
888
  _forceRemove(currentNode);
712
889
  return true;
713
890
  }
714
891
 
715
- /* Take care of an mXSS using HTML inside SVG affecting old Chrome */
716
- if (tagName === 'svg' && currentNode.querySelectorAll('p, br, table, form, noscript').length > 0) {
892
+ if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
717
893
  _forceRemove(currentNode);
718
894
  return true;
719
895
  }