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