dompurify 2.2.8 → 2.3.2
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 +3 -3
- package/dist/purify.cjs.js +63 -20
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.js +63 -20
- package/dist/purify.es.js.map +1 -1
- package/dist/purify.js +63 -20
- 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 +10 -11
package/dist/purify.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.
|
|
1
|
+
/*! @license DOMPurify 2.3.2 | (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.2/LICENSE */
|
|
2
2
|
|
|
3
3
|
(function (global, factory) {
|
|
4
4
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
@@ -249,7 +249,7 @@
|
|
|
249
249
|
* Version label, exposed for easier checks
|
|
250
250
|
* if DOMPurify is up to date or not
|
|
251
251
|
*/
|
|
252
|
-
DOMPurify.version = '2.2
|
|
252
|
+
DOMPurify.version = '2.3.2';
|
|
253
253
|
|
|
254
254
|
/**
|
|
255
255
|
* Array of elements that DOMPurify removed during sanitation.
|
|
@@ -307,7 +307,8 @@
|
|
|
307
307
|
var _document = document,
|
|
308
308
|
implementation = _document.implementation,
|
|
309
309
|
createNodeIterator = _document.createNodeIterator,
|
|
310
|
-
createDocumentFragment = _document.createDocumentFragment
|
|
310
|
+
createDocumentFragment = _document.createDocumentFragment,
|
|
311
|
+
getElementsByTagName = _document.getElementsByTagName;
|
|
311
312
|
var importNode = originalDocument.importNode;
|
|
312
313
|
|
|
313
314
|
|
|
@@ -414,7 +415,8 @@
|
|
|
414
415
|
var USE_PROFILES = {};
|
|
415
416
|
|
|
416
417
|
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
417
|
-
var FORBID_CONTENTS =
|
|
418
|
+
var FORBID_CONTENTS = null;
|
|
419
|
+
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']);
|
|
418
420
|
|
|
419
421
|
/* Tags that are safe for data: URIs */
|
|
420
422
|
var DATA_URI_TAGS = null;
|
|
@@ -422,13 +424,20 @@
|
|
|
422
424
|
|
|
423
425
|
/* Attributes safe for values like "javascript:" */
|
|
424
426
|
var URI_SAFE_ATTRIBUTES = null;
|
|
425
|
-
var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
427
|
+
var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
426
428
|
|
|
427
429
|
var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
428
430
|
var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
429
431
|
var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
|
430
432
|
/* Document namespace */
|
|
431
433
|
var NAMESPACE = HTML_NAMESPACE;
|
|
434
|
+
var IS_EMPTY_INPUT = false;
|
|
435
|
+
|
|
436
|
+
/* Parsing of strict XHTML documents */
|
|
437
|
+
var PARSER_MEDIA_TYPE = void 0;
|
|
438
|
+
var SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
|
439
|
+
var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
|
440
|
+
var transformCaseFunc = void 0;
|
|
432
441
|
|
|
433
442
|
/* Keep a reference to config to pass to hooks */
|
|
434
443
|
var CONFIG = null;
|
|
@@ -462,6 +471,7 @@
|
|
|
462
471
|
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
|
|
463
472
|
URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
464
473
|
DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
|
|
474
|
+
FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
|
|
465
475
|
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
|
|
466
476
|
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
|
|
467
477
|
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
|
|
@@ -479,7 +489,13 @@
|
|
|
479
489
|
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
480
490
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
481
491
|
IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
|
|
482
|
-
NAMESPACE = cfg.NAMESPACE ||
|
|
492
|
+
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
|
493
|
+
PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE in SUPPORTED_PARSER_MEDIA_TYPES ? cfg.PARSER_MEDIA_TYPE : DEFAULT_PARSER_MEDIA_TYPE;
|
|
494
|
+
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
495
|
+
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
|
|
496
|
+
return x;
|
|
497
|
+
} : stringToLowerCase;
|
|
498
|
+
|
|
483
499
|
if (SAFE_FOR_TEMPLATES) {
|
|
484
500
|
ALLOW_DATA_ATTR = false;
|
|
485
501
|
}
|
|
@@ -537,6 +553,14 @@
|
|
|
537
553
|
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
|
|
538
554
|
}
|
|
539
555
|
|
|
556
|
+
if (cfg.FORBID_CONTENTS) {
|
|
557
|
+
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
558
|
+
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
|
|
562
|
+
}
|
|
563
|
+
|
|
540
564
|
/* Add #text in case KEEP_CONTENT is set to true */
|
|
541
565
|
if (KEEP_CONTENT) {
|
|
542
566
|
ALLOWED_TAGS['#text'] = true;
|
|
@@ -675,6 +699,7 @@
|
|
|
675
699
|
var _forceRemove = function _forceRemove(node) {
|
|
676
700
|
arrayPush(DOMPurify.removed, { element: node });
|
|
677
701
|
try {
|
|
702
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
|
678
703
|
node.parentNode.removeChild(node);
|
|
679
704
|
} catch (_) {
|
|
680
705
|
try {
|
|
@@ -739,6 +764,11 @@
|
|
|
739
764
|
leadingWhitespace = matches && matches[0];
|
|
740
765
|
}
|
|
741
766
|
|
|
767
|
+
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml') {
|
|
768
|
+
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
|
|
769
|
+
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
770
|
+
}
|
|
771
|
+
|
|
742
772
|
var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
743
773
|
/*
|
|
744
774
|
* Use the DOMParser API by default, fallback later if needs be
|
|
@@ -746,14 +776,18 @@
|
|
|
746
776
|
*/
|
|
747
777
|
if (NAMESPACE === HTML_NAMESPACE) {
|
|
748
778
|
try {
|
|
749
|
-
doc = new DOMParser().parseFromString(dirtyPayload,
|
|
779
|
+
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
|
750
780
|
} catch (_) {}
|
|
751
781
|
}
|
|
752
782
|
|
|
753
783
|
/* Use createHTMLDocument in case DOMParser is not available */
|
|
754
784
|
if (!doc || !doc.documentElement) {
|
|
755
785
|
doc = implementation.createDocument(NAMESPACE, 'template', null);
|
|
756
|
-
|
|
786
|
+
try {
|
|
787
|
+
doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
|
|
788
|
+
} catch (_) {
|
|
789
|
+
// Syntax error if dirtyPayload is invalid xml
|
|
790
|
+
}
|
|
757
791
|
}
|
|
758
792
|
|
|
759
793
|
var body = doc.body || doc.documentElement;
|
|
@@ -763,6 +797,10 @@
|
|
|
763
797
|
}
|
|
764
798
|
|
|
765
799
|
/* Work on whole document or just its body */
|
|
800
|
+
if (NAMESPACE === HTML_NAMESPACE) {
|
|
801
|
+
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
|
802
|
+
}
|
|
803
|
+
|
|
766
804
|
return WHOLE_DOCUMENT ? doc.documentElement : body;
|
|
767
805
|
};
|
|
768
806
|
|
|
@@ -773,9 +811,7 @@
|
|
|
773
811
|
* @return {Iterator} iterator instance
|
|
774
812
|
*/
|
|
775
813
|
var _createIterator = function _createIterator(root) {
|
|
776
|
-
return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT,
|
|
777
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
778
|
-
}, false);
|
|
814
|
+
return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
|
|
779
815
|
};
|
|
780
816
|
|
|
781
817
|
/**
|
|
@@ -853,7 +889,7 @@
|
|
|
853
889
|
}
|
|
854
890
|
|
|
855
891
|
/* Now let's check the element's type and name */
|
|
856
|
-
var tagName =
|
|
892
|
+
var tagName = transformCaseFunc(currentNode.nodeName);
|
|
857
893
|
|
|
858
894
|
/* Execute a hook if present */
|
|
859
895
|
_executeHook('uponSanitizeElement', currentNode, {
|
|
@@ -867,6 +903,12 @@
|
|
|
867
903
|
return true;
|
|
868
904
|
}
|
|
869
905
|
|
|
906
|
+
/* Mitigate a problem with templates inside select */
|
|
907
|
+
if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
|
|
908
|
+
_forceRemove(currentNode);
|
|
909
|
+
return true;
|
|
910
|
+
}
|
|
911
|
+
|
|
870
912
|
/* Remove element if anything forbids its presence */
|
|
871
913
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
872
914
|
/* Keep content except for bad-listed elements */
|
|
@@ -935,7 +977,7 @@
|
|
|
935
977
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
936
978
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
937
979
|
We don't need to check the value; it's always URI safe. */
|
|
938
|
-
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
980
|
+
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]) {
|
|
939
981
|
return false;
|
|
940
982
|
|
|
941
983
|
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
@@ -988,7 +1030,7 @@
|
|
|
988
1030
|
namespaceURI = _attr.namespaceURI;
|
|
989
1031
|
|
|
990
1032
|
value = stringTrim(attr.value);
|
|
991
|
-
lcName =
|
|
1033
|
+
lcName = transformCaseFunc(name);
|
|
992
1034
|
|
|
993
1035
|
/* Execute a hook if present */
|
|
994
1036
|
hookEvent.attrName = lcName;
|
|
@@ -1023,7 +1065,7 @@
|
|
|
1023
1065
|
}
|
|
1024
1066
|
|
|
1025
1067
|
/* Is `value` valid for this attribute? */
|
|
1026
|
-
var lcTag = currentNode.nodeName
|
|
1068
|
+
var lcTag = transformCaseFunc(currentNode.nodeName);
|
|
1027
1069
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1028
1070
|
continue;
|
|
1029
1071
|
}
|
|
@@ -1096,7 +1138,8 @@
|
|
|
1096
1138
|
/* Make sure we have a string to sanitize.
|
|
1097
1139
|
DO NOT return early, as this will return the wrong type if
|
|
1098
1140
|
the user has requested a DOM object rather than a string */
|
|
1099
|
-
|
|
1141
|
+
IS_EMPTY_INPUT = !dirty;
|
|
1142
|
+
if (IS_EMPTY_INPUT) {
|
|
1100
1143
|
dirty = '<!-->';
|
|
1101
1144
|
}
|
|
1102
1145
|
|
|
@@ -1152,7 +1195,7 @@
|
|
|
1152
1195
|
} else if (importedNode.nodeName === 'HTML') {
|
|
1153
1196
|
body = importedNode;
|
|
1154
1197
|
} else {
|
|
1155
|
-
// eslint-disable-next-line unicorn/prefer-node-append
|
|
1198
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
1156
1199
|
body.appendChild(importedNode);
|
|
1157
1200
|
}
|
|
1158
1201
|
} else {
|
|
@@ -1216,7 +1259,7 @@
|
|
|
1216
1259
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
1217
1260
|
|
|
1218
1261
|
while (body.firstChild) {
|
|
1219
|
-
// eslint-disable-next-line unicorn/prefer-node-append
|
|
1262
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
1220
1263
|
returnNode.appendChild(body.firstChild);
|
|
1221
1264
|
}
|
|
1222
1265
|
} else {
|
|
@@ -1285,8 +1328,8 @@
|
|
|
1285
1328
|
_parseConfig({});
|
|
1286
1329
|
}
|
|
1287
1330
|
|
|
1288
|
-
var lcTag =
|
|
1289
|
-
var lcName =
|
|
1331
|
+
var lcTag = transformCaseFunc(tag);
|
|
1332
|
+
var lcName = transformCaseFunc(attr);
|
|
1290
1333
|
return _isValidAttribute(lcTag, lcName, value);
|
|
1291
1334
|
};
|
|
1292
1335
|
|