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