dompurify 3.0.0 → 3.0.2
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 +6 -6
- package/dist/purify.cjs.js +251 -415
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.js +252 -416
- package/dist/purify.es.js.map +1 -1
- package/dist/purify.js +251 -415
- 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 +1 -2
package/dist/purify.cjs.js
CHANGED
|
@@ -1,200 +1,24 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.0.
|
|
1
|
+
/*! @license DOMPurify 3.0.2 | (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.2/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++) {
|
|
@@ -261,13 +85,13 @@ function addToSet(set, array, transformCaseFunc) {
|
|
|
261
85
|
setPrototypeOf(set, null);
|
|
262
86
|
}
|
|
263
87
|
|
|
264
|
-
|
|
88
|
+
let l = array.length;
|
|
265
89
|
|
|
266
90
|
while (l--) {
|
|
267
|
-
|
|
91
|
+
let element = array[l];
|
|
268
92
|
|
|
269
93
|
if (typeof element === 'string') {
|
|
270
|
-
|
|
94
|
+
const lcElement = transformCaseFunc(element);
|
|
271
95
|
|
|
272
96
|
if (lcElement !== element) {
|
|
273
97
|
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
@@ -287,23 +111,10 @@ function addToSet(set, array, transformCaseFunc) {
|
|
|
287
111
|
/* Shallow clone an object */
|
|
288
112
|
|
|
289
113
|
function clone(object) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
var _iterator = _createForOfIteratorHelper(entries(object)),
|
|
293
|
-
_step;
|
|
114
|
+
const newObject = create(null);
|
|
294
115
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
var _step$value = _slicedToArray(_step.value, 2),
|
|
298
|
-
property = _step$value[0],
|
|
299
|
-
value = _step$value[1];
|
|
300
|
-
|
|
301
|
-
newObject[property] = value;
|
|
302
|
-
}
|
|
303
|
-
} catch (err) {
|
|
304
|
-
_iterator.e(err);
|
|
305
|
-
} finally {
|
|
306
|
-
_iterator.f();
|
|
116
|
+
for (const [property, value] of entries(object)) {
|
|
117
|
+
newObject[property] = value;
|
|
307
118
|
}
|
|
308
119
|
|
|
309
120
|
return newObject;
|
|
@@ -313,7 +124,7 @@ function clone(object) {
|
|
|
313
124
|
|
|
314
125
|
function lookupGetter(object, prop) {
|
|
315
126
|
while (object !== null) {
|
|
316
|
-
|
|
127
|
+
const desc = getOwnPropertyDescriptor(object, prop);
|
|
317
128
|
|
|
318
129
|
if (desc) {
|
|
319
130
|
if (desc.get) {
|
|
@@ -336,44 +147,55 @@ function lookupGetter(object, prop) {
|
|
|
336
147
|
return fallbackValue;
|
|
337
148
|
}
|
|
338
149
|
|
|
339
|
-
|
|
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
|
|
340
151
|
|
|
341
|
-
|
|
342
|
-
|
|
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', '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
154
|
// We still need to know them so that we can do namespace
|
|
344
155
|
// checks properly in case one wants to add them to
|
|
345
156
|
// allow-list.
|
|
346
157
|
|
|
347
|
-
|
|
348
|
-
|
|
158
|
+
const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
|
|
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,
|
|
349
160
|
// even those that we disallow by default.
|
|
350
161
|
|
|
351
|
-
|
|
352
|
-
|
|
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']);
|
|
353
164
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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']);
|
|
358
169
|
|
|
359
|
-
|
|
170
|
+
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
360
171
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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
|
|
364
175
|
|
|
365
|
-
|
|
176
|
+
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
366
177
|
|
|
367
|
-
|
|
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
|
|
368
179
|
);
|
|
369
|
-
|
|
370
|
-
|
|
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
|
|
371
182
|
);
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
var
|
|
375
|
-
|
|
376
|
-
|
|
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;
|
|
377
199
|
/**
|
|
378
200
|
* Creates a no-op policy for internal use only.
|
|
379
201
|
* Don't export this function outside this module!
|
|
@@ -384,31 +206,33 @@ var getGlobal = function getGlobal() {
|
|
|
384
206
|
*/
|
|
385
207
|
|
|
386
208
|
|
|
387
|
-
|
|
388
|
-
if (
|
|
209
|
+
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
|
|
210
|
+
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
|
389
211
|
return null;
|
|
390
212
|
} // Allow the callers to control the unique policy name
|
|
391
213
|
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
|
392
214
|
// Policy creation with duplicate names throws in Trusted Types.
|
|
393
215
|
|
|
394
216
|
|
|
395
|
-
|
|
396
|
-
|
|
217
|
+
let suffix = null;
|
|
218
|
+
const ATTR_NAME = 'data-tt-policy-suffix';
|
|
397
219
|
|
|
398
220
|
if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
|
|
399
221
|
suffix = document.currentScript.getAttribute(ATTR_NAME);
|
|
400
222
|
}
|
|
401
223
|
|
|
402
|
-
|
|
224
|
+
const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
|
|
403
225
|
|
|
404
226
|
try {
|
|
405
227
|
return trustedTypes.createPolicy(policyName, {
|
|
406
|
-
createHTML
|
|
228
|
+
createHTML(html) {
|
|
407
229
|
return html;
|
|
408
230
|
},
|
|
409
|
-
|
|
231
|
+
|
|
232
|
+
createScriptURL(scriptUrl) {
|
|
410
233
|
return scriptUrl;
|
|
411
234
|
}
|
|
235
|
+
|
|
412
236
|
});
|
|
413
237
|
} catch (_) {
|
|
414
238
|
// Policy creation failed (most likely another DOMPurify script has
|
|
@@ -420,18 +244,16 @@ var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes,
|
|
|
420
244
|
};
|
|
421
245
|
|
|
422
246
|
function createDOMPurify() {
|
|
423
|
-
|
|
247
|
+
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
424
248
|
|
|
425
|
-
|
|
426
|
-
return createDOMPurify(root);
|
|
427
|
-
};
|
|
249
|
+
const DOMPurify = root => createDOMPurify(root);
|
|
428
250
|
/**
|
|
429
251
|
* Version label, exposed for easier checks
|
|
430
252
|
* if DOMPurify is up to date or not
|
|
431
253
|
*/
|
|
432
254
|
|
|
433
255
|
|
|
434
|
-
DOMPurify.version = '3.0.
|
|
256
|
+
DOMPurify.version = '3.0.2';
|
|
435
257
|
/**
|
|
436
258
|
* Array of elements that DOMPurify removed during sanitation.
|
|
437
259
|
* Empty if nothing was removed.
|
|
@@ -446,23 +268,26 @@ function createDOMPurify() {
|
|
|
446
268
|
return DOMPurify;
|
|
447
269
|
}
|
|
448
270
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
271
|
+
const originalDocument = window.document;
|
|
272
|
+
let {
|
|
273
|
+
document
|
|
274
|
+
} = window;
|
|
275
|
+
const {
|
|
276
|
+
DocumentFragment,
|
|
277
|
+
HTMLTemplateElement,
|
|
278
|
+
Node,
|
|
279
|
+
Element,
|
|
280
|
+
NodeFilter,
|
|
281
|
+
NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
|
|
282
|
+
HTMLFormElement,
|
|
283
|
+
DOMParser,
|
|
284
|
+
trustedTypes
|
|
285
|
+
} = window;
|
|
286
|
+
const ElementPrototype = Element.prototype;
|
|
287
|
+
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
|
288
|
+
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
|
289
|
+
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
|
290
|
+
const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); // As per issue #47, the web-components registry is inherited by a
|
|
466
291
|
// new document created via createHTMLDocument. As per the spec
|
|
467
292
|
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
468
293
|
// a new empty registry is used when creating a template contents owner
|
|
@@ -470,36 +295,43 @@ function createDOMPurify() {
|
|
|
470
295
|
// is inherited.
|
|
471
296
|
|
|
472
297
|
if (typeof HTMLTemplateElement === 'function') {
|
|
473
|
-
|
|
298
|
+
const template = document.createElement('template');
|
|
474
299
|
|
|
475
300
|
if (template.content && template.content.ownerDocument) {
|
|
476
301
|
document = template.content.ownerDocument;
|
|
477
302
|
}
|
|
478
303
|
}
|
|
479
304
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
305
|
+
const trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
|
|
306
|
+
|
|
307
|
+
const emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
|
|
308
|
+
const {
|
|
309
|
+
implementation,
|
|
310
|
+
createNodeIterator,
|
|
311
|
+
createDocumentFragment,
|
|
312
|
+
getElementsByTagName
|
|
313
|
+
} = document;
|
|
314
|
+
const {
|
|
315
|
+
importNode
|
|
316
|
+
} = originalDocument;
|
|
317
|
+
let hooks = {};
|
|
490
318
|
/**
|
|
491
319
|
* Expose whether this browser supports running the full DOMPurify.
|
|
492
320
|
*/
|
|
493
321
|
|
|
494
322
|
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined';
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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;
|
|
503
335
|
/**
|
|
504
336
|
* We consider the elements and attributes below to be safe. Ideally
|
|
505
337
|
* don't add any new ones but feel free to remove unwanted ones.
|
|
@@ -507,12 +339,12 @@ function createDOMPurify() {
|
|
|
507
339
|
|
|
508
340
|
/* allowed element names */
|
|
509
341
|
|
|
510
|
-
|
|
511
|
-
|
|
342
|
+
let ALLOWED_TAGS = null;
|
|
343
|
+
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
|
|
512
344
|
/* Allowed attribute names */
|
|
513
345
|
|
|
514
|
-
|
|
515
|
-
|
|
346
|
+
let ALLOWED_ATTR = null;
|
|
347
|
+
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
|
516
348
|
/*
|
|
517
349
|
* Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
|
|
518
350
|
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
|
@@ -520,7 +352,7 @@ function createDOMPurify() {
|
|
|
520
352
|
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
|
521
353
|
*/
|
|
522
354
|
|
|
523
|
-
|
|
355
|
+
let CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
|
|
524
356
|
tagNameCheck: {
|
|
525
357
|
writable: true,
|
|
526
358
|
configurable: false,
|
|
@@ -542,57 +374,57 @@ function createDOMPurify() {
|
|
|
542
374
|
}));
|
|
543
375
|
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
|
544
376
|
|
|
545
|
-
|
|
377
|
+
let FORBID_TAGS = null;
|
|
546
378
|
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
|
547
379
|
|
|
548
|
-
|
|
380
|
+
let FORBID_ATTR = null;
|
|
549
381
|
/* Decide if ARIA attributes are okay */
|
|
550
382
|
|
|
551
|
-
|
|
383
|
+
let ALLOW_ARIA_ATTR = true;
|
|
552
384
|
/* Decide if custom data attributes are okay */
|
|
553
385
|
|
|
554
|
-
|
|
386
|
+
let ALLOW_DATA_ATTR = true;
|
|
555
387
|
/* Decide if unknown protocols are okay */
|
|
556
388
|
|
|
557
|
-
|
|
389
|
+
let ALLOW_UNKNOWN_PROTOCOLS = false;
|
|
558
390
|
/* Decide if self-closing tags in attributes are allowed.
|
|
559
391
|
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
|
560
392
|
|
|
561
|
-
|
|
393
|
+
let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
|
562
394
|
/* Output should be safe for common template engines.
|
|
563
395
|
* This means, DOMPurify removes data attributes, mustaches and ERB
|
|
564
396
|
*/
|
|
565
397
|
|
|
566
|
-
|
|
398
|
+
let SAFE_FOR_TEMPLATES = false;
|
|
567
399
|
/* Decide if document with <html>... should be returned */
|
|
568
400
|
|
|
569
|
-
|
|
401
|
+
let WHOLE_DOCUMENT = false;
|
|
570
402
|
/* Track whether config is already set on this instance of DOMPurify. */
|
|
571
403
|
|
|
572
|
-
|
|
404
|
+
let SET_CONFIG = false;
|
|
573
405
|
/* Decide if all elements (e.g. style, script) must be children of
|
|
574
406
|
* document.body. By default, browsers might move them to document.head */
|
|
575
407
|
|
|
576
|
-
|
|
408
|
+
let FORCE_BODY = false;
|
|
577
409
|
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
578
410
|
* string (or a TrustedHTML object if Trusted Types are supported).
|
|
579
411
|
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
|
580
412
|
*/
|
|
581
413
|
|
|
582
|
-
|
|
414
|
+
let RETURN_DOM = false;
|
|
583
415
|
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
584
416
|
* string (or a TrustedHTML object if Trusted Types are supported) */
|
|
585
417
|
|
|
586
|
-
|
|
418
|
+
let RETURN_DOM_FRAGMENT = false;
|
|
587
419
|
/* Try to return a Trusted Type object instead of a string, return a string in
|
|
588
420
|
* case Trusted Types are not supported */
|
|
589
421
|
|
|
590
|
-
|
|
422
|
+
let RETURN_TRUSTED_TYPE = false;
|
|
591
423
|
/* Output should be free from DOM clobbering attacks?
|
|
592
424
|
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
|
593
425
|
*/
|
|
594
426
|
|
|
595
|
-
|
|
427
|
+
let SANITIZE_DOM = true;
|
|
596
428
|
/* Achieve full DOM Clobbering protection by isolating the namespace of named
|
|
597
429
|
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
|
|
598
430
|
*
|
|
@@ -607,57 +439,57 @@ function createDOMPurify() {
|
|
|
607
439
|
* with a constant string, i.e., `user-content-`
|
|
608
440
|
*/
|
|
609
441
|
|
|
610
|
-
|
|
611
|
-
|
|
442
|
+
let SANITIZE_NAMED_PROPS = false;
|
|
443
|
+
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
|
612
444
|
/* Keep element content when removing element? */
|
|
613
445
|
|
|
614
|
-
|
|
446
|
+
let KEEP_CONTENT = true;
|
|
615
447
|
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
|
|
616
448
|
* of importing it into a new Document and returning a sanitized copy */
|
|
617
449
|
|
|
618
|
-
|
|
450
|
+
let IN_PLACE = false;
|
|
619
451
|
/* Allow usage of profiles like html, svg and mathMl */
|
|
620
452
|
|
|
621
|
-
|
|
453
|
+
let USE_PROFILES = {};
|
|
622
454
|
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
623
455
|
|
|
624
|
-
|
|
625
|
-
|
|
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']);
|
|
626
458
|
/* Tags that are safe for data: URIs */
|
|
627
459
|
|
|
628
|
-
|
|
629
|
-
|
|
460
|
+
let DATA_URI_TAGS = null;
|
|
461
|
+
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
|
630
462
|
/* Attributes safe for values like "javascript:" */
|
|
631
463
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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';
|
|
637
469
|
/* Document namespace */
|
|
638
470
|
|
|
639
|
-
|
|
640
|
-
|
|
471
|
+
let NAMESPACE = HTML_NAMESPACE;
|
|
472
|
+
let IS_EMPTY_INPUT = false;
|
|
641
473
|
/* Allowed XHTML+XML namespaces */
|
|
642
474
|
|
|
643
|
-
|
|
644
|
-
|
|
475
|
+
let ALLOWED_NAMESPACES = null;
|
|
476
|
+
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
|
645
477
|
/* Parsing of strict XHTML documents */
|
|
646
478
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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;
|
|
651
483
|
/* Keep a reference to config to pass to hooks */
|
|
652
484
|
|
|
653
|
-
|
|
485
|
+
let CONFIG = null;
|
|
654
486
|
/* Ideally, do not touch anything below this line */
|
|
655
487
|
|
|
656
488
|
/* ______________________________________________ */
|
|
657
489
|
|
|
658
|
-
|
|
490
|
+
const formElement = document.createElement('form');
|
|
659
491
|
|
|
660
|
-
|
|
492
|
+
const isRegexOrFunction = function isRegexOrFunction(testValue) {
|
|
661
493
|
return testValue instanceof RegExp || testValue instanceof Function;
|
|
662
494
|
};
|
|
663
495
|
/**
|
|
@@ -668,14 +500,14 @@ function createDOMPurify() {
|
|
|
668
500
|
// eslint-disable-next-line complexity
|
|
669
501
|
|
|
670
502
|
|
|
671
|
-
|
|
503
|
+
const _parseConfig = function _parseConfig(cfg) {
|
|
672
504
|
if (CONFIG && CONFIG === cfg) {
|
|
673
505
|
return;
|
|
674
506
|
}
|
|
675
507
|
/* Shield configuration object from tampering */
|
|
676
508
|
|
|
677
509
|
|
|
678
|
-
if (!cfg ||
|
|
510
|
+
if (!cfg || typeof cfg !== 'object') {
|
|
679
511
|
cfg = {};
|
|
680
512
|
}
|
|
681
513
|
/* Shield configuration object from prototype pollution */
|
|
@@ -733,8 +565,9 @@ function createDOMPurify() {
|
|
|
733
565
|
|
|
734
566
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
735
567
|
|
|
736
|
-
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI
|
|
568
|
+
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
|
737
569
|
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
|
570
|
+
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
|
738
571
|
|
|
739
572
|
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
|
|
740
573
|
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
|
|
@@ -759,7 +592,7 @@ function createDOMPurify() {
|
|
|
759
592
|
|
|
760
593
|
|
|
761
594
|
if (USE_PROFILES) {
|
|
762
|
-
ALLOWED_TAGS = addToSet({},
|
|
595
|
+
ALLOWED_TAGS = addToSet({}, [...text]);
|
|
763
596
|
ALLOWED_ATTR = [];
|
|
764
597
|
|
|
765
598
|
if (USE_PROFILES.html === true) {
|
|
@@ -844,21 +677,21 @@ function createDOMPurify() {
|
|
|
844
677
|
CONFIG = cfg;
|
|
845
678
|
};
|
|
846
679
|
|
|
847
|
-
|
|
848
|
-
|
|
680
|
+
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
681
|
+
const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']); // Certain elements are allowed in both SVG and HTML
|
|
849
682
|
// namespace. We need to specify them explicitly
|
|
850
683
|
// so that they don't get erroneously deleted from
|
|
851
684
|
// HTML namespace.
|
|
852
685
|
|
|
853
|
-
|
|
686
|
+
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
|
854
687
|
/* Keep track of all possible SVG and MathML tags
|
|
855
688
|
* so that we can perform the namespace checks
|
|
856
689
|
* correctly. */
|
|
857
690
|
|
|
858
|
-
|
|
691
|
+
const ALL_SVG_TAGS = addToSet({}, svg$1);
|
|
859
692
|
addToSet(ALL_SVG_TAGS, svgFilters);
|
|
860
693
|
addToSet(ALL_SVG_TAGS, svgDisallowed);
|
|
861
|
-
|
|
694
|
+
const ALL_MATHML_TAGS = addToSet({}, mathMl$1);
|
|
862
695
|
addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
|
|
863
696
|
/**
|
|
864
697
|
*
|
|
@@ -869,8 +702,8 @@ function createDOMPurify() {
|
|
|
869
702
|
* return. Return true otherwise.
|
|
870
703
|
*/
|
|
871
704
|
|
|
872
|
-
|
|
873
|
-
|
|
705
|
+
const _checkValidNamespace = function _checkValidNamespace(element) {
|
|
706
|
+
let parent = getParentNode(element); // In JSDOM, if we're inside shadow DOM, then parentNode
|
|
874
707
|
// can be null. We just simulate parent in this case.
|
|
875
708
|
|
|
876
709
|
if (!parent || !parent.tagName) {
|
|
@@ -880,8 +713,8 @@ function createDOMPurify() {
|
|
|
880
713
|
};
|
|
881
714
|
}
|
|
882
715
|
|
|
883
|
-
|
|
884
|
-
|
|
716
|
+
const tagName = stringToLowerCase(element.tagName);
|
|
717
|
+
const parentTagName = stringToLowerCase(parent.tagName);
|
|
885
718
|
|
|
886
719
|
if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
887
720
|
return false;
|
|
@@ -961,7 +794,7 @@ function createDOMPurify() {
|
|
|
961
794
|
*/
|
|
962
795
|
|
|
963
796
|
|
|
964
|
-
|
|
797
|
+
const _forceRemove = function _forceRemove(node) {
|
|
965
798
|
arrayPush(DOMPurify.removed, {
|
|
966
799
|
element: node
|
|
967
800
|
});
|
|
@@ -981,7 +814,7 @@ function createDOMPurify() {
|
|
|
981
814
|
*/
|
|
982
815
|
|
|
983
816
|
|
|
984
|
-
|
|
817
|
+
const _removeAttribute = function _removeAttribute(name, node) {
|
|
985
818
|
try {
|
|
986
819
|
arrayPush(DOMPurify.removed, {
|
|
987
820
|
attribute: node.getAttributeNode(name),
|
|
@@ -1016,16 +849,16 @@ function createDOMPurify() {
|
|
|
1016
849
|
*/
|
|
1017
850
|
|
|
1018
851
|
|
|
1019
|
-
|
|
852
|
+
const _initDocument = function _initDocument(dirty) {
|
|
1020
853
|
/* Create a HTML document */
|
|
1021
|
-
|
|
1022
|
-
|
|
854
|
+
let doc;
|
|
855
|
+
let leadingWhitespace;
|
|
1023
856
|
|
|
1024
857
|
if (FORCE_BODY) {
|
|
1025
858
|
dirty = '<remove></remove>' + dirty;
|
|
1026
859
|
} else {
|
|
1027
860
|
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
|
1028
|
-
|
|
861
|
+
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
|
|
1029
862
|
leadingWhitespace = matches && matches[0];
|
|
1030
863
|
}
|
|
1031
864
|
|
|
@@ -1034,7 +867,7 @@ function createDOMPurify() {
|
|
|
1034
867
|
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
1035
868
|
}
|
|
1036
869
|
|
|
1037
|
-
|
|
870
|
+
const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
1038
871
|
/*
|
|
1039
872
|
* Use the DOMParser API by default, fallback later if needs be
|
|
1040
873
|
* DOMParser not work for svg when has multiple root element.
|
|
@@ -1057,7 +890,7 @@ function createDOMPurify() {
|
|
|
1057
890
|
}
|
|
1058
891
|
}
|
|
1059
892
|
|
|
1060
|
-
|
|
893
|
+
const body = doc.body || doc.documentElement;
|
|
1061
894
|
|
|
1062
895
|
if (dirty && leadingWhitespace) {
|
|
1063
896
|
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
|
@@ -1079,7 +912,7 @@ function createDOMPurify() {
|
|
|
1079
912
|
*/
|
|
1080
913
|
|
|
1081
914
|
|
|
1082
|
-
|
|
915
|
+
const _createIterator = function _createIterator(root) {
|
|
1083
916
|
return createNodeIterator.call(root.ownerDocument || root, root, // eslint-disable-next-line no-bitwise
|
|
1084
917
|
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
|
|
1085
918
|
};
|
|
@@ -1091,7 +924,7 @@ function createDOMPurify() {
|
|
|
1091
924
|
*/
|
|
1092
925
|
|
|
1093
926
|
|
|
1094
|
-
|
|
927
|
+
const _isClobbered = function _isClobbered(elm) {
|
|
1095
928
|
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');
|
|
1096
929
|
};
|
|
1097
930
|
/**
|
|
@@ -1102,8 +935,8 @@ function createDOMPurify() {
|
|
|
1102
935
|
*/
|
|
1103
936
|
|
|
1104
937
|
|
|
1105
|
-
|
|
1106
|
-
return
|
|
938
|
+
const _isNode = function _isNode(object) {
|
|
939
|
+
return typeof Node === 'object' ? object instanceof Node : object && typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
|
|
1107
940
|
};
|
|
1108
941
|
/**
|
|
1109
942
|
* _executeHook
|
|
@@ -1115,12 +948,12 @@ function createDOMPurify() {
|
|
|
1115
948
|
*/
|
|
1116
949
|
|
|
1117
950
|
|
|
1118
|
-
|
|
951
|
+
const _executeHook = function _executeHook(entryPoint, currentNode, data) {
|
|
1119
952
|
if (!hooks[entryPoint]) {
|
|
1120
953
|
return;
|
|
1121
954
|
}
|
|
1122
955
|
|
|
1123
|
-
arrayForEach(hooks[entryPoint],
|
|
956
|
+
arrayForEach(hooks[entryPoint], hook => {
|
|
1124
957
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
1125
958
|
});
|
|
1126
959
|
};
|
|
@@ -1136,8 +969,8 @@ function createDOMPurify() {
|
|
|
1136
969
|
*/
|
|
1137
970
|
|
|
1138
971
|
|
|
1139
|
-
|
|
1140
|
-
|
|
972
|
+
const _sanitizeElements = function _sanitizeElements(currentNode) {
|
|
973
|
+
let content;
|
|
1141
974
|
/* Execute a hook if present */
|
|
1142
975
|
|
|
1143
976
|
_executeHook('beforeSanitizeElements', currentNode, null);
|
|
@@ -1152,11 +985,11 @@ function createDOMPurify() {
|
|
|
1152
985
|
/* Now let's check the element's type and name */
|
|
1153
986
|
|
|
1154
987
|
|
|
1155
|
-
|
|
988
|
+
const tagName = transformCaseFunc(currentNode.nodeName);
|
|
1156
989
|
/* Execute a hook if present */
|
|
1157
990
|
|
|
1158
991
|
_executeHook('uponSanitizeElement', currentNode, {
|
|
1159
|
-
tagName
|
|
992
|
+
tagName,
|
|
1160
993
|
allowedTags: ALLOWED_TAGS
|
|
1161
994
|
});
|
|
1162
995
|
/* Detect mXSS attempts abusing namespace confusion */
|
|
@@ -1180,13 +1013,13 @@ function createDOMPurify() {
|
|
|
1180
1013
|
|
|
1181
1014
|
|
|
1182
1015
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
1183
|
-
|
|
1184
|
-
|
|
1016
|
+
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
|
1017
|
+
const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
|
1185
1018
|
|
|
1186
1019
|
if (childNodes && parentNode) {
|
|
1187
|
-
|
|
1020
|
+
const childCount = childNodes.length;
|
|
1188
1021
|
|
|
1189
|
-
for (
|
|
1022
|
+
for (let i = childCount - 1; i >= 0; --i) {
|
|
1190
1023
|
parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
|
|
1191
1024
|
}
|
|
1192
1025
|
}
|
|
@@ -1218,9 +1051,9 @@ function createDOMPurify() {
|
|
|
1218
1051
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
|
|
1219
1052
|
/* Get the element's text content */
|
|
1220
1053
|
content = currentNode.textContent;
|
|
1221
|
-
content = stringReplace(content, MUSTACHE_EXPR
|
|
1222
|
-
content = stringReplace(content, ERB_EXPR
|
|
1223
|
-
content = stringReplace(content, TMPLIT_EXPR
|
|
1054
|
+
content = stringReplace(content, MUSTACHE_EXPR, ' ');
|
|
1055
|
+
content = stringReplace(content, ERB_EXPR, ' ');
|
|
1056
|
+
content = stringReplace(content, TMPLIT_EXPR, ' ');
|
|
1224
1057
|
|
|
1225
1058
|
if (currentNode.textContent !== content) {
|
|
1226
1059
|
arrayPush(DOMPurify.removed, {
|
|
@@ -1247,7 +1080,7 @@ function createDOMPurify() {
|
|
|
1247
1080
|
// eslint-disable-next-line complexity
|
|
1248
1081
|
|
|
1249
1082
|
|
|
1250
|
-
|
|
1083
|
+
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1251
1084
|
/* Make sure attribute cannot clobber */
|
|
1252
1085
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1253
1086
|
return false;
|
|
@@ -1258,7 +1091,7 @@ function createDOMPurify() {
|
|
|
1258
1091
|
We don't need to check the value; it's always URI safe. */
|
|
1259
1092
|
|
|
1260
1093
|
|
|
1261
|
-
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR
|
|
1094
|
+
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]) {
|
|
1262
1095
|
if ( // First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
1263
1096
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1264
1097
|
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
@@ -1269,7 +1102,7 @@ function createDOMPurify() {
|
|
|
1269
1102
|
}
|
|
1270
1103
|
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
1271
1104
|
|
|
1272
|
-
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE
|
|
1105
|
+
} 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) ; else {
|
|
1273
1106
|
return false;
|
|
1274
1107
|
}
|
|
1275
1108
|
|
|
@@ -1283,7 +1116,7 @@ function createDOMPurify() {
|
|
|
1283
1116
|
*/
|
|
1284
1117
|
|
|
1285
1118
|
|
|
1286
|
-
|
|
1119
|
+
const _basicCustomElementTest = function _basicCustomElementTest(tagName) {
|
|
1287
1120
|
return tagName.indexOf('-') > 0;
|
|
1288
1121
|
};
|
|
1289
1122
|
/**
|
|
@@ -1298,23 +1131,25 @@ function createDOMPurify() {
|
|
|
1298
1131
|
*/
|
|
1299
1132
|
|
|
1300
1133
|
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1134
|
+
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
1135
|
+
let attr;
|
|
1136
|
+
let value;
|
|
1137
|
+
let lcName;
|
|
1138
|
+
let l;
|
|
1306
1139
|
/* Execute a hook if present */
|
|
1307
1140
|
|
|
1308
1141
|
_executeHook('beforeSanitizeAttributes', currentNode, null);
|
|
1309
1142
|
|
|
1310
|
-
|
|
1143
|
+
const {
|
|
1144
|
+
attributes
|
|
1145
|
+
} = currentNode;
|
|
1311
1146
|
/* Check if we have attributes; if not we might have a text node */
|
|
1312
1147
|
|
|
1313
1148
|
if (!attributes) {
|
|
1314
1149
|
return;
|
|
1315
1150
|
}
|
|
1316
1151
|
|
|
1317
|
-
|
|
1152
|
+
const hookEvent = {
|
|
1318
1153
|
attrName: '',
|
|
1319
1154
|
attrValue: '',
|
|
1320
1155
|
keepAttr: true,
|
|
@@ -1325,9 +1160,10 @@ function createDOMPurify() {
|
|
|
1325
1160
|
|
|
1326
1161
|
while (l--) {
|
|
1327
1162
|
attr = attributes[l];
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1163
|
+
const {
|
|
1164
|
+
name,
|
|
1165
|
+
namespaceURI
|
|
1166
|
+
} = attr;
|
|
1331
1167
|
value = name === 'value' ? attr.value : stringTrim(attr.value);
|
|
1332
1168
|
lcName = transformCaseFunc(name);
|
|
1333
1169
|
/* Execute a hook if present */
|
|
@@ -1367,14 +1203,14 @@ function createDOMPurify() {
|
|
|
1367
1203
|
|
|
1368
1204
|
|
|
1369
1205
|
if (SAFE_FOR_TEMPLATES) {
|
|
1370
|
-
value = stringReplace(value, MUSTACHE_EXPR
|
|
1371
|
-
value = stringReplace(value, ERB_EXPR
|
|
1372
|
-
value = stringReplace(value, TMPLIT_EXPR
|
|
1206
|
+
value = stringReplace(value, MUSTACHE_EXPR, ' ');
|
|
1207
|
+
value = stringReplace(value, ERB_EXPR, ' ');
|
|
1208
|
+
value = stringReplace(value, TMPLIT_EXPR, ' ');
|
|
1373
1209
|
}
|
|
1374
1210
|
/* Is `value` valid for this attribute? */
|
|
1375
1211
|
|
|
1376
1212
|
|
|
1377
|
-
|
|
1213
|
+
const lcTag = transformCaseFunc(currentNode.nodeName);
|
|
1378
1214
|
|
|
1379
1215
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1380
1216
|
continue;
|
|
@@ -1394,7 +1230,7 @@ function createDOMPurify() {
|
|
|
1394
1230
|
/* Handle attributes that require Trusted Types */
|
|
1395
1231
|
|
|
1396
1232
|
|
|
1397
|
-
if (trustedTypesPolicy &&
|
|
1233
|
+
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
|
1398
1234
|
if (namespaceURI) ; else {
|
|
1399
1235
|
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
|
1400
1236
|
case 'TrustedHTML':
|
|
@@ -1433,10 +1269,10 @@ function createDOMPurify() {
|
|
|
1433
1269
|
*/
|
|
1434
1270
|
|
|
1435
1271
|
|
|
1436
|
-
|
|
1437
|
-
|
|
1272
|
+
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
|
1273
|
+
let shadowNode;
|
|
1438
1274
|
|
|
1439
|
-
|
|
1275
|
+
const shadowIterator = _createIterator(fragment);
|
|
1440
1276
|
/* Execute a hook if present */
|
|
1441
1277
|
|
|
1442
1278
|
|
|
@@ -1478,11 +1314,11 @@ function createDOMPurify() {
|
|
|
1478
1314
|
|
|
1479
1315
|
|
|
1480
1316
|
DOMPurify.sanitize = function (dirty) {
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1317
|
+
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1318
|
+
let body;
|
|
1319
|
+
let importedNode;
|
|
1320
|
+
let currentNode;
|
|
1321
|
+
let returnNode;
|
|
1486
1322
|
/* Make sure we have a string to sanitize.
|
|
1487
1323
|
DO NOT return early, as this will return the wrong type if
|
|
1488
1324
|
the user has requested a DOM object rather than a string */
|
|
@@ -1532,7 +1368,7 @@ function createDOMPurify() {
|
|
|
1532
1368
|
if (IN_PLACE) {
|
|
1533
1369
|
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
|
1534
1370
|
if (dirty.nodeName) {
|
|
1535
|
-
|
|
1371
|
+
const tagName = transformCaseFunc(dirty.nodeName);
|
|
1536
1372
|
|
|
1537
1373
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1538
1374
|
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
@@ -1578,7 +1414,7 @@ function createDOMPurify() {
|
|
|
1578
1414
|
/* Get node iterator */
|
|
1579
1415
|
|
|
1580
1416
|
|
|
1581
|
-
|
|
1417
|
+
const nodeIterator = _createIterator(IN_PLACE ? dirty : body);
|
|
1582
1418
|
/* Now start iterating over the created document */
|
|
1583
1419
|
|
|
1584
1420
|
|
|
@@ -1633,7 +1469,7 @@ function createDOMPurify() {
|
|
|
1633
1469
|
return returnNode;
|
|
1634
1470
|
}
|
|
1635
1471
|
|
|
1636
|
-
|
|
1472
|
+
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
|
1637
1473
|
/* Serialize doctype if allowed */
|
|
1638
1474
|
|
|
1639
1475
|
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
|
@@ -1643,9 +1479,9 @@ function createDOMPurify() {
|
|
|
1643
1479
|
|
|
1644
1480
|
|
|
1645
1481
|
if (SAFE_FOR_TEMPLATES) {
|
|
1646
|
-
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR
|
|
1647
|
-
serializedHTML = stringReplace(serializedHTML, ERB_EXPR
|
|
1648
|
-
serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR
|
|
1482
|
+
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR, ' ');
|
|
1483
|
+
serializedHTML = stringReplace(serializedHTML, ERB_EXPR, ' ');
|
|
1484
|
+
serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR, ' ');
|
|
1649
1485
|
}
|
|
1650
1486
|
|
|
1651
1487
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
@@ -1692,8 +1528,8 @@ function createDOMPurify() {
|
|
|
1692
1528
|
_parseConfig({});
|
|
1693
1529
|
}
|
|
1694
1530
|
|
|
1695
|
-
|
|
1696
|
-
|
|
1531
|
+
const lcTag = transformCaseFunc(tag);
|
|
1532
|
+
const lcName = transformCaseFunc(attr);
|
|
1697
1533
|
return _isValidAttribute(lcTag, lcName, value);
|
|
1698
1534
|
};
|
|
1699
1535
|
/**
|