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.
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.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
  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.0';
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,98 @@ 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
+ /* Ideally, do not touch anything below this line */
557
511
  /* ______________________________________________ */
558
512
 
559
513
  var formElement = document.createElement('form');
560
-
561
514
  var isRegexOrFunction = function isRegexOrFunction(testValue) {
562
515
  return testValue instanceof RegExp || testValue instanceof Function;
563
516
  };
517
+
564
518
  /**
565
519
  * _parseConfig
566
520
  *
567
521
  * @param {Object} cfg optional config literal
568
522
  */
569
523
  // eslint-disable-next-line complexity
570
-
571
-
572
524
  var _parseConfig = function _parseConfig(cfg) {
573
525
  if (CONFIG && CONFIG === cfg) {
574
526
  return;
575
527
  }
576
- /* Shield configuration object from tampering */
577
-
578
528
 
529
+ /* Shield configuration object from tampering */
579
530
  if (!cfg || _typeof(cfg) !== 'object') {
580
531
  cfg = {};
581
532
  }
582
- /* Shield configuration object from prototype pollution */
583
-
584
533
 
534
+ /* Shield configuration object from prototype pollution */
585
535
  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.
536
+ PARSER_MEDIA_TYPE =
537
+ // eslint-disable-next-line unicorn/prefer-includes
538
+ SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
588
539
 
540
+ // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
589
541
  transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
590
- /* Set configuration parameters */
591
542
 
543
+ /* Set configuration parameters */
592
544
  ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
593
545
  ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
594
546
  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
547
+ URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),
548
+ // eslint-disable-line indent
549
+ cfg.ADD_URI_SAFE_ATTR,
550
+ // eslint-disable-line indent
597
551
  transformCaseFunc // eslint-disable-line indent
598
552
  ) // eslint-disable-line indent
599
553
  : 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
554
+ DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS),
555
+ // eslint-disable-line indent
556
+ cfg.ADD_DATA_URI_TAGS,
557
+ // eslint-disable-line indent
602
558
  transformCaseFunc // eslint-disable-line indent
603
559
  ) // eslint-disable-line indent
604
560
  : DEFAULT_DATA_URI_TAGS;
@@ -607,161 +563,128 @@ function createDOMPurify() {
607
563
  FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
608
564
  USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
609
565
  ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
610
-
611
566
  ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
612
-
613
567
  ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
614
-
615
568
  ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
616
-
617
569
  SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
618
-
570
+ SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
619
571
  WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
620
-
621
572
  RETURN_DOM = cfg.RETURN_DOM || false; // Default false
622
-
623
573
  RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
624
-
625
574
  RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
626
-
627
575
  FORCE_BODY = cfg.FORCE_BODY || false; // Default false
628
-
629
576
  SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
630
-
631
577
  SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
632
-
633
578
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
634
-
635
579
  IN_PLACE = cfg.IN_PLACE || false; // Default false
636
-
637
580
  IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1;
638
581
  NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
639
582
  CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
640
-
641
583
  if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
642
584
  CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
643
585
  }
644
-
645
586
  if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
646
587
  CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
647
588
  }
648
-
649
589
  if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
650
590
  CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
651
591
  }
652
-
653
592
  if (SAFE_FOR_TEMPLATES) {
654
593
  ALLOW_DATA_ATTR = false;
655
594
  }
656
-
657
595
  if (RETURN_DOM_FRAGMENT) {
658
596
  RETURN_DOM = true;
659
597
  }
660
- /* Parse profile info */
661
-
662
598
 
599
+ /* Parse profile info */
663
600
  if (USE_PROFILES) {
664
601
  ALLOWED_TAGS = addToSet({}, _toConsumableArray(text));
665
602
  ALLOWED_ATTR = [];
666
-
667
603
  if (USE_PROFILES.html === true) {
668
604
  addToSet(ALLOWED_TAGS, html$1);
669
605
  addToSet(ALLOWED_ATTR, html);
670
606
  }
671
-
672
607
  if (USE_PROFILES.svg === true) {
673
608
  addToSet(ALLOWED_TAGS, svg$1);
674
609
  addToSet(ALLOWED_ATTR, svg);
675
610
  addToSet(ALLOWED_ATTR, xml);
676
611
  }
677
-
678
612
  if (USE_PROFILES.svgFilters === true) {
679
613
  addToSet(ALLOWED_TAGS, svgFilters);
680
614
  addToSet(ALLOWED_ATTR, svg);
681
615
  addToSet(ALLOWED_ATTR, xml);
682
616
  }
683
-
684
617
  if (USE_PROFILES.mathMl === true) {
685
618
  addToSet(ALLOWED_TAGS, mathMl$1);
686
619
  addToSet(ALLOWED_ATTR, mathMl);
687
620
  addToSet(ALLOWED_ATTR, xml);
688
621
  }
689
622
  }
690
- /* Merge configuration parameters */
691
-
692
623
 
624
+ /* Merge configuration parameters */
693
625
  if (cfg.ADD_TAGS) {
694
626
  if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
695
627
  ALLOWED_TAGS = clone(ALLOWED_TAGS);
696
628
  }
697
-
698
629
  addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
699
630
  }
700
-
701
631
  if (cfg.ADD_ATTR) {
702
632
  if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
703
633
  ALLOWED_ATTR = clone(ALLOWED_ATTR);
704
634
  }
705
-
706
635
  addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
707
636
  }
708
-
709
637
  if (cfg.ADD_URI_SAFE_ATTR) {
710
638
  addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
711
639
  }
712
-
713
640
  if (cfg.FORBID_CONTENTS) {
714
641
  if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
715
642
  FORBID_CONTENTS = clone(FORBID_CONTENTS);
716
643
  }
