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