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