717
-
718
644
  addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
719
645
  }
720
- /* Add #text in case KEEP_CONTENT is set to true */
721
-
722
646
 
647
+ /* Add #text in case KEEP_CONTENT is set to true */
723
648
  if (KEEP_CONTENT) {
724
649
  ALLOWED_TAGS['#text'] = true;
725
650
  }
726
- /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
727
-
728
651
 
652
+ /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
729
653
  if (WHOLE_DOCUMENT) {
730
654
  addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
731
655
  }
732
- /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
733
-
734
656
 
657
+ /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
735
658
  if (ALLOWED_TAGS.table) {
736
659
  addToSet(ALLOWED_TAGS, ['tbody']);
737
660
  delete FORBID_TAGS.tbody;
738
- } // Prevent further manipulation of configuration.
739
- // Not available in IE8, Safari 5, etc.
740
-
661
+ }
741
662
 
663
+ // Prevent further manipulation of configuration.
664
+ // Not available in IE8, Safari 5, etc.
742
665
  if (freeze) {
743
666
  freeze(cfg);
744
667
  }
745
-
746
668
  CONFIG = cfg;
747
669
  };
748
-
749
670
  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
671
+ var HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);
672
+
673
+ // Certain elements are allowed in both SVG and HTML
751
674
  // namespace. We need to specify them explicitly
752
675
  // so that they don't get erroneously deleted from
753
676
  // HTML namespace.
754
-
755
677
  var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
678
+
756
679
  /* Keep track of all possible SVG and MathML tags
757
680
  * so that we can perform the namespace checks
758
681
  * correctly. */
759
-
760
682
  var ALL_SVG_TAGS = addToSet({}, svg$1);
761
683
  addToSet(ALL_SVG_TAGS, svgFilters);
762
684
  addToSet(ALL_SVG_TAGS, svgDisallowed);
763
685
  var ALL_MATHML_TAGS = addToSet({}, mathMl$1);
764
686
  addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
687
+
765
688
  /**
766
689
  *
767
690
  *
@@ -770,64 +693,59 @@ function createDOMPurify() {
770
693
  * namespace that a spec-compliant parser would never
771
694
  * return. Return true otherwise.
772
695
  */
773
-
774
696
  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.
697
+ var parent = getParentNode(element);
777
698
 
699
+ // In JSDOM, if we're inside shadow DOM, then parentNode
700
+ // can be null. We just simulate parent in this case.
778
701
  if (!parent || !parent.tagName) {
779
702
  parent = {
780
703
  namespaceURI: NAMESPACE,
781
704
  tagName: 'template'
782
705
  };
783
706
  }
784
-
785
707
  var tagName = stringToLowerCase(element.tagName);
786
708
  var parentTagName = stringToLowerCase(parent.tagName);
787
-
788
709
  if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
789
710
  return false;
790
711
  }
791
-
792
712
  if (element.namespaceURI === SVG_NAMESPACE) {
793
713
  // The only way to switch from HTML namespace to SVG
794
714
  // is via <svg>. If it happens via any other tag, then
795
715
  // it should be killed.
796
716
  if (parent.namespaceURI === HTML_NAMESPACE) {
797
717
  return tagName === 'svg';
798
- } // The only way to switch from MathML to SVG is via`
718
+ }
719
+
720
+ // The only way to switch from MathML to SVG is via`
799
721
  // svg if parent is either <annotation-xml> or MathML
800
722
  // text integration points.
801
-
802
-
803
723
  if (parent.namespaceURI === MATHML_NAMESPACE) {
804
724
  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
-
725
+ }
808
726
 
727
+ // We only allow elements that are defined in SVG
728
+ // spec. All others are disallowed in SVG namespace.
809
729
  return Boolean(ALL_SVG_TAGS[tagName]);
810
730
  }
811
-
812
731
  if (element.namespaceURI === MATHML_NAMESPACE) {
813
732
  // The only way to switch from HTML namespace to MathML
814
733
  // is via <math>. If it happens via any other tag, then
815
734
  // it should be killed.
816
735
  if (parent.namespaceURI === HTML_NAMESPACE) {
817
736
  return tagName === 'math';
818
- } // The only way to switch from SVG to MathML is via
819
- // <math> and HTML integration points
820
-
737
+ }
821
738
 
739
+ // The only way to switch from SVG to MathML is via
740
+ // <math> and HTML integration points
822
741
  if (parent.namespaceURI === SVG_NAMESPACE) {
823
742
  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
-
743
+ }
827
744
 
745
+ // We only allow elements that are defined in MathML
746
+ // spec. All others are disallowed in MathML namespace.
828
747
  return Boolean(ALL_MATHML_TAGS[tagName]);
829
748
  }
830
-
831
749
  if (element.namespaceURI === HTML_NAMESPACE) {
832
750
  // The only way to switch from SVG to HTML is via
833
751
  // HTML integration points, and from MathML to HTML
@@ -835,39 +753,36 @@ function createDOMPurify() {
835
753
  if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
836
754
  return false;
837
755
  }
838
-
839
756
  if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
840
757
  return false;
841
- } // We disallow tags that are specific for MathML
842
- // or SVG and should never appear in HTML namespace
843
-
758
+ }
844
759
 
760
+ // We disallow tags that are specific for MathML
761
+ // or SVG and should never appear in HTML namespace
845
762
  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
-
763
+ }
848
764
 
765
+ // For XHTML and XML documents that support custom namespaces
849
766
  if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
850
767
  return true;
851
- } // The code should never reach this place (this means
768
+ }
769
+
770
+ // The code should never reach this place (this means
852
771
  // that the element somehow got namespace that is not
