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