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