dompurify 3.0.1 → 3.0.3
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 +16 -7
- package/dist/purify.cjs.js +295 -430
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.js +296 -431
- package/dist/purify.es.js.map +1 -1
- package/dist/purify.js +295 -430
- 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 +2 -3
package/dist/purify.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.0.
|
|
1
|
+
/*! @license DOMPurify 3.0.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.0.3/LICENSE */
|
|
2
2
|
|
|
3
3
|
(function (global, factory) {
|
|
4
4
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
@@ -6,199 +6,23 @@
|
|
|
6
6
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DOMPurify = factory());
|
|
7
7
|
})(this, (function () { 'use strict';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function _isNativeReflectConstruct() {
|
|
29
|
-
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
|
|
30
|
-
if (Reflect.construct.sham) return false;
|
|
31
|
-
if (typeof Proxy === "function") return true;
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
|
35
|
-
return true;
|
|
36
|
-
} catch (e) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function _construct(Parent, args, Class) {
|
|
42
|
-
if (_isNativeReflectConstruct()) {
|
|
43
|
-
_construct = Reflect.construct;
|
|
44
|
-
} else {
|
|
45
|
-
_construct = function _construct(Parent, args, Class) {
|
|
46
|
-
var a = [null];
|
|
47
|
-
a.push.apply(a, args);
|
|
48
|
-
var Constructor = Function.bind.apply(Parent, a);
|
|
49
|
-
var instance = new Constructor();
|
|
50
|
-
if (Class) _setPrototypeOf(instance, Class.prototype);
|
|
51
|
-
return instance;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return _construct.apply(null, arguments);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function _slicedToArray(arr, i) {
|
|
59
|
-
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
|
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 _arrayWithHoles(arr) {
|
|
71
|
-
if (Array.isArray(arr)) return arr;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function _iterableToArray(iter) {
|
|
75
|
-
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function _iterableToArrayLimit(arr, i) {
|
|
79
|
-
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
80
|
-
|
|
81
|
-
if (_i == null) return;
|
|
82
|
-
var _arr = [];
|
|
83
|
-
var _n = true;
|
|
84
|
-
var _d = false;
|
|
85
|
-
|
|
86
|
-
var _s, _e;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
|
|
90
|
-
_arr.push(_s.value);
|
|
91
|
-
|
|
92
|
-
if (i && _arr.length === i) break;
|
|
93
|
-
}
|
|
94
|
-
} catch (err) {
|
|
95
|
-
_d = true;
|
|
96
|
-
_e = err;
|
|
97
|
-
} finally {
|
|
98
|
-
try {
|
|
99
|
-
if (!_n && _i["return"] != null) _i["return"]();
|
|
100
|
-
} finally {
|
|
101
|
-
if (_d) throw _e;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return _arr;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function _unsupportedIterableToArray(o, minLen) {
|
|
109
|
-
if (!o) return;
|
|
110
|
-
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
|
111
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
112
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
113
|
-
if (n === "Map" || n === "Set") return Array.from(o);
|
|
114
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function _arrayLikeToArray(arr, len) {
|
|
118
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
119
|
-
|
|
120
|
-
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
|
121
|
-
|
|
122
|
-
return arr2;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function _nonIterableSpread() {
|
|
126
|
-
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function _nonIterableRest() {
|
|
130
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function _createForOfIteratorHelper(o, allowArrayLike) {
|
|
134
|
-
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
|
|
135
|
-
|
|
136
|
-
if (!it) {
|
|
137
|
-
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
|
|
138
|
-
if (it) o = it;
|
|
139
|
-
var i = 0;
|
|
140
|
-
|
|
141
|
-
var F = function () {};
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
s: F,
|
|
145
|
-
n: function () {
|
|
146
|
-
if (i >= o.length) return {
|
|
147
|
-
done: true
|
|
148
|
-
};
|
|
149
|
-
return {
|
|
150
|
-
done: false,
|
|
151
|
-
value: o[i++]
|
|
152
|
-
};
|
|
153
|
-
},
|
|
154
|
-
e: function (e) {
|
|
155
|
-
throw e;
|
|
156
|
-
},
|
|
157
|
-
f: F
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
var normalCompletion = true,
|
|
165
|
-
didErr = false,
|
|
166
|
-
err;
|
|
167
|
-
return {
|
|
168
|
-
s: function () {
|
|
169
|
-
it = it.call(o);
|
|
170
|
-
},
|
|
171
|
-
n: function () {
|
|
172
|
-
var step = it.next();
|
|
173
|
-
normalCompletion = step.done;
|
|
174
|
-
return step;
|
|
175
|
-
},
|
|
176
|
-
e: function (e) {
|
|
177
|
-
didErr = true;
|
|
178
|
-
err = e;
|
|
179
|
-
},
|
|
180
|
-
f: function () {
|
|
181
|
-
try {
|
|
182
|
-
if (!normalCompletion && it.return != null) it.return();
|
|
183
|
-
} finally {
|
|
184
|
-
if (didErr) throw err;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
var entries = Object.entries,
|
|
191
|
-
setPrototypeOf = Object.setPrototypeOf,
|
|
192
|
-
isFrozen = Object.isFrozen,
|
|
193
|
-
getPrototypeOf = Object.getPrototypeOf,
|
|
194
|
-
getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
195
|
-
var freeze = Object.freeze,
|
|
196
|
-
seal = Object.seal,
|
|
197
|
-
create = Object.create; // eslint-disable-line import/no-mutable-exports
|
|
198
|
-
|
|
199
|
-
var _ref = typeof Reflect !== 'undefined' && Reflect,
|
|
200
|
-
apply = _ref.apply,
|
|
201
|
-
construct = _ref.construct;
|
|
9
|
+
const {
|
|
10
|
+
entries,
|
|
11
|
+
setPrototypeOf,
|
|
12
|
+
isFrozen,
|
|
13
|
+
getPrototypeOf,
|
|
14
|
+
getOwnPropertyDescriptor
|
|
15
|
+
} = Object;
|
|
16
|
+
let {
|
|
17
|
+
freeze,
|
|
18
|
+
seal,
|
|
19
|
+
create
|
|
20
|
+
} = Object; // eslint-disable-line import/no-mutable-exports
|
|
21
|
+
|
|
22
|
+
let {
|
|
23
|
+
apply,
|
|
24
|
+
construct
|
|
25
|
+
} = typeof Reflect !== 'undefined' && Reflect;
|
|
202
26
|
|
|
203
27
|
if (!apply) {
|
|
204
28
|
apply = function apply(fun, thisValue, args) {
|
|
@@ -220,21 +44,21 @@
|
|
|
220
44
|
|
|
221
45
|
if (!construct) {
|
|
222
46
|
construct = function construct(Func, args) {
|
|
223
|
-
return
|
|
47
|
+
return new Func(...args);
|
|
224
48
|
};
|
|
225
49
|
}
|
|
226
50
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
51
|
+
const arrayForEach = unapply(Array.prototype.forEach);
|
|
52
|
+
const arrayPop = unapply(Array.prototype.pop);
|
|
53
|
+
const arrayPush = unapply(Array.prototype.push);
|
|
54
|
+
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
55
|
+
const stringToString = unapply(String.prototype.toString);
|
|
56
|
+
const stringMatch = unapply(String.prototype.match);
|
|
57
|
+
const stringReplace = unapply(String.prototype.replace);
|
|
58
|
+
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
59
|
+
const stringTrim = unapply(String.prototype.trim);
|
|
60
|
+
const regExpTest = unapply(RegExp.prototype.test);
|
|
61
|
+
const typeErrorCreate = unconstruct(TypeError);
|
|
238
62
|
function unapply(func) {
|
|
239
63
|
return function (thisArg) {
|
|
240
64
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
@@ -256,7 +80,9 @@
|
|
|
256
80
|
/* Add properties to a lookup table */
|
|
257
81
|
|
|
258
82
|
function addToSet(set, array, transformCaseFunc) {
|
|
259
|
-
|
|
83
|
+
var _transformCaseFunc;
|
|
84
|
+
|
|
85
|
+
transformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;
|
|
260
86
|
|
|
261
87
|
if (setPrototypeOf) {
|
|
262
88
|
// Make 'in' and truthy checks like Boolean(set.constructor)
|
|
@@ -265,13 +91,13 @@
|
|
|
265
91
|
setPrototypeOf(set, null);
|
|
266
92
|
}
|
|
267
93
|
|
|
268
|
-
|
|
94
|
+
let l = array.length;
|
|
269
95
|
|
|
270
96
|
while (l--) {
|
|
271
|
-
|
|
97
|
+
let element = array[l];
|
|
272
98
|
|
|
273
99
|
if (typeof element === 'string') {
|
|
274
|
-
|
|
100
|
+
const lcElement = transformCaseFunc(element);
|
|
275
101
|
|
|
276
102
|
if (lcElement !== element) {
|
|
277
103
|
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
@@ -291,23 +117,10 @@
|
|
|
291
117
|
/* Shallow clone an object */
|
|
292
118
|
|
|
293
119
|
function clone(object) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
var _iterator = _createForOfIteratorHelper(entries(object)),
|
|
297
|
-
_step;
|
|
298
|
-
|
|
299
|
-
try {
|
|
300
|
-
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
301
|
-
var _step$value = _slicedToArray(_step.value, 2),
|
|
302
|
-
property = _step$value[0],
|
|
303
|
-
value = _step$value[1];
|
|
120
|
+
const newObject = create(null);
|
|
304
121
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
} catch (err) {
|
|
308
|
-
_iterator.e(err);
|
|
309
|
-
} finally {
|
|
310
|
-
_iterator.f();
|
|
122
|
+
for (const [property, value] of entries(object)) {
|
|
123
|
+
newObject[property] = value;
|
|
311
124
|
}
|
|
312
125
|
|
|
313
126
|
return newObject;
|
|
@@ -317,7 +130,7 @@
|
|
|
317
130
|
|
|
318
131
|
function lookupGetter(object, prop) {
|
|
319
132
|
while (object !== null) {
|
|
320
|
-
|
|
133
|
+
const desc = getOwnPropertyDescriptor(object, prop);
|
|
321
134
|
|
|
322
135
|
if (desc) {
|
|
323
136
|
if (desc.get) {
|
|
@@ -340,79 +153,92 @@
|
|
|
340
153
|
return fallbackValue;
|
|
341
154
|
}
|
|
342
155
|
|
|
343
|
-
|
|
156
|
+
const 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
|
|
344
157
|
|
|
345
|
-
|
|
346
|
-
|
|
158
|
+
const 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']);
|
|
159
|
+
const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', '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.
|
|
347
160
|
// We still need to know them so that we can do namespace
|
|
348
161
|
// checks properly in case one wants to add them to
|
|
349
162
|
// allow-list.
|
|
350
163
|
|
|
351
|
-
|
|
352
|
-
|
|
164
|
+
const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', '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']);
|
|
165
|
+
const 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', 'mprescripts']); // Similarly to SVG, we want to know all MathML elements,
|
|
353
166
|
// even those that we disallow by default.
|
|
354
167
|
|
|
355
|
-
|
|
356
|
-
|
|
168
|
+
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
169
|
+
const text = freeze(['#text']);
|
|
357
170
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
171
|
+
const 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']);
|
|
172
|
+
const 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']);
|
|
173
|
+
const 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']);
|
|
174
|
+
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
362
175
|
|
|
363
|
-
|
|
176
|
+
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
364
177
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
178
|
+
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
|
179
|
+
const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
|
|
180
|
+
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
|
|
368
181
|
|
|
369
|
-
|
|
182
|
+
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
370
183
|
|
|
371
|
-
|
|
184
|
+
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
372
185
|
);
|
|
373
|
-
|
|
374
|
-
|
|
186
|
+
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
|
187
|
+
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
375
188
|
);
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
var
|
|
379
|
-
|
|
380
|
-
|
|
189
|
+
const DOCTYPE_NAME = seal(/^html$/i);
|
|
190
|
+
|
|
191
|
+
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
|
192
|
+
__proto__: null,
|
|
193
|
+
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
194
|
+
ERB_EXPR: ERB_EXPR,
|
|
195
|
+
TMPLIT_EXPR: TMPLIT_EXPR,
|
|
196
|
+
DATA_ATTR: DATA_ATTR,
|
|
197
|
+
ARIA_ATTR: ARIA_ATTR,
|
|
198
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
199
|
+
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
|
200
|
+
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
|
201
|
+
DOCTYPE_NAME: DOCTYPE_NAME
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const getGlobal = () => typeof window === 'undefined' ? null : window;
|
|
381
205
|
/**
|
|
382
206
|
* Creates a no-op policy for internal use only.
|
|
383
207
|
* Don't export this function outside this module!
|
|
384
208
|
* @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
|
|
385
|
-
* @param {
|
|
209
|
+
* @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
|
|
386
210
|
* @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
|
|
387
|
-
* are not supported).
|
|
211
|
+
* are not supported or creating the policy failed).
|
|
388
212
|
*/
|
|
389
213
|
|
|
390
214
|
|
|
391
|
-
|
|
392
|
-
if (
|
|
215
|
+
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
|
|
216
|
+
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
|
393
217
|
return null;
|
|
394
218
|
} // Allow the callers to control the unique policy name
|
|
395
219
|
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
|
396
220
|
// Policy creation with duplicate names throws in Trusted Types.
|
|
397
221
|
|
|
398
222
|
|
|
399
|
-
|
|
400
|
-
|
|
223
|
+
let suffix = null;
|
|
224
|
+
const ATTR_NAME = 'data-tt-policy-suffix';
|
|
401
225
|
|
|
402
|
-
if (
|
|
403
|
-
suffix =
|
|
226
|
+
if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
|
|
227
|
+
suffix = purifyHostElement.getAttribute(ATTR_NAME);
|
|
404
228
|
}
|
|
405
229
|
|
|
406
|
-
|
|
230
|
+
const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
|
|
407
231
|
|
|
408
232
|
try {
|
|
409
233
|
return trustedTypes.createPolicy(policyName, {
|
|
410
|
-
createHTML
|
|
234
|
+
createHTML(html) {
|
|
411
235
|
return html;
|
|
412
236
|
},
|
|
413
|
-
|
|
237
|
+
|
|
238
|
+
createScriptURL(scriptUrl) {
|
|
414
239
|
return scriptUrl;
|
|
415
240
|
}
|
|
241
|
+
|
|
416
242
|
});
|
|
417
243
|
} catch (_) {
|
|
418
244
|
// Policy creation failed (most likely another DOMPurify script has
|
|
@@ -424,18 +250,16 @@
|
|
|
424
250
|
};
|
|
425
251
|
|
|
426
252
|
function createDOMPurify() {
|
|
427
|
-
|
|
253
|
+
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
428
254
|
|
|
429
|
-
|
|
430
|
-
return createDOMPurify(root);
|
|
431
|
-
};
|
|
255
|
+
const DOMPurify = root => createDOMPurify(root);
|
|
432
256
|
/**
|
|
433
257
|
* Version label, exposed for easier checks
|
|
434
258
|
* if DOMPurify is up to date or not
|
|
435
259
|
*/
|
|
436
260
|
|
|
437
261
|
|
|
438
|
-
DOMPurify.version = '3.0.
|
|
262
|
+
DOMPurify.version = '3.0.3';
|
|
439
263
|
/**
|
|
440
264
|
* Array of elements that DOMPurify removed during sanitation.
|
|
441
265
|
* Empty if nothing was removed.
|
|
@@ -450,23 +274,27 @@
|
|
|
450
274
|
return DOMPurify;
|
|
451
275
|
}
|
|
452
276
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
277
|
+
const originalDocument = window.document;
|
|
278
|
+
const currentScript = originalDocument.currentScript;
|
|
279
|
+
let {
|
|
280
|
+
document
|
|
281
|
+
} = window;
|
|
282
|
+
const {
|
|
283
|
+
DocumentFragment,
|
|
284
|
+
HTMLTemplateElement,
|
|
285
|
+
Node,
|
|
286
|
+
Element,
|
|
287
|
+
NodeFilter,
|
|
288
|
+
NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
|
|
289
|
+
HTMLFormElement,
|
|
290
|
+
DOMParser,
|
|
291
|
+
trustedTypes
|
|
292
|
+
} = window;
|
|
293
|
+
const ElementPrototype = Element.prototype;
|
|
294
|
+
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
|
295
|
+
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
|
296
|
+
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
|
297
|
+
const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); // As per issue #47, the web-components registry is inherited by a
|
|
470
298
|
// new document created via createHTMLDocument. As per the spec
|
|
471
299
|
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
472
300
|
// a new empty registry is used when creating a template contents owner
|
|
@@ -474,36 +302,42 @@
|
|
|
474
302
|
// is inherited.
|
|
475
303
|
|
|
476
304
|
if (typeof HTMLTemplateElement === 'function') {
|
|
477
|
-
|
|
305
|
+
const template = document.createElement('template');
|
|
478
306
|
|
|
479
307
|
if (template.content && template.content.ownerDocument) {
|
|
480
308
|
document = template.content.ownerDocument;
|
|
481
309
|
}
|
|
482
310
|
}
|
|
483
311
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
312
|
+
let trustedTypesPolicy;
|
|
313
|
+
let emptyHTML = '';
|
|
314
|
+
const {
|
|
315
|
+
implementation,
|
|
316
|
+
createNodeIterator,
|
|
317
|
+
createDocumentFragment,
|
|
318
|
+
getElementsByTagName
|
|
319
|
+
} = document;
|
|
320
|
+
const {
|
|
321
|
+
importNode
|
|
322
|
+
} = originalDocument;
|
|
323
|
+
let hooks = {};
|
|
494
324
|
/**
|
|
495
325
|
* Expose whether this browser supports running the full DOMPurify.
|
|
496
326
|
*/
|
|
497
327
|
|
|
498
|
-
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation &&
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
328
|
+
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
|
|
329
|
+
const {
|
|
330
|
+
MUSTACHE_EXPR,
|
|
331
|
+
ERB_EXPR,
|
|
332
|
+
TMPLIT_EXPR,
|
|
333
|
+
DATA_ATTR,
|
|
334
|
+
ARIA_ATTR,
|
|
335
|
+
IS_SCRIPT_OR_DATA,
|
|
336
|
+
ATTR_WHITESPACE
|
|
337
|
+
} = EXPRESSIONS;
|
|
338
|
+
let {
|
|
339
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
|
340
|
+
} = EXPRESSIONS;
|
|
507
341
|
/**
|
|
508
342
|
* We consider the elements and attributes below to be safe. Ideally
|
|
509
343
|
* don't add any new ones but feel free to remove unwanted ones.
|
|
@@ -511,12 +345,12 @@
|
|
|
511
345
|
|
|
512
346
|
/* allowed element names */
|
|
513
347
|
|
|
514
|
-
|
|
515
|
-
|
|
348
|
+
let ALLOWED_TAGS = null;
|
|
349
|
+
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
|
|
516
350
|
/* Allowed attribute names */
|
|
517
351
|
|
|
518
|
-
|
|
519
|
-
|
|
352
|
+
let ALLOWED_ATTR = null;
|
|
353
|
+
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
|
520
354
|
/*
|
|
521
355
|
* Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
|
|
522
356
|
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
|
@@ -524,7 +358,7 @@
|
|
|
524
358
|
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
|
525
359
|
*/
|
|
526
360
|
|
|
527
|
-
|
|
361
|
+
let CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
|
|
528
362
|
tagNameCheck: {
|
|
529
363
|
writable: true,
|
|
530
364
|
configurable: false,
|
|
@@ -546,57 +380,57 @@
|
|
|
546
380
|
}));
|
|
547
381
|
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
|
548
382
|
|
|
549
|
-
|
|
383
|
+
let FORBID_TAGS = null;
|
|
550
384
|
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
|
551
385
|
|
|
552
|
-
|
|
386
|
+
let FORBID_ATTR = null;
|
|
553
387
|
/* Decide if ARIA attributes are okay */
|
|
554
388
|
|
|
555
|
-
|
|
389
|
+
let ALLOW_ARIA_ATTR = true;
|
|
556
390
|
/* Decide if custom data attributes are okay */
|
|
557
391
|
|
|
558
|
-
|
|
392
|
+
let ALLOW_DATA_ATTR = true;
|
|
559
393
|
/* Decide if unknown protocols are okay */
|
|
560
394
|
|
|
561
|
-
|
|
395
|
+
let ALLOW_UNKNOWN_PROTOCOLS = false;
|
|
562
396
|
/* Decide if self-closing tags in attributes are allowed.
|
|
563
397
|
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
|
564
398
|
|
|
565
|
-
|
|
399
|
+
let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
|
566
400
|
/* Output should be safe for common template engines.
|
|
567
401
|
* This means, DOMPurify removes data attributes, mustaches and ERB
|
|
568
402
|
*/
|
|
569
403
|
|
|
570
|
-
|
|
404
|
+
let SAFE_FOR_TEMPLATES = false;
|
|
571
405
|
/* Decide if document with <html>... should be returned */
|
|
572
406
|
|
|
573
|
-
|
|
407
|
+
let WHOLE_DOCUMENT = false;
|
|
574
408
|
/* Track whether config is already set on this instance of DOMPurify. */
|
|
575
409
|
|
|
576
|
-
|
|
410
|
+
let SET_CONFIG = false;
|
|
577
411
|
/* Decide if all elements (e.g. style, script) must be children of
|
|
578
412
|
* document.body. By default, browsers might move them to document.head */
|
|
579
413
|
|
|
580
|
-
|
|
414
|
+
let FORCE_BODY = false;
|
|
581
415
|
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
582
416
|
* string (or a TrustedHTML object if Trusted Types are supported).
|
|
583
417
|
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
|
584
418
|
*/
|
|
585
419
|
|
|
586
|
-
|
|
420
|
+
let RETURN_DOM = false;
|
|
587
421
|
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
588
422
|
* string (or a TrustedHTML object if Trusted Types are supported) */
|
|
589
423
|
|
|
590
|
-
|
|
424
|
+
let RETURN_DOM_FRAGMENT = false;
|
|
591
425
|
/* Try to return a Trusted Type object instead of a string, return a string in
|
|
592
426
|
* case Trusted Types are not supported */
|
|
593
427
|
|
|
594
|
-
|
|
428
|
+
let RETURN_TRUSTED_TYPE = false;
|
|
595
429
|
/* Output should be free from DOM clobbering attacks?
|
|
596
430
|
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
|
597
431
|
*/
|
|
598
432
|
|
|
599
|
-
|
|
433
|
+
let SANITIZE_DOM = true;
|
|
600
434
|
/* Achieve full DOM Clobbering protection by isolating the namespace of named
|
|
601
435
|
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
|
|
602
436
|
*
|
|
@@ -611,57 +445,57 @@
|
|
|
611
445
|
* with a constant string, i.e., `user-content-`
|
|
612
446
|
*/
|
|
613
447
|
|
|
614
|
-
|
|
615
|
-
|
|
448
|
+
let SANITIZE_NAMED_PROPS = false;
|
|
449
|
+
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
|
616
450
|
/* Keep element content when removing element? */
|
|
617
451
|
|
|
618
|
-
|
|
452
|
+
let KEEP_CONTENT = true;
|
|
619
453
|
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
|
|
620
454
|
* of importing it into a new Document and returning a sanitized copy */
|
|
621
455
|
|
|
622
|
-
|
|
456
|
+
let IN_PLACE = false;
|
|
623
457
|
/* Allow usage of profiles like html, svg and mathMl */
|
|
624
458
|
|
|
625
|
-
|
|
459
|
+
let USE_PROFILES = {};
|
|
626
460
|
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
627
461
|
|
|
628
|
-
|
|
629
|
-
|
|
462
|
+
let FORBID_CONTENTS = null;
|
|
463
|
+
const 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']);
|
|
630
464
|
/* Tags that are safe for data: URIs */
|
|
631
465
|
|
|
632
|
-
|
|
633
|
-
|
|
466
|
+
let DATA_URI_TAGS = null;
|
|
467
|
+
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
|
634
468
|
/* Attributes safe for values like "javascript:" */
|
|
635
469
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
470
|
+
let URI_SAFE_ATTRIBUTES = null;
|
|
471
|
+
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
472
|
+
const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
473
|
+
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
474
|
+
const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
|
641
475
|
/* Document namespace */
|
|
642
476
|
|
|
643
|
-
|
|
644
|
-
|
|
477
|
+
let NAMESPACE = HTML_NAMESPACE;
|
|
478
|
+
let IS_EMPTY_INPUT = false;
|
|
645
479
|
/* Allowed XHTML+XML namespaces */
|
|
646
480
|
|
|
647
|
-
|
|
648
|
-
|
|
481
|
+
let ALLOWED_NAMESPACES = null;
|
|
482
|
+
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
|
649
483
|
/* Parsing of strict XHTML documents */
|
|
650
484
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
485
|
+
let PARSER_MEDIA_TYPE;
|
|
486
|
+
const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
|
487
|
+
const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
|
488
|
+
let transformCaseFunc;
|
|
655
489
|
/* Keep a reference to config to pass to hooks */
|
|
656
490
|
|
|
657
|
-
|
|
491
|
+
let CONFIG = null;
|
|
658
492
|
/* Ideally, do not touch anything below this line */
|
|
659
493
|
|
|
660
494
|
/* ______________________________________________ */
|
|
661
495
|
|
|
662
|
-
|
|
496
|
+
const formElement = document.createElement('form');
|
|
663
497
|
|
|
664
|
-
|
|
498
|
+
const isRegexOrFunction = function isRegexOrFunction(testValue) {
|
|
665
499
|
return testValue instanceof RegExp || testValue instanceof Function;
|
|
666
500
|
};
|
|
667
501
|
/**
|
|
@@ -672,14 +506,14 @@
|
|
|
672
506
|
// eslint-disable-next-line complexity
|
|
673
507
|
|
|
674
508
|
|
|
675
|
-
|
|
509
|
+
const _parseConfig = function _parseConfig(cfg) {
|
|
676
510
|
if (CONFIG && CONFIG === cfg) {
|
|
677
511
|
return;
|
|
678
512
|
}
|
|
679
513
|
/* Shield configuration object from tampering */
|
|
680
514
|
|
|
681
515
|
|
|
682
|
-
if (!cfg ||
|
|
516
|
+
if (!cfg || typeof cfg !== 'object') {
|
|
683
517
|
cfg = {};
|
|
684
518
|
}
|
|
685
519
|
/* Shield configuration object from prototype pollution */
|
|
@@ -737,7 +571,7 @@
|
|
|
737
571
|
|
|
738
572
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
739
573
|
|
|
740
|
-
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI
|
|
574
|
+
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
|
741
575
|
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
|
742
576
|
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
|
743
577
|
|
|
@@ -764,7 +598,7 @@
|
|
|
764
598
|
|
|
765
599
|
|
|
766
600
|
if (USE_PROFILES) {
|
|
767
|
-
ALLOWED_TAGS = addToSet({},
|
|
601
|
+
ALLOWED_TAGS = addToSet({}, [...text]);
|
|
768
602
|
ALLOWED_ATTR = [];
|
|
769
603
|
|
|
770
604
|
if (USE_PROFILES.html === true) {
|
|
@@ -838,6 +672,31 @@
|
|
|
838
672
|
if (ALLOWED_TAGS.table) {
|
|
839
673
|
addToSet(ALLOWED_TAGS, ['tbody']);
|
|
840
674
|
delete FORBID_TAGS.tbody;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (cfg.TRUSTED_TYPES_POLICY) {
|
|
678
|
+
if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
|
|
679
|
+
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
|
|
683
|
+
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
|
684
|
+
} // Overwrite existing TrustedTypes policy.
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; // Sign local variables required by `sanitize`.
|
|
688
|
+
|
|
689
|
+
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
690
|
+
} else {
|
|
691
|
+
// Uninitialized policy, attempt to initialize the internal dompurify policy.
|
|
692
|
+
if (trustedTypesPolicy === undefined) {
|
|
693
|
+
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
|
694
|
+
} // If creating the internal policy succeeded sign internal variables.
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
|
|
698
|
+
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
699
|
+
}
|
|
841
700
|
} // Prevent further manipulation of configuration.
|
|
842
701
|
// Not available in IE8, Safari 5, etc.
|
|
843
702
|
|
|
@@ -849,21 +708,21 @@
|
|
|
849
708
|
CONFIG = cfg;
|
|
850
709
|
};
|
|
851
710
|
|
|
852
|
-
|
|
853
|
-
|
|
711
|
+
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
712
|
+
const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']); // Certain elements are allowed in both SVG and HTML
|
|
854
713
|
// namespace. We need to specify them explicitly
|
|
855
714
|
// so that they don't get erroneously deleted from
|
|
856
715
|
// HTML namespace.
|
|
857
716
|
|
|
858
|
-
|
|
717
|
+
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
|
859
718
|
/* Keep track of all possible SVG and MathML tags
|
|
860
719
|
* so that we can perform the namespace checks
|
|
861
720
|
* correctly. */
|
|
862
721
|
|
|
863
|
-
|
|
722
|
+
const ALL_SVG_TAGS = addToSet({}, svg$1);
|
|
864
723
|
addToSet(ALL_SVG_TAGS, svgFilters);
|
|
865
724
|
addToSet(ALL_SVG_TAGS, svgDisallowed);
|
|
866
|
-
|
|
725
|
+
const ALL_MATHML_TAGS = addToSet({}, mathMl$1);
|
|
867
726
|
addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
|
|
868
727
|
/**
|
|
869
728
|
*
|
|
@@ -874,8 +733,8 @@
|
|
|
874
733
|
* return. Return true otherwise.
|
|
875
734
|
*/
|
|
876
735
|
|
|
877
|
-
|
|
878
|
-
|
|
736
|
+
const _checkValidNamespace = function _checkValidNamespace(element) {
|
|
737
|
+
let parent = getParentNode(element); // In JSDOM, if we're inside shadow DOM, then parentNode
|
|
879
738
|
// can be null. We just simulate parent in this case.
|
|
880
739
|
|
|
881
740
|
if (!parent || !parent.tagName) {
|
|
@@ -885,8 +744,8 @@
|
|
|
885
744
|
};
|
|
886
745
|
}
|
|
887
746
|
|
|
888
|
-
|
|
889
|
-
|
|
747
|
+
const tagName = stringToLowerCase(element.tagName);
|
|
748
|
+
const parentTagName = stringToLowerCase(parent.tagName);
|
|
890
749
|
|
|
891
750
|
if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
892
751
|
return false;
|
|
@@ -966,7 +825,7 @@
|
|
|
966
825
|
*/
|
|
967
826
|
|
|
968
827
|
|
|
969
|
-
|
|
828
|
+
const _forceRemove = function _forceRemove(node) {
|
|
970
829
|
arrayPush(DOMPurify.removed, {
|
|
971
830
|
element: node
|
|
972
831
|
});
|
|
@@ -986,7 +845,7 @@
|
|
|
986
845
|
*/
|
|
987
846
|
|
|
988
847
|
|
|
989
|
-
|
|
848
|
+
const _removeAttribute = function _removeAttribute(name, node) {
|
|
990
849
|
try {
|
|
991
850
|
arrayPush(DOMPurify.removed, {
|
|
992
851
|
attribute: node.getAttributeNode(name),
|
|
@@ -1021,16 +880,16 @@
|
|
|
1021
880
|
*/
|
|
1022
881
|
|
|
1023
882
|
|
|
1024
|
-
|
|
883
|
+
const _initDocument = function _initDocument(dirty) {
|
|
1025
884
|
/* Create a HTML document */
|
|
1026
|
-
|
|
1027
|
-
|
|
885
|
+
let doc;
|
|
886
|
+
let leadingWhitespace;
|
|
1028
887
|
|
|
1029
888
|
if (FORCE_BODY) {
|
|
1030
889
|
dirty = '<remove></remove>' + dirty;
|
|
1031
890
|
} else {
|
|
1032
891
|
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
|
1033
|
-
|
|
892
|
+
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
|
|
1034
893
|
leadingWhitespace = matches && matches[0];
|
|
1035
894
|
}
|
|
1036
895
|
|
|
@@ -1039,7 +898,7 @@
|
|
|
1039
898
|
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
1040
899
|
}
|
|
1041
900
|
|
|
1042
|
-
|
|
901
|
+
const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
1043
902
|
/*
|
|
1044
903
|
* Use the DOMParser API by default, fallback later if needs be
|
|
1045
904
|
* DOMParser not work for svg when has multiple root element.
|
|
@@ -1062,7 +921,7 @@
|
|
|
1062
921
|
}
|
|
1063
922
|
}
|
|
1064
923
|
|
|
1065
|
-
|
|
924
|
+
const body = doc.body || doc.documentElement;
|
|
1066
925
|
|
|
1067
926
|
if (dirty && leadingWhitespace) {
|
|
1068
927
|
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
|
@@ -1084,7 +943,7 @@
|
|
|
1084
943
|
*/
|
|
1085
944
|
|
|
1086
945
|
|
|
1087
|
-
|
|
946
|
+
const _createIterator = function _createIterator(root) {
|
|
1088
947
|
return createNodeIterator.call(root.ownerDocument || root, root, // eslint-disable-next-line no-bitwise
|
|
1089
948
|
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
|
|
1090
949
|
};
|
|
@@ -1096,7 +955,7 @@
|
|
|
1096
955
|
*/
|
|
1097
956
|
|
|
1098
957
|
|
|
1099
|
-
|
|
958
|
+
const _isClobbered = function _isClobbered(elm) {
|
|
1100
959
|
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' || typeof elm.hasChildNodes !== 'function');
|
|
1101
960
|
};
|
|
1102
961
|
/**
|
|
@@ -1107,8 +966,8 @@
|
|
|
1107
966
|
*/
|
|
1108
967
|
|
|
1109
968
|
|
|
1110
|
-
|
|
1111
|
-
return
|
|
969
|
+
const _isNode = function _isNode(object) {
|
|
970
|
+
return typeof Node === 'object' ? object instanceof Node : object && typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
|
|
1112
971
|
};
|
|
1113
972
|
/**
|
|
1114
973
|
* _executeHook
|
|
@@ -1120,12 +979,12 @@
|
|
|
1120
979
|
*/
|
|
1121
980
|
|
|
1122
981
|
|
|
1123
|
-
|
|
982
|
+
const _executeHook = function _executeHook(entryPoint, currentNode, data) {
|
|
1124
983
|
if (!hooks[entryPoint]) {
|
|
1125
984
|
return;
|
|
1126
985
|
}
|
|
1127
986
|
|
|
1128
|
-
arrayForEach(hooks[entryPoint],
|
|
987
|
+
arrayForEach(hooks[entryPoint], hook => {
|
|
1129
988
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
1130
989
|
});
|
|
1131
990
|
};
|
|
@@ -1141,8 +1000,8 @@
|
|
|
1141
1000
|
*/
|
|
1142
1001
|
|
|
1143
1002
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1003
|
+
const _sanitizeElements = function _sanitizeElements(currentNode) {
|
|
1004
|
+
let content;
|
|
1146
1005
|
/* Execute a hook if present */
|
|
1147
1006
|
|
|
1148
1007
|
_executeHook('beforeSanitizeElements', currentNode, null);
|
|
@@ -1157,11 +1016,11 @@
|
|
|
1157
1016
|
/* Now let's check the element's type and name */
|
|
1158
1017
|
|
|
1159
1018
|
|
|
1160
|
-
|
|
1019
|
+
const tagName = transformCaseFunc(currentNode.nodeName);
|
|
1161
1020
|
/* Execute a hook if present */
|
|
1162
1021
|
|
|
1163
1022
|
_executeHook('uponSanitizeElement', currentNode, {
|
|
1164
|
-
tagName
|
|
1023
|
+
tagName,
|
|
1165
1024
|
allowedTags: ALLOWED_TAGS
|
|
1166
1025
|
});
|
|
1167
1026
|
/* Detect mXSS attempts abusing namespace confusion */
|
|
@@ -1185,13 +1044,13 @@
|
|
|
1185
1044
|
|
|
1186
1045
|
|
|
1187
1046
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
1188
|
-
|
|
1189
|
-
|
|
1047
|
+
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
|
1048
|
+
const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
|
1190
1049
|
|
|
1191
1050
|
if (childNodes && parentNode) {
|
|
1192
|
-
|
|
1051
|
+
const childCount = childNodes.length;
|
|
1193
1052
|
|
|
1194
|
-
for (
|
|
1053
|
+
for (let i = childCount - 1; i >= 0; --i) {
|
|
1195
1054
|
parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
|
|
1196
1055
|
}
|
|
1197
1056
|
}
|
|
@@ -1223,9 +1082,9 @@
|
|
|
1223
1082
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
|
|
1224
1083
|
/* Get the element's text content */
|
|
1225
1084
|
content = currentNode.textContent;
|
|
1226
|
-
content = stringReplace(content, MUSTACHE_EXPR
|
|
1227
|
-
content = stringReplace(content, ERB_EXPR
|
|
1228
|
-
content = stringReplace(content, TMPLIT_EXPR
|
|
1085
|
+
content = stringReplace(content, MUSTACHE_EXPR, ' ');
|
|
1086
|
+
content = stringReplace(content, ERB_EXPR, ' ');
|
|
1087
|
+
content = stringReplace(content, TMPLIT_EXPR, ' ');
|
|
1229
1088
|
|
|
1230
1089
|
if (currentNode.textContent !== content) {
|
|
1231
1090
|
arrayPush(DOMPurify.removed, {
|
|
@@ -1252,7 +1111,7 @@
|
|
|
1252
1111
|
// eslint-disable-next-line complexity
|
|
1253
1112
|
|
|
1254
1113
|
|
|
1255
|
-
|
|
1114
|
+
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1256
1115
|
/* Make sure attribute cannot clobber */
|
|
1257
1116
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1258
1117
|
return false;
|
|
@@ -1263,7 +1122,7 @@
|
|
|
1263
1122
|
We don't need to check the value; it's always URI safe. */
|
|
1264
1123
|
|
|
1265
1124
|
|
|
1266
|
-
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR
|
|
1125
|
+
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
1267
1126
|
if ( // First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
1268
1127
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1269
1128
|
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
@@ -1274,9 +1133,9 @@
|
|
|
1274
1133
|
}
|
|
1275
1134
|
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
1276
1135
|
|
|
1277
|
-
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE
|
|
1136
|
+
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; 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, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
|
|
1278
1137
|
return false;
|
|
1279
|
-
}
|
|
1138
|
+
} else ;
|
|
1280
1139
|
|
|
1281
1140
|
return true;
|
|
1282
1141
|
};
|
|
@@ -1288,7 +1147,7 @@
|
|
|
1288
1147
|
*/
|
|
1289
1148
|
|
|
1290
1149
|
|
|
1291
|
-
|
|
1150
|
+
const _basicCustomElementTest = function _basicCustomElementTest(tagName) {
|
|
1292
1151
|
return tagName.indexOf('-') > 0;
|
|
1293
1152
|
};
|
|
1294
1153
|
/**
|
|
@@ -1303,23 +1162,25 @@
|
|
|
1303
1162
|
*/
|
|
1304
1163
|
|
|
1305
1164
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1165
|
+
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
1166
|
+
let attr;
|
|
1167
|
+
let value;
|
|
1168
|
+
let lcName;
|
|
1169
|
+
let l;
|
|
1311
1170
|
/* Execute a hook if present */
|
|
1312
1171
|
|
|
1313
1172
|
_executeHook('beforeSanitizeAttributes', currentNode, null);
|
|
1314
1173
|
|
|
1315
|
-
|
|
1174
|
+
const {
|
|
1175
|
+
attributes
|
|
1176
|
+
} = currentNode;
|
|
1316
1177
|
/* Check if we have attributes; if not we might have a text node */
|
|
1317
1178
|
|
|
1318
1179
|
if (!attributes) {
|
|
1319
1180
|
return;
|
|
1320
1181
|
}
|
|
1321
1182
|
|
|
1322
|
-
|
|
1183
|
+
const hookEvent = {
|
|
1323
1184
|
attrName: '',
|
|
1324
1185
|
attrValue: '',
|
|
1325
1186
|
keepAttr: true,
|
|
@@ -1330,9 +1191,10 @@
|
|
|
1330
1191
|
|
|
1331
1192
|
while (l--) {
|
|
1332
1193
|
attr = attributes[l];
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1194
|
+
const {
|
|
1195
|
+
name,
|
|
1196
|
+
namespaceURI
|
|
1197
|
+
} = attr;
|
|
1336
1198
|
value = name === 'value' ? attr.value : stringTrim(attr.value);
|
|
1337
1199
|
lcName = transformCaseFunc(name);
|
|
1338
1200
|
/* Execute a hook if present */
|
|
@@ -1372,14 +1234,14 @@
|
|
|
1372
1234
|
|
|
1373
1235
|
|
|
1374
1236
|
if (SAFE_FOR_TEMPLATES) {
|
|
1375
|
-
value = stringReplace(value, MUSTACHE_EXPR
|
|
1376
|
-
value = stringReplace(value, ERB_EXPR
|
|
1377
|
-
value = stringReplace(value, TMPLIT_EXPR
|
|
1237
|
+
value = stringReplace(value, MUSTACHE_EXPR, ' ');
|
|
1238
|
+
value = stringReplace(value, ERB_EXPR, ' ');
|
|
1239
|
+
value = stringReplace(value, TMPLIT_EXPR, ' ');
|
|
1378
1240
|
}
|
|
1379
1241
|
/* Is `value` valid for this attribute? */
|
|
1380
1242
|
|
|
1381
1243
|
|
|
1382
|
-
|
|
1244
|
+
const lcTag = transformCaseFunc(currentNode.nodeName);
|
|
1383
1245
|
|
|
1384
1246
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1385
1247
|
continue;
|
|
@@ -1399,16 +1261,20 @@
|
|
|
1399
1261
|
/* Handle attributes that require Trusted Types */
|
|
1400
1262
|
|
|
1401
1263
|
|
|
1402
|
-
if (trustedTypesPolicy &&
|
|
1264
|
+
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
|
1403
1265
|
if (namespaceURI) ; else {
|
|
1404
1266
|
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
|
1405
1267
|
case 'TrustedHTML':
|
|
1406
|
-
|
|
1407
|
-
|
|
1268
|
+
{
|
|
1269
|
+
value = trustedTypesPolicy.createHTML(value);
|
|
1270
|
+
break;
|
|
1271
|
+
}
|
|
1408
1272
|
|
|
1409
1273
|
case 'TrustedScriptURL':
|
|
1410
|
-
|
|
1411
|
-
|
|
1274
|
+
{
|
|
1275
|
+
value = trustedTypesPolicy.createScriptURL(value);
|
|
1276
|
+
break;
|
|
1277
|
+
}
|
|
1412
1278
|
}
|
|
1413
1279
|
}
|
|
1414
1280
|
}
|
|
@@ -1438,10 +1304,10 @@
|
|
|
1438
1304
|
*/
|
|
1439
1305
|
|
|
1440
1306
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1307
|
+
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
|
1308
|
+
let shadowNode;
|
|
1443
1309
|
|
|
1444
|
-
|
|
1310
|
+
const shadowIterator = _createIterator(fragment);
|
|
1445
1311
|
/* Execute a hook if present */
|
|
1446
1312
|
|
|
1447
1313
|
|
|
@@ -1483,11 +1349,11 @@
|
|
|
1483
1349
|
|
|
1484
1350
|
|
|
1485
1351
|
DOMPurify.sanitize = function (dirty) {
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1352
|
+
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1353
|
+
let body;
|
|
1354
|
+
let importedNode;
|
|
1355
|
+
let currentNode;
|
|
1356
|
+
let returnNode;
|
|
1491
1357
|
/* Make sure we have a string to sanitize.
|
|
1492
1358
|
DO NOT return early, as this will return the wrong type if
|
|
1493
1359
|
the user has requested a DOM object rather than a string */
|
|
@@ -1501,15 +1367,14 @@
|
|
|
1501
1367
|
|
|
1502
1368
|
|
|
1503
1369
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
1504
|
-
|
|
1505
|
-
if (typeof dirty.toString !== 'function') {
|
|
1506
|
-
throw typeErrorCreate('toString is not a function');
|
|
1507
|
-
} else {
|
|
1370
|
+
if (typeof dirty.toString === 'function') {
|
|
1508
1371
|
dirty = dirty.toString();
|
|
1509
1372
|
|
|
1510
1373
|
if (typeof dirty !== 'string') {
|
|
1511
1374
|
throw typeErrorCreate('dirty is not a string, aborting');
|
|
1512
1375
|
}
|
|
1376
|
+
} else {
|
|
1377
|
+
throw typeErrorCreate('toString is not a function');
|
|
1513
1378
|
}
|
|
1514
1379
|
}
|
|
1515
1380
|
/* Return dirty HTML if DOMPurify cannot run */
|
|
@@ -1537,7 +1402,7 @@
|
|
|
1537
1402
|
if (IN_PLACE) {
|
|
1538
1403
|
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
|
1539
1404
|
if (dirty.nodeName) {
|
|
1540
|
-
|
|
1405
|
+
const tagName = transformCaseFunc(dirty.nodeName);
|
|
1541
1406
|
|
|
1542
1407
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1543
1408
|
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
@@ -1583,7 +1448,7 @@
|
|
|
1583
1448
|
/* Get node iterator */
|
|
1584
1449
|
|
|
1585
1450
|
|
|
1586
|
-
|
|
1451
|
+
const nodeIterator = _createIterator(IN_PLACE ? dirty : body);
|
|
1587
1452
|
/* Now start iterating over the created document */
|
|
1588
1453
|
|
|
1589
1454
|
|
|
@@ -1638,7 +1503,7 @@
|
|
|
1638
1503
|
return returnNode;
|
|
1639
1504
|
}
|
|
1640
1505
|
|
|
1641
|
-
|
|
1506
|
+
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
|
1642
1507
|
/* Serialize doctype if allowed */
|
|
1643
1508
|
|
|
1644
1509
|
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
|
@@ -1648,9 +1513,9 @@
|
|
|
1648
1513
|
|
|
1649
1514
|
|
|
1650
1515
|
if (SAFE_FOR_TEMPLATES) {
|
|
1651
|
-
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR
|
|
1652
|
-
serializedHTML = stringReplace(serializedHTML, ERB_EXPR
|
|
1653
|
-
serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR
|
|
1516
|
+
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR, ' ');
|
|
1517
|
+
serializedHTML = stringReplace(serializedHTML, ERB_EXPR, ' ');
|
|
1518
|
+
serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR, ' ');
|
|
1654
1519
|
}
|
|
1655
1520
|
|
|
1656
1521
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
@@ -1697,8 +1562,8 @@
|
|
|
1697
1562
|
_parseConfig({});
|
|
1698
1563
|
}
|
|
1699
1564
|
|
|
1700
|
-
|
|
1701
|
-
|
|
1565
|
+
const lcTag = transformCaseFunc(tag);
|
|
1566
|
+
const lcName = transformCaseFunc(attr);
|
|
1702
1567
|
return _isValidAttribute(lcTag, lcName, value);
|
|
1703
1568
|
};
|
|
1704
1569
|
/**
|