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