853
772
  // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
854
773
  // Return false just in case.
855
-
856
-
857
774
  return false;
858
775
  };
776
+
859
777
  /**
860
778
  * _forceRemove
861
779
  *
862
780
  * @param {Node} node a DOM node
863
781
  */
864
-
865
-
866
782
  var _forceRemove = function _forceRemove(node) {
867
783
  arrayPush(DOMPurify.removed, {
868
784
  element: node
869
785
  });
870
-
871
786
  try {
872
787
  // eslint-disable-next-line unicorn/prefer-dom-node-remove
873
788
  node.parentNode.removeChild(node);
@@ -879,14 +794,13 @@ function createDOMPurify() {
879
794
  }
880
795
  }
881
796
  };
797
+
882
798
  /**
883
799
  * _removeAttribute
884
800
  *
885
801
  * @param {String} name an Attribute name
886
802
  * @param {Node} node a DOM node
887
803
  */
888
-
889
-
890
804
  var _removeAttribute = function _removeAttribute(name, node) {
891
805
  try {
892
806
  arrayPush(DOMPurify.removed, {
@@ -899,9 +813,9 @@ function createDOMPurify() {
899
813
  from: node
900
814
  });
901
815
  }
816
+ node.removeAttribute(name);
902
817
 
903
- node.removeAttribute(name); // We void attribute values for unremovable "is"" attributes
904
-
818
+ // We void attribute values for unremovable "is"" attributes
905
819
  if (name === 'is' && !ALLOWED_ATTR[name]) {
906
820
  if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
907
821
  try {
@@ -914,19 +828,17 @@ function createDOMPurify() {
914
828
  }
915
829
  }
916
830
  };
831
+
917
832
  /**
918
833
  * _initDocument
919
834
  *
920
835
  * @param {String} dirty a string of dirty markup
921
836
  * @return {Document} a DOM, filled with the dirty markup
922
837
  */
923
-
924
-
925
838
  var _initDocument = function _initDocument(dirty) {
926
839
  /* Create a HTML document */
927
840
  var doc;
928
841
  var leadingWhitespace;
929
-
930
842
  if (FORCE_BODY) {
931
843
  dirty = '<remove></remove>' + dirty;
932
844
  } else {
@@ -934,83 +846,74 @@ function createDOMPurify() {
934
846
  var matches = stringMatch(dirty, /^[\r\n\t ]+/);
935
847
  leadingWhitespace = matches && matches[0];
936
848
  }
937
-
938
849
  if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
939
850
  // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
940
851
  dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
941
852
  }
942
-
943
853
  var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
944
854
  /*
945
855
  * Use the DOMParser API by default, fallback later if needs be
946
856
  * DOMParser not work for svg when has multiple root element.
947
857
  */
948
-
949
858
  if (NAMESPACE === HTML_NAMESPACE) {
950
859
  try {
951
860
  doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
952
861
  } catch (_) {}
953
862
  }
954
- /* Use createHTMLDocument in case DOMParser is not available */
955
-
956
863
 
864
+ /* Use createHTMLDocument in case DOMParser is not available */
957
865
  if (!doc || !doc.documentElement) {
958
866
  doc = implementation.createDocument(NAMESPACE, 'template', null);
959
-
960
867
  try {
961
868
  doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
962
- } catch (_) {// Syntax error if dirtyPayload is invalid xml
869
+ } catch (_) {
870
+ // Syntax error if dirtyPayload is invalid xml
963
871
  }
964
872
  }
965
-
966
873
  var body = doc.body || doc.documentElement;
967
-
968
874
  if (dirty && leadingWhitespace) {
969
875
  body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
970
876
  }
971
- /* Work on whole document or just its body */
972
-
973
877
 
878
+ /* Work on whole document or just its body */
974
879
  if (NAMESPACE === HTML_NAMESPACE) {
975
880
  return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
976
881
  }
977
-
978
882
  return WHOLE_DOCUMENT ? doc.documentElement : body;
979
883
  };
884
+
980
885
  /**
981
886
  * _createIterator
982
887
  *
983
888
  * @param {Document} root document/fragment to create iterator for
984
889
  * @return {Iterator} iterator instance
985
890
  */
986
-
987
-
988
891
  var _createIterator = function _createIterator(root) {
989
- return createNodeIterator.call(root.ownerDocument || root, root, // eslint-disable-next-line no-bitwise
892
+ return createNodeIterator.call(root.ownerDocument || root, root,
893
+ // eslint-disable-next-line no-bitwise
990
894
  NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null, false);
991
895
  };
896
+
992
897
  /**
993
898
  * _isClobbered
994
899
  *
995
900
  * @param {Node} elm element to check for clobbering attacks
996
901
  * @return {Boolean} true if clobbered, false if safe
997
902
  */
998
-
999
-
1000
903
  var _isClobbered = function _isClobbered(elm) {
1001
904
  return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
1002
905
  };
906
+
1003
907
  /**
1004
908
  * _isNode
1005
909
  *
1006
910
  * @param {Node} obj object to check whether it's a DOM node
1007
911
  * @return {Boolean} true is object is a DOM node
1008
912
  */
1009
-
1010
-
1011
913
  var _isNode = function _isNode(object) {
1012
914
  return _typeof(Node) === 'object' ? object instanceof Node : object && _typeof(object) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
1013
915
  };
916
+
1014
917
  /**
1015
918
  * _executeHook
1016
919
  * Execute user configurable hooks
@@ -1019,17 +922,15 @@ function createDOMPurify() {
1019
922
  * @param {Node} currentNode node to work on with the hook
1020
923
  * @param {Object} data additional hook parameters
1021
924
  */
1022
-
1023
-
1024
925
  var _executeHook = function _executeHook(entryPoint, currentNode, data) {
1025
926
  if (!hooks[entryPoint]) {
1026
927
  return;
1027
928
  }
1028
-
1029
929
  arrayForEach(hooks[entryPoint], function (hook) {
1030
930
  hook.call(DOMPurify, currentNode, data, CONFIG);
1031
931
  });
1032
932
  };
933
+
1033
934
  /**
1034
935
  * _sanitizeElements
1035
936
  *
@@ -1040,118 +941,99 @@ function createDOMPurify() {
1040
941
  * @param {Node} currentNode to check for permission to exist
1041
942
  * @return {Boolean} true if node was killed, false if left alive
1042
943
  */
1043
-
1044
-
1045
944
  var _sanitizeElements = function _sanitizeElements(currentNode) {
1046
945
  var content;
1047
- /* Execute a hook if present */
1048
946
 
947
+ /* Execute a hook if present */
1049
948
  _executeHook('beforeSanitizeElements', currentNode, null);
1050
- /* Check if element is clobbered or can clobber */
1051
-
1052
949
 
950
+ /* Check if element is clobbered or can clobber */
1053
951
  if (_isClobbered(currentNode)) {
1054
952
  _forceRemove(currentNode);
1055
-
1056
953
  return true;
1057
954
  }
1058
- /* Check if tagname contains Unicode */
1059
-
1060
955
 
956
+ /* Check if tagname contains Unicode */
1061
957
  if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) {
1062
958
  _forceRemove(currentNode);
1063
-
1064
959
  return true;
1065
960
  }
1066
- /* Now let's check the element's type and name */
1067
-
1068
961
 
962
+ /* Now let's check the element's type and name */
1069
963
  var tagName = transformCaseFunc(currentNode.nodeName);
1070
- /* Execute a hook if present */
1071
964
 
965
+ /* Execute a hook if present */
1072
966
  _executeHook('uponSanitizeElement', currentNode, {
1073
967
  tagName: tagName,
1074
968
  allowedTags: ALLOWED_TAGS
1075
969
  });
1076
- /* Detect mXSS attempts abusing namespace confusion */
1077
-
1078
970
 
971
+ /* Detect mXSS attempts abusing namespace confusion */
1079
972
  if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
1080
973
  _forceRemove(currentNode);
1081
-
1082
974
  return true;
1083
975
  }
1084
- /* Mitigate a problem with templates inside select */
1085
-
1086
976
 
977
+ /* Mitigate a problem with templates inside select */
1087
978
  if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
1088
979
  _forceRemove(currentNode);
1089
-
1090
980
  return true;
1091
981
  }
1092
- /* Remove any ocurrence of processing instructions */
1093
-
1094
982
 
983
+ /* Remove any ocurrence of processing instructions */
1095
984
  if (currentNode.nodeType === 7) {
1096
985
  _forceRemove(currentNode);
1097
-
1098
986
  return true;
1099
987
  }
1100
- /* Remove element if anything forbids its presence */
1101
988
 
989
+ /* Remove any kind of possibly harmful comments */
990
+ if (SAFE_FOR_XML && currentNode.nodeType === 8 && regExpTest(/<[/\w]/g, currentNode.data)) {
991
+ _forceRemove(currentNode);
992
+ return true;
993
+ }
1102
994
 
995
+ /* Remove element if anything forbids its presence */
1103
996
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
1104
997
  /* Check if we have a custom element to handle */
1105
998
  if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
1106
999
  if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
1107
1000
  if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
1108
1001
  }
