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