dompurify 2.4.9 → 2.5.0

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