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