1109
- /* Keep content except for bad-listed elements */
1110
-
1111
1002
 
1003
+ /* Keep content except for bad-listed elements */
1112
1004
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
1113
1005
  var parentNode = getParentNode(currentNode) || currentNode.parentNode;
1114
1006
  var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
1115
-
1116
1007
  if (childNodes && parentNode) {
1117
1008
  var childCount = childNodes.length;
1118
-
1119
1009
  for (var i = childCount - 1; i >= 0; --i) {
1120
1010
  parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
1121
1011
  }
1122
1012
  }
1123
1013
  }
1124
-
1125
1014
  _forceRemove(currentNode);
1126
-
1127
1015
  return true;
1128
1016
  }
1129
- /* Check whether element has a valid namespace */
1130
-
1131
1017
 
1018
+ /* Check whether element has a valid namespace */
1132
1019
  if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
1133
1020
  _forceRemove(currentNode);
1134
-
1135
1021
  return true;
1136
1022
  }
1137
- /* Make sure that older browsers don't get fallback-tag mXSS */
1138
-
1139
1023
 
1024
+ /* Make sure that older browsers don't get fallback-tag mXSS */
1140
1025
  if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
1141
1026
  _forceRemove(currentNode);
1142
-
1143
1027
  return true;
1144
1028
  }
1145
- /* Sanitize element content to be template-safe */
1146
-
1147
1029
 
1030
+ /* Sanitize element content to be template-safe */
1148
1031
  if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
1149
1032
  /* Get the element's text content */
1150
1033
  content = currentNode.textContent;
1151
1034
  content = stringReplace(content, MUSTACHE_EXPR$1, ' ');
1152
1035
  content = stringReplace(content, ERB_EXPR$1, ' ');
1153
1036
  content = stringReplace(content, TMPLIT_EXPR$1, ' ');
