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