dompurify 2.4.8 → 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 +235 -418
- package/dist/purify.cjs.js.map +1 -1
- package/dist/purify.es.js +235 -418
- package/dist/purify.es.js.map +1 -1
- package/dist/purify.js +235 -418
- 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,25 +220,24 @@
|
|
|
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);
|
|
269
232
|
var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
270
233
|
);
|
|
271
234
|
var DOCTYPE_NAME = seal(/^html$/i);
|
|
272
|
-
var CUSTOM_ELEMENT = seal(/^[a-z][
|
|
235
|
+
var CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
|
273
236
|
|
|
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.8';
|
|
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,
|
|
996
|
-
|
|
898
|
+
return createNodeIterator.call(root.ownerDocument || root, root,
|
|
899
|
+
// eslint-disable-next-line no-bitwise
|
|
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,110 +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);
|
|
986
|
+
return true;
|
|
987
|
+
}
|
|
1095
988
|
|
|
989
|
+
/* Remove any ocurrence of processing instructions */
|
|
990
|
+
if (currentNode.nodeType === 7) {
|
|
991
|
+
_forceRemove(currentNode);
|
|
1096
992
|
return true;
|
|
1097
993
|
}
|
|
1098
|
-
/* Remove element if anything forbids its presence */
|
|
1099
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
|
+
}
|
|
1100
1000
|
|
|
1001
|
+
/* Remove element if anything forbids its presence */
|
|
1101
1002
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1102
1003
|
/* Check if we have a custom element to handle */
|
|
1103
1004
|
if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
|
|
1104
1005
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
|
|
1105
1006
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
|
|
1106
1007
|
}
|
|
1107
|
-
/* Keep content except for bad-listed elements */
|
|
1108
|
-
|
|
1109
1008
|
|
|
1009
|
+
/* Keep content except for bad-listed elements */
|
|
1110
1010
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
1111
1011
|
var parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
|
1112
1012
|
var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
|
1113
|
-
|
|
1114
1013
|
if (childNodes && parentNode) {
|
|
1115
1014
|
var childCount = childNodes.length;
|
|
1116
|
-
|
|
1117
1015
|
for (var i = childCount - 1; i >= 0; --i) {
|
|
1118
1016
|
parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
|
|
1119
1017
|
}
|
|
1120
1018
|
}
|
|
1121
1019
|
}
|
|
1122
|
-
|
|
1123
1020
|
_forceRemove(currentNode);
|
|
1124
|
-
|
|
1125
1021
|
return true;
|
|
1126
1022
|
}
|
|
1127
|
-
/* Check whether element has a valid namespace */
|
|
1128
|
-
|
|
1129
1023
|
|
|
1024
|
+
/* Check whether element has a valid namespace */
|
|
1130
1025
|
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
|
|
1131
1026
|
_forceRemove(currentNode);
|
|
1132
|
-
|
|
1133
1027
|
return true;
|
|
1134
1028
|
}
|
|
1135
|
-
/* Make sure that older browsers don't get fallback-tag mXSS */
|
|
1136
|
-
|
|
1137
1029
|
|
|
1030
|
+
/* Make sure that older browsers don't get fallback-tag mXSS */
|
|
1138
1031
|
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
|
|
1139
1032
|
_forceRemove(currentNode);
|
|
1140
|
-
|
|
1141
1033
|
return true;
|
|
1142
1034
|
}
|
|
1143
|
-
/* Sanitize element content to be template-safe */
|
|
1144
|
-
|
|
1145
1035
|
|
|
1036
|
+
/* Sanitize element content to be template-safe */
|
|
1146
1037
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
|
|
1147
1038
|
/* Get the element's text content */
|
|
1148
1039
|
content = currentNode.textContent;
|
|
1149
1040
|
content = stringReplace(content, MUSTACHE_EXPR$1, ' ');
|
|
1150
1041
|
content = stringReplace(content, ERB_EXPR$1, ' ');
|
|
1151
1042
|
content = stringReplace(content, TMPLIT_EXPR$1, ' ');
|
|
1152
|
-
|
|
1153
1043
|
if (currentNode.textContent !== content) {
|
|
1154
1044
|
arrayPush(DOMPurify.removed, {
|
|
1155
1045
|
element: currentNode.cloneNode()
|
|
@@ -1157,13 +1047,12 @@
|
|
|
1157
1047
|
currentNode.textContent = content;
|
|
1158
1048
|
}
|
|
1159
1049
|
}
|
|
1160
|
-
/* Execute a hook if present */
|
|
1161
|
-
|
|
1162
1050
|
|
|
1051
|
+
/* Execute a hook if present */
|
|
1163
1052
|
_executeHook('afterSanitizeElements', currentNode, null);
|
|
1164
|
-
|
|
1165
1053
|
return false;
|
|
1166
1054
|
};
|
|
1055
|
+
|
|
1167
1056
|
/**
|
|
1168
1057
|
* _isValidAttribute
|
|
1169
1058
|
*
|
|
@@ -1173,47 +1062,44 @@
|
|
|
1173
1062
|
* @return {Boolean} Returns true if `value` is valid, otherwise false.
|
|
1174
1063
|
*/
|
|
1175
1064
|
// eslint-disable-next-line complexity
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
1065
|
var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1179
1066
|
/* Make sure attribute cannot clobber */
|
|
1180
1067
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1181
1068
|
return false;
|
|
1182
1069
|
}
|
|
1070
|
+
|
|
1183
1071
|
/* Allow valid data-* attributes: At least one character after "-"
|
|
1184
1072
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
1185
1073
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
1186
1074
|
We don't need to check the value; it's always URI safe. */
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
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]) {
|
|
1190
|
-
if (
|
|
1076
|
+
if (
|
|
1077
|
+
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
1191
1078
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1192
1079
|
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
1193
|
-
_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
|
|
1194
1082
|
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1195
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 {
|
|
1196
1084
|
return false;
|
|
1197
1085
|
}
|
|
1198
1086
|
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
1199
|
-
|
|
1200
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) {
|
|
1201
1088
|
return false;
|
|
1202
1089
|
} else ;
|
|
1203
|
-
|
|
1204
1090
|
return true;
|
|
1205
1091
|
};
|
|
1092
|
+
|
|
1206
1093
|
/**
|
|
1207
1094
|
* _basicCustomElementCheck
|
|
1208
1095
|
* checks if at least one dash is included in tagName, and it's not the first char
|
|
1209
1096
|
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
|
1210
1097
|
* @param {string} tagName name of the tag of the node to sanitize
|
|
1211
1098
|
*/
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
1099
|
var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
|
|
1215
1100
|
return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT$1);
|
|
1216
1101
|
};
|
|
1102
|
+
|
|
1217
1103
|
/**
|
|
1218
1104
|
* _sanitizeAttributes
|
|
1219
1105
|
*
|
|
@@ -1224,24 +1110,19 @@
|
|
|
1224
1110
|
*
|
|
1225
1111
|
* @param {Node} currentNode to sanitize
|
|
1226
1112
|
*/
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
1113
|
var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
1230
1114
|
var attr;
|
|
1231
1115
|
var value;
|
|
1232
1116
|
var lcName;
|
|
1233
1117
|
var l;
|
|
1234
1118
|
/* Execute a hook if present */
|
|
1235
|
-
|
|
1236
1119
|
_executeHook('beforeSanitizeAttributes', currentNode, null);
|
|
1237
|
-
|
|
1238
1120
|
var attributes = currentNode.attributes;
|
|
1239
|
-
/* Check if we have attributes; if not we might have a text node */
|
|
1240
1121
|
|
|
1122
|
+
/* Check if we have attributes; if not we might have a text node */
|
|
1241
1123
|
if (!attributes) {
|
|
1242
1124
|
return;
|
|
1243
1125
|
}
|
|
1244
|
-
|
|
1245
1126
|
var hookEvent = {
|
|
1246
1127
|
attrName: '',
|
|
1247
1128
|
attrValue: '',
|
|
@@ -1249,79 +1130,67 @@
|
|
|
1249
1130
|
allowedAttributes: ALLOWED_ATTR
|
|
1250
1131
|
};
|
|
1251
1132
|
l = attributes.length;
|
|
1252
|
-
/* Go backwards over all attributes; safely remove bad ones */
|
|
1253
1133
|
|
|
1134
|
+
/* Go backwards over all attributes; safely remove bad ones */
|
|
1254
1135
|
while (l--) {
|
|
1255
1136
|
attr = attributes[l];
|
|
1256
1137
|
var _attr = attr,
|
|
1257
|
-
|
|
1258
|
-
|
|
1138
|
+
name = _attr.name,
|
|
1139
|
+
namespaceURI = _attr.namespaceURI;
|
|
1259
1140
|
value = name === 'value' ? attr.value : stringTrim(attr.value);
|
|
1260
1141
|
lcName = transformCaseFunc(name);
|
|
1261
|
-
/* Execute a hook if present */
|
|
1262
1142
|
|
|
1143
|
+
/* Execute a hook if present */
|
|
1263
1144
|
hookEvent.attrName = lcName;
|
|
1264
1145
|
hookEvent.attrValue = value;
|
|
1265
1146
|
hookEvent.keepAttr = true;
|
|
1266
1147
|
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
|
1267
|
-
|
|
1268
1148
|
_executeHook('uponSanitizeAttribute', currentNode, hookEvent);
|
|
1269
|
-
|
|
1270
1149
|
value = hookEvent.attrValue;
|
|
1271
1150
|
/* Did the hooks approve of the attribute? */
|
|
1272
|
-
|
|
1273
1151
|
if (hookEvent.forceKeepAttr) {
|
|
1274
1152
|
continue;
|
|
1275
1153
|
}
|
|
1276
|
-
/* Remove attribute */
|
|
1277
|
-
|
|
1278
1154
|
|
|
1155
|
+
/* Remove attribute */
|
|
1279
1156
|
_removeAttribute(name, currentNode);
|
|
1280
|
-
/* Did the hooks approve of the attribute? */
|
|
1281
|
-
|
|
1282
1157
|
|
|
1158
|
+
/* Did the hooks approve of the attribute? */
|
|
1283
1159
|
if (!hookEvent.keepAttr) {
|
|
1284
1160
|
continue;
|
|
1285
1161
|
}
|
|
1286
|
-
/* Work around a security issue in jQuery 3.0 */
|
|
1287
|
-
|
|
1288
1162
|
|
|
1163
|
+
/* Work around a security issue in jQuery 3.0 */
|
|
1289
1164
|
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
|
1290
1165
|
_removeAttribute(name, currentNode);
|
|
1291
|
-
|
|
1292
1166
|
continue;
|
|
1293
1167
|
}
|
|
1294
|
-
/* Sanitize attribute content to be template-safe */
|
|
1295
|
-
|
|
1296
1168
|
|
|
1169
|
+
/* Sanitize attribute content to be template-safe */
|
|
1297
1170
|
if (SAFE_FOR_TEMPLATES) {
|
|
1298
1171
|
value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
|
|
1299
1172
|
value = stringReplace(value, ERB_EXPR$1, ' ');
|
|
1300
1173
|
value = stringReplace(value, TMPLIT_EXPR$1, ' ');
|
|
1301
1174
|
}
|
|
1302
|
-
/* Is `value` valid for this attribute? */
|
|
1303
|
-
|
|
1304
1175
|
|
|
1176
|
+
/* Is `value` valid for this attribute? */
|
|
1305
1177
|
var lcTag = transformCaseFunc(currentNode.nodeName);
|
|
1306
|
-
|
|
1307
1178
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1308
1179
|
continue;
|
|
1309
1180
|
}
|
|
1181
|
+
|
|
1310
1182
|
/* Full DOM Clobbering protection via namespace isolation,
|
|
1311
1183
|
* Prefix id and name attributes with `user-content-`
|
|
1312
1184
|
*/
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
1185
|
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
1316
1186
|
// Remove the attribute with this value
|
|
1317
|
-
_removeAttribute(name, currentNode);
|
|
1318
|
-
|
|
1187
|
+
_removeAttribute(name, currentNode);
|
|
1319
1188
|
|
|
1189
|
+
// Prefix the value and later re-create the attribute with the sanitized value
|
|
1320
1190
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
1321
1191
|
}
|
|
1322
|
-
/* Handle attributes that require Trusted Types */
|
|
1323
|
-
|
|
1324
1192
|
|
|
1193
|
+
/* Handle attributes that require Trusted Types */
|
|
1325
1194
|
if (trustedTypesPolicy && _typeof(trustedTypes) === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
|
1326
1195
|
if (namespaceURI) ; else {
|
|
1327
1196
|
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
|
@@ -1330,7 +1199,6 @@
|
|
|
1330
1199
|
value = trustedTypesPolicy.createHTML(value);
|
|
1331
1200
|
break;
|
|
1332
1201
|
}
|
|
1333
|
-
|
|
1334
1202
|
case 'TrustedScriptURL':
|
|
1335
1203
|
{
|
|
1336
1204
|
value = trustedTypesPolicy.createScriptURL(value);
|
|
@@ -1339,9 +1207,8 @@
|
|
|
1339
1207
|
}
|
|
1340
1208
|
}
|
|
1341
1209
|
}
|
|
1342
|
-
/* Handle invalid data-* attribute set by try-catching it */
|
|
1343
|
-
|
|
1344
1210
|
|
|
1211
|
+
/* Handle invalid data-* attribute set by try-catching it */
|
|
1345
1212
|
try {
|
|
1346
1213
|
if (namespaceURI) {
|
|
1347
1214
|
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
@@ -1349,56 +1216,47 @@
|
|
|
1349
1216
|
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
|
1350
1217
|
currentNode.setAttribute(name, value);
|
|
1351
1218
|
}
|
|
1352
|
-
|
|
1353
1219
|
arrayPop(DOMPurify.removed);
|
|
1354
1220
|
} catch (_) {}
|
|
1355
1221
|
}
|
|
1356
|
-
/* Execute a hook if present */
|
|
1357
|
-
|
|
1358
1222
|
|
|
1223
|
+
/* Execute a hook if present */
|
|
1359
1224
|
_executeHook('afterSanitizeAttributes', currentNode, null);
|
|
1360
1225
|
};
|
|
1226
|
+
|
|
1361
1227
|
/**
|
|
1362
1228
|
* _sanitizeShadowDOM
|
|
1363
1229
|
*
|
|
1364
1230
|
* @param {DocumentFragment} fragment to iterate over recursively
|
|
1365
1231
|
*/
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
1232
|
var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
|
1369
1233
|
var shadowNode;
|
|
1370
|
-
|
|
1371
1234
|
var shadowIterator = _createIterator(fragment);
|
|
1372
|
-
/* Execute a hook if present */
|
|
1373
|
-
|
|
1374
1235
|
|
|
1236
|
+
/* Execute a hook if present */
|
|
1375
1237
|
_executeHook('beforeSanitizeShadowDOM', fragment, null);
|
|
1376
|
-
|
|
1377
1238
|
while (shadowNode = shadowIterator.nextNode()) {
|
|
1378
1239
|
/* Execute a hook if present */
|
|
1379
1240
|
_executeHook('uponSanitizeShadowNode', shadowNode, null);
|
|
1380
|
-
/* Sanitize tags and elements */
|
|
1381
|
-
|
|
1382
1241
|
|
|
1242
|
+
/* Sanitize tags and elements */
|
|
1383
1243
|
if (_sanitizeElements(shadowNode)) {
|
|
1384
1244
|
continue;
|
|
1385
1245
|
}
|
|
1386
|
-
/* Deep shadow DOM detected */
|
|
1387
|
-
|
|
1388
1246
|
|
|
1247
|
+
/* Deep shadow DOM detected */
|
|
1389
1248
|
if (shadowNode.content instanceof DocumentFragment) {
|
|
1390
1249
|
_sanitizeShadowDOM(shadowNode.content);
|
|
1391
1250
|
}
|
|
1392
|
-
/* Check attributes, sanitize if necessary */
|
|
1393
|
-
|
|
1394
1251
|
|
|
1252
|
+
/* Check attributes, sanitize if necessary */
|
|
1395
1253
|
_sanitizeAttributes(shadowNode);
|
|
1396
1254
|
}
|
|
1397
|
-
/* Execute a hook if present */
|
|
1398
|
-
|
|
1399
1255
|
|
|
1256
|
+
/* Execute a hook if present */
|
|
1400
1257
|
_executeHook('afterSanitizeShadowDOM', fragment, null);
|
|
1401
1258
|
};
|
|
1259
|
+
|
|
1402
1260
|
/**
|
|
1403
1261
|
* Sanitize
|
|
1404
1262
|
* Public method providing core sanitation functionality
|
|
@@ -1407,8 +1265,6 @@
|
|
|
1407
1265
|
* @param {Object} configuration object
|
|
1408
1266
|
*/
|
|
1409
1267
|
// eslint-disable-next-line complexity
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
1268
|
DOMPurify.sanitize = function (dirty) {
|
|
1413
1269
|
var cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1414
1270
|
var body;
|
|
@@ -1419,19 +1275,15 @@
|
|
|
1419
1275
|
/* Make sure we have a string to sanitize.
|
|
1420
1276
|
DO NOT return early, as this will return the wrong type if
|
|
1421
1277
|
the user has requested a DOM object rather than a string */
|
|
1422
|
-
|
|
1423
1278
|
IS_EMPTY_INPUT = !dirty;
|
|
1424
|
-
|
|
1425
1279
|
if (IS_EMPTY_INPUT) {
|
|
1426
1280
|
dirty = '<!-->';
|
|
1427
1281
|
}
|
|
1428
|
-
/* Stringify, in case dirty is an object */
|
|
1429
|
-
|
|
1430
1282
|
|
|
1283
|
+
/* Stringify, in case dirty is an object */
|
|
1431
1284
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
1432
1285
|
if (typeof dirty.toString === 'function') {
|
|
1433
1286
|
dirty = dirty.toString();
|
|
1434
|
-
|
|
1435
1287
|
if (typeof dirty !== 'string') {
|
|
1436
1288
|
throw typeErrorCreate('dirty is not a string, aborting');
|
|
1437
1289
|
}
|
|
@@ -1439,43 +1291,36 @@
|
|
|
1439
1291
|
throw typeErrorCreate('toString is not a function');
|
|
1440
1292
|
}
|
|
1441
1293
|
}
|
|
1442
|
-
/* Check we can run. Otherwise fall back or ignore */
|
|
1443
|
-
|
|
1444
1294
|
|
|
1295
|
+
/* Check we can run. Otherwise fall back or ignore */
|
|
1445
1296
|
if (!DOMPurify.isSupported) {
|
|
1446
1297
|
if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
|
|
1447
1298
|
if (typeof dirty === 'string') {
|
|
1448
1299
|
return window.toStaticHTML(dirty);
|
|
1449
1300
|
}
|
|
1450
|
-
|
|
1451
1301
|
if (_isNode(dirty)) {
|
|
1452
1302
|
return window.toStaticHTML(dirty.outerHTML);
|
|
1453
1303
|
}
|
|
1454
1304
|
}
|
|
1455
|
-
|
|
1456
1305
|
return dirty;
|
|
1457
1306
|
}
|
|
1458
|
-
/* Assign config vars */
|
|
1459
|
-
|
|
1460
1307
|
|
|
1308
|
+
/* Assign config vars */
|
|
1461
1309
|
if (!SET_CONFIG) {
|
|
1462
1310
|
_parseConfig(cfg);
|
|
1463
1311
|
}
|
|
1464
|
-
/* Clean up removed elements */
|
|
1465
|
-
|
|
1466
1312
|
|
|
1313
|
+
/* Clean up removed elements */
|
|
1467
1314
|
DOMPurify.removed = [];
|
|
1468
|
-
/* Check if dirty is correctly typed for IN_PLACE */
|
|
1469
1315
|
|
|
1316
|
+
/* Check if dirty is correctly typed for IN_PLACE */
|
|
1470
1317
|
if (typeof dirty === 'string') {
|
|
1471
1318
|
IN_PLACE = false;
|
|
1472
1319
|
}
|
|
1473
|
-
|
|
1474
1320
|
if (IN_PLACE) {
|
|
1475
1321
|
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
|
1476
1322
|
if (dirty.nodeName) {
|
|
1477
1323
|
var tagName = transformCaseFunc(dirty.nodeName);
|
|
1478
|
-
|
|
1479
1324
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1480
1325
|
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
1481
1326
|
}
|
|
@@ -1485,7 +1330,6 @@
|
|
|
1485
1330
|
elements being stripped by the parser */
|
|
1486
1331
|
body = _initDocument('<!---->');
|
|
1487
1332
|
importedNode = body.ownerDocument.importNode(dirty, true);
|
|
1488
|
-
|
|
1489
1333
|
if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
|
|
1490
1334
|
/* Node is already a body, use as is */
|
|
1491
1335
|
body = importedNode;
|
|
@@ -1497,71 +1341,61 @@
|
|
|
1497
1341
|
}
|
|
1498
1342
|
} else {
|
|
1499
1343
|
/* Exit directly if we have nothing to do */
|
|
1500
|
-
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
|
|
1501
1346
|
dirty.indexOf('<') === -1) {
|
|
1502
1347
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
1503
1348
|
}
|
|
1504
|
-
/* Initialize the document to work on */
|
|
1505
|
-
|
|
1506
1349
|
|
|
1350
|
+
/* Initialize the document to work on */
|
|
1507
1351
|
body = _initDocument(dirty);
|
|
1508
|
-
/* Check we have a DOM node from the data */
|
|
1509
1352
|
|
|
1353
|
+
/* Check we have a DOM node from the data */
|
|
1510
1354
|
if (!body) {
|
|
1511
1355
|
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
|
|
1512
1356
|
}
|
|
1513
1357
|
}
|
|
1514
|
-
/* Remove first element node (ours) if FORCE_BODY is set */
|
|
1515
|
-
|
|
1516
1358
|
|
|
1359
|
+
/* Remove first element node (ours) if FORCE_BODY is set */
|
|
1517
1360
|
if (body && FORCE_BODY) {
|
|
1518
1361
|
_forceRemove(body.firstChild);
|
|
1519
1362
|
}
|
|
1520
|
-
/* Get node iterator */
|
|
1521
|
-
|
|
1522
1363
|
|
|
1364
|
+
/* Get node iterator */
|
|
1523
1365
|
var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
|
|
1524
|
-
/* Now start iterating over the created document */
|
|
1525
|
-
|
|
1526
1366
|
|
|
1367
|
+
/* Now start iterating over the created document */
|
|
1527
1368
|
while (currentNode = nodeIterator.nextNode()) {
|
|
1528
1369
|
/* Fix IE's strange behavior with manipulated textNodes #89 */
|
|
1529
1370
|
if (currentNode.nodeType === 3 && currentNode === oldNode) {
|
|
1530
1371
|
continue;
|
|
1531
1372
|
}
|
|
1532
|
-
/* Sanitize tags and elements */
|
|
1533
|
-
|
|
1534
1373
|
|
|
1374
|
+
/* Sanitize tags and elements */
|
|
1535
1375
|
if (_sanitizeElements(currentNode)) {
|
|
1536
1376
|
continue;
|
|
1537
1377
|
}
|
|
1538
|
-
/* Shadow DOM detected, sanitize it */
|
|
1539
|
-
|
|
1540
1378
|
|
|
1379
|
+
/* Shadow DOM detected, sanitize it */
|
|
1541
1380
|
if (currentNode.content instanceof DocumentFragment) {
|
|
1542
1381
|
_sanitizeShadowDOM(currentNode.content);
|
|
1543
1382
|
}
|
|
1544
|
-
/* Check attributes, sanitize if necessary */
|
|
1545
|
-
|
|
1546
1383
|
|
|
1384
|
+
/* Check attributes, sanitize if necessary */
|
|
1547
1385
|
_sanitizeAttributes(currentNode);
|
|
1548
|
-
|
|
1549
1386
|
oldNode = currentNode;
|
|
1550
1387
|
}
|
|
1551
|
-
|
|
1552
1388
|
oldNode = null;
|
|
1553
|
-
/* If we sanitized `dirty` in-place, return it. */
|
|
1554
1389
|
|
|
1390
|
+
/* If we sanitized `dirty` in-place, return it. */
|
|
1555
1391
|
if (IN_PLACE) {
|
|
1556
1392
|
return dirty;
|
|
1557
1393
|
}
|
|
1558
|
-
/* Return sanitized string or DOM */
|
|
1559
|
-
|
|
1560
1394
|
|
|
1395
|
+
/* Return sanitized string or DOM */
|
|
1561
1396
|
if (RETURN_DOM) {
|
|
1562
1397
|
if (RETURN_DOM_FRAGMENT) {
|
|
1563
1398
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
1564
|
-
|
|
1565
1399
|
while (body.firstChild) {
|
|
1566
1400
|
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
1567
1401
|
returnNode.appendChild(body.firstChild);
|
|
@@ -1569,7 +1403,6 @@
|
|
|
1569
1403
|
} else {
|
|
1570
1404
|
returnNode = body;
|
|
1571
1405
|
}
|
|
1572
|
-
|
|
1573
1406
|
if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmod) {
|
|
1574
1407
|
/*
|
|
1575
1408
|
AdoptNode() is not used because internal state is not reset
|
|
@@ -1580,51 +1413,45 @@
|
|
|
1580
1413
|
*/
|
|
1581
1414
|
returnNode = importNode.call(originalDocument, returnNode, true);
|
|
1582
1415
|
}
|
|
1583
|
-
|
|
1584
1416
|
return returnNode;
|
|
1585
1417
|
}
|
|
1586
|
-
|
|
1587
1418
|
var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
|
1588
|
-
/* Serialize doctype if allowed */
|
|
1589
1419
|
|
|
1420
|
+
/* Serialize doctype if allowed */
|
|
1590
1421
|
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
|
1591
1422
|
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
|
1592
1423
|
}
|
|
1593
|
-
/* Sanitize final string template-safe */
|
|
1594
|
-
|
|
1595
1424
|
|
|
1425
|
+
/* Sanitize final string template-safe */
|
|
1596
1426
|
if (SAFE_FOR_TEMPLATES) {
|
|
1597
1427
|
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, ' ');
|
|
1598
1428
|
serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, ' ');
|
|
1599
1429
|
serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR$1, ' ');
|
|
1600
1430
|
}
|
|
1601
|
-
|
|
1602
1431
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
1603
1432
|
};
|
|
1433
|
+
|
|
1604
1434
|
/**
|
|
1605
1435
|
* Public method to set the configuration once
|
|
1606
1436
|
* setConfig
|
|
1607
1437
|
*
|
|
1608
1438
|
* @param {Object} cfg configuration object
|
|
1609
1439
|
*/
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
1440
|
DOMPurify.setConfig = function (cfg) {
|
|
1613
1441
|
_parseConfig(cfg);
|
|
1614
|
-
|
|
1615
1442
|
SET_CONFIG = true;
|
|
1616
1443
|
};
|
|
1444
|
+
|
|
1617
1445
|
/**
|
|
1618
1446
|
* Public method to remove the configuration
|
|
1619
1447
|
* clearConfig
|
|
1620
1448
|
*
|
|
1621
1449
|
*/
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
1450
|
DOMPurify.clearConfig = function () {
|
|
1625
1451
|
CONFIG = null;
|
|
1626
1452
|
SET_CONFIG = false;
|
|
1627
1453
|
};
|
|
1454
|
+
|
|
1628
1455
|
/**
|
|
1629
1456
|
* Public method to check if an attribute value is valid.
|
|
1630
1457
|
* Uses last set config, if any. Otherwise, uses config defaults.
|
|
@@ -1635,18 +1462,16 @@
|
|
|
1635
1462
|
* @param {string} value Attribute value.
|
|
1636
1463
|
* @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
|
|
1637
1464
|
*/
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
1465
|
DOMPurify.isValidAttribute = function (tag, attr, value) {
|
|
1641
1466
|
/* Initialize shared config vars if necessary. */
|
|
1642
1467
|
if (!CONFIG) {
|
|
1643
1468
|
_parseConfig({});
|
|
1644
1469
|
}
|
|
1645
|
-
|
|
1646
1470
|
var lcTag = transformCaseFunc(tag);
|
|
1647
1471
|
var lcName = transformCaseFunc(attr);
|
|
1648
1472
|
return _isValidAttribute(lcTag, lcName, value);
|
|
1649
1473
|
};
|
|
1474
|
+
|
|
1650
1475
|
/**
|
|
1651
1476
|
* AddHook
|
|
1652
1477
|
* Public method to add DOMPurify hooks
|
|
@@ -1654,16 +1479,14 @@
|
|
|
1654
1479
|
* @param {String} entryPoint entry point for the hook to add
|
|
1655
1480
|
* @param {Function} hookFunction function to execute
|
|
1656
1481
|
*/
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
1482
|
DOMPurify.addHook = function (entryPoint, hookFunction) {
|
|
1660
1483
|
if (typeof hookFunction !== 'function') {
|
|
1661
1484
|
return;
|
|
1662
1485
|
}
|
|
1663
|
-
|
|
1664
1486
|
hooks[entryPoint] = hooks[entryPoint] || [];
|
|
1665
1487
|
arrayPush(hooks[entryPoint], hookFunction);
|
|
1666
1488
|
};
|
|
1489
|
+
|
|
1667
1490
|
/**
|
|
1668
1491
|
* RemoveHook
|
|
1669
1492
|
* Public method to remove a DOMPurify hook at a given entryPoint
|
|
@@ -1672,40 +1495,34 @@
|
|
|
1672
1495
|
* @param {String} entryPoint entry point for the hook to remove
|
|
1673
1496
|
* @return {Function} removed(popped) hook
|
|
1674
1497
|
*/
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
1498
|
DOMPurify.removeHook = function (entryPoint) {
|
|
1678
1499
|
if (hooks[entryPoint]) {
|
|
1679
1500
|
return arrayPop(hooks[entryPoint]);
|
|
1680
1501
|
}
|
|
1681
1502
|
};
|
|
1503
|
+
|
|
1682
1504
|
/**
|
|
1683
1505
|
* RemoveHooks
|
|
1684
1506
|
* Public method to remove all DOMPurify hooks at a given entryPoint
|
|
1685
1507
|
*
|
|
1686
1508
|
* @param {String} entryPoint entry point for the hooks to remove
|
|
1687
1509
|
*/
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
1510
|
DOMPurify.removeHooks = function (entryPoint) {
|
|
1691
1511
|
if (hooks[entryPoint]) {
|
|
1692
1512
|
hooks[entryPoint] = [];
|
|
1693
1513
|
}
|
|
1694
1514
|
};
|
|
1515
|
+
|
|
1695
1516
|
/**
|
|
1696
1517
|
* RemoveAllHooks
|
|
1697
1518
|
* Public method to remove all DOMPurify hooks
|
|
1698
1519
|
*
|
|
1699
1520
|
*/
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
1521
|
DOMPurify.removeAllHooks = function () {
|
|
1703
1522
|
hooks = {};
|
|
1704
1523
|
};
|
|
1705
|
-
|
|
1706
1524
|
return DOMPurify;
|
|
1707
1525
|
}
|
|
1708
|
-
|
|
1709
1526
|
var purify = createDOMPurify();
|
|
1710
1527
|
|
|
1711
1528
|
return purify;
|