1154
-
1155
1037
  if (currentNode.textContent !== content) {
1156
1038
  arrayPush(DOMPurify.removed, {
1157
1039
  element: currentNode.cloneNode()
@@ -1159,13 +1041,12 @@ function createDOMPurify() {
1159
1041
  currentNode.textContent = content;
1160
1042
  }
1161
1043
  }
1162
- /* Execute a hook if present */
1163
-
1164
1044
 
1045
+ /* Execute a hook if present */
1165
1046
  _executeHook('afterSanitizeElements', currentNode, null);
1166
-
1167
1047
  return false;
1168
1048
  };
1049
+
1169
1050
  /**
1170
1051
  * _isValidAttribute
1171
1052
  *
@@ -1175,47 +1056,44 @@ function createDOMPurify() {
1175
1056
  * @return {Boolean} Returns true if `value` is valid, otherwise false.
1176
1057
  */
1177
1058
  // eslint-disable-next-line complexity
1178
-
1179
-
1180
1059
  var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
1181
1060
  /* Make sure attribute cannot clobber */
1182
1061
  if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
1183
1062
  return false;
1184
1063
  }
1064
+
1185
1065
  /* Allow valid data-* attributes: At least one character after "-"
1186
1066
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
1187
1067
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
1188
1068
  We don't need to check the value; it's always URI safe. */
1189
-
1190
-
1191
1069
  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
1070
+ if (
1071
+ // First condition does a very basic check if a) it's basically a valid custom element tagname AND
1193
1072
  // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
1194
1073
  // 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
1074
+ _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)) ||
1075
+ // Alternative, second condition checks if it's an `is`-attribute, AND
1196
1076
  // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
1197
1077
  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
1078
  return false;
1199
1079
  }
1200
1080
  /* Check value is safe. First, is attr inert? If so, is safe */
1201
-
1202
1081
  } 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
1082
  return false;
1204
1083
  } else ;
1205
-
1206
1084
  return true;
1207
1085
  };
1086
+
1208
1087
  /**
1209
1088
  * _basicCustomElementCheck
1210
1089
  * checks if at least one dash is included in tagName, and it's not the first char
1211
1090
  * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
1212
1091
  * @param {string} tagName name of the tag of the node to sanitize
1213
1092
  */
1214
-
1215
-
1216
1093
  var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
1217
1094
  return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT$1);
1218
1095
  };
1096
+
1219
1097
  /**
1220
1098
  * _sanitizeAttributes
1221
1099
  *
@@ -1226,24 +1104,19 @@ function createDOMPurify() {
1226
1104
  *
1227
1105
  * @param {Node} currentNode to sanitize
1228
1106
  */
1229
-
1230
-
1231
1107
  var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
1232
1108
  var attr;
1233
1109
  var value;
1234
1110
  var lcName;
1235
1111
  var l;
1236
1112
  /* Execute a hook if present */
1237
-
1238
1113
  _executeHook('beforeSanitizeAttributes', currentNode, null);
1239
-
1240
1114
  var attributes = currentNode.attributes;
1241
- /* Check if we have attributes; if not we might have a text node */
1242
1115
 
1116
+ /* Check if we have attributes; if not we might have a text node */
1243
1117
  if (!attributes) {
1244
1118
  return;
1245
1119
  }
1246
-
1247
1120
  var hookEvent = {
1248
1121
  attrName: '',
1249
1122
  attrValue: '',
@@ -1251,79 +1124,67 @@ function createDOMPurify() {
1251
1124
  allowedAttributes: ALLOWED_ATTR
1252
1125
  };
1253
1126
  l = attributes.length;
1254
- /* Go backwards over all attributes; safely remove bad ones */
1255
1127
 
1128
+ /* Go backwards over all attributes; safely remove bad ones */
1256
1129
  while (l--) {
1257
1130
  attr = attributes[l];
1258
1131
  var _attr = attr,
1259
- name = _attr.name,
1260
- namespaceURI = _attr.namespaceURI;
1132
+ name = _attr.name,
1133
+ namespaceURI = _attr.namespaceURI;
1261
1134
  value = name === 'value' ? attr.value : stringTrim(attr.value);
1262
1135
  lcName = transformCaseFunc(name);
1263
- /* Execute a hook if present */
1264
1136
 
1137
+ /* Execute a hook if present */
1265
1138
  hookEvent.attrName = lcName;
1266
1139
  hookEvent.attrValue = value;
1267
1140
  hookEvent.keepAttr = true;
1268
1141
  hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
1269
-
1270
1142
  _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
1271
-
1272
1143
  value = hookEvent.attrValue;
1273
1144
  /* Did the hooks approve of the attribute? */
1274
-
1275
1145
  if (hookEvent.forceKeepAttr) {
1276
1146
  continue;
1277
1147
  }
1278
- /* Remove attribute */
1279
-
1280
1148
 
1149
+ /* Remove attribute */
1281
1150
  _removeAttribute(name, currentNode);
1282
- /* Did the hooks approve of the attribute? */
1283
-
1284
1151
 
1152
+ /* Did the hooks approve of the attribute? */
1285
1153
  if (!hookEvent.keepAttr) {
1286
1154
  continue;
1287
1155
  }
1288
- /* Work around a security issue in jQuery 3.0 */
1289
-
1290
1156
 
1157
+ /* Work around a security issue in jQuery 3.0 */
1291
1158
  if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
1292
1159
  _removeAttribute(name, currentNode);
1293
-
1294
1160
  continue;
1295
1161
  }
1296
- /* Sanitize attribute content to be template-safe */
1297
-
1298
1162
 
1163
+ /* Sanitize attribute content to be template-safe */
1299
1164
  if (SAFE_FOR_TEMPLATES) {
1300
1165
  value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
1301
1166
  value = stringReplace(value, ERB_EXPR$1, ' ');
1302
1167
  value = stringReplace(value, TMPLIT_EXPR$1, ' ');
1303
1168
  }
1304
- /* Is `value` valid for this attribute? */
1305
-
1306
1169
 
1170
+ /* Is `value` valid for this attribute? */
1307
1171
  var lcTag = transformCaseFunc(currentNode.nodeName);
1308
-
1309
1172
  if (!_isValidAttribute(lcTag, lcName, value)) {
1310
1173
  continue;
1311
1174
  }
1175
+
1312
1176
  /* Full DOM Clobbering protection via namespace isolation,
1313
1177
  * Prefix id and name attributes with `user-content-`
1314
1178
  */
1315
-
1316
-
1317
1179
  if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
1318
1180
  // Remove the attribute with this value
1319
- _removeAttribute(name, currentNode); // Prefix the value and later re-create the attribute with the sanitized value
1320
-
1181
+ _removeAttribute(name, currentNode);
1321
1182
 
1183
+ // Prefix the value and later re-create the attribute with the sanitized value
1322
1184
  value = SANITIZE_NAMED_PROPS_PREFIX + value;
1323
1185
  }
