@carbon/ibmdotcom-utilities 2.9.0 → 2.10.0-canary.9119336364.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/package.json +2 -2
- package/umd/ibmdotcom-utilities.js +193 -176
- package/umd/ibmdotcom-utilities.min.js +1 -1
|
@@ -590,7 +590,7 @@
|
|
|
590
590
|
|
|
591
591
|
var purify = {exports: {}};
|
|
592
592
|
|
|
593
|
-
/*! @license DOMPurify 2.
|
|
593
|
+
/*! @license DOMPurify 2.5.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.5.0/LICENSE */
|
|
594
594
|
(function (module, exports) {
|
|
595
595
|
(function (global, factory) {
|
|
596
596
|
module.exports = factory() ;
|
|
@@ -671,7 +671,6 @@
|
|
|
671
671
|
var freeze = Object.freeze,
|
|
672
672
|
seal = Object.seal,
|
|
673
673
|
create = Object.create; // eslint-disable-line import/no-mutable-exports
|
|
674
|
-
|
|
675
674
|
var _ref = typeof Reflect !== 'undefined' && Reflect,
|
|
676
675
|
apply = _ref.apply,
|
|
677
676
|
construct = _ref.construct;
|
|
@@ -722,8 +721,8 @@
|
|
|
722
721
|
return construct(func, args);
|
|
723
722
|
};
|
|
724
723
|
}
|
|
725
|
-
/* Add properties to a lookup table */
|
|
726
724
|
|
|
725
|
+
/* Add properties to a lookup table */
|
|
727
726
|
function addToSet(set, array, transformCaseFunc) {
|
|
728
727
|
var _transformCaseFunc;
|
|
729
728
|
transformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;
|
|
@@ -750,8 +749,8 @@
|
|
|
750
749
|
}
|
|
751
750
|
return set;
|
|
752
751
|
}
|
|
753
|
-
/* Shallow clone an object */
|
|
754
752
|
|
|
753
|
+
/* Shallow clone an object */
|
|
755
754
|
function clone(object) {
|
|
756
755
|
var newObject = create(null);
|
|
757
756
|
var property;
|
|
@@ -762,11 +761,11 @@
|
|
|
762
761
|
}
|
|
763
762
|
return newObject;
|
|
764
763
|
}
|
|
764
|
+
|
|
765
765
|
/* IE10 doesn't support __lookupGetter__ so lets'
|
|
766
766
|
* simulate it. It also automatically checks
|
|
767
767
|
* if the prop is function or getter and behaves
|
|
768
768
|
* accordingly. */
|
|
769
|
-
|
|
770
769
|
function lookupGetter(object, prop) {
|
|
771
770
|
while (object !== null) {
|
|
772
771
|
var desc = getOwnPropertyDescriptor(object, prop);
|
|
@@ -786,41 +785,45 @@
|
|
|
786
785
|
}
|
|
787
786
|
return fallbackValue;
|
|
788
787
|
}
|
|
789
|
-
var html$1 = 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']);
|
|
788
|
+
var html$1 = 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']);
|
|
790
789
|
|
|
790
|
+
// SVG
|
|
791
791
|
var svg$1 = 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']);
|
|
792
|
-
var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
|
|
792
|
+
var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
|
|
793
|
+
|
|
794
|
+
// List of SVG elements that are disallowed by default.
|
|
793
795
|
// We still need to know them so that we can do namespace
|
|
794
796
|
// checks properly in case one wants to add them to
|
|
795
797
|
// allow-list.
|
|
796
|
-
|
|
797
798
|
var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', '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']);
|
|
798
|
-
var mathMl$1 = 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']);
|
|
799
|
-
// even those that we disallow by default.
|
|
799
|
+
var mathMl$1 = 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']);
|
|
800
800
|
|
|
801
|
+
// Similarly to SVG, we want to know all MathML elements,
|
|
802
|
+
// even those that we disallow by default.
|
|
801
803
|
var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
802
804
|
var text = freeze(['#text']);
|
|
803
805
|
var html = 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', 'nonce', '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']);
|
|
804
806
|
var svg = 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', 'transform-origin', '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']);
|
|
805
807
|
var mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
|
|
806
808
|
var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
807
|
-
var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
808
809
|
|
|
810
|
+
// eslint-disable-next-line unicorn/better-regex
|
|
811
|
+
var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
809
812
|
var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
|
810
813
|
var TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
|
|
811
814
|
var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
|
|
812
|
-
|
|
813
815
|
var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
814
|
-
|
|
815
816
|
var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
816
817
|
);
|
|
817
818
|
var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
|
818
819
|
var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
819
820
|
);
|
|
820
821
|
var DOCTYPE_NAME = seal(/^html$/i);
|
|
822
|
+
var CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
|
821
823
|
var getGlobal = function getGlobal() {
|
|
822
824
|
return typeof window === 'undefined' ? null : window;
|
|
823
825
|
};
|
|
826
|
+
|
|
824
827
|
/**
|
|
825
828
|
* Creates a no-op policy for internal use only.
|
|
826
829
|
* Don't export this function outside this module!
|
|
@@ -829,14 +832,14 @@
|
|
|
829
832
|
* @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
|
|
830
833
|
* are not supported).
|
|
831
834
|
*/
|
|
832
|
-
|
|
833
835
|
var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
|
|
834
836
|
if (_typeof(trustedTypes) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
|
835
837
|
return null;
|
|
836
|
-
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// Allow the callers to control the unique policy name
|
|
837
841
|
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
|
838
842
|
// Policy creation with duplicate names throws in Trusted Types.
|
|
839
|
-
|
|
840
843
|
var suffix = null;
|
|
841
844
|
var ATTR_NAME = 'data-tt-policy-suffix';
|
|
842
845
|
if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
|
|
@@ -865,17 +868,17 @@
|
|
|
865
868
|
var DOMPurify = function DOMPurify(root) {
|
|
866
869
|
return createDOMPurify(root);
|
|
867
870
|
};
|
|
871
|
+
|
|
868
872
|
/**
|
|
869
873
|
* Version label, exposed for easier checks
|
|
870
874
|
* if DOMPurify is up to date or not
|
|
871
875
|
*/
|
|
876
|
+
DOMPurify.version = '2.5.0';
|
|
872
877
|
|
|
873
|
-
DOMPurify.version = '2.4.7';
|
|
874
878
|
/**
|
|
875
879
|
* Array of elements that DOMPurify removed during sanitation.
|
|
876
880
|
* Empty if nothing was removed.
|
|
877
881
|
*/
|
|
878
|
-
|
|
879
882
|
DOMPurify.removed = [];
|
|
880
883
|
if (!window || !window.document || window.document.nodeType !== 9) {
|
|
881
884
|
// Not running in a browser, provide a factory function
|
|
@@ -899,13 +902,14 @@
|
|
|
899
902
|
var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
|
900
903
|
var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
|
901
904
|
var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
|
902
|
-
var getParentNode = lookupGetter(ElementPrototype, 'parentNode');
|
|
905
|
+
var getParentNode = lookupGetter(ElementPrototype, 'parentNode');
|
|
906
|
+
|
|
907
|
+
// As per issue #47, the web-components registry is inherited by a
|
|
903
908
|
// new document created via createHTMLDocument. As per the spec
|
|
904
909
|
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
905
910
|
// a new empty registry is used when creating a template contents owner
|
|
906
911
|
// document, so we use that as our parent document to ensure nothing
|
|
907
912
|
// is inherited.
|
|
908
|
-
|
|
909
913
|
if (typeof HTMLTemplateElement === 'function') {
|
|
910
914
|
var template = document.createElement('template');
|
|
911
915
|
if (template.content && template.content.ownerDocument) {
|
|
@@ -925,10 +929,10 @@
|
|
|
925
929
|
documentMode = clone(document).documentMode ? document.documentMode : {};
|
|
926
930
|
} catch (_) {}
|
|
927
931
|
var hooks = {};
|
|
932
|
+
|
|
928
933
|
/**
|
|
929
934
|
* Expose whether this browser supports running the full DOMPurify.
|
|
930
935
|
*/
|
|
931
|
-
|
|
932
936
|
DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined && documentMode !== 9;
|
|
933
937
|
var MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
|
|
934
938
|
ERB_EXPR$1 = ERB_EXPR,
|
|
@@ -936,28 +940,29 @@
|
|
|
936
940
|
DATA_ATTR$1 = DATA_ATTR,
|
|
937
941
|
ARIA_ATTR$1 = ARIA_ATTR,
|
|
938
942
|
IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
|
|
939
|
-
ATTR_WHITESPACE$1 = ATTR_WHITESPACE
|
|
943
|
+
ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
|
|
944
|
+
CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
|
|
940
945
|
var IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
|
|
946
|
+
|
|
941
947
|
/**
|
|
942
948
|
* We consider the elements and attributes below to be safe. Ideally
|
|
943
949
|
* don't add any new ones but feel free to remove unwanted ones.
|
|
944
950
|
*/
|
|
945
951
|
|
|
946
952
|
/* allowed element names */
|
|
947
|
-
|
|
948
953
|
var ALLOWED_TAGS = null;
|
|
949
954
|
var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text)));
|
|
950
|
-
/* Allowed attribute names */
|
|
951
955
|
|
|
956
|
+
/* Allowed attribute names */
|
|
952
957
|
var ALLOWED_ATTR = null;
|
|
953
958
|
var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml)));
|
|
959
|
+
|
|
954
960
|
/*
|
|
955
961
|
* Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
|
|
956
962
|
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
|
957
963
|
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
|
|
958
964
|
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
|
959
965
|
*/
|
|
960
|
-
|
|
961
966
|
var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
|
|
962
967
|
tagNameCheck: {
|
|
963
968
|
writable: true,
|
|
@@ -978,59 +983,65 @@
|
|
|
978
983
|
value: false
|
|
979
984
|
}
|
|
980
985
|
}));
|
|
981
|
-
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
|
982
986
|
|
|
987
|
+
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
|
983
988
|
var FORBID_TAGS = null;
|
|
984
|
-
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
|
985
989
|
|
|
990
|
+
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
|
986
991
|
var FORBID_ATTR = null;
|
|
987
|
-
/* Decide if ARIA attributes are okay */
|
|
988
992
|
|
|
993
|
+
/* Decide if ARIA attributes are okay */
|
|
989
994
|
var ALLOW_ARIA_ATTR = true;
|
|
990
|
-
/* Decide if custom data attributes are okay */
|
|
991
995
|
|
|
996
|
+
/* Decide if custom data attributes are okay */
|
|
992
997
|
var ALLOW_DATA_ATTR = true;
|
|
993
|
-
/* Decide if unknown protocols are okay */
|
|
994
998
|
|
|
999
|
+
/* Decide if unknown protocols are okay */
|
|
995
1000
|
var ALLOW_UNKNOWN_PROTOCOLS = false;
|
|
1001
|
+
|
|
996
1002
|
/* Decide if self-closing tags in attributes are allowed.
|
|
997
1003
|
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
|
998
|
-
|
|
999
1004
|
var ALLOW_SELF_CLOSE_IN_ATTR = true;
|
|
1005
|
+
|
|
1000
1006
|
/* Output should be safe for common template engines.
|
|
1001
1007
|
* This means, DOMPurify removes data attributes, mustaches and ERB
|
|
1002
1008
|
*/
|
|
1003
|
-
|
|
1004
1009
|
var SAFE_FOR_TEMPLATES = false;
|
|
1005
|
-
/* Decide if document with <html>... should be returned */
|
|
1006
1010
|
|
|
1011
|
+
/* Output should be safe even for XML used within HTML and alike.
|
|
1012
|
+
* This means, DOMPurify removes comments when containing risky content.
|
|
1013
|
+
*/
|
|
1014
|
+
var SAFE_FOR_XML = true;
|
|
1015
|
+
|
|
1016
|
+
/* Decide if document with <html>... should be returned */
|
|
1007
1017
|
var WHOLE_DOCUMENT = false;
|
|
1008
|
-
/* Track whether config is already set on this instance of DOMPurify. */
|
|
1009
1018
|
|
|
1019
|
+
/* Track whether config is already set on this instance of DOMPurify. */
|
|
1010
1020
|
var SET_CONFIG = false;
|
|
1021
|
+
|
|
1011
1022
|
/* Decide if all elements (e.g. style, script) must be children of
|
|
1012
1023
|
* document.body. By default, browsers might move them to document.head */
|
|
1013
|
-
|
|
1014
1024
|
var FORCE_BODY = false;
|
|
1025
|
+
|
|
1015
1026
|
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
1016
1027
|
* string (or a TrustedHTML object if Trusted Types are supported).
|
|
1017
1028
|
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
|
1018
1029
|
*/
|
|
1019
|
-
|
|
1020
1030
|
var RETURN_DOM = false;
|
|
1031
|
+
|
|
1021
1032
|
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
1022
1033
|
* string (or a TrustedHTML object if Trusted Types are supported) */
|
|
1023
|
-
|
|
1024
1034
|
var RETURN_DOM_FRAGMENT = false;
|
|
1035
|
+
|
|
1025
1036
|
/* Try to return a Trusted Type object instead of a string, return a string in
|
|
1026
1037
|
* case Trusted Types are not supported */
|
|
1027
|
-
|
|
1028
1038
|
var RETURN_TRUSTED_TYPE = false;
|
|
1039
|
+
|
|
1029
1040
|
/* Output should be free from DOM clobbering attacks?
|
|
1030
1041
|
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
|
1031
1042
|
*/
|
|
1032
|
-
|
|
1033
1043
|
var SANITIZE_DOM = true;
|
|
1044
|
+
|
|
1034
1045
|
/* Achieve full DOM Clobbering protection by isolating the namespace of named
|
|
1035
1046
|
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
|
|
1036
1047
|
*
|
|
@@ -1044,85 +1055,84 @@
|
|
|
1044
1055
|
* Namespace isolation is implemented by prefixing `id` and `name` attributes
|
|
1045
1056
|
* with a constant string, i.e., `user-content-`
|
|
1046
1057
|
*/
|
|
1047
|
-
|
|
1048
1058
|
var SANITIZE_NAMED_PROPS = false;
|
|
1049
1059
|
var SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
|
1050
|
-
/* Keep element content when removing element? */
|
|
1051
1060
|
|
|
1061
|
+
/* Keep element content when removing element? */
|
|
1052
1062
|
var KEEP_CONTENT = true;
|
|
1063
|
+
|
|
1053
1064
|
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
|
|
1054
1065
|
* of importing it into a new Document and returning a sanitized copy */
|
|
1055
|
-
|
|
1056
1066
|
var IN_PLACE = false;
|
|
1057
|
-
/* Allow usage of profiles like html, svg and mathMl */
|
|
1058
1067
|
|
|
1068
|
+
/* Allow usage of profiles like html, svg and mathMl */
|
|
1059
1069
|
var USE_PROFILES = {};
|
|
1060
|
-
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
1061
1070
|
|
|
1071
|
+
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
1062
1072
|
var FORBID_CONTENTS = null;
|
|
1063
1073
|
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']);
|
|
1064
|
-
/* Tags that are safe for data: URIs */
|
|
1065
1074
|
|
|
1075
|
+
/* Tags that are safe for data: URIs */
|
|
1066
1076
|
var DATA_URI_TAGS = null;
|
|
1067
1077
|
var DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
|
1068
|
-
/* Attributes safe for values like "javascript:" */
|
|
1069
1078
|
|
|
1079
|
+
/* Attributes safe for values like "javascript:" */
|
|
1070
1080
|
var URI_SAFE_ATTRIBUTES = null;
|
|
1071
1081
|
var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
1072
1082
|
var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
1073
1083
|
var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
1074
1084
|
var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
|
1075
1085
|
/* Document namespace */
|
|
1076
|
-
|
|
1077
1086
|
var NAMESPACE = HTML_NAMESPACE;
|
|
1078
1087
|
var IS_EMPTY_INPUT = false;
|
|
1079
|
-
/* Allowed XHTML+XML namespaces */
|
|
1080
1088
|
|
|
1089
|
+
/* Allowed XHTML+XML namespaces */
|
|
1081
1090
|
var ALLOWED_NAMESPACES = null;
|
|
1082
1091
|
var DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
|
1083
|
-
/* Parsing of strict XHTML documents */
|
|
1084
1092
|
|
|
1093
|
+
/* Parsing of strict XHTML documents */
|
|
1085
1094
|
var PARSER_MEDIA_TYPE;
|
|
1086
1095
|
var SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
|
1087
1096
|
var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
|
1088
1097
|
var transformCaseFunc;
|
|
1089
|
-
/* Keep a reference to config to pass to hooks */
|
|
1090
1098
|
|
|
1099
|
+
/* Keep a reference to config to pass to hooks */
|
|
1091
1100
|
var CONFIG = null;
|
|
1092
|
-
/* Ideally, do not touch anything below this line */
|
|
1093
1101
|
|
|
1102
|
+
/* Ideally, do not touch anything below this line */
|
|
1094
1103
|
/* ______________________________________________ */
|
|
1095
1104
|
|
|
1096
1105
|
var formElement = document.createElement('form');
|
|
1097
1106
|
var isRegexOrFunction = function isRegexOrFunction(testValue) {
|
|
1098
1107
|
return testValue instanceof RegExp || testValue instanceof Function;
|
|
1099
1108
|
};
|
|
1109
|
+
|
|
1100
1110
|
/**
|
|
1101
1111
|
* _parseConfig
|
|
1102
1112
|
*
|
|
1103
1113
|
* @param {Object} cfg optional config literal
|
|
1104
1114
|
*/
|
|
1105
1115
|
// eslint-disable-next-line complexity
|
|
1106
|
-
|
|
1107
1116
|
var _parseConfig = function _parseConfig(cfg) {
|
|
1108
1117
|
if (CONFIG && CONFIG === cfg) {
|
|
1109
1118
|
return;
|
|
1110
1119
|
}
|
|
1111
|
-
/* Shield configuration object from tampering */
|
|
1112
1120
|
|
|
1121
|
+
/* Shield configuration object from tampering */
|
|
1113
1122
|
if (!cfg || _typeof(cfg) !== 'object') {
|
|
1114
1123
|
cfg = {};
|
|
1115
1124
|
}
|
|
1116
|
-
/* Shield configuration object from prototype pollution */
|
|
1117
1125
|
|
|
1126
|
+
/* Shield configuration object from prototype pollution */
|
|
1118
1127
|
cfg = clone(cfg);
|
|
1119
1128
|
PARSER_MEDIA_TYPE =
|
|
1120
1129
|
// eslint-disable-next-line unicorn/prefer-includes
|
|
1121
|
-
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
|
|
1130
|
+
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
|
|
1122
1131
|
|
|
1132
|
+
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
1123
1133
|
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
|
1124
|
-
/* Set configuration parameters */
|
|
1125
1134
|
|
|
1135
|
+
/* Set configuration parameters */
|
|
1126
1136
|
ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
|
1127
1137
|
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
|
1128
1138
|
ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
|
@@ -1145,33 +1155,20 @@
|
|
|
1145
1155
|
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
|
1146
1156
|
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
|
|
1147
1157
|
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
1148
|
-
|
|
1149
1158
|
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
|
1150
|
-
|
|
1151
1159
|
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
|
|
1152
|
-
|
|
1153
1160
|
ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
|
|
1154
|
-
|
|
1155
1161
|
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
|
|
1156
|
-
|
|
1162
|
+
SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
|
|
1157
1163
|
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
|
|
1158
|
-
|
|
1159
1164
|
RETURN_DOM = cfg.RETURN_DOM || false; // Default false
|
|
1160
|
-
|
|
1161
1165
|
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
|
|
1162
|
-
|
|
1163
1166
|
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
|
|
1164
|
-
|
|
1165
1167
|
FORCE_BODY = cfg.FORCE_BODY || false; // Default false
|
|
1166
|
-
|
|
1167
1168
|
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
|
|
1168
|
-
|
|
1169
1169
|
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
|
|
1170
|
-
|
|
1171
1170
|
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
1172
|
-
|
|
1173
1171
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
1174
|
-
|
|
1175
1172
|
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1;
|
|
1176
1173
|
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
|
1177
1174
|
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
|
@@ -1190,8 +1187,8 @@
|
|
|
1190
1187
|
if (RETURN_DOM_FRAGMENT) {
|
|
1191
1188
|
RETURN_DOM = true;
|
|
1192
1189
|
}
|
|
1193
|
-
/* Parse profile info */
|
|
1194
1190
|
|
|
1191
|
+
/* Parse profile info */
|
|
1195
1192
|
if (USE_PROFILES) {
|
|
1196
1193
|
ALLOWED_TAGS = addToSet({}, _toConsumableArray(text));
|
|
1197
1194
|
ALLOWED_ATTR = [];
|
|
@@ -1215,8 +1212,8 @@
|
|
|
1215
1212
|
addToSet(ALLOWED_ATTR, xml);
|
|
1216
1213
|
}
|
|
1217
1214
|
}
|
|
1218
|
-
/* Merge configuration parameters */
|
|
1219
1215
|
|
|
1216
|
+
/* Merge configuration parameters */
|
|
1220
1217
|
if (cfg.ADD_TAGS) {
|
|
1221
1218
|
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
1222
1219
|
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
@@ -1238,45 +1235,48 @@
|
|
|
1238
1235
|
}
|
|
1239
1236
|
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
1240
1237
|
}
|
|
1241
|
-
/* Add #text in case KEEP_CONTENT is set to true */
|
|
1242
1238
|
|
|
1239
|
+
/* Add #text in case KEEP_CONTENT is set to true */
|
|
1243
1240
|
if (KEEP_CONTENT) {
|
|
1244
1241
|
ALLOWED_TAGS['#text'] = true;
|
|
1245
1242
|
}
|
|
1246
|
-
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
|
|
1247
1243
|
|
|
1244
|
+
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
|
|
1248
1245
|
if (WHOLE_DOCUMENT) {
|
|
1249
1246
|
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
|
|
1250
1247
|
}
|
|
1251
|
-
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
|
|
1252
1248
|
|
|
1249
|
+
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
|
|
1253
1250
|
if (ALLOWED_TAGS.table) {
|
|
1254
1251
|
addToSet(ALLOWED_TAGS, ['tbody']);
|
|
1255
1252
|
delete FORBID_TAGS.tbody;
|
|
1256
|
-
}
|
|
1257
|
-
// Not available in IE8, Safari 5, etc.
|
|
1253
|
+
}
|
|
1258
1254
|
|
|
1255
|
+
// Prevent further manipulation of configuration.
|
|
1256
|
+
// Not available in IE8, Safari 5, etc.
|
|
1259
1257
|
if (freeze) {
|
|
1260
1258
|
freeze(cfg);
|
|
1261
1259
|
}
|
|
1262
1260
|
CONFIG = cfg;
|
|
1263
1261
|
};
|
|
1264
1262
|
var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
1265
|
-
var HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
|
|
1263
|
+
var HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
|
|
1264
|
+
|
|
1265
|
+
// Certain elements are allowed in both SVG and HTML
|
|
1266
1266
|
// namespace. We need to specify them explicitly
|
|
1267
1267
|
// so that they don't get erroneously deleted from
|
|
1268
1268
|
// HTML namespace.
|
|
1269
|
-
|
|
1270
1269
|
var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
|
1270
|
+
|
|
1271
1271
|
/* Keep track of all possible SVG and MathML tags
|
|
1272
1272
|
* so that we can perform the namespace checks
|
|
1273
1273
|
* correctly. */
|
|
1274
|
-
|
|
1275
1274
|
var ALL_SVG_TAGS = addToSet({}, svg$1);
|
|
1276
1275
|
addToSet(ALL_SVG_TAGS, svgFilters);
|
|
1277
1276
|
addToSet(ALL_SVG_TAGS, svgDisallowed);
|
|
1278
1277
|
var ALL_MATHML_TAGS = addToSet({}, mathMl$1);
|
|
1279
1278
|
addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
|
|
1279
|
+
|
|
1280
1280
|
/**
|
|
1281
1281
|
*
|
|
1282
1282
|
*
|
|
@@ -1285,11 +1285,11 @@
|
|
|
1285
1285
|
* namespace that a spec-compliant parser would never
|
|
1286
1286
|
* return. Return true otherwise.
|
|
1287
1287
|
*/
|
|
1288
|
-
|
|
1289
1288
|
var _checkValidNamespace = function _checkValidNamespace(element) {
|
|
1290
|
-
var parent = getParentNode(element);
|
|
1291
|
-
// can be null. We just simulate parent in this case.
|
|
1289
|
+
var parent = getParentNode(element);
|
|
1292
1290
|
|
|
1291
|
+
// In JSDOM, if we're inside shadow DOM, then parentNode
|
|
1292
|
+
// can be null. We just simulate parent in this case.
|
|
1293
1293
|
if (!parent || !parent.tagName) {
|
|
1294
1294
|
parent = {
|
|
1295
1295
|
namespaceURI: NAMESPACE,
|
|
@@ -1307,15 +1307,17 @@
|
|
|
1307
1307
|
// it should be killed.
|
|
1308
1308
|
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
1309
1309
|
return tagName === 'svg';
|
|
1310
|
-
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
// The only way to switch from MathML to SVG is via`
|
|
1311
1313
|
// svg if parent is either <annotation-xml> or MathML
|
|
1312
1314
|
// text integration points.
|
|
1313
|
-
|
|
1314
1315
|
if (parent.namespaceURI === MATHML_NAMESPACE) {
|
|
1315
1316
|
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
|
1316
|
-
}
|
|
1317
|
-
// spec. All others are disallowed in SVG namespace.
|
|
1317
|
+
}
|
|
1318
1318
|
|
|
1319
|
+
// We only allow elements that are defined in SVG
|
|
1320
|
+
// spec. All others are disallowed in SVG namespace.
|
|
1319
1321
|
return Boolean(ALL_SVG_TAGS[tagName]);
|
|
1320
1322
|
}
|
|
1321
1323
|
if (element.namespaceURI === MATHML_NAMESPACE) {
|
|
@@ -1324,14 +1326,16 @@
|
|
|
1324
1326
|
// it should be killed.
|
|
1325
1327
|
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
1326
1328
|
return tagName === 'math';
|
|
1327
|
-
}
|
|
1328
|
-
// <math> and HTML integration points
|
|
1329
|
+
}
|
|
1329
1330
|
|
|
1331
|
+
// The only way to switch from SVG to MathML is via
|
|
1332
|
+
// <math> and HTML integration points
|
|
1330
1333
|
if (parent.namespaceURI === SVG_NAMESPACE) {
|
|
1331
1334
|
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
|
1332
|
-
}
|
|
1333
|
-
// spec. All others are disallowed in MathML namespace.
|
|
1335
|
+
}
|
|
1334
1336
|
|
|
1337
|
+
// We only allow elements that are defined in MathML
|
|
1338
|
+
// spec. All others are disallowed in MathML namespace.
|
|
1335
1339
|
return Boolean(ALL_MATHML_TAGS[tagName]);
|
|
1336
1340
|
}
|
|
1337
1341
|
if (element.namespaceURI === HTML_NAMESPACE) {
|
|
@@ -1343,27 +1347,30 @@
|
|
|
1343
1347
|
}
|
|
1344
1348
|
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
|
1345
1349
|
return false;
|
|
1346
|
-
}
|
|
1347
|
-
// or SVG and should never appear in HTML namespace
|
|
1350
|
+
}
|
|
1348
1351
|
|
|
1352
|
+
// We disallow tags that are specific for MathML
|
|
1353
|
+
// or SVG and should never appear in HTML namespace
|
|
1349
1354
|
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
|
1350
|
-
}
|
|
1355
|
+
}
|
|
1351
1356
|
|
|
1357
|
+
// For XHTML and XML documents that support custom namespaces
|
|
1352
1358
|
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
1353
1359
|
return true;
|
|
1354
|
-
}
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
// The code should never reach this place (this means
|
|
1355
1363
|
// that the element somehow got namespace that is not
|
|
1356
1364
|
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
|
|
1357
1365
|
// Return false just in case.
|
|
1358
|
-
|
|
1359
1366
|
return false;
|
|
1360
1367
|
};
|
|
1368
|
+
|
|
1361
1369
|
/**
|
|
1362
1370
|
* _forceRemove
|
|
1363
1371
|
*
|
|
1364
1372
|
* @param {Node} node a DOM node
|
|
1365
1373
|
*/
|
|
1366
|
-
|
|
1367
1374
|
var _forceRemove = function _forceRemove(node) {
|
|
1368
1375
|
arrayPush(DOMPurify.removed, {
|
|
1369
1376
|
element: node
|
|
@@ -1379,13 +1386,13 @@
|
|
|
1379
1386
|
}
|
|
1380
1387
|
}
|
|
1381
1388
|
};
|
|
1389
|
+
|
|
1382
1390
|
/**
|
|
1383
1391
|
* _removeAttribute
|
|
1384
1392
|
*
|
|
1385
1393
|
* @param {String} name an Attribute name
|
|
1386
1394
|
* @param {Node} node a DOM node
|
|
1387
1395
|
*/
|
|
1388
|
-
|
|
1389
1396
|
var _removeAttribute = function _removeAttribute(name, node) {
|
|
1390
1397
|
try {
|
|
1391
1398
|
arrayPush(DOMPurify.removed, {
|
|
@@ -1398,8 +1405,9 @@
|
|
|
1398
1405
|
from: node
|
|
1399
1406
|
});
|
|
1400
1407
|
}
|
|
1401
|
-
node.removeAttribute(name);
|
|
1408
|
+
node.removeAttribute(name);
|
|
1402
1409
|
|
|
1410
|
+
// We void attribute values for unremovable "is"" attributes
|
|
1403
1411
|
if (name === 'is' && !ALLOWED_ATTR[name]) {
|
|
1404
1412
|
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
|
1405
1413
|
try {
|
|
@@ -1412,13 +1420,13 @@
|
|
|
1412
1420
|
}
|
|
1413
1421
|
}
|
|
1414
1422
|
};
|
|
1423
|
+
|
|
1415
1424
|
/**
|
|
1416
1425
|
* _initDocument
|
|
1417
1426
|
*
|
|
1418
1427
|
* @param {String} dirty a string of dirty markup
|
|
1419
1428
|
* @return {Document} a DOM, filled with the dirty markup
|
|
1420
1429
|
*/
|
|
1421
|
-
|
|
1422
1430
|
var _initDocument = function _initDocument(dirty) {
|
|
1423
1431
|
/* Create a HTML document */
|
|
1424
1432
|
var doc;
|
|
@@ -1439,64 +1447,65 @@
|
|
|
1439
1447
|
* Use the DOMParser API by default, fallback later if needs be
|
|
1440
1448
|
* DOMParser not work for svg when has multiple root element.
|
|
1441
1449
|
*/
|
|
1442
|
-
|
|
1443
1450
|
if (NAMESPACE === HTML_NAMESPACE) {
|
|
1444
1451
|
try {
|
|
1445
1452
|
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
|
1446
1453
|
} catch (_) {}
|
|
1447
1454
|
}
|
|
1448
|
-
/* Use createHTMLDocument in case DOMParser is not available */
|
|
1449
1455
|
|
|
1456
|
+
/* Use createHTMLDocument in case DOMParser is not available */
|
|
1450
1457
|
if (!doc || !doc.documentElement) {
|
|
1451
1458
|
doc = implementation.createDocument(NAMESPACE, 'template', null);
|
|
1452
1459
|
try {
|
|
1453
1460
|
doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
|
|
1454
|
-
} catch (_) {
|
|
1461
|
+
} catch (_) {
|
|
1462
|
+
// Syntax error if dirtyPayload is invalid xml
|
|
1455
1463
|
}
|
|
1456
1464
|
}
|
|
1457
1465
|
var body = doc.body || doc.documentElement;
|
|
1458
1466
|
if (dirty && leadingWhitespace) {
|
|
1459
1467
|
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
|
1460
1468
|
}
|
|
1461
|
-
/* Work on whole document or just its body */
|
|
1462
1469
|
|
|
1470
|
+
/* Work on whole document or just its body */
|
|
1463
1471
|
if (NAMESPACE === HTML_NAMESPACE) {
|
|
1464
1472
|
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
|
1465
1473
|
}
|
|
1466
1474
|
return WHOLE_DOCUMENT ? doc.documentElement : body;
|
|
1467
1475
|
};
|
|
1476
|
+
|
|
1468
1477
|
/**
|
|
1469
1478
|
* _createIterator
|
|
1470
1479
|
*
|
|
1471
1480
|
* @param {Document} root document/fragment to create iterator for
|
|
1472
1481
|
* @return {Iterator} iterator instance
|
|
1473
1482
|
*/
|
|
1474
|
-
|
|
1475
1483
|
var _createIterator = function _createIterator(root) {
|
|
1476
1484
|
return createNodeIterator.call(root.ownerDocument || root, root,
|
|
1477
1485
|
// eslint-disable-next-line no-bitwise
|
|
1478
|
-
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
|
|
1486
|
+
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null, false);
|
|
1479
1487
|
};
|
|
1488
|
+
|
|
1480
1489
|
/**
|
|
1481
1490
|
* _isClobbered
|
|
1482
1491
|
*
|
|
1483
1492
|
* @param {Node} elm element to check for clobbering attacks
|
|
1484
1493
|
* @return {Boolean} true if clobbered, false if safe
|
|
1485
1494
|
*/
|
|
1486
|
-
|
|
1487
1495
|
var _isClobbered = function _isClobbered(elm) {
|
|
1488
1496
|
return elm instanceof HTMLFormElement && (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' || typeof elm.hasChildNodes !== 'function');
|
|
1489
1497
|
};
|
|
1498
|
+
|
|
1490
1499
|
/**
|
|
1491
1500
|
* _isNode
|
|
1492
1501
|
*
|
|
1493
1502
|
* @param {Node} obj object to check whether it's a DOM node
|
|
1494
1503
|
* @return {Boolean} true is object is a DOM node
|
|
1495
1504
|
*/
|
|
1496
|
-
|
|
1497
1505
|
var _isNode = function _isNode(object) {
|
|
1498
1506
|
return _typeof(Node) === 'object' ? object instanceof Node : object && _typeof(object) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
|
|
1499
1507
|
};
|
|
1508
|
+
|
|
1500
1509
|
/**
|
|
1501
1510
|
* _executeHook
|
|
1502
1511
|
* Execute user configurable hooks
|
|
@@ -1505,7 +1514,6 @@
|
|
|
1505
1514
|
* @param {Node} currentNode node to work on with the hook
|
|
1506
1515
|
* @param {Object} data additional hook parameters
|
|
1507
1516
|
*/
|
|
1508
|
-
|
|
1509
1517
|
var _executeHook = function _executeHook(entryPoint, currentNode, data) {
|
|
1510
1518
|
if (!hooks[entryPoint]) {
|
|
1511
1519
|
return;
|
|
@@ -1514,6 +1522,7 @@
|
|
|
1514
1522
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
1515
1523
|
});
|
|
1516
1524
|
};
|
|
1525
|
+
|
|
1517
1526
|
/**
|
|
1518
1527
|
* _sanitizeElements
|
|
1519
1528
|
*
|
|
@@ -1524,55 +1533,66 @@
|
|
|
1524
1533
|
* @param {Node} currentNode to check for permission to exist
|
|
1525
1534
|
* @return {Boolean} true if node was killed, false if left alive
|
|
1526
1535
|
*/
|
|
1527
|
-
|
|
1528
1536
|
var _sanitizeElements = function _sanitizeElements(currentNode) {
|
|
1529
1537
|
var content;
|
|
1530
|
-
/* Execute a hook if present */
|
|
1531
1538
|
|
|
1539
|
+
/* Execute a hook if present */
|
|
1532
1540
|
_executeHook('beforeSanitizeElements', currentNode, null);
|
|
1533
|
-
/* Check if element is clobbered or can clobber */
|
|
1534
1541
|
|
|
1542
|
+
/* Check if element is clobbered or can clobber */
|
|
1535
1543
|
if (_isClobbered(currentNode)) {
|
|
1536
1544
|
_forceRemove(currentNode);
|
|
1537
1545
|
return true;
|
|
1538
1546
|
}
|
|
1539
|
-
/* Check if tagname contains Unicode */
|
|
1540
1547
|
|
|
1548
|
+
/* Check if tagname contains Unicode */
|
|
1541
1549
|
if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) {
|
|
1542
1550
|
_forceRemove(currentNode);
|
|
1543
1551
|
return true;
|
|
1544
1552
|
}
|
|
1545
|
-
/* Now let's check the element's type and name */
|
|
1546
1553
|
|
|
1554
|
+
/* Now let's check the element's type and name */
|
|
1547
1555
|
var tagName = transformCaseFunc(currentNode.nodeName);
|
|
1548
|
-
/* Execute a hook if present */
|
|
1549
1556
|
|
|
1557
|
+
/* Execute a hook if present */
|
|
1550
1558
|
_executeHook('uponSanitizeElement', currentNode, {
|
|
1551
1559
|
tagName: tagName,
|
|
1552
1560
|
allowedTags: ALLOWED_TAGS
|
|
1553
1561
|
});
|
|
1554
|
-
/* Detect mXSS attempts abusing namespace confusion */
|
|
1555
1562
|
|
|
1563
|
+
/* Detect mXSS attempts abusing namespace confusion */
|
|
1556
1564
|
if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
|
|
1557
1565
|
_forceRemove(currentNode);
|
|
1558
1566
|
return true;
|
|
1559
1567
|
}
|
|
1560
|
-
/* Mitigate a problem with templates inside select */
|
|
1561
1568
|
|
|
1569
|
+
/* Mitigate a problem with templates inside select */
|
|
1562
1570
|
if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
|
|
1563
1571
|
_forceRemove(currentNode);
|
|
1564
1572
|
return true;
|
|
1565
1573
|
}
|
|
1566
|
-
/* Remove element if anything forbids its presence */
|
|
1567
1574
|
|
|
1575
|
+
/* Remove any ocurrence of processing instructions */
|
|
1576
|
+
if (currentNode.nodeType === 7) {
|
|
1577
|
+
_forceRemove(currentNode);
|
|
1578
|
+
return true;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
/* Remove any kind of possibly harmful comments */
|
|
1582
|
+
if (SAFE_FOR_XML && currentNode.nodeType === 8 && regExpTest(/<[/\w]/g, currentNode.data)) {
|
|
1583
|
+
_forceRemove(currentNode);
|
|
1584
|
+
return true;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
/* Remove element if anything forbids its presence */
|
|
1568
1588
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1569
1589
|
/* Check if we have a custom element to handle */
|
|
1570
1590
|
if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
|
|
1571
1591
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
|
|
1572
1592
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
|
|
1573
1593
|
}
|
|
1574
|
-
/* Keep content except for bad-listed elements */
|
|
1575
1594
|
|
|
1595
|
+
/* Keep content except for bad-listed elements */
|
|
1576
1596
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
1577
1597
|
var parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
|
1578
1598
|
var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
|
@@ -1586,20 +1606,20 @@
|
|
|
1586
1606
|
_forceRemove(currentNode);
|
|
1587
1607
|
return true;
|
|
1588
1608
|
}
|
|
1589
|
-
/* Check whether element has a valid namespace */
|
|
1590
1609
|
|
|
1610
|
+
/* Check whether element has a valid namespace */
|
|
1591
1611
|
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
|
|
1592
1612
|
_forceRemove(currentNode);
|
|
1593
1613
|
return true;
|
|
1594
1614
|
}
|
|
1595
|
-
/* Make sure that older browsers don't get fallback-tag mXSS */
|
|
1596
1615
|
|
|
1616
|
+
/* Make sure that older browsers don't get fallback-tag mXSS */
|
|
1597
1617
|
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
|
|
1598
1618
|
_forceRemove(currentNode);
|
|
1599
1619
|
return true;
|
|
1600
1620
|
}
|
|
1601
|
-
/* Sanitize element content to be template-safe */
|
|
1602
1621
|
|
|
1622
|
+
/* Sanitize element content to be template-safe */
|
|
1603
1623
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
|
|
1604
1624
|
/* Get the element's text content */
|
|
1605
1625
|
content = currentNode.textContent;
|
|
@@ -1613,11 +1633,12 @@
|
|
|
1613
1633
|
currentNode.textContent = content;
|
|
1614
1634
|
}
|
|
1615
1635
|
}
|
|
1616
|
-
/* Execute a hook if present */
|
|
1617
1636
|
|
|
1637
|
+
/* Execute a hook if present */
|
|
1618
1638
|
_executeHook('afterSanitizeElements', currentNode, null);
|
|
1619
1639
|
return false;
|
|
1620
1640
|
};
|
|
1641
|
+
|
|
1621
1642
|
/**
|
|
1622
1643
|
* _isValidAttribute
|
|
1623
1644
|
*
|
|
@@ -1627,17 +1648,16 @@
|
|
|
1627
1648
|
* @return {Boolean} Returns true if `value` is valid, otherwise false.
|
|
1628
1649
|
*/
|
|
1629
1650
|
// eslint-disable-next-line complexity
|
|
1630
|
-
|
|
1631
1651
|
var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1632
1652
|
/* Make sure attribute cannot clobber */
|
|
1633
1653
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1634
1654
|
return false;
|
|
1635
1655
|
}
|
|
1656
|
+
|
|
1636
1657
|
/* Allow valid data-* attributes: At least one character after "-"
|
|
1637
1658
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
1638
1659
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
1639
1660
|
We don't need to check the value; it's always URI safe. */
|
|
1640
|
-
|
|
1641
1661
|
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]) {
|
|
1642
1662
|
if (
|
|
1643
1663
|
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
@@ -1655,16 +1675,17 @@
|
|
|
1655
1675
|
} else ;
|
|
1656
1676
|
return true;
|
|
1657
1677
|
};
|
|
1678
|
+
|
|
1658
1679
|
/**
|
|
1659
1680
|
* _basicCustomElementCheck
|
|
1660
1681
|
* checks if at least one dash is included in tagName, and it's not the first char
|
|
1661
1682
|
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
|
1662
1683
|
* @param {string} tagName name of the tag of the node to sanitize
|
|
1663
1684
|
*/
|
|
1664
|
-
|
|
1665
1685
|
var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
|
|
1666
|
-
return tagName
|
|
1686
|
+
return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT$1);
|
|
1667
1687
|
};
|
|
1688
|
+
|
|
1668
1689
|
/**
|
|
1669
1690
|
* _sanitizeAttributes
|
|
1670
1691
|
*
|
|
@@ -1675,18 +1696,16 @@
|
|
|
1675
1696
|
*
|
|
1676
1697
|
* @param {Node} currentNode to sanitize
|
|
1677
1698
|
*/
|
|
1678
|
-
|
|
1679
1699
|
var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
1680
1700
|
var attr;
|
|
1681
1701
|
var value;
|
|
1682
1702
|
var lcName;
|
|
1683
1703
|
var l;
|
|
1684
1704
|
/* Execute a hook if present */
|
|
1685
|
-
|
|
1686
1705
|
_executeHook('beforeSanitizeAttributes', currentNode, null);
|
|
1687
1706
|
var attributes = currentNode.attributes;
|
|
1688
|
-
/* Check if we have attributes; if not we might have a text node */
|
|
1689
1707
|
|
|
1708
|
+
/* Check if we have attributes; if not we might have a text node */
|
|
1690
1709
|
if (!attributes) {
|
|
1691
1710
|
return;
|
|
1692
1711
|
}
|
|
@@ -1697,8 +1716,8 @@
|
|
|
1697
1716
|
allowedAttributes: ALLOWED_ATTR
|
|
1698
1717
|
};
|
|
1699
1718
|
l = attributes.length;
|
|
1700
|
-
/* Go backwards over all attributes; safely remove bad ones */
|
|
1701
1719
|
|
|
1720
|
+
/* Go backwards over all attributes; safely remove bad ones */
|
|
1702
1721
|
while (l--) {
|
|
1703
1722
|
attr = attributes[l];
|
|
1704
1723
|
var _attr = attr,
|
|
@@ -1706,59 +1725,58 @@
|
|
|
1706
1725
|
namespaceURI = _attr.namespaceURI;
|
|
1707
1726
|
value = name === 'value' ? attr.value : stringTrim(attr.value);
|
|
1708
1727
|
lcName = transformCaseFunc(name);
|
|
1709
|
-
/* Execute a hook if present */
|
|
1710
1728
|
|
|
1729
|
+
/* Execute a hook if present */
|
|
1711
1730
|
hookEvent.attrName = lcName;
|
|
1712
1731
|
hookEvent.attrValue = value;
|
|
1713
1732
|
hookEvent.keepAttr = true;
|
|
1714
1733
|
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
|
1715
|
-
|
|
1716
1734
|
_executeHook('uponSanitizeAttribute', currentNode, hookEvent);
|
|
1717
1735
|
value = hookEvent.attrValue;
|
|
1718
1736
|
/* Did the hooks approve of the attribute? */
|
|
1719
|
-
|
|
1720
1737
|
if (hookEvent.forceKeepAttr) {
|
|
1721
1738
|
continue;
|
|
1722
1739
|
}
|
|
1723
|
-
/* Remove attribute */
|
|
1724
1740
|
|
|
1741
|
+
/* Remove attribute */
|
|
1725
1742
|
_removeAttribute(name, currentNode);
|
|
1726
|
-
/* Did the hooks approve of the attribute? */
|
|
1727
1743
|
|
|
1744
|
+
/* Did the hooks approve of the attribute? */
|
|
1728
1745
|
if (!hookEvent.keepAttr) {
|
|
1729
1746
|
continue;
|
|
1730
1747
|
}
|
|
1731
|
-
/* Work around a security issue in jQuery 3.0 */
|
|
1732
1748
|
|
|
1749
|
+
/* Work around a security issue in jQuery 3.0 */
|
|
1733
1750
|
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
|
1734
1751
|
_removeAttribute(name, currentNode);
|
|
1735
1752
|
continue;
|
|
1736
1753
|
}
|
|
1737
|
-
/* Sanitize attribute content to be template-safe */
|
|
1738
1754
|
|
|
1755
|
+
/* Sanitize attribute content to be template-safe */
|
|
1739
1756
|
if (SAFE_FOR_TEMPLATES) {
|
|
1740
1757
|
value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
|
|
1741
1758
|
value = stringReplace(value, ERB_EXPR$1, ' ');
|
|
1742
1759
|
value = stringReplace(value, TMPLIT_EXPR$1, ' ');
|
|
1743
1760
|
}
|
|
1744
|
-
/* Is `value` valid for this attribute? */
|
|
1745
1761
|
|
|
1762
|
+
/* Is `value` valid for this attribute? */
|
|
1746
1763
|
var lcTag = transformCaseFunc(currentNode.nodeName);
|
|
1747
1764
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1748
1765
|
continue;
|
|
1749
1766
|
}
|
|
1767
|
+
|
|
1750
1768
|
/* Full DOM Clobbering protection via namespace isolation,
|
|
1751
1769
|
* Prefix id and name attributes with `user-content-`
|
|
1752
1770
|
*/
|
|
1753
|
-
|
|
1754
1771
|
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
1755
1772
|
// Remove the attribute with this value
|
|
1756
|
-
_removeAttribute(name, currentNode);
|
|
1773
|
+
_removeAttribute(name, currentNode);
|
|
1757
1774
|
|
|
1775
|
+
// Prefix the value and later re-create the attribute with the sanitized value
|
|
1758
1776
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
1759
1777
|
}
|
|
1760
|
-
/* Handle attributes that require Trusted Types */
|
|
1761
1778
|
|
|
1779
|
+
/* Handle attributes that require Trusted Types */
|
|
1762
1780
|
if (trustedTypesPolicy && _typeof(trustedTypes) === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
|
1763
1781
|
if (namespaceURI) ;else {
|
|
1764
1782
|
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
|
@@ -1775,8 +1793,8 @@
|
|
|
1775
1793
|
}
|
|
1776
1794
|
}
|
|
1777
1795
|
}
|
|
1778
|
-
/* Handle invalid data-* attribute set by try-catching it */
|
|
1779
1796
|
|
|
1797
|
+
/* Handle invalid data-* attribute set by try-catching it */
|
|
1780
1798
|
try {
|
|
1781
1799
|
if (namespaceURI) {
|
|
1782
1800
|
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
@@ -1787,43 +1805,44 @@
|
|
|
1787
1805
|
arrayPop(DOMPurify.removed);
|
|
1788
1806
|
} catch (_) {}
|
|
1789
1807
|
}
|
|
1790
|
-
/* Execute a hook if present */
|
|
1791
1808
|
|
|
1809
|
+
/* Execute a hook if present */
|
|
1792
1810
|
_executeHook('afterSanitizeAttributes', currentNode, null);
|
|
1793
1811
|
};
|
|
1812
|
+
|
|
1794
1813
|
/**
|
|
1795
1814
|
* _sanitizeShadowDOM
|
|
1796
1815
|
*
|
|
1797
1816
|
* @param {DocumentFragment} fragment to iterate over recursively
|
|
1798
1817
|
*/
|
|
1799
|
-
|
|
1800
1818
|
var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
|
1801
1819
|
var shadowNode;
|
|
1802
1820
|
var shadowIterator = _createIterator(fragment);
|
|
1803
|
-
/* Execute a hook if present */
|
|
1804
1821
|
|
|
1822
|
+
/* Execute a hook if present */
|
|
1805
1823
|
_executeHook('beforeSanitizeShadowDOM', fragment, null);
|
|
1806
1824
|
while (shadowNode = shadowIterator.nextNode()) {
|
|
1807
1825
|
/* Execute a hook if present */
|
|
1808
1826
|
_executeHook('uponSanitizeShadowNode', shadowNode, null);
|
|
1809
|
-
/* Sanitize tags and elements */
|
|
1810
1827
|
|
|
1828
|
+
/* Sanitize tags and elements */
|
|
1811
1829
|
if (_sanitizeElements(shadowNode)) {
|
|
1812
1830
|
continue;
|
|
1813
1831
|
}
|
|
1814
|
-
/* Deep shadow DOM detected */
|
|
1815
1832
|
|
|
1833
|
+
/* Deep shadow DOM detected */
|
|
1816
1834
|
if (shadowNode.content instanceof DocumentFragment) {
|
|
1817
1835
|
_sanitizeShadowDOM(shadowNode.content);
|
|
1818
1836
|
}
|
|
1819
|
-
/* Check attributes, sanitize if necessary */
|
|
1820
1837
|
|
|
1838
|
+
/* Check attributes, sanitize if necessary */
|
|
1821
1839
|
_sanitizeAttributes(shadowNode);
|
|
1822
1840
|
}
|
|
1823
|
-
/* Execute a hook if present */
|
|
1824
1841
|
|
|
1842
|
+
/* Execute a hook if present */
|
|
1825
1843
|
_executeHook('afterSanitizeShadowDOM', fragment, null);
|
|
1826
1844
|
};
|
|
1845
|
+
|
|
1827
1846
|
/**
|
|
1828
1847
|
* Sanitize
|
|
1829
1848
|
* Public method providing core sanitation functionality
|
|
@@ -1832,7 +1851,6 @@
|
|
|
1832
1851
|
* @param {Object} configuration object
|
|
1833
1852
|
*/
|
|
1834
1853
|
// eslint-disable-next-line complexity
|
|
1835
|
-
|
|
1836
1854
|
DOMPurify.sanitize = function (dirty) {
|
|
1837
1855
|
var cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1838
1856
|
var body;
|
|
@@ -1843,13 +1861,12 @@
|
|
|
1843
1861
|
/* Make sure we have a string to sanitize.
|
|
1844
1862
|
DO NOT return early, as this will return the wrong type if
|
|
1845
1863
|
the user has requested a DOM object rather than a string */
|
|
1846
|
-
|
|
1847
1864
|
IS_EMPTY_INPUT = !dirty;
|
|
1848
1865
|
if (IS_EMPTY_INPUT) {
|
|
1849
1866
|
dirty = '<!-->';
|
|
1850
1867
|
}
|
|
1851
|
-
/* Stringify, in case dirty is an object */
|
|
1852
1868
|
|
|
1869
|
+
/* Stringify, in case dirty is an object */
|
|
1853
1870
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
1854
1871
|
if (typeof dirty.toString === 'function') {
|
|
1855
1872
|
dirty = dirty.toString();
|
|
@@ -1860,8 +1877,8 @@
|
|
|
1860
1877
|
throw typeErrorCreate('toString is not a function');
|
|
1861
1878
|
}
|
|
1862
1879
|
}
|
|
1863
|
-
/* Check we can run. Otherwise fall back or ignore */
|
|
1864
1880
|
|
|
1881
|
+
/* Check we can run. Otherwise fall back or ignore */
|
|
1865
1882
|
if (!DOMPurify.isSupported) {
|
|
1866
1883
|
if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
|
|
1867
1884
|
if (typeof dirty === 'string') {
|
|
@@ -1873,16 +1890,16 @@
|
|
|
1873
1890
|
}
|
|
1874
1891
|
return dirty;
|
|
1875
1892
|
}
|
|
1876
|
-
/* Assign config vars */
|
|
1877
1893
|
|
|
1894
|
+
/* Assign config vars */
|
|
1878
1895
|
if (!SET_CONFIG) {
|
|
1879
1896
|
_parseConfig(cfg);
|
|
1880
1897
|
}
|
|
1881
|
-
/* Clean up removed elements */
|
|
1882
1898
|
|
|
1899
|
+
/* Clean up removed elements */
|
|
1883
1900
|
DOMPurify.removed = [];
|
|
1884
|
-
/* Check if dirty is correctly typed for IN_PLACE */
|
|
1885
1901
|
|
|
1902
|
+
/* Check if dirty is correctly typed for IN_PLACE */
|
|
1886
1903
|
if (typeof dirty === 'string') {
|
|
1887
1904
|
IN_PLACE = false;
|
|
1888
1905
|
}
|
|
@@ -1915,53 +1932,53 @@
|
|
|
1915
1932
|
dirty.indexOf('<') === -1) {
|
|
1916
1933
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
1917
1934
|
}
|
|
1918
|
-
/* Initialize the document to work on */
|
|
1919
1935
|
|
|
1936
|
+
/* Initialize the document to work on */
|
|
1920
1937
|
body = _initDocument(dirty);
|
|
1921
|
-
/* Check we have a DOM node from the data */
|
|
1922
1938
|
|
|
1939
|
+
/* Check we have a DOM node from the data */
|
|
1923
1940
|
if (!body) {
|
|
1924
1941
|
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
|
|
1925
1942
|
}
|
|
1926
1943
|
}
|
|
1927
|
-
/* Remove first element node (ours) if FORCE_BODY is set */
|
|
1928
1944
|
|
|
1945
|
+
/* Remove first element node (ours) if FORCE_BODY is set */
|
|
1929
1946
|
if (body && FORCE_BODY) {
|
|
1930
1947
|
_forceRemove(body.firstChild);
|
|
1931
1948
|
}
|
|
1932
|
-
/* Get node iterator */
|
|
1933
1949
|
|
|
1950
|
+
/* Get node iterator */
|
|
1934
1951
|
var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
|
|
1935
|
-
/* Now start iterating over the created document */
|
|
1936
1952
|
|
|
1953
|
+
/* Now start iterating over the created document */
|
|
1937
1954
|
while (currentNode = nodeIterator.nextNode()) {
|
|
1938
1955
|
/* Fix IE's strange behavior with manipulated textNodes #89 */
|
|
1939
1956
|
if (currentNode.nodeType === 3 && currentNode === oldNode) {
|
|
1940
1957
|
continue;
|
|
1941
1958
|
}
|
|
1942
|
-
/* Sanitize tags and elements */
|
|
1943
1959
|
|
|
1960
|
+
/* Sanitize tags and elements */
|
|
1944
1961
|
if (_sanitizeElements(currentNode)) {
|
|
1945
1962
|
continue;
|
|
1946
1963
|
}
|
|
1947
|
-
/* Shadow DOM detected, sanitize it */
|
|
1948
1964
|
|
|
1965
|
+
/* Shadow DOM detected, sanitize it */
|
|
1949
1966
|
if (currentNode.content instanceof DocumentFragment) {
|
|
1950
1967
|
_sanitizeShadowDOM(currentNode.content);
|
|
1951
1968
|
}
|
|
1952
|
-
/* Check attributes, sanitize if necessary */
|
|
1953
1969
|
|
|
1970
|
+
/* Check attributes, sanitize if necessary */
|
|
1954
1971
|
_sanitizeAttributes(currentNode);
|
|
1955
1972
|
oldNode = currentNode;
|
|
1956
1973
|
}
|
|
1957
1974
|
oldNode = null;
|
|
1958
|
-
/* If we sanitized `dirty` in-place, return it. */
|
|
1959
1975
|
|
|
1976
|
+
/* If we sanitized `dirty` in-place, return it. */
|
|
1960
1977
|
if (IN_PLACE) {
|
|
1961
1978
|
return dirty;
|
|
1962
1979
|
}
|
|
1963
|
-
/* Return sanitized string or DOM */
|
|
1964
1980
|
|
|
1981
|
+
/* Return sanitized string or DOM */
|
|
1965
1982
|
if (RETURN_DOM) {
|
|
1966
1983
|
if (RETURN_DOM_FRAGMENT) {
|
|
1967
1984
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
@@ -1985,13 +2002,13 @@
|
|
|
1985
2002
|
return returnNode;
|
|
1986
2003
|
}
|
|
1987
2004
|
var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
|
1988
|
-
/* Serialize doctype if allowed */
|
|
1989
2005
|
|
|
2006
|
+
/* Serialize doctype if allowed */
|
|
1990
2007
|
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
|
1991
2008
|
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
|
1992
2009
|
}
|
|
1993
|
-
/* Sanitize final string template-safe */
|
|
1994
2010
|
|
|
2011
|
+
/* Sanitize final string template-safe */
|
|
1995
2012
|
if (SAFE_FOR_TEMPLATES) {
|
|
1996
2013
|
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, ' ');
|
|
1997
2014
|
serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, ' ');
|
|
@@ -1999,27 +2016,28 @@
|
|
|
1999
2016
|
}
|
|
2000
2017
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
2001
2018
|
};
|
|
2019
|
+
|
|
2002
2020
|
/**
|
|
2003
2021
|
* Public method to set the configuration once
|
|
2004
2022
|
* setConfig
|
|
2005
2023
|
*
|
|
2006
2024
|
* @param {Object} cfg configuration object
|
|
2007
2025
|
*/
|
|
2008
|
-
|
|
2009
2026
|
DOMPurify.setConfig = function (cfg) {
|
|
2010
2027
|
_parseConfig(cfg);
|
|
2011
2028
|
SET_CONFIG = true;
|
|
2012
2029
|
};
|
|
2030
|
+
|
|
2013
2031
|
/**
|
|
2014
2032
|
* Public method to remove the configuration
|
|
2015
2033
|
* clearConfig
|
|
2016
2034
|
*
|
|
2017
2035
|
*/
|
|
2018
|
-
|
|
2019
2036
|
DOMPurify.clearConfig = function () {
|
|
2020
2037
|
CONFIG = null;
|
|
2021
2038
|
SET_CONFIG = false;
|
|
2022
2039
|
};
|
|
2040
|
+
|
|
2023
2041
|
/**
|
|
2024
2042
|
* Public method to check if an attribute value is valid.
|
|
2025
2043
|
* Uses last set config, if any. Otherwise, uses config defaults.
|
|
@@ -2030,7 +2048,6 @@
|
|
|
2030
2048
|
* @param {string} value Attribute value.
|
|
2031
2049
|
* @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
|
|
2032
2050
|
*/
|
|
2033
|
-
|
|
2034
2051
|
DOMPurify.isValidAttribute = function (tag, attr, value) {
|
|
2035
2052
|
/* Initialize shared config vars if necessary. */
|
|
2036
2053
|
if (!CONFIG) {
|
|
@@ -2040,6 +2057,7 @@
|
|
|
2040
2057
|
var lcName = transformCaseFunc(attr);
|
|
2041
2058
|
return _isValidAttribute(lcTag, lcName, value);
|
|
2042
2059
|
};
|
|
2060
|
+
|
|
2043
2061
|
/**
|
|
2044
2062
|
* AddHook
|
|
2045
2063
|
* Public method to add DOMPurify hooks
|
|
@@ -2047,7 +2065,6 @@
|
|
|
2047
2065
|
* @param {String} entryPoint entry point for the hook to add
|
|
2048
2066
|
* @param {Function} hookFunction function to execute
|
|
2049
2067
|
*/
|
|
2050
|
-
|
|
2051
2068
|
DOMPurify.addHook = function (entryPoint, hookFunction) {
|
|
2052
2069
|
if (typeof hookFunction !== 'function') {
|
|
2053
2070
|
return;
|
|
@@ -2055,6 +2072,7 @@
|
|
|
2055
2072
|
hooks[entryPoint] = hooks[entryPoint] || [];
|
|
2056
2073
|
arrayPush(hooks[entryPoint], hookFunction);
|
|
2057
2074
|
};
|
|
2075
|
+
|
|
2058
2076
|
/**
|
|
2059
2077
|
* RemoveHook
|
|
2060
2078
|
* Public method to remove a DOMPurify hook at a given entryPoint
|
|
@@ -2063,30 +2081,29 @@
|
|
|
2063
2081
|
* @param {String} entryPoint entry point for the hook to remove
|
|
2064
2082
|
* @return {Function} removed(popped) hook
|
|
2065
2083
|
*/
|
|
2066
|
-
|
|
2067
2084
|
DOMPurify.removeHook = function (entryPoint) {
|
|
2068
2085
|
if (hooks[entryPoint]) {
|
|
2069
2086
|
return arrayPop(hooks[entryPoint]);
|
|
2070
2087
|
}
|
|
2071
2088
|
};
|
|
2089
|
+
|
|
2072
2090
|
/**
|
|
2073
2091
|
* RemoveHooks
|
|
2074
2092
|
* Public method to remove all DOMPurify hooks at a given entryPoint
|
|
2075
2093
|
*
|
|
2076
2094
|
* @param {String} entryPoint entry point for the hooks to remove
|
|
2077
2095
|
*/
|
|
2078
|
-
|
|
2079
2096
|
DOMPurify.removeHooks = function (entryPoint) {
|
|
2080
2097
|
if (hooks[entryPoint]) {
|
|
2081
2098
|
hooks[entryPoint] = [];
|
|
2082
2099
|
}
|
|
2083
2100
|
};
|
|
2101
|
+
|
|
2084
2102
|
/**
|
|
2085
2103
|
* RemoveAllHooks
|
|
2086
2104
|
* Public method to remove all DOMPurify hooks
|
|
2087
2105
|
*
|
|
2088
2106
|
*/
|
|
2089
|
-
|
|
2090
2107
|
DOMPurify.removeAllHooks = function () {
|
|
2091
2108
|
hooks = {};
|
|
2092
2109
|
};
|