dompurify 2.2.7 → 2.3.1

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.1 | (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.1/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
 
@@ -166,7 +166,7 @@ var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv
166
166
 
167
167
  var text = freeze(['#text']);
168
168
 
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']);
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']);
170
170
 
171
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']);
172
172
 
@@ -243,7 +243,7 @@ function createDOMPurify() {
243
243
  * Version label, exposed for easier checks
244
244
  * if DOMPurify is up to date or not
245
245
  */
246
- DOMPurify.version = '2.2.7';
246
+ DOMPurify.version = '2.3.1';
247
247
 
248
248
  /**
249
249
  * Array of elements that DOMPurify removed during sanitation.
@@ -301,8 +301,8 @@ function createDOMPurify() {
301
301
  var _document = document,
302
302
  implementation = _document.implementation,
303
303
  createNodeIterator = _document.createNodeIterator,
304
- getElementsByTagName = _document.getElementsByTagName,
305
- createDocumentFragment = _document.createDocumentFragment;
304
+ createDocumentFragment = _document.createDocumentFragment,
305
+ getElementsByTagName = _document.getElementsByTagName;
306
306
  var importNode = originalDocument.importNode;
307
307
 
308
308
 
@@ -409,7 +409,8 @@ function createDOMPurify() {
409
409
  var USE_PROFILES = {};
410
410
 
411
411
  /* Tags to ignore content of when KEEP_CONTENT is true */
412
- 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']);
412
+ var FORBID_CONTENTS = null;
413
+ var DEFAULT_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']);
413
414
 
414
415
  /* Tags that are safe for data: URIs */
415
416
  var DATA_URI_TAGS = null;
@@ -417,7 +418,14 @@ function createDOMPurify() {
417
418
 
418
419
  /* Attributes safe for values like "javascript:" */
419
420
  var URI_SAFE_ATTRIBUTES = null;
420
- var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
421
+ var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
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
+ var IS_EMPTY_INPUT = false;
421
429
 
422
430
  /* Keep a reference to config to pass to hooks */
423
431
  var CONFIG = null;
@@ -451,6 +459,7 @@ function createDOMPurify() {
451
459
  ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
452
460
  URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
453
461
  DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
462
+ FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
454
463
  FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
455
464
  FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
456
465
  USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
@@ -468,6 +477,7 @@ function createDOMPurify() {
468
477
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
469
478
  IN_PLACE = cfg.IN_PLACE || false; // Default false
470
479
  IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
480
+ NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
471
481
  if (SAFE_FOR_TEMPLATES) {
472
482
  ALLOW_DATA_ATTR = false;
473
483
  }
@@ -525,6 +535,14 @@ function createDOMPurify() {
525
535
  addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
526
536
  }
527
537
 
538
+ if (cfg.FORBID_CONTENTS) {
539
+ if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
540
+ FORBID_CONTENTS = clone(FORBID_CONTENTS);
541
+ }
542
+
543
+ addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
544
+ }
545
+
528
546
  /* Add #text in case KEEP_CONTENT is set to true */
529
547
  if (KEEP_CONTENT) {
530
548
  ALLOWED_TAGS['#text'] = true;
@@ -564,10 +582,6 @@ function createDOMPurify() {
564
582
  var ALL_MATHML_TAGS = addToSet({}, mathMl);
565
583
  addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
566
584
 
567
- var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
568
- var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
569
- var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
570
-
571
585
  /**
572
586
  *
573
587
  *
@@ -667,6 +681,7 @@ function createDOMPurify() {
667
681
  var _forceRemove = function _forceRemove(node) {
668
682
  arrayPush(DOMPurify.removed, { element: node });
669
683
  try {
684
+ // eslint-disable-next-line unicorn/prefer-dom-node-remove
670
685
  node.parentNode.removeChild(node);
671
686
  } catch (_) {
672
687
  try {
@@ -732,27 +747,38 @@ function createDOMPurify() {
732
747
  }
733
748
 
734
749
  var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
735
- /* Use the DOMParser API by default, fallback later if needs be */
736
- try {
737
- doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
738
- } catch (_) {}
750
+ /*
751
+ * Use the DOMParser API by default, fallback later if needs be
752
+ * DOMParser not work for svg when has multiple root element.
753
+ */
754
+ if (NAMESPACE === HTML_NAMESPACE) {
755
+ try {
756
+ doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
757
+ } catch (_) {}
758
+ }
739
759
 
740
760
  /* Use createHTMLDocument in case DOMParser is not available */
741
761
  if (!doc || !doc.documentElement) {
742
- doc = implementation.createHTMLDocument('');
743
- var _doc = doc,
744
- body = _doc.body;
745
-
746
- body.parentNode.removeChild(body.parentNode.firstElementChild);
747
- body.outerHTML = dirtyPayload;
762
+ doc = implementation.createDocument(NAMESPACE, 'template', null);
763
+ try {
764
+ doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
765
+ } catch (_) {
766
+ // Syntax error if dirtyPayload is invalid xml
767
+ }
748
768
  }
749
769
 
770
+ var body = doc.body || doc.documentElement;
771
+
750
772
  if (dirty && leadingWhitespace) {
751
- doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
773
+ body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
752
774
  }
753
775
 
754
776
  /* Work on whole document or just its body */
755
- return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
777
+ if (NAMESPACE === HTML_NAMESPACE) {
778
+ return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
779
+ }
780
+
781
+ return WHOLE_DOCUMENT ? doc.documentElement : body;
756
782
  };
757
783
 
758
784
  /**
@@ -762,9 +788,7 @@ function createDOMPurify() {
762
788
  * @return {Iterator} iterator instance
763
789
  */
764
790
  var _createIterator = function _createIterator(root) {
765
- return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, function () {
766
- return NodeFilter.FILTER_ACCEPT;
767
- }, false);
791
+ return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
768
792
  };
769
793
 
770
794
  /**
@@ -856,12 +880,18 @@ function createDOMPurify() {
856
880
  return true;
857
881
  }
858
882
 
883
+ /* Mitigate a problem with templates inside select */
884
+ if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
885
+ _forceRemove(currentNode);
886
+ return true;
887
+ }
888
+
859
889
  /* Remove element if anything forbids its presence */
860
890
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
861
891
  /* Keep content except for bad-listed elements */
862
892
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
863
- var parentNode = getParentNode(currentNode);
864
- var childNodes = getChildNodes(currentNode);
893
+ var parentNode = getParentNode(currentNode) || currentNode.parentNode;
894
+ var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
865
895
 
866
896
  if (childNodes && parentNode) {
867
897
  var childCount = childNodes.length;
@@ -924,7 +954,7 @@ function createDOMPurify() {
924
954
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
925
955
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
926
956
  We don't need to check the value; it's always URI safe. */
927
- 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]) {
957
+ 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]) {
928
958
  return false;
929
959
 
930
960
  /* Check value is safe. First, is attr inert? If so, is safe */
@@ -1085,7 +1115,8 @@ function createDOMPurify() {
1085
1115
  /* Make sure we have a string to sanitize.
1086
1116
  DO NOT return early, as this will return the wrong type if
1087
1117
  the user has requested a DOM object rather than a string */
1088
- if (!dirty) {
1118
+ IS_EMPTY_INPUT = !dirty;
1119
+ if (IS_EMPTY_INPUT) {
1089
1120
  dirty = '<!-->';
1090
1121
  }
1091
1122
 
@@ -1141,7 +1172,7 @@ function createDOMPurify() {
1141
1172
  } else if (importedNode.nodeName === 'HTML') {
1142
1173
  body = importedNode;
1143
1174
  } else {
1144
- // eslint-disable-next-line unicorn/prefer-node-append
1175
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
1145
1176
  body.appendChild(importedNode);
1146
1177
  }
1147
1178
  } else {
@@ -1205,7 +1236,7 @@ function createDOMPurify() {
1205
1236
  returnNode = createDocumentFragment.call(body.ownerDocument);
1206
1237
 
1207
1238
  while (body.firstChild) {
1208
- // eslint-disable-next-line unicorn/prefer-node-append
1239
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
1209
1240
  returnNode.appendChild(body.firstChild);
1210
1241
  }
1211
1242
  } else {