1324
- /* Handle attributes that require Trusted Types */
1325
-
1326
1186
 
1187
+ /* Handle attributes that require Trusted Types */
1327
1188
  if (trustedTypesPolicy && _typeof(trustedTypes) === 'object' && typeof trustedTypes.getAttributeType === 'function') {
1328
1189
  if (namespaceURI) ; else {
1329
1190
  switch (trustedTypes.getAttributeType(lcTag, lcName)) {
@@ -1332,7 +1193,6 @@ function createDOMPurify() {
1332
1193
  value = trustedTypesPolicy.createHTML(value);
1333
1194
  break;
1334
1195
  }
1335
-
1336
1196
  case 'TrustedScriptURL':
1337
1197
  {
1338
1198
  value = trustedTypesPolicy.createScriptURL(value);
@@ -1341,9 +1201,8 @@ function createDOMPurify() {
1341
1201
  }
1342
1202
  }
1343
1203
  }
1344
- /* Handle invalid data-* attribute set by try-catching it */
1345
-
1346
1204
 
1205
+ /* Handle invalid data-* attribute set by try-catching it */
1347
1206
  try {
1348
1207
  if (namespaceURI) {
1349
1208
  currentNode.setAttributeNS(namespaceURI, name, value);
@@ -1351,56 +1210,47 @@ function createDOMPurify() {
1351
1210
  /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
1352
1211
  currentNode.setAttribute(name, value);
1353
1212
  }
1354
-
1355
1213
  arrayPop(DOMPurify.removed);
1356
1214
  } catch (_) {}
1357
1215
  }
1358
- /* Execute a hook if present */
1359
-
1360
1216
 
1217
+ /* Execute a hook if present */
1361
1218
  _executeHook('afterSanitizeAttributes', currentNode, null);
1362
1219
  };
1220
+
1363
1221
  /**
1364
1222
  * _sanitizeShadowDOM
1365
1223
  *
1366
1224
  * @param {DocumentFragment} fragment to iterate over recursively
1367
1225
  */
1368
-
1369
-
1370
1226
  var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
1371
1227
  var shadowNode;
1372
-
1373
1228
  var shadowIterator = _createIterator(fragment);
1374
- /* Execute a hook if present */
1375
-
1376
1229
 
1230
+ /* Execute a hook if present */
1377
1231
  _executeHook('beforeSanitizeShadowDOM', fragment, null);
1378
-
1379
1232
  while (shadowNode = shadowIterator.nextNode()) {
1380
1233
  /* Execute a hook if present */
1381
1234
  _executeHook('uponSanitizeShadowNode', shadowNode, null);
1382
- /* Sanitize tags and elements */
1383
-
1384
1235
 
1236
+ /* Sanitize tags and elements */
1385
1237
  if (_sanitizeElements(shadowNode)) {
1386
1238
  continue;
1387
1239
  }
1388
- /* Deep shadow DOM detected */
1389
-
1390
1240
 
1241
+ /* Deep shadow DOM detected */
1391
1242
  if (shadowNode.content instanceof DocumentFragment) {
1392
1243
  _sanitizeShadowDOM(shadowNode.content);
1393
1244
  }
1394
- /* Check attributes, sanitize if necessary */
1395
-
1396
1245
 
1246
+ /* Check attributes, sanitize if necessary */
1397
1247
  _sanitizeAttributes(shadowNode);
1398
1248
  }
1399
- /* Execute a hook if present */
1400
-
1401
1249
 
1250
+ /* Execute a hook if present */
1402
1251
  _executeHook('afterSanitizeShadowDOM', fragment, null);
1403
1252
  };
1253
+
1404
1254
  /**
1405
1255
  * Sanitize
1406
1256
  * Public method providing core sanitation functionality
@@ -1409,8 +1259,6 @@ function createDOMPurify() {
1409
1259
  * @param {Object} configuration object
1410
1260
  */
1411
1261
  // eslint-disable-next-line complexity
