source: imaps-frontend/node_modules/dompurify/dist/purify.cjs.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 62.8 KB
RevLine 
[79a0317]1/*! @license DOMPurify 2.5.8 | (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.8/LICENSE */
2
3'use strict';
4
5function _typeof(obj) {
6 "@babel/helpers - typeof";
7
8 return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
9 return typeof obj;
10 } : function (obj) {
11 return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
12 }, _typeof(obj);
13}
14function _setPrototypeOf(o, p) {
15 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
16 o.__proto__ = p;
17 return o;
18 };
19 return _setPrototypeOf(o, p);
20}
21function _isNativeReflectConstruct() {
22 if (typeof Reflect === "undefined" || !Reflect.construct) return false;
23 if (Reflect.construct.sham) return false;
24 if (typeof Proxy === "function") return true;
25 try {
26 Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
27 return true;
28 } catch (e) {
29 return false;
30 }
31}
32function _construct(Parent, args, Class) {
33 if (_isNativeReflectConstruct()) {
34 _construct = Reflect.construct;
35 } else {
36 _construct = function _construct(Parent, args, Class) {
37 var a = [null];
38 a.push.apply(a, args);
39 var Constructor = Function.bind.apply(Parent, a);
40 var instance = new Constructor();
41 if (Class) _setPrototypeOf(instance, Class.prototype);
42 return instance;
43 };
44 }
45 return _construct.apply(null, arguments);
46}
47function _toConsumableArray(arr) {
48 return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
49}
50function _arrayWithoutHoles(arr) {
51 if (Array.isArray(arr)) return _arrayLikeToArray(arr);
52}
53function _iterableToArray(iter) {
54 if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
55}
56function _unsupportedIterableToArray(o, minLen) {
57 if (!o) return;
58 if (typeof o === "string") return _arrayLikeToArray(o, minLen);
59 var n = Object.prototype.toString.call(o).slice(8, -1);
60 if (n === "Object" && o.constructor) n = o.constructor.name;
61 if (n === "Map" || n === "Set") return Array.from(o);
62 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
63}
64function _arrayLikeToArray(arr, len) {
65 if (len == null || len > arr.length) len = arr.length;
66 for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
67 return arr2;
68}
69function _nonIterableSpread() {
70 throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
71}
72
73var hasOwnProperty = Object.hasOwnProperty,
74 setPrototypeOf = Object.setPrototypeOf,
75 isFrozen = Object.isFrozen,
76 getPrototypeOf = Object.getPrototypeOf,
77 getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
78var freeze = Object.freeze,
79 seal = Object.seal,
80 create = Object.create; // eslint-disable-line import/no-mutable-exports
81var _ref = typeof Reflect !== 'undefined' && Reflect,
82 apply = _ref.apply,
83 construct = _ref.construct;
84if (!apply) {
85 apply = function apply(fun, thisValue, args) {
86 return fun.apply(thisValue, args);
87 };
88}
89if (!freeze) {
90 freeze = function freeze(x) {
91 return x;
92 };
93}
94if (!seal) {
95 seal = function seal(x) {
96 return x;
97 };
98}
99if (!construct) {
100 construct = function construct(Func, args) {
101 return _construct(Func, _toConsumableArray(args));
102 };
103}
104var arrayForEach = unapply(Array.prototype.forEach);
105var arrayPop = unapply(Array.prototype.pop);
106var arrayPush = unapply(Array.prototype.push);
107var stringToLowerCase = unapply(String.prototype.toLowerCase);
108var stringToString = unapply(String.prototype.toString);
109var stringMatch = unapply(String.prototype.match);
110var stringReplace = unapply(String.prototype.replace);
111var stringIndexOf = unapply(String.prototype.indexOf);
112var stringTrim = unapply(String.prototype.trim);
113var regExpTest = unapply(RegExp.prototype.test);
114var typeErrorCreate = unconstruct(TypeError);
115function unapply(func) {
116 return function (thisArg) {
117 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
118 args[_key - 1] = arguments[_key];
119 }
120 return apply(func, thisArg, args);
121 };
122}
123function unconstruct(func) {
124 return function () {
125 for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
126 args[_key2] = arguments[_key2];
127 }
128 return construct(func, args);
129 };
130}
131
132/* Add properties to a lookup table */
133function addToSet(set, array, transformCaseFunc) {
134 var _transformCaseFunc;
135 transformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;
136 if (setPrototypeOf) {
137 // Make 'in' and truthy checks like Boolean(set.constructor)
138 // independent of any properties defined on Object.prototype.
139 // Prevent prototype setters from intercepting set as a this value.
140 setPrototypeOf(set, null);
141 }
142 var l = array.length;
143 while (l--) {
144 var element = array[l];
145 if (typeof element === 'string') {
146 var lcElement = transformCaseFunc(element);
147 if (lcElement !== element) {
148 // Config presets (e.g. tags.js, attrs.js) are immutable.
149 if (!isFrozen(array)) {
150 array[l] = lcElement;
151 }
152 element = lcElement;
153 }
154 }
155 set[element] = true;
156 }
157 return set;
158}
159
160/* Shallow clone an object */
161function clone(object) {
162 var newObject = create(null);
163 var property;
164 for (property in object) {
165 if (apply(hasOwnProperty, object, [property]) === true) {
166 newObject[property] = object[property];
167 }
168 }
169 return newObject;
170}
171
172/* IE10 doesn't support __lookupGetter__ so lets'
173 * simulate it. It also automatically checks
174 * if the prop is function or getter and behaves
175 * accordingly. */
176function lookupGetter(object, prop) {
177 while (object !== null) {
178 var desc = getOwnPropertyDescriptor(object, prop);
179 if (desc) {
180 if (desc.get) {
181 return unapply(desc.get);
182 }
183 if (typeof desc.value === 'function') {
184 return unapply(desc.value);
185 }
186 }
187 object = getPrototypeOf(object);
188 }
189 function fallbackValue(element) {
190 console.warn('fallback value for', element);
191 return null;
192 }
193 return fallbackValue;
194}
195
196var 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']);
197
198// SVG
199var 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']);
200var 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']);
201
202// List of SVG elements that are disallowed by default.
203// We still need to know them so that we can do namespace
204// checks properly in case one wants to add them to
205// allow-list.
206var 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']);
207var 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']);
208
209// Similarly to SVG, we want to know all MathML elements,
210// even those that we disallow by default.
211var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
212var text = freeze(['#text']);
213
214var 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']);
215var 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']);
216var 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']);
217var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
218
219// eslint-disable-next-line unicorn/better-regex
220var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
221var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
222var TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
223var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
224var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
225var 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
226);
227var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
228var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
229);
230var DOCTYPE_NAME = seal(/^html$/i);
231var CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
232
233var getGlobal = function getGlobal() {
234 return typeof window === 'undefined' ? null : window;
235};
236
237/**
238 * Creates a no-op policy for internal use only.
239 * Don't export this function outside this module!
240 * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
241 * @param {Document} document The document object (to determine policy name suffix)
242 * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
243 * are not supported).
244 */
245var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
246 if (_typeof(trustedTypes) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
247 return null;
248 }
249
250 // Allow the callers to control the unique policy name
251 // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
252 // Policy creation with duplicate names throws in Trusted Types.
253 var suffix = null;
254 var ATTR_NAME = 'data-tt-policy-suffix';
255 if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
256 suffix = document.currentScript.getAttribute(ATTR_NAME);
257 }
258 var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
259 try {
260 return trustedTypes.createPolicy(policyName, {
261 createHTML: function createHTML(html) {
262 return html;
263 },
264 createScriptURL: function createScriptURL(scriptUrl) {
265 return scriptUrl;
266 }
267 });
268 } catch (_) {
269 // Policy creation failed (most likely another DOMPurify script has
270 // already run). Skip creating the policy, as this will only cause errors
271 // if TT are enforced.
272 console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
273 return null;
274 }
275};
276function createDOMPurify() {
277 var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
278 var DOMPurify = function DOMPurify(root) {
279 return createDOMPurify(root);
280 };
281
282 /**
283 * Version label, exposed for easier checks
284 * if DOMPurify is up to date or not
285 */
286 DOMPurify.version = '2.5.8';
287
288 /**
289 * Array of elements that DOMPurify removed during sanitation.
290 * Empty if nothing was removed.
291 */
292 DOMPurify.removed = [];
293 if (!window || !window.document || window.document.nodeType !== 9) {
294 // Not running in a browser, provide a factory function
295 // so that you can pass your own Window
296 DOMPurify.isSupported = false;
297 return DOMPurify;
298 }
299 var originalDocument = window.document;
300 var document = window.document;
301 var DocumentFragment = window.DocumentFragment,
302 HTMLTemplateElement = window.HTMLTemplateElement,
303 Node = window.Node,
304 Element = window.Element,
305 NodeFilter = window.NodeFilter,
306 _window$NamedNodeMap = window.NamedNodeMap,
307 NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
308 HTMLFormElement = window.HTMLFormElement,
309 DOMParser = window.DOMParser,
310 trustedTypes = window.trustedTypes;
311 var ElementPrototype = Element.prototype;
312 var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
313 var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
314 var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
315 var getParentNode = lookupGetter(ElementPrototype, 'parentNode');
316
317 // As per issue #47, the web-components registry is inherited by a
318 // new document created via createHTMLDocument. As per the spec
319 // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
320 // a new empty registry is used when creating a template contents owner
321 // document, so we use that as our parent document to ensure nothing
322 // is inherited.
323 if (typeof HTMLTemplateElement === 'function') {
324 var template = document.createElement('template');
325 if (template.content && template.content.ownerDocument) {
326 document = template.content.ownerDocument;
327 }
328 }
329 var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
330 var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
331 var _document = document,
332 implementation = _document.implementation,
333 createNodeIterator = _document.createNodeIterator,
334 createDocumentFragment = _document.createDocumentFragment,
335 getElementsByTagName = _document.getElementsByTagName;
336 var importNode = originalDocument.importNode;
337 var documentMode = {};
338 try {
339 documentMode = clone(document).documentMode ? document.documentMode : {};
340 } catch (_) {}
341 var hooks = {};
342
343 /**
344 * Expose whether this browser supports running the full DOMPurify.
345 */
346 DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined && documentMode !== 9;
347 var MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
348 ERB_EXPR$1 = ERB_EXPR,
349 TMPLIT_EXPR$1 = TMPLIT_EXPR,
350 DATA_ATTR$1 = DATA_ATTR,
351 ARIA_ATTR$1 = ARIA_ATTR,
352 IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
353 ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
354 CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
355 var IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
356
357 /**
358 * We consider the elements and attributes below to be safe. Ideally
359 * don't add any new ones but feel free to remove unwanted ones.
360 */
361
362 /* allowed element names */
363 var ALLOWED_TAGS = null;
364 var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text)));
365
366 /* Allowed attribute names */
367 var ALLOWED_ATTR = null;
368 var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml)));
369
370 /*
371 * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
372 * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
373 * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
374 * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
375 */
376 var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
377 tagNameCheck: {
378 writable: true,
379 configurable: false,
380 enumerable: true,
381 value: null
382 },
383 attributeNameCheck: {
384 writable: true,
385 configurable: false,
386 enumerable: true,
387 value: null
388 },
389 allowCustomizedBuiltInElements: {
390 writable: true,
391 configurable: false,
392 enumerable: true,
393 value: false
394 }
395 }));
396
397 /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
398 var FORBID_TAGS = null;
399
400 /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
401 var FORBID_ATTR = null;
402
403 /* Decide if ARIA attributes are okay */
404 var ALLOW_ARIA_ATTR = true;
405
406 /* Decide if custom data attributes are okay */
407 var ALLOW_DATA_ATTR = true;
408
409 /* Decide if unknown protocols are okay */
410 var ALLOW_UNKNOWN_PROTOCOLS = false;
411
412 /* Decide if self-closing tags in attributes are allowed.
413 * Usually removed due to a mXSS issue in jQuery 3.0 */
414 var ALLOW_SELF_CLOSE_IN_ATTR = true;
415
416 /* Output should be safe for common template engines.
417 * This means, DOMPurify removes data attributes, mustaches and ERB
418 */
419 var SAFE_FOR_TEMPLATES = false;
420
421 /* Output should be safe even for XML used within HTML and alike.
422 * This means, DOMPurify removes comments when containing risky content.
423 */
424 var SAFE_FOR_XML = true;
425
426 /* Decide if document with <html>... should be returned */
427 var WHOLE_DOCUMENT = false;
428
429 /* Track whether config is already set on this instance of DOMPurify. */
430 var SET_CONFIG = false;
431
432 /* Decide if all elements (e.g. style, script) must be children of
433 * document.body. By default, browsers might move them to document.head */
434 var FORCE_BODY = false;
435
436 /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
437 * string (or a TrustedHTML object if Trusted Types are supported).
438 * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
439 */
440 var RETURN_DOM = false;
441
442 /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
443 * string (or a TrustedHTML object if Trusted Types are supported) */
444 var RETURN_DOM_FRAGMENT = false;
445
446 /* Try to return a Trusted Type object instead of a string, return a string in
447 * case Trusted Types are not supported */
448 var RETURN_TRUSTED_TYPE = false;
449
450 /* Output should be free from DOM clobbering attacks?
451 * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
452 */
453 var SANITIZE_DOM = true;
454
455 /* Achieve full DOM Clobbering protection by isolating the namespace of named
456 * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
457 *
458 * HTML/DOM spec rules that enable DOM Clobbering:
459 * - Named Access on Window (§7.3.3)
460 * - DOM Tree Accessors (§3.1.5)
461 * - Form Element Parent-Child Relations (§4.10.3)
462 * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
463 * - HTMLCollection (§4.2.10.2)
464 *
465 * Namespace isolation is implemented by prefixing `id` and `name` attributes
466 * with a constant string, i.e., `user-content-`
467 */
468 var SANITIZE_NAMED_PROPS = false;
469 var SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
470
471 /* Keep element content when removing element? */
472 var KEEP_CONTENT = true;
473
474 /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
475 * of importing it into a new Document and returning a sanitized copy */
476 var IN_PLACE = false;
477
478 /* Allow usage of profiles like html, svg and mathMl */
479 var USE_PROFILES = {};
480
481 /* Tags to ignore content of when KEEP_CONTENT is true */
482 var FORBID_CONTENTS = null;
483 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']);
484
485 /* Tags that are safe for data: URIs */
486 var DATA_URI_TAGS = null;
487 var DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
488
489 /* Attributes safe for values like "javascript:" */
490 var URI_SAFE_ATTRIBUTES = null;
491 var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
492 var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
493 var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
494 var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
495 /* Document namespace */
496 var NAMESPACE = HTML_NAMESPACE;
497 var IS_EMPTY_INPUT = false;
498
499 /* Allowed XHTML+XML namespaces */
500 var ALLOWED_NAMESPACES = null;
501 var DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
502
503 /* Parsing of strict XHTML documents */
504 var PARSER_MEDIA_TYPE;
505 var SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
506 var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
507 var transformCaseFunc;
508
509 /* Keep a reference to config to pass to hooks */
510 var CONFIG = null;
511
512 /* Ideally, do not touch anything below this line */
513 /* ______________________________________________ */
514
515 var formElement = document.createElement('form');
516 var isRegexOrFunction = function isRegexOrFunction(testValue) {
517 return testValue instanceof RegExp || testValue instanceof Function;
518 };
519
520 /**
521 * _parseConfig
522 *
523 * @param {Object} cfg optional config literal
524 */
525 // eslint-disable-next-line complexity
526 var _parseConfig = function _parseConfig(cfg) {
527 if (CONFIG && CONFIG === cfg) {
528 return;
529 }
530
531 /* Shield configuration object from tampering */
532 if (!cfg || _typeof(cfg) !== 'object') {
533 cfg = {};
534 }
535
536 /* Shield configuration object from prototype pollution */
537 cfg = clone(cfg);
538 PARSER_MEDIA_TYPE =
539 // eslint-disable-next-line unicorn/prefer-includes
540 SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
541
542 // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
543 transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
544
545 /* Set configuration parameters */
546 ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
547 ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
548 ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
549 URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),
550 // eslint-disable-line indent
551 cfg.ADD_URI_SAFE_ATTR,
552 // eslint-disable-line indent
553 transformCaseFunc // eslint-disable-line indent
554 ) // eslint-disable-line indent
555 : DEFAULT_URI_SAFE_ATTRIBUTES;
556 DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS),
557 // eslint-disable-line indent
558 cfg.ADD_DATA_URI_TAGS,
559 // eslint-disable-line indent
560 transformCaseFunc // eslint-disable-line indent
561 ) // eslint-disable-line indent
562 : DEFAULT_DATA_URI_TAGS;
563 FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
564 FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
565 FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
566 USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
567 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
568 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
569 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
570 ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
571 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
572 SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
573 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
574 RETURN_DOM = cfg.RETURN_DOM || false; // Default false
575 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
576 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
577 FORCE_BODY = cfg.FORCE_BODY || false; // Default false
578 SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
579 SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
580 KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
581 IN_PLACE = cfg.IN_PLACE || false; // Default false
582 IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1;
583 NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
584 CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
585 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
586 CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
587 }
588 if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
589 CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
590 }
591 if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
592 CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
593 }
594 if (SAFE_FOR_TEMPLATES) {
595 ALLOW_DATA_ATTR = false;
596 }
597 if (RETURN_DOM_FRAGMENT) {
598 RETURN_DOM = true;
599 }
600
601 /* Parse profile info */
602 if (USE_PROFILES) {
603 ALLOWED_TAGS = addToSet({}, _toConsumableArray(text));
604 ALLOWED_ATTR = [];
605 if (USE_PROFILES.html === true) {
606 addToSet(ALLOWED_TAGS, html$1);
607 addToSet(ALLOWED_ATTR, html);
608 }
609 if (USE_PROFILES.svg === true) {
610 addToSet(ALLOWED_TAGS, svg$1);
611 addToSet(ALLOWED_ATTR, svg);
612 addToSet(ALLOWED_ATTR, xml);
613 }
614 if (USE_PROFILES.svgFilters === true) {
615 addToSet(ALLOWED_TAGS, svgFilters);
616 addToSet(ALLOWED_ATTR, svg);
617 addToSet(ALLOWED_ATTR, xml);
618 }
619 if (USE_PROFILES.mathMl === true) {
620 addToSet(ALLOWED_TAGS, mathMl$1);
621 addToSet(ALLOWED_ATTR, mathMl);
622 addToSet(ALLOWED_ATTR, xml);
623 }
624 }
625
626 /* Merge configuration parameters */
627 if (cfg.ADD_TAGS) {
628 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
629 ALLOWED_TAGS = clone(ALLOWED_TAGS);
630 }
631 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
632 }
633 if (cfg.ADD_ATTR) {
634 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
635 ALLOWED_ATTR = clone(ALLOWED_ATTR);
636 }
637 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
638 }
639 if (cfg.ADD_URI_SAFE_ATTR) {
640 addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
641 }
642 if (cfg.FORBID_CONTENTS) {
643 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
644 FORBID_CONTENTS = clone(FORBID_CONTENTS);
645 }
646 addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
647 }
648
649 /* Add #text in case KEEP_CONTENT is set to true */
650 if (KEEP_CONTENT) {
651 ALLOWED_TAGS['#text'] = true;
652 }
653
654 /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
655 if (WHOLE_DOCUMENT) {
656 addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
657 }
658
659 /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
660 if (ALLOWED_TAGS.table) {
661 addToSet(ALLOWED_TAGS, ['tbody']);
662 delete FORBID_TAGS.tbody;
663 }
664
665 // Prevent further manipulation of configuration.
666 // Not available in IE8, Safari 5, etc.
667 if (freeze) {
668 freeze(cfg);
669 }
670 CONFIG = cfg;
671 };
672 var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
673 var HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
674
675 // Certain elements are allowed in both SVG and HTML
676 // namespace. We need to specify them explicitly
677 // so that they don't get erroneously deleted from
678 // HTML namespace.
679 var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
680
681 /* Keep track of all possible SVG and MathML tags
682 * so that we can perform the namespace checks
683 * correctly. */
684 var ALL_SVG_TAGS = addToSet({}, svg$1);
685 addToSet(ALL_SVG_TAGS, svgFilters);
686 addToSet(ALL_SVG_TAGS, svgDisallowed);
687 var ALL_MATHML_TAGS = addToSet({}, mathMl$1);
688 addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
689
690 /**
691 *
692 *
693 * @param {Element} element a DOM element whose namespace is being checked
694 * @returns {boolean} Return false if the element has a
695 * namespace that a spec-compliant parser would never
696 * return. Return true otherwise.
697 */
698 var _checkValidNamespace = function _checkValidNamespace(element) {
699 var parent = getParentNode(element);
700
701 // In JSDOM, if we're inside shadow DOM, then parentNode
702 // can be null. We just simulate parent in this case.
703 if (!parent || !parent.tagName) {
704 parent = {
705 namespaceURI: NAMESPACE,
706 tagName: 'template'
707 };
708 }
709 var tagName = stringToLowerCase(element.tagName);
710 var parentTagName = stringToLowerCase(parent.tagName);
711 if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
712 return false;
713 }
714 if (element.namespaceURI === SVG_NAMESPACE) {
715 // The only way to switch from HTML namespace to SVG
716 // is via <svg>. If it happens via any other tag, then
717 // it should be killed.
718 if (parent.namespaceURI === HTML_NAMESPACE) {
719 return tagName === 'svg';
720 }
721
722 // The only way to switch from MathML to SVG is via`
723 // svg if parent is either <annotation-xml> or MathML
724 // text integration points.
725 if (parent.namespaceURI === MATHML_NAMESPACE) {
726 return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
727 }
728
729 // We only allow elements that are defined in SVG
730 // spec. All others are disallowed in SVG namespace.
731 return Boolean(ALL_SVG_TAGS[tagName]);
732 }
733 if (element.namespaceURI === MATHML_NAMESPACE) {
734 // The only way to switch from HTML namespace to MathML
735 // is via <math>. If it happens via any other tag, then
736 // it should be killed.
737 if (parent.namespaceURI === HTML_NAMESPACE) {
738 return tagName === 'math';
739 }
740
741 // The only way to switch from SVG to MathML is via
742 // <math> and HTML integration points
743 if (parent.namespaceURI === SVG_NAMESPACE) {
744 return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
745 }
746
747 // We only allow elements that are defined in MathML
748 // spec. All others are disallowed in MathML namespace.
749 return Boolean(ALL_MATHML_TAGS[tagName]);
750 }
751 if (element.namespaceURI === HTML_NAMESPACE) {
752 // The only way to switch from SVG to HTML is via
753 // HTML integration points, and from MathML to HTML
754 // is via MathML text integration points
755 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
756 return false;
757 }
758 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
759 return false;
760 }
761
762 // We disallow tags that are specific for MathML
763 // or SVG and should never appear in HTML namespace
764 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
765 }
766
767 // For XHTML and XML documents that support custom namespaces
768 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
769 return true;
770 }
771
772 // The code should never reach this place (this means
773 // that the element somehow got namespace that is not
774 // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
775 // Return false just in case.
776 return false;
777 };
778
779 /**
780 * _forceRemove
781 *
782 * @param {Node} node a DOM node
783 */
784 var _forceRemove = function _forceRemove(node) {
785 arrayPush(DOMPurify.removed, {
786 element: node
787 });
788 try {
789 // eslint-disable-next-line unicorn/prefer-dom-node-remove
790 node.parentNode.removeChild(node);
791 } catch (_) {
792 try {
793 node.outerHTML = emptyHTML;
794 } catch (_) {
795 node.remove();
796 }
797 }
798 };
799
800 /**
801 * _removeAttribute
802 *
803 * @param {String} name an Attribute name
804 * @param {Node} node a DOM node
805 */
806 var _removeAttribute = function _removeAttribute(name, node) {
807 try {
808 arrayPush(DOMPurify.removed, {
809 attribute: node.getAttributeNode(name),
810 from: node
811 });
812 } catch (_) {
813 arrayPush(DOMPurify.removed, {
814 attribute: null,
815 from: node
816 });
817 }
818 node.removeAttribute(name);
819
820 // We void attribute values for unremovable "is"" attributes
821 if (name === 'is' && !ALLOWED_ATTR[name]) {
822 if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
823 try {
824 _forceRemove(node);
825 } catch (_) {}
826 } else {
827 try {
828 node.setAttribute(name, '');
829 } catch (_) {}
830 }
831 }
832 };
833
834 /**
835 * _initDocument
836 *
837 * @param {String} dirty a string of dirty markup
838 * @return {Document} a DOM, filled with the dirty markup
839 */
840 var _initDocument = function _initDocument(dirty) {
841 /* Create a HTML document */
842 var doc;
843 var leadingWhitespace;
844 if (FORCE_BODY) {
845 dirty = '<remove></remove>' + dirty;
846 } else {
847 /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
848 var matches = stringMatch(dirty, /^[\r\n\t ]+/);
849 leadingWhitespace = matches && matches[0];
850 }
851 if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
852 // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
853 dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
854 }
855 var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
856 /*
857 * Use the DOMParser API by default, fallback later if needs be
858 * DOMParser not work for svg when has multiple root element.
859 */
860 if (NAMESPACE === HTML_NAMESPACE) {
861 try {
862 doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
863 } catch (_) {}
864 }
865
866 /* Use createHTMLDocument in case DOMParser is not available */
867 if (!doc || !doc.documentElement) {
868 doc = implementation.createDocument(NAMESPACE, 'template', null);
869 try {
870 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
871 } catch (_) {
872 // Syntax error if dirtyPayload is invalid xml
873 }
874 }
875 var body = doc.body || doc.documentElement;
876 if (dirty && leadingWhitespace) {
877 body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
878 }
879
880 /* Work on whole document or just its body */
881 if (NAMESPACE === HTML_NAMESPACE) {
882 return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
883 }
884 return WHOLE_DOCUMENT ? doc.documentElement : body;
885 };
886
887 /**
888 * _createIterator
889 *
890 * @param {Document} root document/fragment to create iterator for
891 * @return {Iterator} iterator instance
892 */
893 var _createIterator = function _createIterator(root) {
894 return createNodeIterator.call(root.ownerDocument || root, root,
895 // eslint-disable-next-line no-bitwise
896 NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null, false);
897 };
898
899 /**
900 * _isClobbered
901 *
902 * @param {Node} elm element to check for clobbering attacks
903 * @return {Boolean} true if clobbered, false if safe
904 */
905 var _isClobbered = function _isClobbered(elm) {
906 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');
907 };
908
909 /**
910 * _isNode
911 *
912 * @param {Node} obj object to check whether it's a DOM node
913 * @return {Boolean} true is object is a DOM node
914 */
915 var _isNode = function _isNode(object) {
916 return _typeof(Node) === 'object' ? object instanceof Node : object && _typeof(object) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
917 };
918
919 /**
920 * _executeHook
921 * Execute user configurable hooks
922 *
923 * @param {String} entryPoint Name of the hook's entry point
924 * @param {Node} currentNode node to work on with the hook
925 * @param {Object} data additional hook parameters
926 */
927 var _executeHook = function _executeHook(entryPoint, currentNode, data) {
928 if (!hooks[entryPoint]) {
929 return;
930 }
931 arrayForEach(hooks[entryPoint], function (hook) {
932 hook.call(DOMPurify, currentNode, data, CONFIG);
933 });
934 };
935
936 /**
937 * _sanitizeElements
938 *
939 * @protect nodeName
940 * @protect textContent
941 * @protect removeChild
942 *
943 * @param {Node} currentNode to check for permission to exist
944 * @return {Boolean} true if node was killed, false if left alive
945 */
946 var _sanitizeElements = function _sanitizeElements(currentNode) {
947 var content;
948
949 /* Execute a hook if present */
950 _executeHook('beforeSanitizeElements', currentNode, null);
951
952 /* Check if element is clobbered or can clobber */
953 if (_isClobbered(currentNode)) {
954 _forceRemove(currentNode);
955 return true;
956 }
957
958 /* Check if tagname contains Unicode */
959 if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) {
960 _forceRemove(currentNode);
961 return true;
962 }
963
964 /* Now let's check the element's type and name */
965 var tagName = transformCaseFunc(currentNode.nodeName);
966
967 /* Execute a hook if present */
968 _executeHook('uponSanitizeElement', currentNode, {
969 tagName: tagName,
970 allowedTags: ALLOWED_TAGS
971 });
972
973 /* Detect mXSS attempts abusing namespace confusion */
974 if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
975 _forceRemove(currentNode);
976 return true;
977 }
978
979 /* Mitigate a problem with templates inside select */
980 if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
981 _forceRemove(currentNode);
982 return true;
983 }
984
985 /* Remove any ocurrence of processing instructions */
986 if (currentNode.nodeType === 7) {
987 _forceRemove(currentNode);
988 return true;
989 }
990
991 /* Remove any kind of possibly harmful comments */
992 if (SAFE_FOR_XML && currentNode.nodeType === 8 && regExpTest(/<[/\w]/g, currentNode.data)) {
993 _forceRemove(currentNode);
994 return true;
995 }
996
997 /* Remove element if anything forbids its presence */
998 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
999 /* Check if we have a custom element to handle */
1000 if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
1001 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
1002 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
1003 }
1004
1005 /* Keep content except for bad-listed elements */
1006 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
1007 var parentNode = getParentNode(currentNode) || currentNode.parentNode;
1008 var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
1009 if (childNodes && parentNode) {
1010 var childCount = childNodes.length;
1011 for (var i = childCount - 1; i >= 0; --i) {
1012 var childClone = cloneNode(childNodes[i], true);
1013 childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
1014 parentNode.insertBefore(childClone, getNextSibling(currentNode));
1015 }
1016 }
1017 }
1018 _forceRemove(currentNode);
1019 return true;
1020 }
1021
1022 /* Check whether element has a valid namespace */
1023 if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
1024 _forceRemove(currentNode);
1025 return true;
1026 }
1027
1028 /* Make sure that older browsers don't get fallback-tag mXSS */
1029 if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
1030 _forceRemove(currentNode);
1031 return true;
1032 }
1033
1034 /* Sanitize element content to be template-safe */
1035 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
1036 /* Get the element's text content */
1037 content = currentNode.textContent;
1038 content = stringReplace(content, MUSTACHE_EXPR$1, ' ');
1039 content = stringReplace(content, ERB_EXPR$1, ' ');
1040 content = stringReplace(content, TMPLIT_EXPR$1, ' ');
1041 if (currentNode.textContent !== content) {
1042 arrayPush(DOMPurify.removed, {
1043 element: currentNode.cloneNode()
1044 });
1045 currentNode.textContent = content;
1046 }
1047 }
1048
1049 /* Execute a hook if present */
1050 _executeHook('afterSanitizeElements', currentNode, null);
1051 return false;
1052 };
1053
1054 /**
1055 * _isValidAttribute
1056 *
1057 * @param {string} lcTag Lowercase tag name of containing element.
1058 * @param {string} lcName Lowercase attribute name.
1059 * @param {string} value Attribute value.
1060 * @return {Boolean} Returns true if `value` is valid, otherwise false.
1061 */
1062 // eslint-disable-next-line complexity
1063 var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
1064 /* Make sure attribute cannot clobber */
1065 if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
1066 return false;
1067 }
1068
1069 /* Allow valid data-* attributes: At least one character after "-"
1070 (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
1071 XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
1072 We don't need to check the value; it's always URI safe. */
1073 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]) {
1074 if (
1075 // First condition does a very basic check if a) it's basically a valid custom element tagname AND
1076 // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
1077 // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
1078 _basicCustomElementTest(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) ||
1079 // Alternative, second condition checks if it's an `is`-attribute, AND
1080 // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
1081 lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else {
1082 return false;
1083 }
1084 /* Check value is safe. First, is attr inert? If so, is safe */
1085 } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if (value) {
1086 return false;
1087 } else ;
1088 return true;
1089 };
1090
1091 /**
1092 * _basicCustomElementCheck
1093 * checks if at least one dash is included in tagName, and it's not the first char
1094 * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
1095 * @param {string} tagName name of the tag of the node to sanitize
1096 */
1097 var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
1098 return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT$1);
1099 };
1100
1101 /**
1102 * _sanitizeAttributes
1103 *
1104 * @protect attributes
1105 * @protect nodeName
1106 * @protect removeAttribute
1107 * @protect setAttribute
1108 *
1109 * @param {Node} currentNode to sanitize
1110 */
1111 var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
1112 var attr;
1113 var value;
1114 var lcName;
1115 var l;
1116 /* Execute a hook if present */
1117 _executeHook('beforeSanitizeAttributes', currentNode, null);
1118 var attributes = currentNode.attributes;
1119
1120 /* Check if we have attributes; if not we might have a text node */
1121 if (!attributes || _isClobbered(currentNode)) {
1122 return;
1123 }
1124 var hookEvent = {
1125 attrName: '',
1126 attrValue: '',
1127 keepAttr: true,
1128 allowedAttributes: ALLOWED_ATTR
1129 };
1130 l = attributes.length;
1131
1132 /* Go backwards over all attributes; safely remove bad ones */
1133 while (l--) {
1134 attr = attributes[l];
1135 var _attr = attr,
1136 name = _attr.name,
1137 namespaceURI = _attr.namespaceURI;
1138 value = name === 'value' ? attr.value : stringTrim(attr.value);
1139 lcName = transformCaseFunc(name);
1140
1141 /* Execute a hook if present */
1142 hookEvent.attrName = lcName;
1143 hookEvent.attrValue = value;
1144 hookEvent.keepAttr = true;
1145 hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
1146 _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
1147 value = hookEvent.attrValue;
1148
1149 /* Did the hooks approve of the attribute? */
1150 if (hookEvent.forceKeepAttr) {
1151 continue;
1152 }
1153
1154 /* Remove attribute */
1155 _removeAttribute(name, currentNode);
1156
1157 /* Did the hooks approve of the attribute? */
1158 if (!hookEvent.keepAttr) {
1159 continue;
1160 }
1161
1162 /* Work around a security issue in jQuery 3.0 */
1163 if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
1164 _removeAttribute(name, currentNode);
1165 continue;
1166 }
1167
1168 /* Sanitize attribute content to be template-safe */
1169 if (SAFE_FOR_TEMPLATES) {
1170 value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
1171 value = stringReplace(value, ERB_EXPR$1, ' ');
1172 value = stringReplace(value, TMPLIT_EXPR$1, ' ');
1173 }
1174
1175 /* Is `value` valid for this attribute? */
1176 var lcTag = transformCaseFunc(currentNode.nodeName);
1177 if (!_isValidAttribute(lcTag, lcName, value)) {
1178 continue;
1179 }
1180
1181 /* Full DOM Clobbering protection via namespace isolation,
1182 * Prefix id and name attributes with `user-content-`
1183 */
1184 if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
1185 // Remove the attribute with this value
1186 _removeAttribute(name, currentNode);
1187
1188 // Prefix the value and later re-create the attribute with the sanitized value
1189 value = SANITIZE_NAMED_PROPS_PREFIX + value;
1190 }
1191
1192 /* Work around a security issue with comments inside attributes */
1193 if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
1194 _removeAttribute(name, currentNode);
1195 continue;
1196 }
1197
1198 /* Handle attributes that require Trusted Types */
1199 if (trustedTypesPolicy && _typeof(trustedTypes) === 'object' && typeof trustedTypes.getAttributeType === 'function') {
1200 if (namespaceURI) ; else {
1201 switch (trustedTypes.getAttributeType(lcTag, lcName)) {
1202 case 'TrustedHTML':
1203 {
1204 value = trustedTypesPolicy.createHTML(value);
1205 break;
1206 }
1207 case 'TrustedScriptURL':
1208 {
1209 value = trustedTypesPolicy.createScriptURL(value);
1210 break;
1211 }
1212 }
1213 }
1214 }
1215
1216 /* Handle invalid data-* attribute set by try-catching it */
1217 try {
1218 if (namespaceURI) {
1219 currentNode.setAttributeNS(namespaceURI, name, value);
1220 } else {
1221 /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1222 currentNode.setAttribute(name, value);
1223 }
1224 if (_isClobbered(currentNode)) {
1225 _forceRemove(currentNode);
1226 } else {
1227 arrayPop(DOMPurify.removed);
1228 }
1229 } catch (_) {}
1230 }
1231
1232 /* Execute a hook if present */
1233 _executeHook('afterSanitizeAttributes', currentNode, null);
1234 };
1235
1236 /**
1237 * _sanitizeShadowDOM
1238 *
1239 * @param {DocumentFragment} fragment to iterate over recursively
1240 */
1241 var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
1242 var shadowNode;
1243 var shadowIterator = _createIterator(fragment);
1244
1245 /* Execute a hook if present */
1246 _executeHook('beforeSanitizeShadowDOM', fragment, null);
1247 while (shadowNode = shadowIterator.nextNode()) {
1248 /* Execute a hook if present */
1249 _executeHook('uponSanitizeShadowNode', shadowNode, null);
1250 /* Sanitize tags and elements */
1251 _sanitizeElements(shadowNode);
1252
1253 /* Check attributes next */
1254 _sanitizeAttributes(shadowNode);
1255
1256 /* Deep shadow DOM detected */
1257 if (shadowNode.content instanceof DocumentFragment) {
1258 _sanitizeShadowDOM(shadowNode.content);
1259 }
1260 }
1261
1262 /* Execute a hook if present */
1263 _executeHook('afterSanitizeShadowDOM', fragment, null);
1264 };
1265
1266 /**
1267 * Sanitize
1268 * Public method providing core sanitation functionality
1269 *
1270 * @param {String|Node} dirty string or DOM node
1271 * @param {Object} configuration object
1272 */
1273 // eslint-disable-next-line complexity
1274 DOMPurify.sanitize = function (dirty) {
1275 var cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1276 var body;
1277 var importedNode;
1278 var currentNode;
1279 var oldNode;
1280 var returnNode;
1281 /* Make sure we have a string to sanitize.
1282 DO NOT return early, as this will return the wrong type if
1283 the user has requested a DOM object rather than a string */
1284 IS_EMPTY_INPUT = !dirty;
1285 if (IS_EMPTY_INPUT) {
1286 dirty = '<!-->';
1287 }
1288
1289 /* Stringify, in case dirty is an object */
1290 if (typeof dirty !== 'string' && !_isNode(dirty)) {
1291 if (typeof dirty.toString === 'function') {
1292 dirty = dirty.toString();
1293 if (typeof dirty !== 'string') {
1294 throw typeErrorCreate('dirty is not a string, aborting');
1295 }
1296 } else {
1297 throw typeErrorCreate('toString is not a function');
1298 }
1299 }
1300
1301 /* Check we can run. Otherwise fall back or ignore */
1302 if (!DOMPurify.isSupported) {
1303 if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
1304 if (typeof dirty === 'string') {
1305 return window.toStaticHTML(dirty);
1306 }
1307 if (_isNode(dirty)) {
1308 return window.toStaticHTML(dirty.outerHTML);
1309 }
1310 }
1311 return dirty;
1312 }
1313
1314 /* Assign config vars */
1315 if (!SET_CONFIG) {
1316 _parseConfig(cfg);
1317 }
1318
1319 /* Clean up removed elements */
1320 DOMPurify.removed = [];
1321
1322 /* Check if dirty is correctly typed for IN_PLACE */
1323 if (typeof dirty === 'string') {
1324 IN_PLACE = false;
1325 }
1326 if (IN_PLACE) {
1327 /* Do some early pre-sanitization to avoid unsafe root nodes */
1328 if (dirty.nodeName) {
1329 var tagName = transformCaseFunc(dirty.nodeName);
1330 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
1331 throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
1332 }
1333 }
1334 } else if (dirty instanceof Node) {
1335 /* If dirty is a DOM element, append to an empty document to avoid
1336 elements being stripped by the parser */
1337 body = _initDocument('<!---->');
1338 importedNode = body.ownerDocument.importNode(dirty, true);
1339 if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
1340 /* Node is already a body, use as is */
1341 body = importedNode;
1342 } else if (importedNode.nodeName === 'HTML') {
1343 body = importedNode;
1344 } else {
1345 // eslint-disable-next-line unicorn/prefer-dom-node-append
1346 body.appendChild(importedNode);
1347 }
1348 } else {
1349 /* Exit directly if we have nothing to do */
1350 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
1351 // eslint-disable-next-line unicorn/prefer-includes
1352 dirty.indexOf('<') === -1) {
1353 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
1354 }
1355
1356 /* Initialize the document to work on */
1357 body = _initDocument(dirty);
1358
1359 /* Check we have a DOM node from the data */
1360 if (!body) {
1361 return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
1362 }
1363 }
1364
1365 /* Remove first element node (ours) if FORCE_BODY is set */
1366 if (body && FORCE_BODY) {
1367 _forceRemove(body.firstChild);
1368 }
1369
1370 /* Get node iterator */
1371 var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
1372
1373 /* Now start iterating over the created document */
1374 while (currentNode = nodeIterator.nextNode()) {
1375 /* Fix IE's strange behavior with manipulated textNodes #89 */
1376 if (currentNode.nodeType === 3 && currentNode === oldNode) {
1377 continue;
1378 }
1379
1380 /* Sanitize tags and elements */
1381 _sanitizeElements(currentNode);
1382
1383 /* Check attributes next */
1384 _sanitizeAttributes(currentNode);
1385
1386 /* Shadow DOM detected, sanitize it */
1387 if (currentNode.content instanceof DocumentFragment) {
1388 _sanitizeShadowDOM(currentNode.content);
1389 }
1390 oldNode = currentNode;
1391 }
1392 oldNode = null;
1393
1394 /* If we sanitized `dirty` in-place, return it. */
1395 if (IN_PLACE) {
1396 return dirty;
1397 }
1398
1399 /* Return sanitized string or DOM */
1400 if (RETURN_DOM) {
1401 if (RETURN_DOM_FRAGMENT) {
1402 returnNode = createDocumentFragment.call(body.ownerDocument);
1403 while (body.firstChild) {
1404 // eslint-disable-next-line unicorn/prefer-dom-node-append
1405 returnNode.appendChild(body.firstChild);
1406 }
1407 } else {
1408 returnNode = body;
1409 }
1410 if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmod) {
1411 /*
1412 AdoptNode() is not used because internal state is not reset
1413 (e.g. the past names map of a HTMLFormElement), this is safe
1414 in theory but we would rather not risk another attack vector.
1415 The state that is cloned by importNode() is explicitly defined
1416 by the specs.
1417 */
1418 returnNode = importNode.call(originalDocument, returnNode, true);
1419 }
1420 return returnNode;
1421 }
1422 var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
1423
1424 /* Serialize doctype if allowed */
1425 if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
1426 serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
1427 }
1428
1429 /* Sanitize final string template-safe */
1430 if (SAFE_FOR_TEMPLATES) {
1431 serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, ' ');
1432 serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, ' ');
1433 serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR$1, ' ');
1434 }
1435 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
1436 };
1437
1438 /**
1439 * Public method to set the configuration once
1440 * setConfig
1441 *
1442 * @param {Object} cfg configuration object
1443 */
1444 DOMPurify.setConfig = function (cfg) {
1445 _parseConfig(cfg);
1446 SET_CONFIG = true;
1447 };
1448
1449 /**
1450 * Public method to remove the configuration
1451 * clearConfig
1452 *
1453 */
1454 DOMPurify.clearConfig = function () {
1455 CONFIG = null;
1456 SET_CONFIG = false;
1457 };
1458
1459 /**
1460 * Public method to check if an attribute value is valid.
1461 * Uses last set config, if any. Otherwise, uses config defaults.
1462 * isValidAttribute
1463 *
1464 * @param {string} tag Tag name of containing element.
1465 * @param {string} attr Attribute name.
1466 * @param {string} value Attribute value.
1467 * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
1468 */
1469 DOMPurify.isValidAttribute = function (tag, attr, value) {
1470 /* Initialize shared config vars if necessary. */
1471 if (!CONFIG) {
1472 _parseConfig({});
1473 }
1474 var lcTag = transformCaseFunc(tag);
1475 var lcName = transformCaseFunc(attr);
1476 return _isValidAttribute(lcTag, lcName, value);
1477 };
1478
1479 /**
1480 * AddHook
1481 * Public method to add DOMPurify hooks
1482 *
1483 * @param {String} entryPoint entry point for the hook to add
1484 * @param {Function} hookFunction function to execute
1485 */
1486 DOMPurify.addHook = function (entryPoint, hookFunction) {
1487 if (typeof hookFunction !== 'function') {
1488 return;
1489 }
1490 hooks[entryPoint] = hooks[entryPoint] || [];
1491 arrayPush(hooks[entryPoint], hookFunction);
1492 };
1493
1494 /**
1495 * RemoveHook
1496 * Public method to remove a DOMPurify hook at a given entryPoint
1497 * (pops it from the stack of hooks if more are present)
1498 *
1499 * @param {String} entryPoint entry point for the hook to remove
1500 * @return {Function} removed(popped) hook
1501 */
1502 DOMPurify.removeHook = function (entryPoint) {
1503 if (hooks[entryPoint]) {
1504 return arrayPop(hooks[entryPoint]);
1505 }
1506 };
1507
1508 /**
1509 * RemoveHooks
1510 * Public method to remove all DOMPurify hooks at a given entryPoint
1511 *
1512 * @param {String} entryPoint entry point for the hooks to remove
1513 */
1514 DOMPurify.removeHooks = function (entryPoint) {
1515 if (hooks[entryPoint]) {
1516 hooks[entryPoint] = [];
1517 }
1518 };
1519
1520 /**
1521 * RemoveAllHooks
1522 * Public method to remove all DOMPurify hooks
1523 *
1524 */
1525 DOMPurify.removeAllHooks = function () {
1526 hooks = {};
1527 };
1528 return DOMPurify;
1529}
1530var purify = createDOMPurify();
1531
1532module.exports = purify;
1533//# sourceMappingURL=purify.cjs.js.map
Note: See TracBrowser for help on using the repository browser.