PluginProbe ʕ •ᴥ•ʔ
GenerateBlocks / 1.0
GenerateBlocks v1.0
trunk 1.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.3.0
generateblocks / assets / js / purify.js
generateblocks / assets / js Last commit date
purify.js 6 years ago purify.min.js 6 years ago purify.min.js.map 6 years ago scripts.js 6 years ago
purify.js
1218 lines
1 /*! @license DOMPurify | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.0.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 = global || self, global.DOMPurify = factory());
7 }(this, function () { 'use strict';
8
9 function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
10
11 var hasOwnProperty = Object.hasOwnProperty,
12 setPrototypeOf = Object.setPrototypeOf,
13 isFrozen = Object.isFrozen,
14 objectKeys = Object.keys;
15 var freeze = Object.freeze,
16 seal = Object.seal; // eslint-disable-line import/no-mutable-exports
17
18 var _ref = typeof Reflect !== 'undefined' && Reflect,
19 apply = _ref.apply,
20 construct = _ref.construct;
21
22 if (!apply) {
23 apply = function apply(fun, thisValue, args) {
24 return fun.apply(thisValue, args);
25 };
26 }
27
28 if (!freeze) {
29 freeze = function freeze(x) {
30 return x;
31 };
32 }
33
34 if (!seal) {
35 seal = function seal(x) {
36 return x;
37 };
38 }
39
40 if (!construct) {
41 construct = function construct(Func, args) {
42 return new (Function.prototype.bind.apply(Func, [null].concat(_toConsumableArray(args))))();
43 };
44 }
45
46 var arrayForEach = unapply(Array.prototype.forEach);
47 var arrayIndexOf = unapply(Array.prototype.indexOf);
48 var arrayJoin = unapply(Array.prototype.join);
49 var arrayPop = unapply(Array.prototype.pop);
50 var arrayPush = unapply(Array.prototype.push);
51 var arraySlice = unapply(Array.prototype.slice);
52
53 var stringToLowerCase = unapply(String.prototype.toLowerCase);
54 var stringMatch = unapply(String.prototype.match);
55 var stringReplace = unapply(String.prototype.replace);
56 var stringIndexOf = unapply(String.prototype.indexOf);
57 var stringTrim = unapply(String.prototype.trim);
58
59 var regExpTest = unapply(RegExp.prototype.test);
60 var regExpCreate = unconstruct(RegExp);
61
62 var typeErrorCreate = unconstruct(TypeError);
63
64 function unapply(func) {
65 return function (thisArg) {
66 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
67 args[_key - 1] = arguments[_key];
68 }
69
70 return apply(func, thisArg, args);
71 };
72 }
73
74 function unconstruct(func) {
75 return function () {
76 for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
77 args[_key2] = arguments[_key2];
78 }
79
80 return construct(func, args);
81 };
82 }
83
84 /* Add properties to a lookup table */
85 function addToSet(set, array) {
86 if (setPrototypeOf) {
87 // Make 'in' and truthy checks like Boolean(set.constructor)
88 // independent of any properties defined on Object.prototype.
89 // Prevent prototype setters from intercepting set as a this value.
90 setPrototypeOf(set, null);
91 }
92
93 var l = array.length;
94 while (l--) {
95 var element = array[l];
96 if (typeof element === 'string') {
97 var lcElement = stringToLowerCase(element);
98 if (lcElement !== element) {
99 // Config presets (e.g. tags.js, attrs.js) are immutable.
100 if (!isFrozen(array)) {
101 array[l] = lcElement;
102 }
103
104 element = lcElement;
105 }
106 }
107
108 set[element] = true;
109 }
110
111 return set;
112 }
113
114 /* Shallow clone an object */
115 function clone(object) {
116 var newObject = {};
117
118 var property = void 0;
119 for (property in object) {
120 if (apply(hasOwnProperty, object, [property])) {
121 newObject[property] = object[property];
122 }
123 }
124
125 return newObject;
126 }
127
128 var html = 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', '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']);
129
130 // SVG
131 var svg = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'audio', 'canvas', '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', 'video', 'view', 'vkern']);
132
133 var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
134
135 var mathMl = 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']);
136
137 var text = freeze(['#text']);
138
139 var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns']);
140
141 var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', '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', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
142
143 var mathMl$1 = 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']);
144
145 var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
146
147 // eslint-disable-next-line unicorn/better-regex
148 var MUSTACHE_EXPR = seal(/\{\{[\s\S]*|[\s\S]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
149 var ERB_EXPR = seal(/<%[\s\S]*|[\s\S]*%>/gm);
150 var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
151 var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
152 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
153 );
154 var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
155 var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g // eslint-disable-line no-control-regex
156 );
157
158 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
159
160 function _toConsumableArray$1(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
161
162 var getGlobal = function getGlobal() {
163 return typeof window === 'undefined' ? null : window;
164 };
165
166 /**
167 * Creates a no-op policy for internal use only.
168 * Don't export this function outside this module!
169 * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
170 * @param {Document} document The document object (to determine policy name suffix)
171 * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
172 * are not supported).
173 */
174 var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
175 if ((typeof trustedTypes === 'undefined' ? 'undefined' : _typeof(trustedTypes)) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
176 return null;
177 }
178
179 // Allow the callers to control the unique policy name
180 // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
181 // Policy creation with duplicate names throws in Trusted Types.
182 var suffix = null;
183 var ATTR_NAME = 'data-tt-policy-suffix';
184 if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
185 suffix = document.currentScript.getAttribute(ATTR_NAME);
186 }
187
188 var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
189
190 try {
191 return trustedTypes.createPolicy(policyName, {
192 createHTML: function createHTML(html$$1) {
193 return html$$1;
194 }
195 });
196 } catch (_) {
197 // Policy creation failed (most likely another DOMPurify script has
198 // already run). Skip creating the policy, as this will only cause errors
199 // if TT are enforced.
200 console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
201 return null;
202 }
203 };
204
205 function createDOMPurify() {
206 var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
207
208 var DOMPurify = function DOMPurify(root) {
209 return createDOMPurify(root);
210 };
211
212 /**
213 * Version label, exposed for easier checks
214 * if DOMPurify is up to date or not
215 */
216 DOMPurify.version = '2.0.10';
217
218 /**
219 * Array of elements that DOMPurify removed during sanitation.
220 * Empty if nothing was removed.
221 */
222 DOMPurify.removed = [];
223
224 if (!window || !window.document || window.document.nodeType !== 9) {
225 // Not running in a browser, provide a factory function
226 // so that you can pass your own Window
227 DOMPurify.isSupported = false;
228
229 return DOMPurify;
230 }
231
232 var originalDocument = window.document;
233 var removeTitle = false;
234
235 var document = window.document;
236 var DocumentFragment = window.DocumentFragment,
237 HTMLTemplateElement = window.HTMLTemplateElement,
238 Node = window.Node,
239 NodeFilter = window.NodeFilter,
240 _window$NamedNodeMap = window.NamedNodeMap,
241 NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
242 Text = window.Text,
243 Comment = window.Comment,
244 DOMParser = window.DOMParser,
245 trustedTypes = window.trustedTypes;
246
247 // As per issue #47, the web-components registry is inherited by a
248 // new document created via createHTMLDocument. As per the spec
249 // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
250 // a new empty registry is used when creating a template contents owner
251 // document, so we use that as our parent document to ensure nothing
252 // is inherited.
253
254 if (typeof HTMLTemplateElement === 'function') {
255 var template = document.createElement('template');
256 if (template.content && template.content.ownerDocument) {
257 document = template.content.ownerDocument;
258 }
259 }
260
261 var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
262 var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
263
264 var _document = document,
265 implementation = _document.implementation,
266 createNodeIterator = _document.createNodeIterator,
267 getElementsByTagName = _document.getElementsByTagName,
268 createDocumentFragment = _document.createDocumentFragment;
269 var importNode = originalDocument.importNode;
270
271
272 var hooks = {};
273
274 /**
275 * Expose whether this browser supports running the full DOMPurify.
276 */
277 DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && document.documentMode !== 9;
278
279 var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,
280 ERB_EXPR$$1 = ERB_EXPR,
281 DATA_ATTR$$1 = DATA_ATTR,
282 ARIA_ATTR$$1 = ARIA_ATTR,
283 IS_SCRIPT_OR_DATA$$1 = IS_SCRIPT_OR_DATA,
284 ATTR_WHITESPACE$$1 = ATTR_WHITESPACE;
285 var IS_ALLOWED_URI$$1 = IS_ALLOWED_URI;
286
287 /**
288 * We consider the elements and attributes below to be safe. Ideally
289 * don't add any new ones but feel free to remove unwanted ones.
290 */
291
292 /* allowed element names */
293
294 var ALLOWED_TAGS = null;
295 var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(html), _toConsumableArray$1(svg), _toConsumableArray$1(svgFilters), _toConsumableArray$1(mathMl), _toConsumableArray$1(text)));
296
297 /* Allowed attribute names */
298 var ALLOWED_ATTR = null;
299 var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray$1(html$1), _toConsumableArray$1(svg$1), _toConsumableArray$1(mathMl$1), _toConsumableArray$1(xml)));
300
301 /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
302 var FORBID_TAGS = null;
303
304 /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
305 var FORBID_ATTR = null;
306
307 /* Decide if ARIA attributes are okay */
308 var ALLOW_ARIA_ATTR = true;
309
310 /* Decide if custom data attributes are okay */
311 var ALLOW_DATA_ATTR = true;
312
313 /* Decide if unknown protocols are okay */
314 var ALLOW_UNKNOWN_PROTOCOLS = false;
315
316 /* Output should be safe for jQuery's $() factory? */
317 var SAFE_FOR_JQUERY = false;
318
319 /* Output should be safe for common template engines.
320 * This means, DOMPurify removes data attributes, mustaches and ERB
321 */
322 var SAFE_FOR_TEMPLATES = false;
323
324 /* Decide if document with <html>... should be returned */
325 var WHOLE_DOCUMENT = false;
326
327 /* Track whether config is already set on this instance of DOMPurify. */
328 var SET_CONFIG = false;
329
330 /* Decide if all elements (e.g. style, script) must be children of
331 * document.body. By default, browsers might move them to document.head */
332 var FORCE_BODY = false;
333
334 /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
335 * string (or a TrustedHTML object if Trusted Types are supported).
336 * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
337 */
338 var RETURN_DOM = false;
339
340 /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
341 * string (or a TrustedHTML object if Trusted Types are supported) */
342 var RETURN_DOM_FRAGMENT = false;
343
344 /* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM
345 * `Node` is imported into the current `Document`. If this flag is not enabled the
346 * `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by
347 * DOMPurify. */
348 var RETURN_DOM_IMPORT = false;
349
350 /* Try to return a Trusted Type object instead of a string, retrun a string in
351 * case Trusted Types are not supported */
352 var RETURN_TRUSTED_TYPE = false;
353
354 /* Output should be free from DOM clobbering attacks? */
355 var SANITIZE_DOM = true;
356
357 /* Keep element content when removing element? */
358 var KEEP_CONTENT = true;
359
360 /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
361 * of importing it into a new Document and returning a sanitized copy */
362 var IN_PLACE = false;
363
364 /* Allow usage of profiles like html, svg and mathMl */
365 var USE_PROFILES = {};
366
367 /* Tags to ignore content of when KEEP_CONTENT is true */
368 var FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
369
370 /* Tags that are safe for data: URIs */
371 var DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
372
373 /* Attributes safe for values like "javascript:" */
374 var URI_SAFE_ATTRIBUTES = null;
375 var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
376
377 /* Keep a reference to config to pass to hooks */
378 var CONFIG = null;
379
380 /* Ideally, do not touch anything below this line */
381 /* ______________________________________________ */
382
383 var formElement = document.createElement('form');
384
385 /**
386 * _parseConfig
387 *
388 * @param {Object} cfg optional config literal
389 */
390 // eslint-disable-next-line complexity
391 var _parseConfig = function _parseConfig(cfg) {
392 if (CONFIG && CONFIG === cfg) {
393 return;
394 }
395
396 /* Shield configuration object from tampering */
397 if (!cfg || (typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') {
398 cfg = {};
399 }
400
401 /* Set configuration parameters */
402 ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
403 ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
404 URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
405 FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
406 FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
407 USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
408 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
409 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
410 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
411 SAFE_FOR_JQUERY = cfg.SAFE_FOR_JQUERY || false; // Default false
412 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
413 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
414 RETURN_DOM = cfg.RETURN_DOM || false; // Default false
415 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
416 RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT || false; // Default false
417 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
418 FORCE_BODY = cfg.FORCE_BODY || false; // Default false
419 SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
420 KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
421 IN_PLACE = cfg.IN_PLACE || false; // Default false
422 IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
423 if (SAFE_FOR_TEMPLATES) {
424 ALLOW_DATA_ATTR = false;
425 }
426
427 if (RETURN_DOM_FRAGMENT) {
428 RETURN_DOM = true;
429 }
430
431 /* Parse profile info */
432 if (USE_PROFILES) {
433 ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(text)));
434 ALLOWED_ATTR = [];
435 if (USE_PROFILES.html === true) {
436 addToSet(ALLOWED_TAGS, html);
437 addToSet(ALLOWED_ATTR, html$1);
438 }
439
440 if (USE_PROFILES.svg === true) {
441 addToSet(ALLOWED_TAGS, svg);
442 addToSet(ALLOWED_ATTR, svg$1);
443 addToSet(ALLOWED_ATTR, xml);
444 }
445
446 if (USE_PROFILES.svgFilters === true) {
447 addToSet(ALLOWED_TAGS, svgFilters);
448 addToSet(ALLOWED_ATTR, svg$1);
449 addToSet(ALLOWED_ATTR, xml);
450 }
451
452 if (USE_PROFILES.mathMl === true) {
453 addToSet(ALLOWED_TAGS, mathMl);
454 addToSet(ALLOWED_ATTR, mathMl$1);
455 addToSet(ALLOWED_ATTR, xml);
456 }
457 }
458
459 /* Merge configuration parameters */
460 if (cfg.ADD_TAGS) {
461 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
462 ALLOWED_TAGS = clone(ALLOWED_TAGS);
463 }
464
465 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
466 }
467
468 if (cfg.ADD_ATTR) {
469 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
470 ALLOWED_ATTR = clone(ALLOWED_ATTR);
471 }
472
473 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
474 }
475
476 if (cfg.ADD_URI_SAFE_ATTR) {
477 addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
478 }
479
480 /* Add #text in case KEEP_CONTENT is set to true */
481 if (KEEP_CONTENT) {
482 ALLOWED_TAGS['#text'] = true;
483 }
484
485 /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
486 if (WHOLE_DOCUMENT) {
487 addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
488 }
489
490 /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
491 if (ALLOWED_TAGS.table) {
492 addToSet(ALLOWED_TAGS, ['tbody']);
493 delete FORBID_TAGS.tbody;
494 }
495
496 // Prevent further manipulation of configuration.
497 // Not available in IE8, Safari 5, etc.
498 if (freeze) {
499 freeze(cfg);
500 }
501
502 CONFIG = cfg;
503 };
504
505 /**
506 * _forceRemove
507 *
508 * @param {Node} node a DOM node
509 */
510 var _forceRemove = function _forceRemove(node) {
511 arrayPush(DOMPurify.removed, { element: node });
512 try {
513 // eslint-disable-next-line unicorn/prefer-node-remove
514 node.parentNode.removeChild(node);
515 } catch (_) {
516 node.outerHTML = emptyHTML;
517 }
518 };
519
520 /**
521 * _removeAttribute
522 *
523 * @param {String} name an Attribute name
524 * @param {Node} node a DOM node
525 */
526 var _removeAttribute = function _removeAttribute(name, node) {
527 try {
528 arrayPush(DOMPurify.removed, {
529 attribute: node.getAttributeNode(name),
530 from: node
531 });
532 } catch (_) {
533 arrayPush(DOMPurify.removed, {
534 attribute: null,
535 from: node
536 });
537 }
538
539 node.removeAttribute(name);
540 };
541
542 /**
543 * _initDocument
544 *
545 * @param {String} dirty a string of dirty markup
546 * @return {Document} a DOM, filled with the dirty markup
547 */
548 var _initDocument = function _initDocument(dirty) {
549 /* Create a HTML document */
550 var doc = void 0;
551 var leadingWhitespace = void 0;
552
553 if (FORCE_BODY) {
554 dirty = '<remove></remove>' + dirty;
555 } else {
556 /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
557 // eslint-disable-next-line unicorn/better-regex
558 var matches = stringMatch(dirty, /^[\s]+/);
559 leadingWhitespace = matches && matches[0];
560 }
561
562 var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
563 /* Use the DOMParser API by default, fallback later if needs be */
564 try {
565 doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
566 } catch (_) {}
567
568 /* Remove title to fix a mXSS bug in older MS Edge */
569 if (removeTitle) {
570 addToSet(FORBID_TAGS, ['title']);
571 }
572
573 /* Use createHTMLDocument in case DOMParser is not available */
574 if (!doc || !doc.documentElement) {
575 doc = implementation.createHTMLDocument('');
576 var _doc = doc,
577 body = _doc.body;
578
579 body.parentNode.removeChild(body.parentNode.firstElementChild);
580 body.outerHTML = dirtyPayload;
581 }
582
583 if (dirty && leadingWhitespace) {
584 doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
585 }
586
587 /* Work on whole document or just its body */
588 return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
589 };
590
591 /* Here we test for a broken feature in Edge that might cause mXSS */
592 if (DOMPurify.isSupported) {
593 (function () {
594 try {
595 var doc = _initDocument('<x/><title>&lt;/title&gt;&lt;img&gt;');
596 if (regExpTest(/<\/title/, doc.querySelector('title').innerHTML)) {
597 removeTitle = true;
598 }
599 } catch (_) {}
600 })();
601 }
602
603 /**
604 * _createIterator
605 *
606 * @param {Document} root document/fragment to create iterator for
607 * @return {Iterator} iterator instance
608 */
609 var _createIterator = function _createIterator(root) {
610 return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, function () {
611 return NodeFilter.FILTER_ACCEPT;
612 }, false);
613 };
614
615 /**
616 * _isClobbered
617 *
618 * @param {Node} elm element to check for clobbering attacks
619 * @return {Boolean} true if clobbered, false if safe
620 */
621 var _isClobbered = function _isClobbered(elm) {
622 if (elm instanceof Text || elm instanceof Comment) {
623 return false;
624 }
625
626 if (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') {
627 return true;
628 }
629
630 return false;
631 };
632
633 /**
634 * _isNode
635 *
636 * @param {Node} obj object to check whether it's a DOM node
637 * @return {Boolean} true is object is a DOM node
638 */
639 var _isNode = function _isNode(object) {
640 return (typeof Node === 'undefined' ? 'undefined' : _typeof(Node)) === 'object' ? object instanceof Node : object && (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
641 };
642
643 /**
644 * _executeHook
645 * Execute user configurable hooks
646 *
647 * @param {String} entryPoint Name of the hook's entry point
648 * @param {Node} currentNode node to work on with the hook
649 * @param {Object} data additional hook parameters
650 */
651 var _executeHook = function _executeHook(entryPoint, currentNode, data) {
652 if (!hooks[entryPoint]) {
653 return;
654 }
655
656 arrayForEach(hooks[entryPoint], function (hook) {
657 hook.call(DOMPurify, currentNode, data, CONFIG);
658 });
659 };
660
661 /**
662 * _sanitizeElements
663 *
664 * @protect nodeName
665 * @protect textContent
666 * @protect removeChild
667 *
668 * @param {Node} currentNode to check for permission to exist
669 * @return {Boolean} true if node was killed, false if left alive
670 */
671 // eslint-disable-next-line complexity
672 var _sanitizeElements = function _sanitizeElements(currentNode) {
673 var content = void 0;
674
675 /* Execute a hook if present */
676 _executeHook('beforeSanitizeElements', currentNode, null);
677
678 /* Check if element is clobbered or can clobber */
679 if (_isClobbered(currentNode)) {
680 _forceRemove(currentNode);
681 return true;
682 }
683
684 /* Now let's check the element's type and name */
685 var tagName = stringToLowerCase(currentNode.nodeName);
686
687 /* Execute a hook if present */
688 _executeHook('uponSanitizeElement', currentNode, {
689 tagName: tagName,
690 allowedTags: ALLOWED_TAGS
691 });
692
693 /* Take care of an mXSS pattern using p, br inside svg, math */
694 if ((tagName === 'svg' || tagName === 'math') && currentNode.querySelectorAll('p, br').length !== 0) {
695 _forceRemove(currentNode);
696 return true;
697 }
698
699 /* Remove element if anything forbids its presence */
700 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
701 /* Keep content except for black-listed elements */
702 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName] && typeof currentNode.insertAdjacentHTML === 'function') {
703 try {
704 var htmlToInsert = currentNode.innerHTML;
705 currentNode.insertAdjacentHTML('AfterEnd', trustedTypesPolicy ? trustedTypesPolicy.createHTML(htmlToInsert) : htmlToInsert);
706 } catch (_) {}
707 }
708
709 _forceRemove(currentNode);
710 return true;
711 }
712
713 /* Remove in case a noscript/noembed XSS is suspected */
714 if (tagName === 'noscript' && regExpTest(/<\/noscript/i, currentNode.innerHTML)) {
715 _forceRemove(currentNode);
716 return true;
717 }
718
719 if (tagName === 'noembed' && regExpTest(/<\/noembed/i, currentNode.innerHTML)) {
720 _forceRemove(currentNode);
721 return true;
722 }
723
724 /* Convert markup to cover jQuery behavior */
725 if (SAFE_FOR_JQUERY && !currentNode.firstElementChild && (!currentNode.content || !currentNode.content.firstElementChild) && regExpTest(/</g, currentNode.textContent)) {
726 arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
727 if (currentNode.innerHTML) {
728 currentNode.innerHTML = stringReplace(currentNode.innerHTML, /</g, '&lt;');
729 } else {
730 currentNode.innerHTML = stringReplace(currentNode.textContent, /</g, '&lt;');
731 }
732 }
733
734 /* Sanitize element content to be template-safe */
735 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
736 /* Get the element's text content */
737 content = currentNode.textContent;
738 content = stringReplace(content, MUSTACHE_EXPR$$1, ' ');
739 content = stringReplace(content, ERB_EXPR$$1, ' ');
740 if (currentNode.textContent !== content) {
741 arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
742 currentNode.textContent = content;
743 }
744 }
745
746 /* Execute a hook if present */
747 _executeHook('afterSanitizeElements', currentNode, null);
748
749 return false;
750 };
751
752 /**
753 * _isValidAttribute
754 *
755 * @param {string} lcTag Lowercase tag name of containing element.
756 * @param {string} lcName Lowercase attribute name.
757 * @param {string} value Attribute value.
758 * @return {Boolean} Returns true if `value` is valid, otherwise false.
759 */
760 // eslint-disable-next-line complexity
761 var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
762 /* Make sure attribute cannot clobber */
763 if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
764 return false;
765 }
766
767 /* Allow valid data-* attributes: At least one character after "-"
768 (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
769 XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
770 We don't need to check the value; it's always URI safe. */
771 if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
772 return false;
773
774 /* Check value is safe. First, is attr inert? If so, is safe */
775 } 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) ; else {
776 return false;
777 }
778
779 return true;
780 };
781
782 /**
783 * _sanitizeAttributes
784 *
785 * @protect attributes
786 * @protect nodeName
787 * @protect removeAttribute
788 * @protect setAttribute
789 *
790 * @param {Node} currentNode to sanitize
791 */
792 // eslint-disable-next-line complexity
793 var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
794 var attr = void 0;
795 var value = void 0;
796 var lcName = void 0;
797 var idAttr = void 0;
798 var l = void 0;
799 /* Execute a hook if present */
800 _executeHook('beforeSanitizeAttributes', currentNode, null);
801
802 var attributes = currentNode.attributes;
803
804 /* Check if we have attributes; if not we might have a text node */
805
806 if (!attributes) {
807 return;
808 }
809
810 var hookEvent = {
811 attrName: '',
812 attrValue: '',
813 keepAttr: true,
814 allowedAttributes: ALLOWED_ATTR
815 };
816 l = attributes.length;
817
818 /* Go backwards over all attributes; safely remove bad ones */
819 while (l--) {
820 attr = attributes[l];
821 var _attr = attr,
822 name = _attr.name,
823 namespaceURI = _attr.namespaceURI;
824
825 value = stringTrim(attr.value);
826 lcName = stringToLowerCase(name);
827
828 /* Execute a hook if present */
829 hookEvent.attrName = lcName;
830 hookEvent.attrValue = value;
831 hookEvent.keepAttr = true;
832 hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
833 _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
834 value = hookEvent.attrValue;
835 /* Did the hooks approve of the attribute? */
836 if (hookEvent.forceKeepAttr) {
837 continue;
838 }
839
840 /* Remove attribute */
841 // Safari (iOS + Mac), last tested v8.0.5, crashes if you try to
842 // remove a "name" attribute from an <img> tag that has an "id"
843 // attribute at the time.
844 if (lcName === 'name' && currentNode.nodeName === 'IMG' && attributes.id) {
845 idAttr = attributes.id;
846 attributes = arraySlice(attributes, []);
847 _removeAttribute('id', currentNode);
848 _removeAttribute(name, currentNode);
849 if (arrayIndexOf(attributes, idAttr) > l) {
850 currentNode.setAttribute('id', idAttr.value);
851 }
852 } else if (
853 // This works around a bug in Safari, where input[type=file]
854 // cannot be dynamically set after type has been removed
855 currentNode.nodeName === 'INPUT' && lcName === 'type' && value === 'file' && hookEvent.keepAttr && (ALLOWED_ATTR[lcName] || !FORBID_ATTR[lcName])) {
856 continue;
857 } else {
858 // This avoids a crash in Safari v9.0 with double-ids.
859 // The trick is to first set the id to be empty and then to
860 // remove the attribute
861 if (name === 'id') {
862 currentNode.setAttribute(name, '');
863 }
864
865 _removeAttribute(name, currentNode);
866 }
867
868 /* Did the hooks approve of the attribute? */
869 if (!hookEvent.keepAttr) {
870 continue;
871 }
872
873 /* Work around a security issue in jQuery 3.0 */
874 if (SAFE_FOR_JQUERY && regExpTest(/\/>/i, value)) {
875 _removeAttribute(name, currentNode);
876 continue;
877 }
878
879 /* Take care of an mXSS pattern using namespace switches */
880 if (regExpTest(/svg|math/i, currentNode.namespaceURI) && regExpTest(regExpCreate('</(' + arrayJoin(objectKeys(FORBID_CONTENTS), '|') + ')', 'i'), value)) {
881 _removeAttribute(name, currentNode);
882 continue;
883 }
884
885 /* Sanitize attribute content to be template-safe */
886 if (SAFE_FOR_TEMPLATES) {
887 value = stringReplace(value, MUSTACHE_EXPR$$1, ' ');
888 value = stringReplace(value, ERB_EXPR$$1, ' ');
889 }
890
891 /* Is `value` valid for this attribute? */
892 var lcTag = currentNode.nodeName.toLowerCase();
893 if (!_isValidAttribute(lcTag, lcName, value)) {
894 continue;
895 }
896
897 /* Handle invalid data-* attribute set by try-catching it */
898 try {
899 if (namespaceURI) {
900 currentNode.setAttributeNS(namespaceURI, name, value);
901 } else {
902 /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
903 currentNode.setAttribute(name, value);
904 }
905
906 arrayPop(DOMPurify.removed);
907 } catch (_) {}
908 }
909
910 /* Execute a hook if present */
911 _executeHook('afterSanitizeAttributes', currentNode, null);
912 };
913
914 /**
915 * _sanitizeShadowDOM
916 *
917 * @param {DocumentFragment} fragment to iterate over recursively
918 */
919 var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
920 var shadowNode = void 0;
921 var shadowIterator = _createIterator(fragment);
922
923 /* Execute a hook if present */
924 _executeHook('beforeSanitizeShadowDOM', fragment, null);
925
926 while (shadowNode = shadowIterator.nextNode()) {
927 /* Execute a hook if present */
928 _executeHook('uponSanitizeShadowNode', shadowNode, null);
929
930 /* Sanitize tags and elements */
931 if (_sanitizeElements(shadowNode)) {
932 continue;
933 }
934
935 /* Deep shadow DOM detected */
936 if (shadowNode.content instanceof DocumentFragment) {
937 _sanitizeShadowDOM(shadowNode.content);
938 }
939
940 /* Check attributes, sanitize if necessary */
941 _sanitizeAttributes(shadowNode);
942 }
943
944 /* Execute a hook if present */
945 _executeHook('afterSanitizeShadowDOM', fragment, null);
946 };
947
948 /**
949 * Sanitize
950 * Public method providing core sanitation functionality
951 *
952 * @param {String|Node} dirty string or DOM node
953 * @param {Object} configuration object
954 */
955 // eslint-disable-next-line complexity
956 DOMPurify.sanitize = function (dirty, cfg) {
957 var body = void 0;
958 var importedNode = void 0;
959 var currentNode = void 0;
960 var oldNode = void 0;
961 var returnNode = void 0;
962 /* Make sure we have a string to sanitize.
963 DO NOT return early, as this will return the wrong type if
964 the user has requested a DOM object rather than a string */
965 if (!dirty) {
966 dirty = '<!-->';
967 }
968
969 /* Stringify, in case dirty is an object */
970 if (typeof dirty !== 'string' && !_isNode(dirty)) {
971 // eslint-disable-next-line no-negated-condition
972 if (typeof dirty.toString !== 'function') {
973 throw typeErrorCreate('toString is not a function');
974 } else {
975 dirty = dirty.toString();
976 if (typeof dirty !== 'string') {
977 throw typeErrorCreate('dirty is not a string, aborting');
978 }
979 }
980 }
981
982 /* Check we can run. Otherwise fall back or ignore */
983 if (!DOMPurify.isSupported) {
984 if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
985 if (typeof dirty === 'string') {
986 return window.toStaticHTML(dirty);
987 }
988
989 if (_isNode(dirty)) {
990 return window.toStaticHTML(dirty.outerHTML);
991 }
992 }
993
994 return dirty;
995 }
996
997 /* Assign config vars */
998 if (!SET_CONFIG) {
999 _parseConfig(cfg);
1000 }
1001
1002 /* Clean up removed elements */
1003 DOMPurify.removed = [];
1004
1005 /* Check if dirty is correctly typed for IN_PLACE */
1006 if (typeof dirty === 'string') {
1007 IN_PLACE = false;
1008 }
1009
1010 if (IN_PLACE) ; else if (dirty instanceof Node) {
1011 /* If dirty is a DOM element, append to an empty document to avoid
1012 elements being stripped by the parser */
1013 body = _initDocument('<!-->');
1014 importedNode = body.ownerDocument.importNode(dirty, true);
1015 if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
1016 /* Node is already a body, use as is */
1017 body = importedNode;
1018 } else if (importedNode.nodeName === 'HTML') {
1019 body = importedNode;
1020 } else {
1021 // eslint-disable-next-line unicorn/prefer-node-append
1022 body.appendChild(importedNode);
1023 }
1024 } else {
1025 /* Exit directly if we have nothing to do */
1026 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && RETURN_TRUSTED_TYPE &&
1027 // eslint-disable-next-line unicorn/prefer-includes
1028 dirty.indexOf('<') === -1) {
1029 return trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
1030 }
1031
1032 /* Initialize the document to work on */
1033 body = _initDocument(dirty);
1034
1035 /* Check we have a DOM node from the data */
1036 if (!body) {
1037 return RETURN_DOM ? null : emptyHTML;
1038 }
1039 }
1040
1041 /* Remove first element node (ours) if FORCE_BODY is set */
1042 if (body && FORCE_BODY) {
1043 _forceRemove(body.firstChild);
1044 }
1045
1046 /* Get node iterator */
1047 var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
1048
1049 /* Now start iterating over the created document */
1050 while (currentNode = nodeIterator.nextNode()) {
1051 /* Fix IE's strange behavior with manipulated textNodes #89 */
1052 if (currentNode.nodeType === 3 && currentNode === oldNode) {
1053 continue;
1054 }
1055
1056 /* Sanitize tags and elements */
1057 if (_sanitizeElements(currentNode)) {
1058 continue;
1059 }
1060
1061 /* Shadow DOM detected, sanitize it */
1062 if (currentNode.content instanceof DocumentFragment) {
1063 _sanitizeShadowDOM(currentNode.content);
1064 }
1065
1066 /* Check attributes, sanitize if necessary */
1067 _sanitizeAttributes(currentNode);
1068
1069 oldNode = currentNode;
1070 }
1071
1072 oldNode = null;
1073
1074 /* If we sanitized `dirty` in-place, return it. */
1075 if (IN_PLACE) {
1076 return dirty;
1077 }
1078
1079 /* Return sanitized string or DOM */
1080 if (RETURN_DOM) {
1081 if (RETURN_DOM_FRAGMENT) {
1082 returnNode = createDocumentFragment.call(body.ownerDocument);
1083
1084 while (body.firstChild) {
1085 // eslint-disable-next-line unicorn/prefer-node-append
1086 returnNode.appendChild(body.firstChild);
1087 }
1088 } else {
1089 returnNode = body;
1090 }
1091
1092 if (RETURN_DOM_IMPORT) {
1093 /*
1094 AdoptNode() is not used because internal state is not reset
1095 (e.g. the past names map of a HTMLFormElement), this is safe
1096 in theory but we would rather not risk another attack vector.
1097 The state that is cloned by importNode() is explicitly defined
1098 by the specs.
1099 */
1100 returnNode = importNode.call(originalDocument, returnNode, true);
1101 }
1102
1103 return returnNode;
1104 }
1105
1106 var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
1107
1108 /* Sanitize final string template-safe */
1109 if (SAFE_FOR_TEMPLATES) {
1110 serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$$1, ' ');
1111 serializedHTML = stringReplace(serializedHTML, ERB_EXPR$$1, ' ');
1112 }
1113
1114 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
1115 };
1116
1117 /**
1118 * Public method to set the configuration once
1119 * setConfig
1120 *
1121 * @param {Object} cfg configuration object
1122 */
1123 DOMPurify.setConfig = function (cfg) {
1124 _parseConfig(cfg);
1125 SET_CONFIG = true;
1126 };
1127
1128 /**
1129 * Public method to remove the configuration
1130 * clearConfig
1131 *
1132 */
1133 DOMPurify.clearConfig = function () {
1134 CONFIG = null;
1135 SET_CONFIG = false;
1136 };
1137
1138 /**
1139 * Public method to check if an attribute value is valid.
1140 * Uses last set config, if any. Otherwise, uses config defaults.
1141 * isValidAttribute
1142 *
1143 * @param {string} tag Tag name of containing element.
1144 * @param {string} attr Attribute name.
1145 * @param {string} value Attribute value.
1146 * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
1147 */
1148 DOMPurify.isValidAttribute = function (tag, attr, value) {
1149 /* Initialize shared config vars if necessary. */
1150 if (!CONFIG) {
1151 _parseConfig({});
1152 }
1153
1154 var lcTag = stringToLowerCase(tag);
1155 var lcName = stringToLowerCase(attr);
1156 return _isValidAttribute(lcTag, lcName, value);
1157 };
1158
1159 /**
1160 * AddHook
1161 * Public method to add DOMPurify hooks
1162 *
1163 * @param {String} entryPoint entry point for the hook to add
1164 * @param {Function} hookFunction function to execute
1165 */
1166 DOMPurify.addHook = function (entryPoint, hookFunction) {
1167 if (typeof hookFunction !== 'function') {
1168 return;
1169 }
1170
1171 hooks[entryPoint] = hooks[entryPoint] || [];
1172 arrayPush(hooks[entryPoint], hookFunction);
1173 };
1174
1175 /**
1176 * RemoveHook
1177 * Public method to remove a DOMPurify hook at a given entryPoint
1178 * (pops it from the stack of hooks if more are present)
1179 *
1180 * @param {String} entryPoint entry point for the hook to remove
1181 */
1182 DOMPurify.removeHook = function (entryPoint) {
1183 if (hooks[entryPoint]) {
1184 arrayPop(hooks[entryPoint]);
1185 }
1186 };
1187
1188 /**
1189 * RemoveHooks
1190 * Public method to remove all DOMPurify hooks at a given entryPoint
1191 *
1192 * @param {String} entryPoint entry point for the hooks to remove
1193 */
1194 DOMPurify.removeHooks = function (entryPoint) {
1195 if (hooks[entryPoint]) {
1196 hooks[entryPoint] = [];
1197 }
1198 };
1199
1200 /**
1201 * RemoveAllHooks
1202 * Public method to remove all DOMPurify hooks
1203 *
1204 */
1205 DOMPurify.removeAllHooks = function () {
1206 hooks = {};
1207 };
1208
1209 return DOMPurify;
1210 }
1211
1212 var purify = createDOMPurify();
1213
1214 return purify;
1215
1216 }));
1217 //# sourceMappingURL=purify.js.map
1218