dompurify 2.0.4 → 2.0.8
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 +26 -21
- package/dist/purify.cjs.js +151 -116
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.js +151 -116
- package/dist/purify.es.js.map +1 -1
- package/dist/purify.js +151 -116
- package/dist/purify.js.map +1 -1
- package/dist/purify.min.js +1 -1
- package/dist/purify.min.js.map +1 -1
- package/package.json +4 -4
package/dist/purify.js
CHANGED
|
@@ -4,42 +4,78 @@
|
|
|
4
4
|
(global.DOMPurify = factory());
|
|
5
5
|
}(this, (function () { 'use strict';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
return x;
|
|
9
|
-
};
|
|
7
|
+
function _toConsumableArray$1(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); } }
|
|
10
8
|
|
|
11
|
-
var
|
|
9
|
+
var hasOwnProperty = Object.hasOwnProperty;
|
|
10
|
+
var setPrototypeOf = Object.setPrototypeOf;
|
|
11
|
+
var isFrozen = Object.isFrozen;
|
|
12
|
+
var objectKeys = Object.keys;
|
|
13
|
+
var freeze = Object.freeze;
|
|
14
|
+
var seal = Object.seal; // eslint-disable-line import/no-mutable-exports
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
var
|
|
16
|
+
var _ref = typeof Reflect !== 'undefined' && Reflect;
|
|
17
|
+
var apply = _ref.apply;
|
|
18
|
+
var construct = _ref.construct;
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
if (!apply) {
|
|
21
|
+
apply = function apply(fun, thisValue, args) {
|
|
22
|
+
return fun.apply(thisValue, args);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
17
25
|
|
|
18
|
-
|
|
26
|
+
if (!freeze) {
|
|
27
|
+
freeze = function freeze(x) {
|
|
28
|
+
return x;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
19
31
|
|
|
20
|
-
|
|
32
|
+
if (!seal) {
|
|
33
|
+
seal = function seal(x) {
|
|
34
|
+
return x;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
21
37
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
38
|
+
if (!construct) {
|
|
39
|
+
construct = function construct(Func, args) {
|
|
40
|
+
return new (Function.prototype.bind.apply(Func, [null].concat(_toConsumableArray$1(args))))();
|
|
41
|
+
};
|
|
42
|
+
}
|
|
25
43
|
|
|
26
|
-
var
|
|
44
|
+
var arrayForEach = unapply(Array.prototype.forEach);
|
|
45
|
+
var arrayIndexOf = unapply(Array.prototype.indexOf);
|
|
46
|
+
var arrayJoin = unapply(Array.prototype.join);
|
|
47
|
+
var arrayPop = unapply(Array.prototype.pop);
|
|
48
|
+
var arrayPush = unapply(Array.prototype.push);
|
|
49
|
+
var arraySlice = unapply(Array.prototype.slice);
|
|
27
50
|
|
|
28
|
-
var
|
|
51
|
+
var stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
52
|
+
var stringMatch = unapply(String.prototype.match);
|
|
53
|
+
var stringReplace = unapply(String.prototype.replace);
|
|
54
|
+
var stringIndexOf = unapply(String.prototype.indexOf);
|
|
55
|
+
var stringTrim = unapply(String.prototype.trim);
|
|
29
56
|
|
|
30
|
-
var
|
|
57
|
+
var regExpTest = unapply(RegExp.prototype.test);
|
|
58
|
+
var regExpCreate = unconstruct(RegExp);
|
|
31
59
|
|
|
32
|
-
var
|
|
60
|
+
var typeErrorCreate = unconstruct(TypeError);
|
|
33
61
|
|
|
34
|
-
|
|
35
|
-
|
|
62
|
+
function unapply(func) {
|
|
63
|
+
return function (thisArg) {
|
|
64
|
+
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
65
|
+
args[_key - 1] = arguments[_key];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return apply(func, thisArg, args);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
36
71
|
|
|
37
|
-
|
|
38
|
-
|
|
72
|
+
function unconstruct(func) {
|
|
73
|
+
return function () {
|
|
74
|
+
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
75
|
+
args[_key2] = arguments[_key2];
|
|
76
|
+
}
|
|
39
77
|
|
|
40
|
-
|
|
41
|
-
apply$1 = function apply(fun, thisValue, args) {
|
|
42
|
-
return fun.apply(thisValue, args);
|
|
78
|
+
return construct(func, args);
|
|
43
79
|
};
|
|
44
80
|
}
|
|
45
81
|
|
|
@@ -56,10 +92,10 @@ function addToSet(set, array) {
|
|
|
56
92
|
while (l--) {
|
|
57
93
|
var element = array[l];
|
|
58
94
|
if (typeof element === 'string') {
|
|
59
|
-
var lcElement = element
|
|
95
|
+
var lcElement = stringToLowerCase(element);
|
|
60
96
|
if (lcElement !== element) {
|
|
61
97
|
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
62
|
-
if (!
|
|
98
|
+
if (!isFrozen(array)) {
|
|
63
99
|
array[l] = lcElement;
|
|
64
100
|
}
|
|
65
101
|
|
|
@@ -79,7 +115,7 @@ function clone(object) {
|
|
|
79
115
|
|
|
80
116
|
var property = void 0;
|
|
81
117
|
for (property in object) {
|
|
82
|
-
if (apply
|
|
118
|
+
if (apply(hasOwnProperty, object, [property])) {
|
|
83
119
|
newObject[property] = object[property];
|
|
84
120
|
}
|
|
85
121
|
}
|
|
@@ -87,9 +123,24 @@ function clone(object) {
|
|
|
87
123
|
return newObject;
|
|
88
124
|
}
|
|
89
125
|
|
|
90
|
-
var
|
|
91
|
-
|
|
92
|
-
|
|
126
|
+
var html = 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', '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']);
|
|
127
|
+
|
|
128
|
+
// SVG
|
|
129
|
+
var svg = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'audio', 'canvas', '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', 'video', 'view', 'vkern']);
|
|
130
|
+
|
|
131
|
+
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']);
|
|
132
|
+
|
|
133
|
+
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']);
|
|
134
|
+
|
|
135
|
+
var text = freeze(['#text']);
|
|
136
|
+
|
|
137
|
+
var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocomplete', 'background', 'bgcolor', 'border', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'coords', 'crossorigin', 'datetime', 'default', 'dir', 'disabled', 'download', 'enctype', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'integrity', 'ismap', 'label', 'lang', 'list', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', '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', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns']);
|
|
138
|
+
|
|
139
|
+
var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', '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', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', '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']);
|
|
140
|
+
|
|
141
|
+
var mathMl$1 = 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']);
|
|
142
|
+
|
|
143
|
+
var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
93
144
|
|
|
94
145
|
var MUSTACHE_EXPR = seal(/\{\{[\s\S]*|[\s\S]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
95
146
|
var ERB_EXPR = seal(/<%[\s\S]*|[\s\S]*%>/gm);
|
|
@@ -105,22 +156,10 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
|
|
105
156
|
|
|
106
157
|
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); } }
|
|
107
158
|
|
|
108
|
-
var _ref = typeof Reflect !== 'undefined' && Reflect;
|
|
109
|
-
var apply = _ref.apply;
|
|
110
|
-
|
|
111
|
-
var arraySlice = Array.prototype.slice;
|
|
112
|
-
var freeze = Object.freeze;
|
|
113
|
-
|
|
114
159
|
var getGlobal = function getGlobal() {
|
|
115
160
|
return typeof window === 'undefined' ? null : window;
|
|
116
161
|
};
|
|
117
162
|
|
|
118
|
-
if (!apply) {
|
|
119
|
-
apply = function apply(fun, thisValue, args) {
|
|
120
|
-
return fun.apply(thisValue, args);
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
163
|
/**
|
|
125
164
|
* Creates a no-op policy for internal use only.
|
|
126
165
|
* Don't export this function outside this module!
|
|
@@ -171,7 +210,7 @@ function createDOMPurify() {
|
|
|
171
210
|
* Version label, exposed for easier checks
|
|
172
211
|
* if DOMPurify is up to date or not
|
|
173
212
|
*/
|
|
174
|
-
DOMPurify.version = '2.0.
|
|
213
|
+
DOMPurify.version = '2.0.8';
|
|
175
214
|
|
|
176
215
|
/**
|
|
177
216
|
* Array of elements that DOMPurify removed during sanitation.
|
|
@@ -189,7 +228,6 @@ function createDOMPurify() {
|
|
|
189
228
|
|
|
190
229
|
var originalDocument = window.document;
|
|
191
230
|
var useDOMParser = false;
|
|
192
|
-
var removeSVGAttr = false;
|
|
193
231
|
var removeTitle = false;
|
|
194
232
|
|
|
195
233
|
var document = window.document;
|
|
@@ -202,7 +240,7 @@ function createDOMPurify() {
|
|
|
202
240
|
Text = window.Text,
|
|
203
241
|
Comment = window.Comment,
|
|
204
242
|
DOMParser = window.DOMParser,
|
|
205
|
-
|
|
243
|
+
trustedTypes = window.trustedTypes;
|
|
206
244
|
|
|
207
245
|
// As per issue #47, the web-components registry is inherited by a
|
|
208
246
|
// new document created via createHTMLDocument. As per the spec
|
|
@@ -218,7 +256,7 @@ function createDOMPurify() {
|
|
|
218
256
|
}
|
|
219
257
|
}
|
|
220
258
|
|
|
221
|
-
var trustedTypesPolicy = _createTrustedTypesPolicy(
|
|
259
|
+
var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
|
|
222
260
|
var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
|
|
223
261
|
|
|
224
262
|
var _document = document,
|
|
@@ -325,7 +363,7 @@ function createDOMPurify() {
|
|
|
325
363
|
var USE_PROFILES = {};
|
|
326
364
|
|
|
327
365
|
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
328
|
-
var FORBID_CONTENTS = addToSet({}, ['audio', 'colgroup', 'head', 'math', 'script', 'style', 'template', 'thead', '
|
|
366
|
+
var FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
|
|
329
367
|
|
|
330
368
|
/* Tags that are safe for data: URIs */
|
|
331
369
|
var DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image']);
|
|
@@ -379,9 +417,7 @@ function createDOMPurify() {
|
|
|
379
417
|
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
|
|
380
418
|
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
381
419
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
382
|
-
|
|
383
420
|
IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
|
|
384
|
-
|
|
385
421
|
if (SAFE_FOR_TEMPLATES) {
|
|
386
422
|
ALLOW_DATA_ATTR = false;
|
|
387
423
|
}
|
|
@@ -470,7 +506,7 @@ function createDOMPurify() {
|
|
|
470
506
|
* @param {Node} node a DOM node
|
|
471
507
|
*/
|
|
472
508
|
var _forceRemove = function _forceRemove(node) {
|
|
473
|
-
DOMPurify.removed
|
|
509
|
+
arrayPush(DOMPurify.removed, { element: node });
|
|
474
510
|
try {
|
|
475
511
|
node.parentNode.removeChild(node);
|
|
476
512
|
} catch (error) {
|
|
@@ -486,12 +522,12 @@ function createDOMPurify() {
|
|
|
486
522
|
*/
|
|
487
523
|
var _removeAttribute = function _removeAttribute(name, node) {
|
|
488
524
|
try {
|
|
489
|
-
DOMPurify.removed
|
|
525
|
+
arrayPush(DOMPurify.removed, {
|
|
490
526
|
attribute: node.getAttributeNode(name),
|
|
491
527
|
from: node
|
|
492
528
|
});
|
|
493
529
|
} catch (error) {
|
|
494
|
-
DOMPurify.removed
|
|
530
|
+
arrayPush(DOMPurify.removed, {
|
|
495
531
|
attribute: null,
|
|
496
532
|
from: node
|
|
497
533
|
});
|
|
@@ -515,17 +551,15 @@ function createDOMPurify() {
|
|
|
515
551
|
dirty = '<remove></remove>' + dirty;
|
|
516
552
|
} else {
|
|
517
553
|
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
|
518
|
-
var matches = dirty
|
|
554
|
+
var matches = stringMatch(dirty, /^[\s]+/);
|
|
519
555
|
leadingWhitespace = matches && matches[0];
|
|
520
|
-
if (leadingWhitespace) {
|
|
521
|
-
dirty = dirty.slice(leadingWhitespace.length);
|
|
522
|
-
}
|
|
523
556
|
}
|
|
524
557
|
|
|
558
|
+
var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
525
559
|
/* Use DOMParser to workaround Firefox bug (see comment below) */
|
|
526
560
|
if (useDOMParser) {
|
|
527
561
|
try {
|
|
528
|
-
doc = new DOMParser().parseFromString(
|
|
562
|
+
doc = new DOMParser().parseFromString(dirtyPayload, 'text/html');
|
|
529
563
|
} catch (error) {}
|
|
530
564
|
}
|
|
531
565
|
|
|
@@ -542,10 +576,10 @@ function createDOMPurify() {
|
|
|
542
576
|
body = _doc.body;
|
|
543
577
|
|
|
544
578
|
body.parentNode.removeChild(body.parentNode.firstElementChild);
|
|
545
|
-
body.outerHTML =
|
|
579
|
+
body.outerHTML = dirtyPayload;
|
|
546
580
|
}
|
|
547
581
|
|
|
548
|
-
if (leadingWhitespace) {
|
|
582
|
+
if (dirty && leadingWhitespace) {
|
|
549
583
|
doc.body.insertBefore(document.createTextNode(leadingWhitespace), doc.body.childNodes[0] || null);
|
|
550
584
|
}
|
|
551
585
|
|
|
@@ -575,20 +609,11 @@ function createDOMPurify() {
|
|
|
575
609
|
(function () {
|
|
576
610
|
try {
|
|
577
611
|
var doc = _initDocument('<x/><title></title><img>');
|
|
578
|
-
if (/<\/title
|
|
612
|
+
if (regExpTest(/<\/title/, doc.querySelector('title').innerHTML)) {
|
|
579
613
|
removeTitle = true;
|
|
580
614
|
}
|
|
581
615
|
} catch (error) {}
|
|
582
616
|
})();
|
|
583
|
-
|
|
584
|
-
(function () {
|
|
585
|
-
try {
|
|
586
|
-
var doc = _initDocument('<svg></p></svg>');
|
|
587
|
-
if (doc.querySelector('svg p')) {
|
|
588
|
-
removeSVGAttr = true;
|
|
589
|
-
}
|
|
590
|
-
} catch (error) {}
|
|
591
|
-
})();
|
|
592
617
|
}
|
|
593
618
|
|
|
594
619
|
/**
|
|
@@ -644,7 +669,7 @@ function createDOMPurify() {
|
|
|
644
669
|
return;
|
|
645
670
|
}
|
|
646
671
|
|
|
647
|
-
hooks[entryPoint]
|
|
672
|
+
arrayForEach(hooks[entryPoint], function (hook) {
|
|
648
673
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
649
674
|
});
|
|
650
675
|
};
|
|
@@ -673,7 +698,7 @@ function createDOMPurify() {
|
|
|
673
698
|
}
|
|
674
699
|
|
|
675
700
|
/* Now let's check the element's type and name */
|
|
676
|
-
var tagName = currentNode.nodeName
|
|
701
|
+
var tagName = stringToLowerCase(currentNode.nodeName);
|
|
677
702
|
|
|
678
703
|
/* Execute a hook if present */
|
|
679
704
|
_executeHook('uponSanitizeElement', currentNode, {
|
|
@@ -681,6 +706,12 @@ function createDOMPurify() {
|
|
|
681
706
|
allowedTags: ALLOWED_TAGS
|
|
682
707
|
});
|
|
683
708
|
|
|
709
|
+
/* Take care of an mXSS pattern using p, br inside svg, math */
|
|
710
|
+
if ((tagName === 'svg' || tagName === 'math') && currentNode.querySelectorAll('p, br').length !== 0) {
|
|
711
|
+
_forceRemove(currentNode);
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
|
|
684
715
|
/* Remove element if anything forbids its presence */
|
|
685
716
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
686
717
|
/* Keep content except for black-listed elements */
|
|
@@ -696,34 +727,23 @@ function createDOMPurify() {
|
|
|
696
727
|
}
|
|
697
728
|
|
|
698
729
|
/* Remove in case a noscript/noembed XSS is suspected */
|
|
699
|
-
if (tagName === 'noscript' && /<\/noscript/i
|
|
730
|
+
if (tagName === 'noscript' && regExpTest(/<\/noscript/i, currentNode.innerHTML)) {
|
|
700
731
|
_forceRemove(currentNode);
|
|
701
732
|
return true;
|
|
702
733
|
}
|
|
703
734
|
|
|
704
|
-
if (tagName === 'noembed' && /<\/noembed/i
|
|
705
|
-
_forceRemove(currentNode);
|
|
706
|
-
return true;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
/* Remove in case an mXSS is suspected */
|
|
710
|
-
if (currentNode.namespaceURI && /svg|math/i.test(currentNode.namespaceURI) && currentNode.textContent && new RegExp('</' + tagName, 'i').test(currentNode.textContent)) {
|
|
711
|
-
_forceRemove(currentNode);
|
|
712
|
-
return true;
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
if ((tagName === 'svg' || tagName === 'math') && (currentNode.querySelectorAll('template') || currentNode.querySelectorAll('svg') || currentNode.querySelectorAll('math'))) {
|
|
735
|
+
if (tagName === 'noembed' && regExpTest(/<\/noembed/i, currentNode.innerHTML)) {
|
|
716
736
|
_forceRemove(currentNode);
|
|
717
737
|
return true;
|
|
718
738
|
}
|
|
719
739
|
|
|
720
740
|
/* Convert markup to cover jQuery behavior */
|
|
721
|
-
if (SAFE_FOR_JQUERY && !currentNode.firstElementChild && (!currentNode.content || !currentNode.content.firstElementChild) && /</g
|
|
722
|
-
DOMPurify.removed
|
|
741
|
+
if (SAFE_FOR_JQUERY && !currentNode.firstElementChild && (!currentNode.content || !currentNode.content.firstElementChild) && regExpTest(/</g, currentNode.textContent)) {
|
|
742
|
+
arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
|
|
723
743
|
if (currentNode.innerHTML) {
|
|
724
|
-
currentNode.innerHTML = currentNode.innerHTML
|
|
744
|
+
currentNode.innerHTML = stringReplace(currentNode.innerHTML, /</g, '<');
|
|
725
745
|
} else {
|
|
726
|
-
currentNode.innerHTML = currentNode.textContent
|
|
746
|
+
currentNode.innerHTML = stringReplace(currentNode.textContent, /</g, '<');
|
|
727
747
|
}
|
|
728
748
|
}
|
|
729
749
|
|
|
@@ -731,10 +751,10 @@ function createDOMPurify() {
|
|
|
731
751
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
|
|
732
752
|
/* Get the element's text content */
|
|
733
753
|
content = currentNode.textContent;
|
|
734
|
-
content = content
|
|
735
|
-
content = content
|
|
754
|
+
content = stringReplace(content, MUSTACHE_EXPR$$1, ' ');
|
|
755
|
+
content = stringReplace(content, ERB_EXPR$$1, ' ');
|
|
736
756
|
if (currentNode.textContent !== content) {
|
|
737
|
-
DOMPurify.removed
|
|
757
|
+
arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
|
|
738
758
|
currentNode.textContent = content;
|
|
739
759
|
}
|
|
740
760
|
}
|
|
@@ -764,9 +784,9 @@ function createDOMPurify() {
|
|
|
764
784
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
765
785
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
766
786
|
We don't need to check the value; it's always URI safe. */
|
|
767
|
-
if (ALLOW_DATA_ATTR && DATA_ATTR$$1
|
|
787
|
+
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$$1, lcName)) {
|
|
768
788
|
// This attribute is safe
|
|
769
|
-
} else if (ALLOW_ARIA_ATTR && ARIA_ATTR$$1
|
|
789
|
+
} else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) {
|
|
770
790
|
// This attribute is safe
|
|
771
791
|
/* Otherwise, check the name is permitted */
|
|
772
792
|
} else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
@@ -777,16 +797,16 @@ function createDOMPurify() {
|
|
|
777
797
|
// This attribute is safe
|
|
778
798
|
/* Check no script, data or unknown possibly unsafe URI
|
|
779
799
|
unless we know URI values are safe for that attribute */
|
|
780
|
-
} else if (IS_ALLOWED_URI$$1
|
|
800
|
+
} else if (regExpTest(IS_ALLOWED_URI$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) {
|
|
781
801
|
// This attribute is safe
|
|
782
802
|
/* Keep image data URIs alive if src/xlink:href is allowed */
|
|
783
803
|
/* Further prevent gadget XSS for dynamically built script tags */
|
|
784
|
-
} else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && value
|
|
804
|
+
} else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) {
|
|
785
805
|
// This attribute is safe
|
|
786
806
|
/* Allow unknown protocols: This provides support for links that
|
|
787
807
|
are handled by protocol handlers which may be unknown ahead of
|
|
788
808
|
time, e.g. fb:, spotify: */
|
|
789
|
-
} else if (ALLOW_UNKNOWN_PROTOCOLS && !IS_SCRIPT_OR_DATA$$1
|
|
809
|
+
} else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) {
|
|
790
810
|
// This attribute is safe
|
|
791
811
|
/* Check for binary attributes */
|
|
792
812
|
// eslint-disable-next-line no-negated-condition
|
|
@@ -843,21 +863,19 @@ function createDOMPurify() {
|
|
|
843
863
|
name = _attr.name,
|
|
844
864
|
namespaceURI = _attr.namespaceURI;
|
|
845
865
|
|
|
846
|
-
value = attr.value
|
|
847
|
-
lcName = name
|
|
866
|
+
value = stringTrim(attr.value);
|
|
867
|
+
lcName = stringToLowerCase(name);
|
|
848
868
|
|
|
849
869
|
/* Execute a hook if present */
|
|
850
870
|
hookEvent.attrName = lcName;
|
|
851
871
|
hookEvent.attrValue = value;
|
|
852
872
|
hookEvent.keepAttr = true;
|
|
873
|
+
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
|
853
874
|
_executeHook('uponSanitizeAttribute', currentNode, hookEvent);
|
|
854
875
|
value = hookEvent.attrValue;
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
if (removeSVGAttr && /<\//.test(value)) {
|
|
859
|
-
_forceRemove(currentNode);
|
|
860
|
-
}
|
|
876
|
+
/* Did the hooks approve of the attribute? */
|
|
877
|
+
if (hookEvent.forceKeepAttr) {
|
|
878
|
+
continue;
|
|
861
879
|
}
|
|
862
880
|
|
|
863
881
|
/* Remove attribute */
|
|
@@ -866,10 +884,10 @@ function createDOMPurify() {
|
|
|
866
884
|
// attribute at the time.
|
|
867
885
|
if (lcName === 'name' && currentNode.nodeName === 'IMG' && attributes.id) {
|
|
868
886
|
idAttr = attributes.id;
|
|
869
|
-
attributes =
|
|
887
|
+
attributes = arraySlice(attributes, []);
|
|
870
888
|
_removeAttribute('id', currentNode);
|
|
871
889
|
_removeAttribute(name, currentNode);
|
|
872
|
-
if (attributes
|
|
890
|
+
if (arrayIndexOf(attributes, idAttr) > l) {
|
|
873
891
|
currentNode.setAttribute('id', idAttr.value);
|
|
874
892
|
}
|
|
875
893
|
} else if (
|
|
@@ -893,10 +911,22 @@ function createDOMPurify() {
|
|
|
893
911
|
continue;
|
|
894
912
|
}
|
|
895
913
|
|
|
914
|
+
/* Work around a security issue in jQuery 3.0 */
|
|
915
|
+
if (SAFE_FOR_JQUERY && regExpTest(/\/>/i, value)) {
|
|
916
|
+
_removeAttribute(name, currentNode);
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/* Take care of an mXSS pattern using namespace switches */
|
|
921
|
+
if (regExpTest(/svg|math/i, currentNode.namespaceURI) && regExpTest(regExpCreate('</(' + arrayJoin(objectKeys(FORBID_CONTENTS), '|') + ')', 'i'), value)) {
|
|
922
|
+
_removeAttribute(name, currentNode);
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
|
|
896
926
|
/* Sanitize attribute content to be template-safe */
|
|
897
927
|
if (SAFE_FOR_TEMPLATES) {
|
|
898
|
-
value = value
|
|
899
|
-
value = value
|
|
928
|
+
value = stringReplace(value, MUSTACHE_EXPR$$1, ' ');
|
|
929
|
+
value = stringReplace(value, ERB_EXPR$$1, ' ');
|
|
900
930
|
}
|
|
901
931
|
|
|
902
932
|
/* Is `value` valid for this attribute? */
|
|
@@ -914,7 +944,7 @@ function createDOMPurify() {
|
|
|
914
944
|
currentNode.setAttribute(name, value);
|
|
915
945
|
}
|
|
916
946
|
|
|
917
|
-
DOMPurify.removed
|
|
947
|
+
arrayPop(DOMPurify.removed);
|
|
918
948
|
} catch (error) {}
|
|
919
949
|
}
|
|
920
950
|
|
|
@@ -981,11 +1011,11 @@ function createDOMPurify() {
|
|
|
981
1011
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
982
1012
|
// eslint-disable-next-line no-negated-condition
|
|
983
1013
|
if (typeof dirty.toString !== 'function') {
|
|
984
|
-
throw
|
|
1014
|
+
throw typeErrorCreate('toString is not a function');
|
|
985
1015
|
} else {
|
|
986
1016
|
dirty = dirty.toString();
|
|
987
1017
|
if (typeof dirty !== 'string') {
|
|
988
|
-
throw
|
|
1018
|
+
throw typeErrorCreate('dirty is not a string, aborting');
|
|
989
1019
|
}
|
|
990
1020
|
}
|
|
991
1021
|
}
|
|
@@ -1013,6 +1043,11 @@ function createDOMPurify() {
|
|
|
1013
1043
|
/* Clean up removed elements */
|
|
1014
1044
|
DOMPurify.removed = [];
|
|
1015
1045
|
|
|
1046
|
+
/* Check if dirty is correctly typed for IN_PLACE */
|
|
1047
|
+
if (typeof dirty === 'string') {
|
|
1048
|
+
IN_PLACE = false;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1016
1051
|
if (IN_PLACE) {
|
|
1017
1052
|
/* No special handling necessary for in-place sanitization */
|
|
1018
1053
|
} else if (dirty instanceof Node) {
|
|
@@ -1111,8 +1146,8 @@ function createDOMPurify() {
|
|
|
1111
1146
|
|
|
1112
1147
|
/* Sanitize final string template-safe */
|
|
1113
1148
|
if (SAFE_FOR_TEMPLATES) {
|
|
1114
|
-
serializedHTML = serializedHTML
|
|
1115
|
-
serializedHTML = serializedHTML
|
|
1149
|
+
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$$1, ' ');
|
|
1150
|
+
serializedHTML = stringReplace(serializedHTML, ERB_EXPR$$1, ' ');
|
|
1116
1151
|
}
|
|
1117
1152
|
|
|
1118
1153
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
@@ -1155,8 +1190,8 @@ function createDOMPurify() {
|
|
|
1155
1190
|
_parseConfig({});
|
|
1156
1191
|
}
|
|
1157
1192
|
|
|
1158
|
-
var lcTag = tag
|
|
1159
|
-
var lcName = attr
|
|
1193
|
+
var lcTag = stringToLowerCase(tag);
|
|
1194
|
+
var lcName = stringToLowerCase(attr);
|
|
1160
1195
|
return _isValidAttribute(lcTag, lcName, value);
|
|
1161
1196
|
};
|
|
1162
1197
|
|
|
@@ -1173,7 +1208,7 @@ function createDOMPurify() {
|
|
|
1173
1208
|
}
|
|
1174
1209
|
|
|
1175
1210
|
hooks[entryPoint] = hooks[entryPoint] || [];
|
|
1176
|
-
hooks[entryPoint]
|
|
1211
|
+
arrayPush(hooks[entryPoint], hookFunction);
|
|
1177
1212
|
};
|
|
1178
1213
|
|
|
1179
1214
|
/**
|
|
@@ -1185,7 +1220,7 @@ function createDOMPurify() {
|
|
|
1185
1220
|
*/
|
|
1186
1221
|
DOMPurify.removeHook = function (entryPoint) {
|
|
1187
1222
|
if (hooks[entryPoint]) {
|
|
1188
|
-
hooks[entryPoint]
|
|
1223
|
+
arrayPop(hooks[entryPoint]);
|
|
1189
1224
|
}
|
|
1190
1225
|
};
|
|
1191
1226
|
|