1412
-
1413
-
1414
1262
  DOMPurify.sanitize = function (dirty) {
1415
1263
  var cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1416
1264
  var body;
@@ -1421,19 +1269,15 @@ function createDOMPurify() {
1421
1269
  /* Make sure we have a string to sanitize.
1422
1270
  DO NOT return early, as this will return the wrong type if
1423
1271
  the user has requested a DOM object rather than a string */
1424
-
1425
1272
  IS_EMPTY_INPUT = !dirty;
1426
-
1427
1273
  if (IS_EMPTY_INPUT) {
1428
1274
  dirty = '<!-->';
1429
1275
  }
1430
- /* Stringify, in case dirty is an object */
1431
-
1432
1276
 
1277
+ /* Stringify, in case dirty is an object */
1433
1278
  if (typeof dirty !== 'string' && !_isNode(dirty)) {
1434
1279
  if (typeof dirty.toString === 'function') {
1435
1280
  dirty = dirty.toString();
1436
-
1437
1281
  if (typeof dirty !== 'string') {
1438
1282
  throw typeErrorCreate('dirty is not a string, aborting');
1439
1283
  }
@@ -1441,43 +1285,36 @@ function createDOMPurify() {
1441
1285
  throw typeErrorCreate('toString is not a function');
1442
1286
  }
1443
1287
  }
1444
- /* Check we can run. Otherwise fall back or ignore */
1445
-
1446
1288
 
1289
+ /* Check we can run. Otherwise fall back or ignore */
1447
1290
  if (!DOMPurify.isSupported) {
1448
1291
  if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
1449
1292
  if (typeof dirty === 'string') {
1450
1293
  return window.toStaticHTML(dirty);
1451
1294
  }
1452
-
1453
1295
  if (_isNode(dirty)) {
1454
1296
  return window.toStaticHTML(dirty.outerHTML);
1455
1297
  }
1456
1298
  }
1457
-
1458
1299
  return dirty;
1459
1300
  }
1460
- /* Assign config vars */
1461
-
1462
1301
 
1302
+ /* Assign config vars */
1463
1303
  if (!SET_CONFIG) {
1464
1304
  _parseConfig(cfg);
1465
1305
  }
1466
- /* Clean up removed elements */
1467
-
1468
1306
 
1307
+ /* Clean up removed elements */
1469
1308
  DOMPurify.removed = [];
1470
- /* Check if dirty is correctly typed for IN_PLACE */
1471
1309
 
1310
+ /* Check if dirty is correctly typed for IN_PLACE */
1472
1311
  if (typeof dirty === 'string') {
1473
1312
  IN_PLACE = false;
1474
1313
  }
1475
-
1476
1314
  if (IN_PLACE) {
1477
1315
  /* Do some early pre-sanitization to avoid unsafe root nodes */
1478
1316
  if (dirty.nodeName) {
1479
1317
  var tagName = transformCaseFunc(dirty.nodeName);
1480
-
1481
1318
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
1482
1319
  throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
1483
1320
  }
@@ -1487,7 +1324,6 @@ function createDOMPurify() {
1487
1324
  elements being stripped by the parser */
1488
1325
  body = _initDocument('<!---->');
1489
1326
  importedNode = body.ownerDocument.importNode(dirty, true);
1490
-
1491
1327
  if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
1492
1328
  /* Node is already a body, use as is */
1493
1329
  body = importedNode;
@@ -1499,71 +1335,61 @@ function createDOMPurify() {
1499
1335
  }
1500
1336
  } else {
1501
1337
  /* Exit directly if we have nothing to do */
1502
- if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && // eslint-disable-next-line unicorn/prefer-includes
1338
+ if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
1339
+ // eslint-disable-next-line unicorn/prefer-includes
1503
1340
  dirty.indexOf('<') === -1) {
1504
1341
  return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
1505
1342
  }
1506
- /* Initialize the document to work on */
1507
-
1508
1343
 
1344
+ /* Initialize the document to work on */
1509
1345
  body = _initDocument(dirty);
1510
- /* Check we have a DOM node from the data */
1511
1346
 
1347
+ /* Check we have a DOM node from the data */
1512
1348
  if (!body) {
1513
1349
  return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
1514
1350
  }
1515
1351
  }
1516
- /* Remove first element node (ours) if FORCE_BODY is set */
1517
-
1518
1352
 
1353
+ /* Remove first element node (ours) if FORCE_BODY is set */
1519
1354
  if (body && FORCE_BODY) {
1520
1355
  _forceRemove(body.firstChild);
1521
1356
  }
1522
- /* Get node iterator */
1523
-
1524
1357
 
1358
+ /* Get node iterator */
1525
1359
  var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
1526
- /* Now start iterating over the created document */
1527
-
1528
1360
 
1361
+ /* Now start iterating over the created document */
1529
1362
  while (currentNode = nodeIterator.nextNode()) {
1530
1363
  /* Fix IE's strange behavior with manipulated textNodes #89 */
1531
1364
  if (currentNode.nodeType === 3 && currentNode === oldNode) {
1532
1365
  continue;
1533
1366
  }
1534
- /* Sanitize tags and elements */
1535
-
1536
1367
 
1368
+ /* Sanitize tags and elements */
1537
1369
  if (_sanitizeElements(currentNode)) {
1538
1370
  continue;
1539
1371
  }
1540
- /* Shadow DOM detected, sanitize it */
1541
-
1542
1372
 
1373
+ /* Shadow DOM detected, sanitize it */
1543
1374
  if (currentNode.content instanceof DocumentFragment) {
1544
1375
  _sanitizeShadowDOM(currentNode.content);
1545
1376
  }
1546
- /* Check attributes, sanitize if necessary */
1547
-
1548
1377
 
1378
+ /* Check attributes, sanitize if necessary */
1549
1379
  _sanitizeAttributes(currentNode);
1550
-
1551
1380
  oldNode = currentNode;
1552
1381
  }
1553
-
1554
1382
  oldNode = null;
1555
- /* If we sanitized `dirty` in-place, return it. */
1556
1383
 
1384
+ /* If we sanitized `dirty` in-place, return it. */
1557
1385
  if (IN_PLACE) {
1558
1386
  return dirty;
1559
1387
  }
1560
- /* Return sanitized string or DOM */
1561
-
1562
1388
 
1389
+ /* Return sanitized string or DOM */
1563
1390
  if (RETURN_DOM) {
1564
1391
  if (RETURN_DOM_FRAGMENT) {
1565
1392
  returnNode = createDocumentFragment.call(body.ownerDocument);
1566
-
1567
1393
  while (body.firstChild) {
1568
1394
  // eslint-disable-next-line unicorn/prefer-dom-node-append
1569
1395
  returnNode.appendChild(body.firstChild);
@@ -1571,7 +1397,6 @@ function createDOMPurify() {
1571
1397
  } else {
1572
1398
  returnNode = body;
1573
1399
  }
1574
-
1575
1400
  if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmod) {
1576
1401
  /*
1577
1402
  AdoptNode() is not used because internal state is not reset
@@ -1582,51 +1407,45 @@ function createDOMPurify() {
1582
1407
  */
1583
1408
  returnNode = importNode.call(originalDocument, returnNode, true);
1584
1409
  }
1585
-
1586
1410
  return returnNode;
1587
1411
  }
1588
-
1589
1412
  var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
1590
- /* Serialize doctype if allowed */
1591
1413
 
1414
+ /* Serialize doctype if allowed */
1592
1415
  if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
1593
1416
  serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
1594
1417
  }
1595
- /* Sanitize final string template-safe */
1596
-
1597
1418
 
1419
+ /* Sanitize final string template-safe */
1598
1420
  if (SAFE_FOR_TEMPLATES) {
1599
1421
  serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, ' ');
1600
1422
  serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, ' ');
1601
1423
  serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR$1, ' ');
