dompurify 2.4.9 → 2.5.1

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