dompurify 2.3.0 → 2.3.4
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/README.md +55 -16
- package/dist/purify.cjs.js +120 -39
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.js +120 -39
- package/dist/purify.es.js.map +1 -1
- package/dist/purify.js +120 -39
- package/dist/purify.js.map +1 -1
- package/dist/purify.min.js +2 -2
- package/dist/purify.min.js.map +1 -1
- package/package.json +1 -1
package/dist/purify.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify 2.3.
|
|
1
|
+
/*! @license DOMPurify 2.3.4 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.4/LICENSE */
|
|
2
2
|
|
|
3
3
|
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
|
4
4
|
|
|
@@ -150,13 +150,13 @@ var html = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside'
|
|
|
150
150
|
// SVG
|
|
151
151
|
var svg = 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']);
|
|
152
152
|
|
|
153
|
-
var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
|
|
153
|
+
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']);
|
|
154
154
|
|
|
155
155
|
// List of SVG elements that are disallowed by default.
|
|
156
156
|
// We still need to know them so that we can do namespace
|
|
157
157
|
// checks properly in case one wants to add them to
|
|
158
158
|
// allow-list.
|
|
159
|
-
var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', '
|
|
159
|
+
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']);
|
|
160
160
|
|
|
161
161
|
var mathMl = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']);
|
|
162
162
|
|
|
@@ -166,7 +166,7 @@ var mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv
|
|
|
166
166
|
|
|
167
167
|
var text = freeze(['#text']);
|
|
168
168
|
|
|
169
|
-
var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
|
|
169
|
+
var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
|
|
170
170
|
|
|
171
171
|
var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
172
172
|
|
|
@@ -243,7 +243,7 @@ function createDOMPurify() {
|
|
|
243
243
|
* Version label, exposed for easier checks
|
|
244
244
|
* if DOMPurify is up to date or not
|
|
245
245
|
*/
|
|
246
|
-
DOMPurify.version = '2.3.
|
|
246
|
+
DOMPurify.version = '2.3.4';
|
|
247
247
|
|
|
248
248
|
/**
|
|
249
249
|
* Array of elements that DOMPurify removed during sanitation.
|
|
@@ -269,8 +269,7 @@ function createDOMPurify() {
|
|
|
269
269
|
NodeFilter = window.NodeFilter,
|
|
270
270
|
_window$NamedNodeMap = window.NamedNodeMap,
|
|
271
271
|
NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
|
|
272
|
-
|
|
273
|
-
Comment = window.Comment,
|
|
272
|
+
HTMLFormElement = window.HTMLFormElement,
|
|
274
273
|
DOMParser = window.DOMParser,
|
|
275
274
|
trustedTypes = window.trustedTypes;
|
|
276
275
|
|
|
@@ -340,6 +339,33 @@ function createDOMPurify() {
|
|
|
340
339
|
var ALLOWED_ATTR = null;
|
|
341
340
|
var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray$1(html$1), _toConsumableArray$1(svg$1), _toConsumableArray$1(mathMl$1), _toConsumableArray$1(xml)));
|
|
342
341
|
|
|
342
|
+
/*
|
|
343
|
+
* Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
|
|
344
|
+
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
|
345
|
+
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
|
|
346
|
+
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
|
347
|
+
*/
|
|
348
|
+
var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
|
|
349
|
+
tagNameCheck: {
|
|
350
|
+
writable: true,
|
|
351
|
+
configurable: false,
|
|
352
|
+
enumerable: true,
|
|
353
|
+
value: null
|
|
354
|
+
},
|
|
355
|
+
attributeNameCheck: {
|
|
356
|
+
writable: true,
|
|
357
|
+
configurable: false,
|
|
358
|
+
enumerable: true,
|
|
359
|
+
value: null
|
|
360
|
+
},
|
|
361
|
+
allowCustomizedBuiltInElements: {
|
|
362
|
+
writable: true,
|
|
363
|
+
configurable: false,
|
|
364
|
+
enumerable: true,
|
|
365
|
+
value: false
|
|
366
|
+
}
|
|
367
|
+
}));
|
|
368
|
+
|
|
343
369
|
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
|
344
370
|
var FORBID_TAGS = null;
|
|
345
371
|
|
|
@@ -380,17 +406,6 @@ function createDOMPurify() {
|
|
|
380
406
|
* string (or a TrustedHTML object if Trusted Types are supported) */
|
|
381
407
|
var RETURN_DOM_FRAGMENT = false;
|
|
382
408
|
|
|
383
|
-
/* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM
|
|
384
|
-
* `Node` is imported into the current `Document`. If this flag is not enabled the
|
|
385
|
-
* `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by
|
|
386
|
-
* DOMPurify.
|
|
387
|
-
*
|
|
388
|
-
* This defaults to `true` starting DOMPurify 2.2.0. Note that setting it to `false`
|
|
389
|
-
* might cause XSS from attacks hidden in closed shadowroots in case the browser
|
|
390
|
-
* supports Declarative Shadow: DOM https://web.dev/declarative-shadow-dom/
|
|
391
|
-
*/
|
|
392
|
-
var RETURN_DOM_IMPORT = true;
|
|
393
|
-
|
|
394
409
|
/* Try to return a Trusted Type object instead of a string, return a string in
|
|
395
410
|
* case Trusted Types are not supported */
|
|
396
411
|
var RETURN_TRUSTED_TYPE = false;
|
|
@@ -409,7 +424,8 @@ function createDOMPurify() {
|
|
|
409
424
|
var USE_PROFILES = {};
|
|
410
425
|
|
|
411
426
|
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
412
|
-
var FORBID_CONTENTS =
|
|
427
|
+
var FORBID_CONTENTS = null;
|
|
428
|
+
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']);
|
|
413
429
|
|
|
414
430
|
/* Tags that are safe for data: URIs */
|
|
415
431
|
var DATA_URI_TAGS = null;
|
|
@@ -417,7 +433,7 @@ function createDOMPurify() {
|
|
|
417
433
|
|
|
418
434
|
/* Attributes safe for values like "javascript:" */
|
|
419
435
|
var URI_SAFE_ATTRIBUTES = null;
|
|
420
|
-
var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
436
|
+
var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
421
437
|
|
|
422
438
|
var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
423
439
|
var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
@@ -426,6 +442,12 @@ function createDOMPurify() {
|
|
|
426
442
|
var NAMESPACE = HTML_NAMESPACE;
|
|
427
443
|
var IS_EMPTY_INPUT = false;
|
|
428
444
|
|
|
445
|
+
/* Parsing of strict XHTML documents */
|
|
446
|
+
var PARSER_MEDIA_TYPE = void 0;
|
|
447
|
+
var SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
|
448
|
+
var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
|
449
|
+
var transformCaseFunc = void 0;
|
|
450
|
+
|
|
429
451
|
/* Keep a reference to config to pass to hooks */
|
|
430
452
|
var CONFIG = null;
|
|
431
453
|
|
|
@@ -434,6 +456,10 @@ function createDOMPurify() {
|
|
|
434
456
|
|
|
435
457
|
var formElement = document.createElement('form');
|
|
436
458
|
|
|
459
|
+
var isRegexOrFunction = function isRegexOrFunction(testValue) {
|
|
460
|
+
return testValue instanceof RegExp || testValue instanceof Function;
|
|
461
|
+
};
|
|
462
|
+
|
|
437
463
|
/**
|
|
438
464
|
* _parseConfig
|
|
439
465
|
*
|
|
@@ -458,6 +484,7 @@ function createDOMPurify() {
|
|
|
458
484
|
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
|
|
459
485
|
URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
460
486
|
DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
|
|
487
|
+
FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
|
|
461
488
|
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
|
|
462
489
|
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
|
|
463
490
|
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
|
|
@@ -468,7 +495,6 @@ function createDOMPurify() {
|
|
|
468
495
|
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
|
|
469
496
|
RETURN_DOM = cfg.RETURN_DOM || false; // Default false
|
|
470
497
|
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
|
|
471
|
-
RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT !== false; // Default true
|
|
472
498
|
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
|
|
473
499
|
FORCE_BODY = cfg.FORCE_BODY || false; // Default false
|
|
474
500
|
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
|
|
@@ -476,6 +502,27 @@ function createDOMPurify() {
|
|
|
476
502
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
477
503
|
IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
|
|
478
504
|
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
|
505
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
|
|
506
|
+
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
|
|
510
|
+
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
|
|
514
|
+
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
PARSER_MEDIA_TYPE =
|
|
518
|
+
// eslint-disable-next-line unicorn/prefer-includes
|
|
519
|
+
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
|
|
520
|
+
|
|
521
|
+
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
522
|
+
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
|
|
523
|
+
return x;
|
|
524
|
+
} : stringToLowerCase;
|
|
525
|
+
|
|
479
526
|
if (SAFE_FOR_TEMPLATES) {
|
|
480
527
|
ALLOW_DATA_ATTR = false;
|
|
481
528
|
}
|
|
@@ -533,6 +580,14 @@ function createDOMPurify() {
|
|
|
533
580
|
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
|
|
534
581
|
}
|
|
535
582
|
|
|
583
|
+
if (cfg.FORBID_CONTENTS) {
|
|
584
|
+
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
585
|
+
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
|
|
589
|
+
}
|
|
590
|
+
|
|
536
591
|
/* Add #text in case KEEP_CONTENT is set to true */
|
|
537
592
|
if (KEEP_CONTENT) {
|
|
538
593
|
ALLOWED_TAGS['#text'] = true;
|
|
@@ -736,6 +791,11 @@ function createDOMPurify() {
|
|
|
736
791
|
leadingWhitespace = matches && matches[0];
|
|
737
792
|
}
|
|
738
793
|
|
|
794
|
+
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml') {
|
|
795
|
+
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
|
|
796
|
+
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
797
|
+
}
|
|
798
|
+
|
|
739
799
|
var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
740
800
|
/*
|
|
741
801
|
* Use the DOMParser API by default, fallback later if needs be
|
|
@@ -743,7 +803,7 @@ function createDOMPurify() {
|
|
|
743
803
|
*/
|
|
744
804
|
if (NAMESPACE === HTML_NAMESPACE) {
|
|
745
805
|
try {
|
|
746
|
-
doc = new DOMParser().parseFromString(dirtyPayload,
|
|
806
|
+
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
|
747
807
|
} catch (_) {}
|
|
748
808
|
}
|
|
749
809
|
|
|
@@ -788,15 +848,7 @@ function createDOMPurify() {
|
|
|
788
848
|
* @return {Boolean} true if clobbered, false if safe
|
|
789
849
|
*/
|
|
790
850
|
var _isClobbered = function _isClobbered(elm) {
|
|
791
|
-
|
|
792
|
-
return false;
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
if (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function') {
|
|
796
|
-
return true;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
return false;
|
|
851
|
+
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');
|
|
800
852
|
};
|
|
801
853
|
|
|
802
854
|
/**
|
|
@@ -856,7 +908,7 @@ function createDOMPurify() {
|
|
|
856
908
|
}
|
|
857
909
|
|
|
858
910
|
/* Now let's check the element's type and name */
|
|
859
|
-
var tagName =
|
|
911
|
+
var tagName = transformCaseFunc(currentNode.nodeName);
|
|
860
912
|
|
|
861
913
|
/* Execute a hook if present */
|
|
862
914
|
_executeHook('uponSanitizeElement', currentNode, {
|
|
@@ -870,6 +922,12 @@ function createDOMPurify() {
|
|
|
870
922
|
return true;
|
|
871
923
|
}
|
|
872
924
|
|
|
925
|
+
/* Mitigate a problem with templates inside select */
|
|
926
|
+
if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
|
|
927
|
+
_forceRemove(currentNode);
|
|
928
|
+
return true;
|
|
929
|
+
}
|
|
930
|
+
|
|
873
931
|
/* Remove element if anything forbids its presence */
|
|
874
932
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
875
933
|
/* Keep content except for bad-listed elements */
|
|
@@ -886,6 +944,11 @@ function createDOMPurify() {
|
|
|
886
944
|
}
|
|
887
945
|
}
|
|
888
946
|
|
|
947
|
+
if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
|
|
948
|
+
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
|
|
949
|
+
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
|
|
950
|
+
}
|
|
951
|
+
|
|
889
952
|
_forceRemove(currentNode);
|
|
890
953
|
return true;
|
|
891
954
|
}
|
|
@@ -939,8 +1002,16 @@ function createDOMPurify() {
|
|
|
939
1002
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
940
1003
|
We don't need to check the value; it's always URI safe. */
|
|
941
1004
|
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]) {
|
|
942
|
-
|
|
943
|
-
|
|
1005
|
+
if (
|
|
1006
|
+
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
1007
|
+
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1008
|
+
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
1009
|
+
_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)) ||
|
|
1010
|
+
// Alternative, second condition checks if it's an `is`-attribute, AND
|
|
1011
|
+
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1012
|
+
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 {
|
|
1013
|
+
return false;
|
|
1014
|
+
}
|
|
944
1015
|
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
945
1016
|
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) ; else if (!value) ; else {
|
|
946
1017
|
return false;
|
|
@@ -949,6 +1020,16 @@ function createDOMPurify() {
|
|
|
949
1020
|
return true;
|
|
950
1021
|
};
|
|
951
1022
|
|
|
1023
|
+
/**
|
|
1024
|
+
* _basicCustomElementCheck
|
|
1025
|
+
* checks if at least one dash is included in tagName, and it's not the first char
|
|
1026
|
+
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
|
1027
|
+
* @param {string} tagName name of the tag of the node to sanitize
|
|
1028
|
+
*/
|
|
1029
|
+
var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
|
|
1030
|
+
return tagName.indexOf('-') > 0;
|
|
1031
|
+
};
|
|
1032
|
+
|
|
952
1033
|
/**
|
|
953
1034
|
* _sanitizeAttributes
|
|
954
1035
|
*
|
|
@@ -991,7 +1072,7 @@ function createDOMPurify() {
|
|
|
991
1072
|
namespaceURI = _attr.namespaceURI;
|
|
992
1073
|
|
|
993
1074
|
value = stringTrim(attr.value);
|
|
994
|
-
lcName =
|
|
1075
|
+
lcName = transformCaseFunc(name);
|
|
995
1076
|
|
|
996
1077
|
/* Execute a hook if present */
|
|
997
1078
|
hookEvent.attrName = lcName;
|
|
@@ -1026,7 +1107,7 @@ function createDOMPurify() {
|
|
|
1026
1107
|
}
|
|
1027
1108
|
|
|
1028
1109
|
/* Is `value` valid for this attribute? */
|
|
1029
|
-
var lcTag = currentNode.nodeName
|
|
1110
|
+
var lcTag = transformCaseFunc(currentNode.nodeName);
|
|
1030
1111
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1031
1112
|
continue;
|
|
1032
1113
|
}
|
|
@@ -1227,7 +1308,7 @@ function createDOMPurify() {
|
|
|
1227
1308
|
returnNode = body;
|
|
1228
1309
|
}
|
|
1229
1310
|
|
|
1230
|
-
if (
|
|
1311
|
+
if (ALLOWED_ATTR.shadowroot) {
|
|
1231
1312
|
/*
|
|
1232
1313
|
AdoptNode() is not used because internal state is not reset
|
|
1233
1314
|
(e.g. the past names map of a HTMLFormElement), this is safe
|
|
@@ -1289,8 +1370,8 @@ function createDOMPurify() {
|
|
|
1289
1370
|
_parseConfig({});
|
|
1290
1371
|
}
|
|
1291
1372
|
|
|
1292
|
-
var lcTag =
|
|
1293
|
-
var lcName =
|
|
1373
|
+
var lcTag = transformCaseFunc(tag);
|
|
1374
|
+
var lcName = transformCaseFunc(attr);
|
|
1294
1375
|
return _isValidAttribute(lcTag, lcName, value);
|
|
1295
1376
|
};
|
|
1296
1377
|
|