1602
1424
  }
1603
-
1604
1425
  return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
1605
1426
  };
1427
+
1606
1428
  /**
1607
1429
  * Public method to set the configuration once
1608
1430
  * setConfig
1609
1431
  *
1610
1432
  * @param {Object} cfg configuration object
1611
1433
  */
1612
-
1613
-
1614
1434
  DOMPurify.setConfig = function (cfg) {
1615
1435
  _parseConfig(cfg);
1616
-
1617
1436
  SET_CONFIG = true;
1618
1437
  };
1438
+
1619
1439
  /**
1620
1440
  * Public method to remove the configuration
1621
1441
  * clearConfig
1622
1442
  *
1623
1443
  */
1624
-
1625
-
1626
1444
  DOMPurify.clearConfig = function () {
1627
1445
  CONFIG = null;
1628
1446
  SET_CONFIG = false;
1629
1447
  };
1448
+
1630
1449
  /**
1631
1450
  * Public method to check if an attribute value is valid.
1632
1451
  * Uses last set config, if any. Otherwise, uses config defaults.
@@ -1637,18 +1456,16 @@ function createDOMPurify() {
1637
1456
  * @param {string} value Attribute value.
1638
1457
  * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
1639
1458
  */
1640
-
1641
-
1642
1459
  DOMPurify.isValidAttribute = function (tag, attr, value) {
1643
1460
  /* Initialize shared config vars if necessary. */
1644
1461
  if (!CONFIG) {
1645
1462
  _parseConfig({});
1646
1463
  }
1647
-
1648
1464
  var lcTag = transformCaseFunc(tag);
1649
1465
  var lcName = transformCaseFunc(attr);
1650
1466
  return _isValidAttribute(lcTag, lcName, value);
1651
1467
  };
1468
+
1652
1469
  /**
1653
1470
  * AddHook
1654
1471
  * Public method to add DOMPurify hooks
@@ -1656,16 +1473,14 @@ function createDOMPurify() {
1656
1473
  * @param {String} entryPoint entry point for the hook to add
1657
1474
  * @param {Function} hookFunction function to execute
1658
1475
  */
1659
-
1660
-
1661
1476
  DOMPurify.addHook = function (entryPoint, hookFunction) {
1662
1477
  if (typeof hookFunction !== 'function') {
1663
1478
  return;
1664
1479
  }
1665
-
1666
1480
  hooks[entryPoint] = hooks[entryPoint] || [];
1667
1481
  arrayPush(hooks[entryPoint], hookFunction);
1668
1482
  };
1483
+
1669
1484
  /**
1670
1485
  * RemoveHook
1671
1486
  * Public method to remove a DOMPurify hook at a given entryPoint
@@ -1674,40 +1489,34 @@ function createDOMPurify() {
1674
1489
  * @param {String} entryPoint entry point for the hook to remove
1675
1490
  * @return {Function} removed(popped) hook
1676
1491
  */
1677
-
1678
-
1679
1492
  DOMPurify.removeHook = function (entryPoint) {
1680
1493
  if (hooks[entryPoint]) {
1681
1494
  return arrayPop(hooks[entryPoint]);
1682
1495
  }
1683
1496
  };
1497
+
1684
1498
  /**
1685
1499
  * RemoveHooks
1686
1500
  * Public method to remove all DOMPurify hooks at a given entryPoint
1687
1501
  *
1688
1502
  * @param {String} entryPoint entry point for the hooks to remove
1689
1503
  */
1690
-
1691
-
1692
1504
  DOMPurify.removeHooks = function (entryPoint) {
1693
1505
  if (hooks[entryPoint]) {
1694
1506
  hooks[entryPoint] = [];
1695
1507
  }
1696
1508
  };
1509
+
1697
1510
  /**
1698
1511
  * RemoveAllHooks
1699
1512
  * Public method to remove all DOMPurify hooks
1700
1513
  *
1701
1514
  */
1702
-
1703
-
1704
1515
  DOMPurify.removeAllHooks = function () {
1705
1516
  hooks = {};
1706
1517
  };
1707
-
1708
1518
  return DOMPurify;
1709
1519
  }
1710
-
1711
1520
  var purify = createDOMPurify();
1712
1521
 
1713
1522
  export { purify as default };