dompurify 2.2.6 → 2.3.0

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/dist/purify.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @license DOMPurify | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.2.2/LICENSE */
1
+ /*! @license DOMPurify 2.3.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.0/LICENSE */
2
2
 
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -143,7 +143,12 @@
143
143
  object = getPrototypeOf(object);
144
144
  }
145
145
 
146
- return null;
146
+ function fallbackValue(element) {
147
+ console.warn('fallback value for', element);
148
+ return null;
149
+ }
150
+
151
+ return fallbackValue;
147
152
  }
148
153
 
149
154
  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']);
@@ -167,7 +172,7 @@
167
172
 
168
173
  var text = freeze(['#text']);
169
174
 
170
- 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']);
175
+ 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']);
171
176
 
172
177
  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']);
173
178
 
@@ -244,7 +249,7 @@
244
249
  * Version label, exposed for easier checks
245
250
  * if DOMPurify is up to date or not
246
251
  */
247
- DOMPurify.version = '2.2.6';
252
+ DOMPurify.version = '2.3.0';
248
253
 
249
254
  /**
250
255
  * Array of elements that DOMPurify removed during sanitation.
@@ -302,8 +307,8 @@
302
307
  var _document = document,
303
308
  implementation = _document.implementation,
304
309
  createNodeIterator = _document.createNodeIterator,
305
- getElementsByTagName = _document.getElementsByTagName,
306
- createDocumentFragment = _document.createDocumentFragment;
310
+ createDocumentFragment = _document.createDocumentFragment,
311
+ getElementsByTagName = _document.getElementsByTagName;
307
312
  var importNode = originalDocument.importNode;
308
313
 
309
314
 
@@ -317,7 +322,7 @@
317
322
  /**
318
323
  * Expose whether this browser supports running the full DOMPurify.
319
324
  */
320
- DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
325
+ DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
321
326
 
322
327
  var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,
323
328
  ERB_EXPR$$1 = ERB_EXPR,
@@ -420,6 +425,13 @@
420
425
  var URI_SAFE_ATTRIBUTES = null;
421
426
  var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
422
427
 
428
+ var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
429
+ var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
430
+ var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
431
+ /* Document namespace */
432
+ var NAMESPACE = HTML_NAMESPACE;
433
+ var IS_EMPTY_INPUT = false;
434
+
423
435
  /* Keep a reference to config to pass to hooks */
424
436
  var CONFIG = null;
425
437
 
@@ -469,6 +481,7 @@
469
481
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
470
482
  IN_PLACE = cfg.IN_PLACE || false; // Default false
471
483
  IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
484
+ NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
472
485
  if (SAFE_FOR_TEMPLATES) {
473
486
  ALLOW_DATA_ATTR = false;
474
487
  }
@@ -565,10 +578,6 @@
565
578
  var ALL_MATHML_TAGS = addToSet({}, mathMl);
566
579
  addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
567
580
 
568
- var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
569
- var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
570
- var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
571
-
572
581
  /**
573
582
  *
574
583
  *
@@ -668,6 +677,7 @@
668
677
  var _forceRemove = function _forceRemove(node) {
669
678
  arrayPush(DOMPurify.removed, { element: node });
670
679
  try {
680
+ // eslint-disable-next-line unicorn/prefer-dom-node-remove
671
681
  node.parentNode.removeChild(node);
672
682
  } catch (_) {
673
683
  try {
@@ -698,6 +708,19 @@
698
708
  }
699
709
 
700
710
  node.removeAttribute(name);
711
+
712
+ // We void attribute values for unremovable "is"" attributes
713
+ if (name === 'is' && !ALLOWED_ATTR[name]) {
714
+ if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
715
+ try {
716
+ _forceRemove(node);
717
+ } catch (_) {}
718
+ } else {
719
+ try {
720
+ node.setAttribute(name, '');
721
+ } catch (_) {}
722
+ }
723
+ }
701
724
  };
702
725
 
703
726
  /**
@@ -720,27 +743,38 @@
720
743
  }
721
744
 
722
745
  var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
723
- /* Use the DOMParser API by default, fallback later if needs be */
724
- try {
725
- doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
726
- } catch (_) {}
746
+ /*
747
+ * Use the DOMParser API by default, fallback later if needs be
748
+ * DOMParser not work for svg when has multiple root element.
749
+ */
750
+ if (NAMESPACE === HTML_NAMESPACE) {
751
+ try {
752
+ doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
753
+ } catch (_) {}
754
+ }
727
755
 
