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.es.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 _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
4
4
 
@@ -137,7 +137,12 @@ function lookupGetter(object, prop) {
137
137
  object = getPrototypeOf(object);
138
138
  }
139
139
 
140
- return null;
140
+ function fallbackValue(element) {
141
+ console.warn('fallback value for', element);
142
+ return null;
143
+ }
144
+
145
+ return fallbackValue;
141
146
  }
142
147
 
143
148
  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']);
@@ -161,7 +166,7 @@ var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv
161
166
 
162
167
  var text = freeze(['#text']);
163
168
 
164
- 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']);
169
+ 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']);
165
170
 
166
171
  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']);
167
172
 
@@ -238,7 +243,7 @@ function createDOMPurify() {
238
243
  * Version label, exposed for easier checks
239
244
  * if DOMPurify is up to date or not
240
245
  */
241
- DOMPurify.version = '2.2.6';
246
+ DOMPurify.version = '2.3.0';
242
247
 
243
248
  /**
244
249
  * Array of elements that DOMPurify removed during sanitation.
@@ -296,8 +301,8 @@ function createDOMPurify() {
296
301
  var _document = document,
297
302
  implementation = _document.implementation,
298
303
  createNodeIterator = _document.createNodeIterator,
299
- getElementsByTagName = _document.getElementsByTagName,
300
- createDocumentFragment = _document.createDocumentFragment;
304
+ createDocumentFragment = _document.createDocumentFragment,
305
+ getElementsByTagName = _document.getElementsByTagName;
301
306
  var importNode = originalDocument.importNode;
302
307
 
303
308
 
@@ -311,7 +316,7 @@ function createDOMPurify() {
311
316
  /**
312
317
  * Expose whether this browser supports running the full DOMPurify.
313
318
  */
314
- DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
319
+ DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
315
320
 
316
321
  var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,
317
322
  ERB_EXPR$$1 = ERB_EXPR,
@@ -414,6 +419,13 @@ function createDOMPurify() {
414
419
  var URI_SAFE_ATTRIBUTES = null;
415
420
  var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
416
421
 
422
+ var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
423
+ var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
424
+ var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
425
+ /* Document namespace */
426
+ var NAMESPACE = HTML_NAMESPACE;
427
+ var IS_EMPTY_INPUT = false;
428
+
417
429
  /* Keep a reference to config to pass to hooks */
418
430
  var CONFIG = null;
419
431
 
@@ -463,6 +475,7 @@ function createDOMPurify() {
463
475
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
464
476
  IN_PLACE = cfg.IN_PLACE || false; // Default false
465
477
  IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
478
+ NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
466
479
  if (SAFE_FOR_TEMPLATES) {
467
480
  ALLOW_DATA_ATTR = false;
468
481
  }
@@ -559,10 +572,6 @@ function createDOMPurify() {
559
572
  var ALL_MATHML_TAGS = addToSet({}, mathMl);
560
573
  addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
561
574
 
562
- var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
563
- var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
564
- var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
565
-
566
575
  /**
567
576
  *
568
577
  *
@@ -662,6 +671,7 @@ function createDOMPurify() {
662
671
  var _forceRemove = function _forceRemove(node) {
663
672
  arrayPush(DOMPurify.removed, { element: node });
664
673
  try {
674
+ // eslint-disable-next-line unicorn/prefer-dom-node-remove
665
675
  node.parentNode.removeChild(node);
666
676
  } catch (_) {
667
677
  try {
@@ -692,6 +702,19 @@ function createDOMPurify() {
692
702
  }
693
703
 
694
704
  node.removeAttribute(name);
705
+
706
+ // We void attribute values for unremovable "is"" attributes
707
+ if (name === 'is' && !ALLOWED_ATTR[name]) {
708
+ if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
709
+ try {
710
+ _forceRemove(node);
711
+ } catch (_) {}
712
+ } else {
713
+ try {
714
+ node.setAttribute(name, '');
715
+ } catch (_) {}
716
+ }
717
+ }
695
718
  };
696
719
 
697
720
  /**
@@ -714,27 +737,38 @@ function createDOMPurify() {
714
737
  }
715
738
 
716
739
  var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
717
- /* Use the DOMParser API by default, fallback later if needs be */
718
- try {
719
- doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
720
- } catch (_) {}
740
+ /*
741
+ * Use the DOMParser API by default, fallback later if needs be
742
+ * DOMParser not work for svg when has multiple root element.
743
+ */
744
+ if (NAMESPACE === HTML_NAMESPACE) {
745
+ try {
746
+ doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
747
+ } catch (_) {}
748
+ }
721
749
 
722
750
  /* Use createHTMLDocument in case DOMParser is not available */
723
751
  if (!doc || !doc.documentElement) {
724
- doc = implementation.createHTMLDocument('');
725
- var _doc = doc,
726
- body = _doc.body;
727
-
728
- body.parentNode.removeChild(body.parentNode.firstElementChild);
729
- body.outerHTML = dirtyPayload;
752
+ doc = implementation.createDocument(NAMESPACE, 'template', null);
753
+ try {
754
+ doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
755
+ } catch (_) {
756
+ // Syntax error if dirtyPayload is invalid xml
757
+ }
730
758
  }
731
759
 
760
+ var body = doc.body || doc.documentElement;
761
+
732
762
  if (dirty && leadingWhitespace) {
733
- doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
763
+ body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
734
764
  }
735
765
 
736
766
  /* Work on whole document or just its body */
737
- return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
767
+ if (NAMESPACE === HTML_NAMESPACE) {
768
+ return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
769
+ }
770
+
771
+ return WHOLE_DOCUMENT ? doc.documentElement : body;
738
772
  };
739
773
 
740
774
  /**
@@ -744,9 +778,7 @@ function createDOMPurify() {
744
778
  * @return {Iterator} iterator instance
745
779
  */
746
780
  var _createIterator = function _createIterator(root) {
747
- return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, function () {
748
- return NodeFilter.FILTER_ACCEPT;
749
- }, false);
781
+ return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
750
782
  };
751
783
 
752
784
  /**
@@ -842,11 +874,15 @@ function createDOMPurify() {
842
874
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
843
875
  /* Keep content except for bad-listed elements */
844
876
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
845
- var parentNode = getParentNode(currentNode);
846
- var childNodes = getChildNodes(currentNode);
847
- var childCount = childNodes.length;
848
- for (var i = childCount - 1; i >= 0; --i) {
849
- parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
877
+ var parentNode = getParentNode(currentNode) || currentNode.parentNode;
878
+ var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
879
+
880
+ if (childNodes && parentNode) {
881
+ var childCount = childNodes.length;
882
+
883
+ for (var i = childCount - 1; i >= 0; --i) {
884
+ parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
885
+ }
850
886
  }
851
887
  }
852
888
 
@@ -902,7 +938,7 @@ function createDOMPurify() {
902
938
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
903
939
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
904
940
  We don't need to check the value; it's always URI safe. */
905
- 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]) {
941
+ 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]) {
906
942
  return false;
907
943
 
908
944
  /* Check value is safe. First, is attr inert? If so, is safe */
@@ -1063,7 +1099,8 @@ function createDOMPurify() {
1063
1099
  /* Make sure we have a string to sanitize.
1064
1100
  DO NOT return early, as this will return the wrong type if
1065
1101
  the user has requested a DOM object rather than a string */
1066
- if (!dirty) {
1102
+ IS_EMPTY_INPUT = !dirty;
1103
+ if (IS_EMPTY_INPUT) {
1067
1104
  dirty = '<!-->';
1068
1105
  }
1069
1106
 
@@ -1119,7 +1156,7 @@ function createDOMPurify() {
1119
1156
  } else if (importedNode.nodeName === 'HTML') {
1120
1157
  body = importedNode;
1121
1158
  } else {
1122
- // eslint-disable-next-line unicorn/prefer-node-append
1159
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
1123
1160
  body.appendChild(importedNode);
1124
1161
  }
1125
1162
  } else {
@@ -1183,7 +1220,7 @@ function createDOMPurify() {
1183
1220
  returnNode = createDocumentFragment.call(body.ownerDocument);
1184
1221
 
1185
1222
  while (body.firstChild) {
1186
- // eslint-disable-next-line unicorn/prefer-node-append
1223
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
1187
1224
  returnNode.appendChild(body.firstChild);
1188
1225
  }
1189
1226
  } else {