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