@touchvue/chat 1.0.0-beta.50 → 1.0.0-beta.51
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/es/node_modules/.pnpm/{dompurify@3.3.0 → dompurify@3.4.3}/node_modules/dompurify/dist/purify.es.mjs +299 -143
- package/es/node_modules/.pnpm/dompurify@3.4.3/node_modules/dompurify/dist/purify.es.mjs.map +1 -0
- package/es/package.json.mjs +1 -1
- package/es/packages/components/touchchat/component/AiRobot/letter.vue2.mjs +1 -1
- package/es/packages/components/touchchat/src/AiChat/AiMessage.vue2.mjs +7 -10
- package/es/packages/components/touchchat/src/AiChat/AiMessage.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/Chat/useMessageRender.mjs +1 -1
- package/es/packages/components/touchchat/src/AiChat/ChatInput.vue2.mjs +2 -1
- package/es/packages/components/touchchat/src/AiChat/ChatInput.vue2.mjs.map +1 -1
- package/es/packages/components/touchchat/src/AiChat/TouchAgent.vue2.mjs +1 -1
- package/es/packages/components/touchchat/utils/markdown.mjs +1 -1
- package/lib/node_modules/.pnpm/{dompurify@3.3.0 → dompurify@3.4.3}/node_modules/dompurify/dist/purify.es.js +299 -143
- package/lib/node_modules/.pnpm/dompurify@3.4.3/node_modules/dompurify/dist/purify.es.js.map +1 -0
- package/lib/package.json.js +1 -1
- package/lib/packages/components/touchchat/component/AiRobot/letter.vue2.js +1 -1
- package/lib/packages/components/touchchat/src/AiChat/AiMessage.vue2.js +7 -10
- package/lib/packages/components/touchchat/src/AiChat/AiMessage.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/Chat/useMessageRender.js +1 -1
- package/lib/packages/components/touchchat/src/AiChat/ChatInput.vue2.js +2 -1
- package/lib/packages/components/touchchat/src/AiChat/ChatInput.vue2.js.map +1 -1
- package/lib/packages/components/touchchat/src/AiChat/TouchAgent.vue2.js +1 -1
- package/lib/packages/components/touchchat/utils/markdown.js +1 -1
- package/package.json +1 -1
- package/es/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.mjs.map +0 -1
- package/lib/node_modules/.pnpm/dompurify@3.3.0/node_modules/dompurify/dist/purify.es.js.map +0 -1
|
@@ -1,21 +1,62 @@
|
|
|
1
|
-
/*! @license DOMPurify 3.3
|
|
1
|
+
/*! @license DOMPurify 3.4.3 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.3/LICENSE */
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
function _arrayLikeToArray(r, a) {
|
|
4
|
+
(null == a || a > r.length) && (a = r.length);
|
|
5
|
+
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
6
|
+
return n;
|
|
7
|
+
}
|
|
8
|
+
function _arrayWithHoles(r) {
|
|
9
|
+
if (Array.isArray(r)) return r;
|
|
10
|
+
}
|
|
11
|
+
function _iterableToArrayLimit(r, l) {
|
|
12
|
+
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
13
|
+
if (null != t) {
|
|
14
|
+
var e,
|
|
15
|
+
n,
|
|
16
|
+
i,
|
|
17
|
+
u,
|
|
18
|
+
a = [],
|
|
19
|
+
f = true,
|
|
20
|
+
o = false;
|
|
21
|
+
try {
|
|
22
|
+
if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
|
|
23
|
+
} catch (r) {
|
|
24
|
+
o = true, n = r;
|
|
25
|
+
} finally {
|
|
26
|
+
try {
|
|
27
|
+
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
|
|
28
|
+
} finally {
|
|
29
|
+
if (o) throw n;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return a;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function _nonIterableRest() {
|
|
36
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
37
|
+
}
|
|
38
|
+
function _slicedToArray(r, e) {
|
|
39
|
+
return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
|
|
40
|
+
}
|
|
41
|
+
function _unsupportedIterableToArray(r, a) {
|
|
42
|
+
if (r) {
|
|
43
|
+
if ("string" == typeof r) return _arrayLikeToArray(r, a);
|
|
44
|
+
var t = {}.toString.call(r).slice(8, -1);
|
|
45
|
+
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const entries = Object.entries,
|
|
50
|
+
setPrototypeOf = Object.setPrototypeOf,
|
|
51
|
+
isFrozen = Object.isFrozen,
|
|
52
|
+
getPrototypeOf = Object.getPrototypeOf,
|
|
53
|
+
getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
54
|
+
let freeze = Object.freeze,
|
|
55
|
+
seal = Object.seal,
|
|
56
|
+
create = Object.create; // eslint-disable-line import/no-mutable-exports
|
|
57
|
+
let _ref = typeof Reflect !== 'undefined' && Reflect,
|
|
58
|
+
apply = _ref.apply,
|
|
59
|
+
construct = _ref.construct;
|
|
19
60
|
if (!freeze) {
|
|
20
61
|
freeze = function freeze(x) {
|
|
21
62
|
return x;
|
|
@@ -47,13 +88,19 @@ const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
|
|
|
47
88
|
const arrayPop = unapply(Array.prototype.pop);
|
|
48
89
|
const arrayPush = unapply(Array.prototype.push);
|
|
49
90
|
const arraySplice = unapply(Array.prototype.splice);
|
|
91
|
+
const arrayIsArray = Array.isArray;
|
|
50
92
|
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
51
93
|
const stringToString = unapply(String.prototype.toString);
|
|
52
94
|
const stringMatch = unapply(String.prototype.match);
|
|
53
95
|
const stringReplace = unapply(String.prototype.replace);
|
|
54
96
|
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
55
97
|
const stringTrim = unapply(String.prototype.trim);
|
|
98
|
+
const numberToString = unapply(Number.prototype.toString);
|
|
99
|
+
const booleanToString = unapply(Boolean.prototype.toString);
|
|
100
|
+
const bigintToString = typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);
|
|
101
|
+
const symbolToString = typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);
|
|
56
102
|
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
|
103
|
+
const objectToString = unapply(Object.prototype.toString);
|
|
57
104
|
const regExpTest = unapply(RegExp.prototype.test);
|
|
58
105
|
const typeErrorCreate = unconstruct(TypeError);
|
|
59
106
|
/**
|
|
@@ -103,6 +150,9 @@ function addToSet(set, array) {
|
|
|
103
150
|
// Prevent prototype setters from intercepting set as a this value.
|
|
104
151
|
setPrototypeOf(set, null);
|
|
105
152
|
}
|
|
153
|
+
if (!arrayIsArray(array)) {
|
|
154
|
+
return set;
|
|
155
|
+
}
|
|
106
156
|
let l = array.length;
|
|
107
157
|
while (l--) {
|
|
108
158
|
let element = array[l];
|
|
@@ -143,10 +193,13 @@ function cleanArray(array) {
|
|
|
143
193
|
*/
|
|
144
194
|
function clone(object) {
|
|
145
195
|
const newObject = create(null);
|
|
146
|
-
for (const
|
|
196
|
+
for (const _ref2 of entries(object)) {
|
|
197
|
+
var _ref3 = _slicedToArray(_ref2, 2);
|
|
198
|
+
const property = _ref3[0];
|
|
199
|
+
const value = _ref3[1];
|
|
147
200
|
const isPropertyExist = objectHasOwnProperty(object, property);
|
|
148
201
|
if (isPropertyExist) {
|
|
149
|
-
if (
|
|
202
|
+
if (arrayIsArray(value)) {
|
|
150
203
|
newObject[property] = cleanArray(value);
|
|
151
204
|
} else if (value && typeof value === 'object' && value.constructor === Object) {
|
|
152
205
|
newObject[property] = clone(value);
|
|
@@ -157,6 +210,58 @@ function clone(object) {
|
|
|
157
210
|
}
|
|
158
211
|
return newObject;
|
|
159
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Convert non-node values into strings without depending on direct property access.
|
|
215
|
+
*
|
|
216
|
+
* @param value - The value to stringify.
|
|
217
|
+
* @returns A string representation of the provided value.
|
|
218
|
+
*/
|
|
219
|
+
function stringifyValue(value) {
|
|
220
|
+
switch (typeof value) {
|
|
221
|
+
case 'string':
|
|
222
|
+
{
|
|
223
|
+
return value;
|
|
224
|
+
}
|
|
225
|
+
case 'number':
|
|
226
|
+
{
|
|
227
|
+
return numberToString(value);
|
|
228
|
+
}
|
|
229
|
+
case 'boolean':
|
|
230
|
+
{
|
|
231
|
+
return booleanToString(value);
|
|
232
|
+
}
|
|
233
|
+
case 'bigint':
|
|
234
|
+
{
|
|
235
|
+
return bigintToString ? bigintToString(value) : '0';
|
|
236
|
+
}
|
|
237
|
+
case 'symbol':
|
|
238
|
+
{
|
|
239
|
+
return symbolToString ? symbolToString(value) : 'Symbol()';
|
|
240
|
+
}
|
|
241
|
+
case 'undefined':
|
|
242
|
+
{
|
|
243
|
+
return objectToString(value);
|
|
244
|
+
}
|
|
245
|
+
case 'function':
|
|
246
|
+
case 'object':
|
|
247
|
+
{
|
|
248
|
+
if (value === null) {
|
|
249
|
+
return objectToString(value);
|
|
250
|
+
}
|
|
251
|
+
const valueAsRecord = value;
|
|
252
|
+
const valueToString = lookupGetter(valueAsRecord, 'toString');
|
|
253
|
+
if (typeof valueToString === 'function') {
|
|
254
|
+
const stringified = valueToString(valueAsRecord);
|
|
255
|
+
return typeof stringified === 'string' ? stringified : objectToString(stringified);
|
|
256
|
+
}
|
|
257
|
+
return objectToString(value);
|
|
258
|
+
}
|
|
259
|
+
default:
|
|
260
|
+
{
|
|
261
|
+
return objectToString(value);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
160
265
|
/**
|
|
161
266
|
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
|
162
267
|
*
|
|
@@ -182,6 +287,14 @@ function lookupGetter(object, prop) {
|
|
|
182
287
|
}
|
|
183
288
|
return fallbackValue;
|
|
184
289
|
}
|
|
290
|
+
function isRegex(value) {
|
|
291
|
+
try {
|
|
292
|
+
regExpTest(value, '');
|
|
293
|
+
return true;
|
|
294
|
+
} catch (_unused) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
185
298
|
|
|
186
299
|
const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', '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']);
|
|
187
300
|
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
|
|
@@ -197,15 +310,14 @@ const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mgly
|
|
|
197
310
|
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
198
311
|
const text = freeze(['#text']);
|
|
199
312
|
|
|
200
|
-
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns'
|
|
313
|
+
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
|
|
201
314
|
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
202
|
-
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', '
|
|
315
|
+
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', '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']);
|
|
203
316
|
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
204
317
|
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
const
|
|
208
|
-
const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
|
|
318
|
+
const MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
|
|
319
|
+
const ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
|
|
320
|
+
const TMPLIT_EXPR = seal(/\${[\w\W]*/g);
|
|
209
321
|
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
|
|
210
322
|
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
211
323
|
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
@@ -216,38 +328,15 @@ const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205
|
|
|
216
328
|
const DOCTYPE_NAME = seal(/^html$/i);
|
|
217
329
|
const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
|
218
330
|
|
|
219
|
-
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
|
220
|
-
__proto__: null,
|
|
221
|
-
ARIA_ATTR: ARIA_ATTR,
|
|
222
|
-
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
|
223
|
-
CUSTOM_ELEMENT: CUSTOM_ELEMENT,
|
|
224
|
-
DATA_ATTR: DATA_ATTR,
|
|
225
|
-
DOCTYPE_NAME: DOCTYPE_NAME,
|
|
226
|
-
ERB_EXPR: ERB_EXPR,
|
|
227
|
-
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
228
|
-
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
|
229
|
-
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
230
|
-
TMPLIT_EXPR: TMPLIT_EXPR
|
|
231
|
-
});
|
|
232
|
-
|
|
233
331
|
/* eslint-disable @typescript-eslint/indent */
|
|
234
332
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
|
235
333
|
const NODE_TYPE = {
|
|
236
334
|
element: 1,
|
|
237
|
-
attribute: 2,
|
|
238
335
|
text: 3,
|
|
239
|
-
cdataSection: 4,
|
|
240
|
-
entityReference: 5,
|
|
241
|
-
// Deprecated
|
|
242
|
-
entityNode: 6,
|
|
243
336
|
// Deprecated
|
|
244
337
|
progressingInstruction: 7,
|
|
245
338
|
comment: 8,
|
|
246
|
-
document: 9
|
|
247
|
-
documentType: 10,
|
|
248
|
-
documentFragment: 11,
|
|
249
|
-
notation: 12 // Deprecated
|
|
250
|
-
};
|
|
339
|
+
document: 9};
|
|
251
340
|
const getGlobal = function getGlobal() {
|
|
252
341
|
return typeof window === 'undefined' ? null : window;
|
|
253
342
|
};
|
|
@@ -305,7 +394,7 @@ const _createHooksMap = function _createHooksMap() {
|
|
|
305
394
|
function createDOMPurify() {
|
|
306
395
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
307
396
|
const DOMPurify = root => createDOMPurify(root);
|
|
308
|
-
DOMPurify.version = '3.3
|
|
397
|
+
DOMPurify.version = '3.4.3';
|
|
309
398
|
DOMPurify.removed = [];
|
|
310
399
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
311
400
|
// Not running in a browser, provide a factory function
|
|
@@ -313,22 +402,19 @@ function createDOMPurify() {
|
|
|
313
402
|
DOMPurify.isSupported = false;
|
|
314
403
|
return DOMPurify;
|
|
315
404
|
}
|
|
316
|
-
let
|
|
317
|
-
document
|
|
318
|
-
} = window;
|
|
405
|
+
let document = window.document;
|
|
319
406
|
const originalDocument = document;
|
|
320
407
|
const currentScript = originalDocument.currentScript;
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
|
|
328
|
-
HTMLFormElement,
|
|
329
|
-
DOMParser,
|
|
330
|
-
trustedTypes
|
|
331
|
-
} = window;
|
|
408
|
+
const DocumentFragment = window.DocumentFragment,
|
|
409
|
+
HTMLTemplateElement = window.HTMLTemplateElement,
|
|
410
|
+
Node = window.Node,
|
|
411
|
+
Element = window.Element,
|
|
412
|
+
NodeFilter = window.NodeFilter,
|
|
413
|
+
_window$NamedNodeMap = window.NamedNodeMap,
|
|
414
|
+
NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
|
|
415
|
+
HTMLFormElement = window.HTMLFormElement,
|
|
416
|
+
DOMParser = window.DOMParser,
|
|
417
|
+
trustedTypes = window.trustedTypes;
|
|
332
418
|
const ElementPrototype = Element.prototype;
|
|
333
419
|
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
|
334
420
|
const remove = lookupGetter(ElementPrototype, 'remove');
|
|
@@ -349,33 +435,26 @@ function createDOMPurify() {
|
|
|
349
435
|
}
|
|
350
436
|
let trustedTypesPolicy;
|
|
351
437
|
let emptyHTML = '';
|
|
352
|
-
const
|
|
353
|
-
implementation,
|
|
354
|
-
createNodeIterator,
|
|
355
|
-
createDocumentFragment,
|
|
356
|
-
getElementsByTagName
|
|
357
|
-
|
|
358
|
-
const {
|
|
359
|
-
importNode
|
|
360
|
-
} = originalDocument;
|
|
438
|
+
const _document = document,
|
|
439
|
+
implementation = _document.implementation,
|
|
440
|
+
createNodeIterator = _document.createNodeIterator,
|
|
441
|
+
createDocumentFragment = _document.createDocumentFragment,
|
|
442
|
+
getElementsByTagName = _document.getElementsByTagName;
|
|
443
|
+
const importNode = originalDocument.importNode;
|
|
361
444
|
let hooks = _createHooksMap();
|
|
362
445
|
/**
|
|
363
446
|
* Expose whether this browser supports running the full DOMPurify.
|
|
364
447
|
*/
|
|
365
448
|
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
} = EXPRESSIONS;
|
|
376
|
-
let {
|
|
377
|
-
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
|
378
|
-
} = EXPRESSIONS;
|
|
449
|
+
const MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
|
|
450
|
+
ERB_EXPR$1 = ERB_EXPR,
|
|
451
|
+
TMPLIT_EXPR$1 = TMPLIT_EXPR,
|
|
452
|
+
DATA_ATTR$1 = DATA_ATTR,
|
|
453
|
+
ARIA_ATTR$1 = ARIA_ATTR,
|
|
454
|
+
IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
|
|
455
|
+
ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
|
|
456
|
+
CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
|
|
457
|
+
let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
|
|
379
458
|
/**
|
|
380
459
|
* We consider the elements and attributes below to be safe. Ideally
|
|
381
460
|
* don't add any new ones but feel free to remove unwanted ones.
|
|
@@ -553,15 +632,15 @@ function createDOMPurify() {
|
|
|
553
632
|
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
554
633
|
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
|
555
634
|
/* Set configuration parameters */
|
|
556
|
-
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
|
557
|
-
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
|
558
|
-
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
|
559
|
-
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
560
|
-
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
|
|
561
|
-
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
|
562
|
-
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
|
|
563
|
-
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
|
|
564
|
-
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
|
|
635
|
+
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') && arrayIsArray(cfg.ALLOWED_TAGS) ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
|
636
|
+
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') && arrayIsArray(cfg.ALLOWED_ATTR) ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
|
637
|
+
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') && arrayIsArray(cfg.ALLOWED_NAMESPACES) ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
|
638
|
+
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') && arrayIsArray(cfg.ADD_URI_SAFE_ATTR) ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
639
|
+
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') && arrayIsArray(cfg.ADD_DATA_URI_TAGS) ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
|
|
640
|
+
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') && arrayIsArray(cfg.FORBID_CONTENTS) ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
|
641
|
+
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') && arrayIsArray(cfg.FORBID_TAGS) ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
|
|
642
|
+
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') && arrayIsArray(cfg.FORBID_ATTR) ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
|
|
643
|
+
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === 'object' ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false;
|
|
565
644
|
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
566
645
|
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
|
567
646
|
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
|
|
@@ -577,19 +656,20 @@ function createDOMPurify() {
|
|
|
577
656
|
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
|
|
578
657
|
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
579
658
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
580
|
-
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP
|
|
581
|
-
NAMESPACE = cfg.NAMESPACE
|
|
582
|
-
MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS
|
|
583
|
-
HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
659
|
+
IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; // Default regexp
|
|
660
|
+
NAMESPACE = typeof cfg.NAMESPACE === 'string' ? cfg.NAMESPACE : HTML_NAMESPACE; // Default HTML namespace
|
|
661
|
+
MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, 'MATHML_TEXT_INTEGRATION_POINTS') && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === 'object' ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']); // Default built-in map
|
|
662
|
+
HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, 'HTML_INTEGRATION_POINTS') && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === 'object' ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, ['annotation-xml']); // Default built-in map
|
|
663
|
+
const customElementHandling = objectHasOwnProperty(cfg, 'CUSTOM_ELEMENT_HANDLING') && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === 'object' ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null);
|
|
664
|
+
CUSTOM_ELEMENT_HANDLING = create(null);
|
|
665
|
+
if (objectHasOwnProperty(customElementHandling, 'tagNameCheck') && isRegexOrFunction(customElementHandling.tagNameCheck)) {
|
|
666
|
+
CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; // Default undefined
|
|
587
667
|
}
|
|
588
|
-
if (
|
|
589
|
-
CUSTOM_ELEMENT_HANDLING.attributeNameCheck =
|
|
668
|
+
if (objectHasOwnProperty(customElementHandling, 'attributeNameCheck') && isRegexOrFunction(customElementHandling.attributeNameCheck)) {
|
|
669
|
+
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; // Default undefined
|
|
590
670
|
}
|
|
591
|
-
if (
|
|
592
|
-
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements =
|
|
671
|
+
if (objectHasOwnProperty(customElementHandling, 'allowCustomizedBuiltInElements') && typeof customElementHandling.allowCustomizedBuiltInElements === 'boolean') {
|
|
672
|
+
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; // Default undefined
|
|
593
673
|
}
|
|
594
674
|
if (SAFE_FOR_TEMPLATES) {
|
|
595
675
|
ALLOW_DATA_ATTR = false;
|
|
@@ -600,7 +680,7 @@ function createDOMPurify() {
|
|
|
600
680
|
/* Parse profile info */
|
|
601
681
|
if (USE_PROFILES) {
|
|
602
682
|
ALLOWED_TAGS = addToSet({}, text);
|
|
603
|
-
ALLOWED_ATTR =
|
|
683
|
+
ALLOWED_ATTR = create(null);
|
|
604
684
|
if (USE_PROFILES.html === true) {
|
|
605
685
|
addToSet(ALLOWED_TAGS, html$1);
|
|
606
686
|
addToSet(ALLOWED_ATTR, html);
|
|
@@ -621,36 +701,46 @@ function createDOMPurify() {
|
|
|
621
701
|
addToSet(ALLOWED_ATTR, xml);
|
|
622
702
|
}
|
|
623
703
|
}
|
|
704
|
+
/* Always reset function-based ADD_TAGS / ADD_ATTR checks to prevent
|
|
705
|
+
* leaking across calls when switching from function to array config */
|
|
706
|
+
EXTRA_ELEMENT_HANDLING.tagCheck = null;
|
|
707
|
+
EXTRA_ELEMENT_HANDLING.attributeCheck = null;
|
|
624
708
|
/* Merge configuration parameters */
|
|
625
|
-
if (cfg
|
|
709
|
+
if (objectHasOwnProperty(cfg, 'ADD_TAGS')) {
|
|
626
710
|
if (typeof cfg.ADD_TAGS === 'function') {
|
|
627
711
|
EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
|
|
628
|
-
} else {
|
|
712
|
+
} else if (arrayIsArray(cfg.ADD_TAGS)) {
|
|
629
713
|
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
630
714
|
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
631
715
|
}
|
|
632
716
|
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
633
717
|
}
|
|
634
718
|
}
|
|
635
|
-
if (cfg
|
|
719
|
+
if (objectHasOwnProperty(cfg, 'ADD_ATTR')) {
|
|
636
720
|
if (typeof cfg.ADD_ATTR === 'function') {
|
|
637
721
|
EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
|
|
638
|
-
} else {
|
|
722
|
+
} else if (arrayIsArray(cfg.ADD_ATTR)) {
|
|
639
723
|
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
640
724
|
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
641
725
|
}
|
|
642
726
|
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
643
727
|
}
|
|
644
728
|
}
|
|
645
|
-
if (cfg.ADD_URI_SAFE_ATTR) {
|
|
729
|
+
if (objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) {
|
|
646
730
|
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
647
731
|
}
|
|
648
|
-
if (cfg.FORBID_CONTENTS) {
|
|
732
|
+
if (objectHasOwnProperty(cfg, 'FORBID_CONTENTS') && arrayIsArray(cfg.FORBID_CONTENTS)) {
|
|
649
733
|
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
650
734
|
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
651
735
|
}
|
|
652
736
|
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
653
737
|
}
|
|
738
|
+
if (objectHasOwnProperty(cfg, 'ADD_FORBID_CONTENTS') && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
|
|
739
|
+
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
740
|
+
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
741
|
+
}
|
|
742
|
+
addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
|
|
743
|
+
}
|
|
654
744
|
/* Add #text in case KEEP_CONTENT is set to true */
|
|
655
745
|
if (KEEP_CONTENT) {
|
|
656
746
|
ALLOWED_TAGS['#text'] = true;
|
|
@@ -937,6 +1027,11 @@ function createDOMPurify() {
|
|
|
937
1027
|
_forceRemove(currentNode);
|
|
938
1028
|
return true;
|
|
939
1029
|
}
|
|
1030
|
+
/* Remove risky CSS construction leading to mXSS */
|
|
1031
|
+
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === 'style' && _isNode(currentNode.firstElementChild)) {
|
|
1032
|
+
_forceRemove(currentNode);
|
|
1033
|
+
return true;
|
|
1034
|
+
}
|
|
940
1035
|
/* Remove any occurrence of processing instructions */
|
|
941
1036
|
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
|
|
942
1037
|
_forceRemove(currentNode);
|
|
@@ -948,7 +1043,7 @@ function createDOMPurify() {
|
|
|
948
1043
|
return true;
|
|
949
1044
|
}
|
|
950
1045
|
/* Remove element if anything forbids its presence */
|
|
951
|
-
if (!(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) &&
|
|
1046
|
+
if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
|
|
952
1047
|
/* Check if we have a custom element to handle */
|
|
953
1048
|
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
|
954
1049
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
@@ -966,7 +1061,6 @@ function createDOMPurify() {
|
|
|
966
1061
|
const childCount = childNodes.length;
|
|
967
1062
|
for (let i = childCount - 1; i >= 0; --i) {
|
|
968
1063
|
const childClone = cloneNode(childNodes[i], true);
|
|
969
|
-
childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
|
|
970
1064
|
parentNode.insertBefore(childClone, getNextSibling(currentNode));
|
|
971
1065
|
}
|
|
972
1066
|
}
|
|
@@ -988,7 +1082,7 @@ function createDOMPurify() {
|
|
|
988
1082
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
|
|
989
1083
|
/* Get the element's text content */
|
|
990
1084
|
content = currentNode.textContent;
|
|
991
|
-
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
1085
|
+
arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
|
|
992
1086
|
content = stringReplace(content, expr, ' ');
|
|
993
1087
|
});
|
|
994
1088
|
if (currentNode.textContent !== content) {
|
|
@@ -1012,15 +1106,20 @@ function createDOMPurify() {
|
|
|
1012
1106
|
*/
|
|
1013
1107
|
// eslint-disable-next-line complexity
|
|
1014
1108
|
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1109
|
+
/* FORBID_ATTR must always win, even if ADD_ATTR predicate would allow it */
|
|
1110
|
+
if (FORBID_ATTR[lcName]) {
|
|
1111
|
+
return false;
|
|
1112
|
+
}
|
|
1015
1113
|
/* Make sure attribute cannot clobber */
|
|
1016
1114
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1017
1115
|
return false;
|
|
1018
1116
|
}
|
|
1117
|
+
const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
|
|
1019
1118
|
/* Allow valid data-* attributes: At least one character after "-"
|
|
1020
1119
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
1021
1120
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
1022
1121
|
We don't need to check the value; it's always URI safe. */
|
|
1023
|
-
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (
|
|
1122
|
+
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ; else if (!nameIsPermitted || FORBID_ATTR[lcName]) {
|
|
1024
1123
|
if (
|
|
1025
1124
|
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
1026
1125
|
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
@@ -1032,11 +1131,15 @@ function createDOMPurify() {
|
|
|
1032
1131
|
return false;
|
|
1033
1132
|
}
|
|
1034
1133
|
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
1035
|
-
} else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
|
|
1134
|
+
} 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) {
|
|
1036
1135
|
return false;
|
|
1037
1136
|
} else ;
|
|
1038
1137
|
return true;
|
|
1039
1138
|
};
|
|
1139
|
+
/* Names the HTML spec reserves from valid-custom-element-name; these must
|
|
1140
|
+
* never be treated as basic custom elements even when a permissive
|
|
1141
|
+
* CUSTOM_ELEMENT_HANDLING.tagNameCheck is configured. */
|
|
1142
|
+
const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ['annotation-xml', 'color-profile', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'missing-glyph']);
|
|
1040
1143
|
/**
|
|
1041
1144
|
* _isBasicCustomElement
|
|
1042
1145
|
* checks if at least one dash is included in tagName, and it's not the first char
|
|
@@ -1046,7 +1149,7 @@ function createDOMPurify() {
|
|
|
1046
1149
|
* @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
|
|
1047
1150
|
*/
|
|
1048
1151
|
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
|
|
1049
|
-
return tagName
|
|
1152
|
+
return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
|
|
1050
1153
|
};
|
|
1051
1154
|
/**
|
|
1052
1155
|
* _sanitizeAttributes
|
|
@@ -1061,9 +1164,7 @@ function createDOMPurify() {
|
|
|
1061
1164
|
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
1062
1165
|
/* Execute a hook if present */
|
|
1063
1166
|
_executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
|
|
1064
|
-
const
|
|
1065
|
-
attributes
|
|
1066
|
-
} = currentNode;
|
|
1167
|
+
const attributes = currentNode.attributes;
|
|
1067
1168
|
/* Check if we have attributes; if not we might have a text node */
|
|
1068
1169
|
if (!attributes || _isClobbered(currentNode)) {
|
|
1069
1170
|
return;
|
|
@@ -1079,11 +1180,9 @@ function createDOMPurify() {
|
|
|
1079
1180
|
/* Go backwards over all attributes; safely remove bad ones */
|
|
1080
1181
|
while (l--) {
|
|
1081
1182
|
const attr = attributes[l];
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
value: attrValue
|
|
1086
|
-
} = attr;
|
|
1183
|
+
const name = attr.name,
|
|
1184
|
+
namespaceURI = attr.namespaceURI,
|
|
1185
|
+
attrValue = attr.value;
|
|
1087
1186
|
const lcName = transformCaseFunc(name);
|
|
1088
1187
|
const initValue = attrValue;
|
|
1089
1188
|
let value = name === 'value' ? initValue : stringTrim(initValue);
|
|
@@ -1097,14 +1196,16 @@ function createDOMPurify() {
|
|
|
1097
1196
|
/* Full DOM Clobbering protection via namespace isolation,
|
|
1098
1197
|
* Prefix id and name attributes with `user-content-`
|
|
1099
1198
|
*/
|
|
1100
|
-
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
1199
|
+
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name') && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
|
|
1101
1200
|
// Remove the attribute with this value
|
|
1102
1201
|
_removeAttribute(name, currentNode);
|
|
1103
1202
|
// Prefix the value and later re-create the attribute with the sanitized value
|
|
1104
1203
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
1105
1204
|
}
|
|
1205
|
+
// Else: already prefixed, leave the attribute alone — the prefix is
|
|
1206
|
+
// itself the clobbering protection, and re-applying it is incorrect.
|
|
1106
1207
|
/* Work around a security issue with comments inside attributes */
|
|
1107
|
-
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title|textarea)/i, value)) {
|
|
1208
|
+
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
|
|
1108
1209
|
_removeAttribute(name, currentNode);
|
|
1109
1210
|
continue;
|
|
1110
1211
|
}
|
|
@@ -1129,7 +1230,7 @@ function createDOMPurify() {
|
|
|
1129
1230
|
}
|
|
1130
1231
|
/* Sanitize attribute content to be template-safe */
|
|
1131
1232
|
if (SAFE_FOR_TEMPLATES) {
|
|
1132
|
-
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
1233
|
+
arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
|
|
1133
1234
|
value = stringReplace(value, expr, ' ');
|
|
1134
1235
|
});
|
|
1135
1236
|
}
|
|
@@ -1183,7 +1284,7 @@ function createDOMPurify() {
|
|
|
1183
1284
|
*
|
|
1184
1285
|
* @param fragment to iterate over recursively
|
|
1185
1286
|
*/
|
|
1186
|
-
const
|
|
1287
|
+
const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) {
|
|
1187
1288
|
let shadowNode = null;
|
|
1188
1289
|
const shadowIterator = _createNodeIterator(fragment);
|
|
1189
1290
|
/* Execute a hook if present */
|
|
@@ -1197,12 +1298,55 @@ function createDOMPurify() {
|
|
|
1197
1298
|
_sanitizeAttributes(shadowNode);
|
|
1198
1299
|
/* Deep shadow DOM detected */
|
|
1199
1300
|
if (shadowNode.content instanceof DocumentFragment) {
|
|
1200
|
-
|
|
1301
|
+
_sanitizeShadowDOM2(shadowNode.content);
|
|
1201
1302
|
}
|
|
1202
1303
|
}
|
|
1203
1304
|
/* Execute a hook if present */
|
|
1204
1305
|
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
|
|
1205
1306
|
};
|
|
1307
|
+
/**
|
|
1308
|
+
* _sanitizeAttachedShadowRoots
|
|
1309
|
+
*
|
|
1310
|
+
* Walks `root` and feeds every attached shadow root we encounter into
|
|
1311
|
+
* the existing _sanitizeShadowDOM pipeline. The default node iterator
|
|
1312
|
+
* does not descend into shadow trees, so nodes inside an attached
|
|
1313
|
+
* shadow root would otherwise be skipped entirely.
|
|
1314
|
+
*
|
|
1315
|
+
* Two real input paths put attached shadow roots in front of us:
|
|
1316
|
+
* 1. IN_PLACE on a DOM node that already has shadow roots attached.
|
|
1317
|
+
* 2. DOM-node input where importNode(dirty, true) deep-clones the
|
|
1318
|
+
* shadow root because it was created with `clonable: true`.
|
|
1319
|
+
*
|
|
1320
|
+
* This pass runs once, up front, so the main iteration loop (and the
|
|
1321
|
+
* existing _sanitizeShadowDOM template-content recursion) stay
|
|
1322
|
+
* untouched — string-input paths are not affected.
|
|
1323
|
+
*
|
|
1324
|
+
* @param root the subtree root to walk for attached shadow roots
|
|
1325
|
+
*/
|
|
1326
|
+
const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) {
|
|
1327
|
+
if (root.nodeType === NODE_TYPE.element && root.shadowRoot instanceof DocumentFragment) {
|
|
1328
|
+
const sr = root.shadowRoot;
|
|
1329
|
+
// Recurse first so that nested shadow roots are reached even if
|
|
1330
|
+
// _sanitizeShadowDOM removes hosts at this level.
|
|
1331
|
+
_sanitizeAttachedShadowRoots2(sr);
|
|
1332
|
+
_sanitizeShadowDOM2(sr);
|
|
1333
|
+
}
|
|
1334
|
+
// Snapshot children before recursing. Sanitization of one subtree
|
|
1335
|
+
// (e.g. via an uponSanitizeShadowNode hook) may detach siblings,
|
|
1336
|
+
// and naive nextSibling traversal would silently skip the rest of
|
|
1337
|
+
// the list once a node is detached.
|
|
1338
|
+
const childNodes = root.childNodes;
|
|
1339
|
+
if (!childNodes) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const snapshot = [];
|
|
1343
|
+
arrayForEach(childNodes, child => {
|
|
1344
|
+
arrayPush(snapshot, child);
|
|
1345
|
+
});
|
|
1346
|
+
for (const child of snapshot) {
|
|
1347
|
+
_sanitizeAttachedShadowRoots2(child);
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1206
1350
|
// eslint-disable-next-line complexity
|
|
1207
1351
|
DOMPurify.sanitize = function (dirty) {
|
|
1208
1352
|
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -1219,13 +1363,9 @@ function createDOMPurify() {
|
|
|
1219
1363
|
}
|
|
1220
1364
|
/* Stringify, in case dirty is an object */
|
|
1221
1365
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
throw typeErrorCreate('dirty is not a string, aborting');
|
|
1226
|
-
}
|
|
1227
|
-
} else {
|
|
1228
|
-
throw typeErrorCreate('toString is not a function');
|
|
1366
|
+
dirty = stringifyValue(dirty);
|
|
1367
|
+
if (typeof dirty !== 'string') {
|
|
1368
|
+
throw typeErrorCreate('dirty is not a string, aborting');
|
|
1229
1369
|
}
|
|
1230
1370
|
}
|
|
1231
1371
|
/* Return dirty HTML if DOMPurify cannot run */
|
|
@@ -1244,12 +1384,16 @@ function createDOMPurify() {
|
|
|
1244
1384
|
}
|
|
1245
1385
|
if (IN_PLACE) {
|
|
1246
1386
|
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
|
1247
|
-
|
|
1248
|
-
|
|
1387
|
+
const nn = dirty.nodeName;
|
|
1388
|
+
if (typeof nn === 'string') {
|
|
1389
|
+
const tagName = transformCaseFunc(nn);
|
|
1249
1390
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1250
1391
|
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
1251
1392
|
}
|
|
1252
1393
|
}
|
|
1394
|
+
/* Sanitize attached shadow roots before the main iterator runs.
|
|
1395
|
+
The iterator does not descend into shadow trees. */
|
|
1396
|
+
_sanitizeAttachedShadowRoots2(dirty);
|
|
1253
1397
|
} else if (dirty instanceof Node) {
|
|
1254
1398
|
/* If dirty is a DOM element, append to an empty document to avoid
|
|
1255
1399
|
elements being stripped by the parser */
|
|
@@ -1264,6 +1408,10 @@ function createDOMPurify() {
|
|
|
1264
1408
|
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
1265
1409
|
body.appendChild(importedNode);
|
|
1266
1410
|
}
|
|
1411
|
+
/* Clonable shadow roots are deep-cloned by importNode(); sanitize
|
|
1412
|
+
them before the main iterator runs, since the iterator does not
|
|
1413
|
+
descend into shadow trees. */
|
|
1414
|
+
_sanitizeAttachedShadowRoots2(importedNode);
|
|
1267
1415
|
} else {
|
|
1268
1416
|
/* Exit directly if we have nothing to do */
|
|
1269
1417
|
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
|
|
@@ -1292,7 +1440,7 @@ function createDOMPurify() {
|
|
|
1292
1440
|
_sanitizeAttributes(currentNode);
|
|
1293
1441
|
/* Shadow DOM detected, sanitize it */
|
|
1294
1442
|
if (currentNode.content instanceof DocumentFragment) {
|
|
1295
|
-
|
|
1443
|
+
_sanitizeShadowDOM2(currentNode.content);
|
|
1296
1444
|
}
|
|
1297
1445
|
}
|
|
1298
1446
|
/* If we sanitized `dirty` in-place, return it. */
|
|
@@ -1301,6 +1449,14 @@ function createDOMPurify() {
|
|
|
1301
1449
|
}
|
|
1302
1450
|
/* Return sanitized string or DOM */
|
|
1303
1451
|
if (RETURN_DOM) {
|
|
1452
|
+
if (SAFE_FOR_TEMPLATES) {
|
|
1453
|
+
body.normalize();
|
|
1454
|
+
let html = body.innerHTML;
|
|
1455
|
+
arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
|
|
1456
|
+
html = stringReplace(html, expr, ' ');
|
|
1457
|
+
});
|
|
1458
|
+
body.innerHTML = html;
|
|
1459
|
+
}
|
|
1304
1460
|
if (RETURN_DOM_FRAGMENT) {
|
|
1305
1461
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
1306
1462
|
while (body.firstChild) {
|
|
@@ -1329,7 +1485,7 @@ function createDOMPurify() {
|
|
|
1329
1485
|
}
|
|
1330
1486
|
/* Sanitize final string template-safe */
|
|
1331
1487
|
if (SAFE_FOR_TEMPLATES) {
|
|
1332
|
-
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
|
1488
|
+
arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
|
|
1333
1489
|
serializedHTML = stringReplace(serializedHTML, expr, ' ');
|
|
1334
1490
|
});
|
|
1335
1491
|
}
|