728
756
  /* Use createHTMLDocument in case DOMParser is not available */
729
757
  if (!doc || !doc.documentElement) {
730
- doc = implementation.createHTMLDocument('');
731
- var _doc = doc,
732
- body = _doc.body;
733
-
734
- body.parentNode.removeChild(body.parentNode.firstElementChild);
735
- body.outerHTML = dirtyPayload;
758
+ doc = implementation.createDocument(NAMESPACE, 'template', null);
759
+ try {
760
+ doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
761
+ } catch (_) {
762
+ // Syntax error if dirtyPayload is invalid xml
763
+ }
736
764
  }
737
765
 
766
+ var body = doc.body || doc.documentElement;
767
+
738
768
  if (dirty && leadingWhitespace) {
739
- doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
769
+ body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
740
770
  }
741
771
 
742
772
  /* Work on whole document or just its body */
743
- return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
773
+ if (NAMESPACE === HTML_NAMESPACE) {
774
+ return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
775
+ }
776
+
777
+ return WHOLE_DOCUMENT ? doc.documentElement : body;
744
778
  };
745
779
 
746
780
  /**
@@ -750,9 +784,7 @@
750
784
  * @return {Iterator} iterator instance
751
785
  */
752
786
  var _createIterator = function _createIterator(root) {
753
- return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, function () {
754
- return NodeFilter.FILTER_ACCEPT;
755
- }, false);
787
+ return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
756
788
  };
757
789
 
758
790
  /**
@@ -848,11 +880,15 @@
848
880
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
849
881
  /* Keep content except for bad-listed elements */
850
882
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
851
- var parentNode = getParentNode(currentNode);
852
- var childNodes = getChildNodes(currentNode);
853
- var childCount = childNodes.length;
854
- for (var i = childCount - 1; i >= 0; --i) {
855
- parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
883
+ var parentNode = getParentNode(currentNode) || currentNode.parentNode;
884
+ var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
885
+
886
+ if (childNodes && parentNode) {
887
+ var childCount = childNodes.length;
888
+
889
+ for (var i = childCount - 1; i >= 0; --i) {
890
+ parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
891
+ }
856
892
  }
857
893
  }
858
894
 
@@ -908,7 +944,7 @@
908
944
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
909
945
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
910
946
  We don't need to check the value; it's always URI safe. */
911
- if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
947
+ if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
912
948
  return false;
913
949
 
914
950
  /* Check value is safe. First, is attr inert? If so, is safe */
@@ -1069,7 +1105,8 @@
1069
1105
  /* Make sure we have a string to sanitize.
1070
1106
  DO NOT return early, as this will return the wrong type if
1071
1107
  the user has requested a DOM object rather than a string */
1072
- if (!dirty) {
1108
+ IS_EMPTY_INPUT = !dirty;
1109
+ if (IS_EMPTY_INPUT) {
1073
1110
  dirty = '<!-->';
1074
1111
  }
1075
1112
 
@@ -1125,7 +1162,7 @@
1125
1162
  } else if (importedNode.nodeName === 'HTML') {
1126
1163
  body = importedNode;
1127
1164
  } else {
1128
- // eslint-disable-next-line unicorn/prefer-node-append
1165
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
1129
1166
  body.appendChild(importedNode);
1130
1167
  }
1131
1168
  } else {
@@ -1189,7 +1226,7 @@
1189
1226
  returnNode = createDocumentFragment.call(body.ownerDocument);
1190
1227
 
1191
1228
  while (body.firstChild) {
1192
- // eslint-disable-next-line unicorn/prefer-node-append
1229
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
1193
1230
  returnNode.appendChild(body.firstChild);
1194
1231
  }
1195
1232
  } else {