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