@bigbinary/neeto-commons-frontend 2.1.34 → 2.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/initializers.cjs.js +1783 -1753
- package/initializers.cjs.js.map +1 -1
- package/initializers.js +1783 -1753
- package/initializers.js.map +1 -1
- package/package.json +1 -1
- package/utils.cjs.js +9 -0
- package/utils.cjs.js.map +1 -1
- package/utils.d.ts +12 -0
- package/utils.js +9 -1
- package/utils.js.map +1 -1
package/initializers.cjs.js
CHANGED
|
@@ -64,6 +64,8 @@ var HEADERS_KEYS = {
|
|
|
64
64
|
contentType: "Content-Type",
|
|
65
65
|
accept: "Accept"
|
|
66
66
|
};
|
|
67
|
+
var LOWERCASED = "__LOWERCASED__";
|
|
68
|
+
var ANY_CASE = "anyCase";
|
|
67
69
|
|
|
68
70
|
var shouldNot = function shouldNot(skip) {
|
|
69
71
|
return _typeof$1(skip) === "object" || !skip;
|
|
@@ -251,2135 +253,2166 @@ function initializeGlobalProps() {
|
|
|
251
253
|
pure.deepFreezeObject(window.globalProps);
|
|
252
254
|
}
|
|
253
255
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
isFrozen,
|
|
260
|
-
getPrototypeOf,
|
|
261
|
-
getOwnPropertyDescriptor
|
|
262
|
-
} = Object;
|
|
263
|
-
let {
|
|
264
|
-
freeze,
|
|
265
|
-
seal,
|
|
266
|
-
create
|
|
267
|
-
} = Object; // eslint-disable-line import/no-mutable-exports
|
|
256
|
+
function _classCallCheck(instance, Constructor) {
|
|
257
|
+
if (!(instance instanceof Constructor)) {
|
|
258
|
+
throw new TypeError("Cannot call a class as a function");
|
|
259
|
+
}
|
|
260
|
+
}
|
|
268
261
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
construct
|
|
272
|
-
} = typeof Reflect !== 'undefined' && Reflect;
|
|
262
|
+
function _typeof(obj) {
|
|
263
|
+
"@babel/helpers - typeof";
|
|
273
264
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
265
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
|
|
266
|
+
return typeof obj;
|
|
267
|
+
} : function (obj) {
|
|
268
|
+
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
269
|
+
}, _typeof(obj);
|
|
278
270
|
}
|
|
279
271
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
272
|
+
function _toPrimitive(input, hint) {
|
|
273
|
+
if (_typeof(input) !== "object" || input === null) return input;
|
|
274
|
+
var prim = input[Symbol.toPrimitive];
|
|
275
|
+
if (prim !== undefined) {
|
|
276
|
+
var res = prim.call(input, hint || "default");
|
|
277
|
+
if (_typeof(res) !== "object") return res;
|
|
278
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
279
|
+
}
|
|
280
|
+
return (hint === "string" ? String : Number)(input);
|
|
284
281
|
}
|
|
285
282
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
};
|
|
283
|
+
function _toPropertyKey(arg) {
|
|
284
|
+
var key = _toPrimitive(arg, "string");
|
|
285
|
+
return _typeof(key) === "symbol" ? key : String(key);
|
|
290
286
|
}
|
|
291
287
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
288
|
+
function _defineProperties(target, props) {
|
|
289
|
+
for (var i = 0; i < props.length; i++) {
|
|
290
|
+
var descriptor = props[i];
|
|
291
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
292
|
+
descriptor.configurable = true;
|
|
293
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
294
|
+
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
|
|
295
|
+
}
|
|
296
296
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const stringReplace = unapply(String.prototype.replace);
|
|
305
|
-
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
306
|
-
const stringTrim = unapply(String.prototype.trim);
|
|
307
|
-
const regExpTest = unapply(RegExp.prototype.test);
|
|
308
|
-
const typeErrorCreate = unconstruct(TypeError);
|
|
309
|
-
function unapply(func) {
|
|
310
|
-
return function (thisArg) {
|
|
311
|
-
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
312
|
-
args[_key - 1] = arguments[_key];
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return apply(func, thisArg, args);
|
|
316
|
-
};
|
|
297
|
+
function _createClass(Constructor, protoProps, staticProps) {
|
|
298
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
299
|
+
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
300
|
+
Object.defineProperty(Constructor, "prototype", {
|
|
301
|
+
writable: false
|
|
302
|
+
});
|
|
303
|
+
return Constructor;
|
|
317
304
|
}
|
|
318
|
-
function unconstruct(func) {
|
|
319
|
-
return function () {
|
|
320
|
-
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
321
|
-
args[_key2] = arguments[_key2];
|
|
322
|
-
}
|
|
323
305
|
|
|
324
|
-
|
|
325
|
-
|
|
306
|
+
var arr = [];
|
|
307
|
+
var each = arr.forEach;
|
|
308
|
+
var slice = arr.slice;
|
|
309
|
+
function defaults(obj) {
|
|
310
|
+
each.call(slice.call(arguments, 1), function (source) {
|
|
311
|
+
if (source) {
|
|
312
|
+
for (var prop in source) {
|
|
313
|
+
if (obj[prop] === undefined) obj[prop] = source[prop];
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
return obj;
|
|
326
318
|
}
|
|
327
|
-
/* Add properties to a lookup table */
|
|
328
|
-
|
|
329
|
-
function addToSet(set, array, transformCaseFunc) {
|
|
330
|
-
var _transformCaseFunc;
|
|
331
319
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
320
|
+
// eslint-disable-next-line no-control-regex
|
|
321
|
+
var fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
|
|
322
|
+
var serializeCookie = function serializeCookie(name, val, options) {
|
|
323
|
+
var opt = options || {};
|
|
324
|
+
opt.path = opt.path || '/';
|
|
325
|
+
var value = encodeURIComponent(val);
|
|
326
|
+
var str = "".concat(name, "=").concat(value);
|
|
327
|
+
if (opt.maxAge > 0) {
|
|
328
|
+
var maxAge = opt.maxAge - 0;
|
|
329
|
+
if (Number.isNaN(maxAge)) throw new Error('maxAge should be a Number');
|
|
330
|
+
str += "; Max-Age=".concat(Math.floor(maxAge));
|
|
339
331
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
while (l--) {
|
|
344
|
-
let element = array[l];
|
|
345
|
-
|
|
346
|
-
if (typeof element === 'string') {
|
|
347
|
-
const lcElement = transformCaseFunc(element);
|
|
348
|
-
|
|
349
|
-
if (lcElement !== element) {
|
|
350
|
-
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
351
|
-
if (!isFrozen(array)) {
|
|
352
|
-
array[l] = lcElement;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
element = lcElement;
|
|
356
|
-
}
|
|
332
|
+
if (opt.domain) {
|
|
333
|
+
if (!fieldContentRegExp.test(opt.domain)) {
|
|
334
|
+
throw new TypeError('option domain is invalid');
|
|
357
335
|
}
|
|
358
|
-
|
|
359
|
-
set[element] = true;
|
|
336
|
+
str += "; Domain=".concat(opt.domain);
|
|
360
337
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
function clone(object) {
|
|
367
|
-
const newObject = create(null);
|
|
368
|
-
|
|
369
|
-
for (const [property, value] of entries(object)) {
|
|
370
|
-
newObject[property] = value;
|
|
338
|
+
if (opt.path) {
|
|
339
|
+
if (!fieldContentRegExp.test(opt.path)) {
|
|
340
|
+
throw new TypeError('option path is invalid');
|
|
341
|
+
}
|
|
342
|
+
str += "; Path=".concat(opt.path);
|
|
371
343
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
/* This method automatically checks if the prop is function
|
|
376
|
-
* or getter and behaves accordingly. */
|
|
377
|
-
|
|
378
|
-
function lookupGetter(object, prop) {
|
|
379
|
-
while (object !== null) {
|
|
380
|
-
const desc = getOwnPropertyDescriptor(object, prop);
|
|
381
|
-
|
|
382
|
-
if (desc) {
|
|
383
|
-
if (desc.get) {
|
|
384
|
-
return unapply(desc.get);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
if (typeof desc.value === 'function') {
|
|
388
|
-
return unapply(desc.value);
|
|
389
|
-
}
|
|
344
|
+
if (opt.expires) {
|
|
345
|
+
if (typeof opt.expires.toUTCString !== 'function') {
|
|
346
|
+
throw new TypeError('option expires is invalid');
|
|
390
347
|
}
|
|
391
|
-
|
|
392
|
-
object = getPrototypeOf(object);
|
|
348
|
+
str += "; Expires=".concat(opt.expires.toUTCString());
|
|
393
349
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
350
|
+
if (opt.httpOnly) str += '; HttpOnly';
|
|
351
|
+
if (opt.secure) str += '; Secure';
|
|
352
|
+
if (opt.sameSite) {
|
|
353
|
+
var sameSite = typeof opt.sameSite === 'string' ? opt.sameSite.toLowerCase() : opt.sameSite;
|
|
354
|
+
switch (sameSite) {
|
|
355
|
+
case true:
|
|
356
|
+
str += '; SameSite=Strict';
|
|
357
|
+
break;
|
|
358
|
+
case 'lax':
|
|
359
|
+
str += '; SameSite=Lax';
|
|
360
|
+
break;
|
|
361
|
+
case 'strict':
|
|
362
|
+
str += '; SameSite=Strict';
|
|
363
|
+
break;
|
|
364
|
+
case 'none':
|
|
365
|
+
str += '; SameSite=None';
|
|
366
|
+
break;
|
|
367
|
+
default:
|
|
368
|
+
throw new TypeError('option sameSite is invalid');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return str;
|
|
372
|
+
};
|
|
373
|
+
var cookie = {
|
|
374
|
+
create: function create(name, value, minutes, domain) {
|
|
375
|
+
var cookieOptions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {
|
|
376
|
+
path: '/',
|
|
377
|
+
sameSite: 'strict'
|
|
378
|
+
};
|
|
379
|
+
if (minutes) {
|
|
380
|
+
cookieOptions.expires = new Date();
|
|
381
|
+
cookieOptions.expires.setTime(cookieOptions.expires.getTime() + minutes * 60 * 1000);
|
|
382
|
+
}
|
|
383
|
+
if (domain) cookieOptions.domain = domain;
|
|
384
|
+
document.cookie = serializeCookie(name, encodeURIComponent(value), cookieOptions);
|
|
385
|
+
},
|
|
386
|
+
read: function read(name) {
|
|
387
|
+
var nameEQ = "".concat(name, "=");
|
|
388
|
+
var ca = document.cookie.split(';');
|
|
389
|
+
for (var i = 0; i < ca.length; i++) {
|
|
390
|
+
var c = ca[i];
|
|
391
|
+
while (c.charAt(0) === ' ') {
|
|
392
|
+
c = c.substring(1, c.length);
|
|
393
|
+
}
|
|
394
|
+
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
|
|
395
|
+
}
|
|
397
396
|
return null;
|
|
397
|
+
},
|
|
398
|
+
remove: function remove(name) {
|
|
399
|
+
this.create(name, '', -1);
|
|
398
400
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
416
|
-
const text = freeze(['#text']);
|
|
417
|
-
|
|
418
|
-
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
|
|
419
|
-
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
420
|
-
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
|
|
421
|
-
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
422
|
-
|
|
423
|
-
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
424
|
-
|
|
425
|
-
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
|
426
|
-
const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
|
|
427
|
-
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
|
|
428
|
-
|
|
429
|
-
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
430
|
-
|
|
431
|
-
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
432
|
-
);
|
|
433
|
-
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
|
434
|
-
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
435
|
-
);
|
|
436
|
-
const DOCTYPE_NAME = seal(/^html$/i);
|
|
437
|
-
|
|
438
|
-
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
|
439
|
-
__proto__: null,
|
|
440
|
-
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
441
|
-
ERB_EXPR: ERB_EXPR,
|
|
442
|
-
TMPLIT_EXPR: TMPLIT_EXPR,
|
|
443
|
-
DATA_ATTR: DATA_ATTR,
|
|
444
|
-
ARIA_ATTR: ARIA_ATTR,
|
|
445
|
-
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
446
|
-
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
|
447
|
-
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
|
448
|
-
DOCTYPE_NAME: DOCTYPE_NAME
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
const getGlobal = () => typeof window === 'undefined' ? null : window;
|
|
452
|
-
/**
|
|
453
|
-
* Creates a no-op policy for internal use only.
|
|
454
|
-
* Don't export this function outside this module!
|
|
455
|
-
* @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
|
|
456
|
-
* @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
|
|
457
|
-
* @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
|
|
458
|
-
* are not supported or creating the policy failed).
|
|
459
|
-
*/
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
|
|
463
|
-
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
|
464
|
-
return null;
|
|
465
|
-
} // Allow the callers to control the unique policy name
|
|
466
|
-
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
|
467
|
-
// Policy creation with duplicate names throws in Trusted Types.
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
let suffix = null;
|
|
471
|
-
const ATTR_NAME = 'data-tt-policy-suffix';
|
|
472
|
-
|
|
473
|
-
if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
|
|
474
|
-
suffix = purifyHostElement.getAttribute(ATTR_NAME);
|
|
401
|
+
};
|
|
402
|
+
var cookie$1 = {
|
|
403
|
+
name: 'cookie',
|
|
404
|
+
lookup: function lookup(options) {
|
|
405
|
+
var found;
|
|
406
|
+
if (options.lookupCookie && typeof document !== 'undefined') {
|
|
407
|
+
var c = cookie.read(options.lookupCookie);
|
|
408
|
+
if (c) found = c;
|
|
409
|
+
}
|
|
410
|
+
return found;
|
|
411
|
+
},
|
|
412
|
+
cacheUserLanguage: function cacheUserLanguage(lng, options) {
|
|
413
|
+
if (options.lookupCookie && typeof document !== 'undefined') {
|
|
414
|
+
cookie.create(options.lookupCookie, lng, options.cookieMinutes, options.cookieDomain, options.cookieOptions);
|
|
415
|
+
}
|
|
475
416
|
}
|
|
417
|
+
};
|
|
476
418
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
createScriptURL(scriptUrl) {
|
|
486
|
-
return scriptUrl;
|
|
419
|
+
var querystring = {
|
|
420
|
+
name: 'querystring',
|
|
421
|
+
lookup: function lookup(options) {
|
|
422
|
+
var found;
|
|
423
|
+
if (typeof window !== 'undefined') {
|
|
424
|
+
var search = window.location.search;
|
|
425
|
+
if (!window.location.search && window.location.hash && window.location.hash.indexOf('?') > -1) {
|
|
426
|
+
search = window.location.hash.substring(window.location.hash.indexOf('?'));
|
|
487
427
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
428
|
+
var query = search.substring(1);
|
|
429
|
+
var params = query.split('&');
|
|
430
|
+
for (var i = 0; i < params.length; i++) {
|
|
431
|
+
var pos = params[i].indexOf('=');
|
|
432
|
+
if (pos > 0) {
|
|
433
|
+
var key = params[i].substring(0, pos);
|
|
434
|
+
if (key === options.lookupQuerystring) {
|
|
435
|
+
found = params[i].substring(pos + 1);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return found;
|
|
496
441
|
}
|
|
497
442
|
};
|
|
498
443
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
DOMPurify.version = '3.0.3';
|
|
510
|
-
/**
|
|
511
|
-
* Array of elements that DOMPurify removed during sanitation.
|
|
512
|
-
* Empty if nothing was removed.
|
|
513
|
-
*/
|
|
514
|
-
|
|
515
|
-
DOMPurify.removed = [];
|
|
516
|
-
|
|
517
|
-
if (!window || !window.document || window.document.nodeType !== 9) {
|
|
518
|
-
// Not running in a browser, provide a factory function
|
|
519
|
-
// so that you can pass your own Window
|
|
520
|
-
DOMPurify.isSupported = false;
|
|
521
|
-
return DOMPurify;
|
|
444
|
+
var hasLocalStorageSupport = null;
|
|
445
|
+
var localStorageAvailable = function localStorageAvailable() {
|
|
446
|
+
if (hasLocalStorageSupport !== null) return hasLocalStorageSupport;
|
|
447
|
+
try {
|
|
448
|
+
hasLocalStorageSupport = window !== 'undefined' && window.localStorage !== null;
|
|
449
|
+
var testKey = 'i18next.translate.boo';
|
|
450
|
+
window.localStorage.setItem(testKey, 'foo');
|
|
451
|
+
window.localStorage.removeItem(testKey);
|
|
452
|
+
} catch (e) {
|
|
453
|
+
hasLocalStorageSupport = false;
|
|
522
454
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
trustedTypes
|
|
539
|
-
} = window;
|
|
540
|
-
const ElementPrototype = Element.prototype;
|
|
541
|
-
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
|
542
|
-
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
|
543
|
-
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
|
544
|
-
const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); // As per issue #47, the web-components registry is inherited by a
|
|
545
|
-
// new document created via createHTMLDocument. As per the spec
|
|
546
|
-
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
547
|
-
// a new empty registry is used when creating a template contents owner
|
|
548
|
-
// document, so we use that as our parent document to ensure nothing
|
|
549
|
-
// is inherited.
|
|
550
|
-
|
|
551
|
-
if (typeof HTMLTemplateElement === 'function') {
|
|
552
|
-
const template = document.createElement('template');
|
|
553
|
-
|
|
554
|
-
if (template.content && template.content.ownerDocument) {
|
|
555
|
-
document = template.content.ownerDocument;
|
|
455
|
+
return hasLocalStorageSupport;
|
|
456
|
+
};
|
|
457
|
+
var localStorage = {
|
|
458
|
+
name: 'localStorage',
|
|
459
|
+
lookup: function lookup(options) {
|
|
460
|
+
var found;
|
|
461
|
+
if (options.lookupLocalStorage && localStorageAvailable()) {
|
|
462
|
+
var lng = window.localStorage.getItem(options.lookupLocalStorage);
|
|
463
|
+
if (lng) found = lng;
|
|
464
|
+
}
|
|
465
|
+
return found;
|
|
466
|
+
},
|
|
467
|
+
cacheUserLanguage: function cacheUserLanguage(lng, options) {
|
|
468
|
+
if (options.lookupLocalStorage && localStorageAvailable()) {
|
|
469
|
+
window.localStorage.setItem(options.lookupLocalStorage, lng);
|
|
556
470
|
}
|
|
557
471
|
}
|
|
472
|
+
};
|
|
558
473
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
TMPLIT_EXPR,
|
|
580
|
-
DATA_ATTR,
|
|
581
|
-
ARIA_ATTR,
|
|
582
|
-
IS_SCRIPT_OR_DATA,
|
|
583
|
-
ATTR_WHITESPACE
|
|
584
|
-
} = EXPRESSIONS;
|
|
585
|
-
let {
|
|
586
|
-
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
|
587
|
-
} = EXPRESSIONS;
|
|
588
|
-
/**
|
|
589
|
-
* We consider the elements and attributes below to be safe. Ideally
|
|
590
|
-
* don't add any new ones but feel free to remove unwanted ones.
|
|
591
|
-
*/
|
|
592
|
-
|
|
593
|
-
/* allowed element names */
|
|
594
|
-
|
|
595
|
-
let ALLOWED_TAGS = null;
|
|
596
|
-
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
|
|
597
|
-
/* Allowed attribute names */
|
|
598
|
-
|
|
599
|
-
let ALLOWED_ATTR = null;
|
|
600
|
-
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
|
601
|
-
/*
|
|
602
|
-
* Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
|
|
603
|
-
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
|
604
|
-
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
|
|
605
|
-
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
|
606
|
-
*/
|
|
607
|
-
|
|
608
|
-
let CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
|
|
609
|
-
tagNameCheck: {
|
|
610
|
-
writable: true,
|
|
611
|
-
configurable: false,
|
|
612
|
-
enumerable: true,
|
|
613
|
-
value: null
|
|
614
|
-
},
|
|
615
|
-
attributeNameCheck: {
|
|
616
|
-
writable: true,
|
|
617
|
-
configurable: false,
|
|
618
|
-
enumerable: true,
|
|
619
|
-
value: null
|
|
620
|
-
},
|
|
621
|
-
allowCustomizedBuiltInElements: {
|
|
622
|
-
writable: true,
|
|
623
|
-
configurable: false,
|
|
624
|
-
enumerable: true,
|
|
625
|
-
value: false
|
|
474
|
+
var hasSessionStorageSupport = null;
|
|
475
|
+
var sessionStorageAvailable = function sessionStorageAvailable() {
|
|
476
|
+
if (hasSessionStorageSupport !== null) return hasSessionStorageSupport;
|
|
477
|
+
try {
|
|
478
|
+
hasSessionStorageSupport = window !== 'undefined' && window.sessionStorage !== null;
|
|
479
|
+
var testKey = 'i18next.translate.boo';
|
|
480
|
+
window.sessionStorage.setItem(testKey, 'foo');
|
|
481
|
+
window.sessionStorage.removeItem(testKey);
|
|
482
|
+
} catch (e) {
|
|
483
|
+
hasSessionStorageSupport = false;
|
|
484
|
+
}
|
|
485
|
+
return hasSessionStorageSupport;
|
|
486
|
+
};
|
|
487
|
+
var sessionStorage = {
|
|
488
|
+
name: 'sessionStorage',
|
|
489
|
+
lookup: function lookup(options) {
|
|
490
|
+
var found;
|
|
491
|
+
if (options.lookupSessionStorage && sessionStorageAvailable()) {
|
|
492
|
+
var lng = window.sessionStorage.getItem(options.lookupSessionStorage);
|
|
493
|
+
if (lng) found = lng;
|
|
626
494
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
let ALLOW_ARIA_ATTR = true;
|
|
637
|
-
/* Decide if custom data attributes are okay */
|
|
638
|
-
|
|
639
|
-
let ALLOW_DATA_ATTR = true;
|
|
640
|
-
/* Decide if unknown protocols are okay */
|
|
641
|
-
|
|
642
|
-
let ALLOW_UNKNOWN_PROTOCOLS = false;
|
|
643
|
-
/* Decide if self-closing tags in attributes are allowed.
|
|
644
|
-
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
|
645
|
-
|
|
646
|
-
let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
|
647
|
-
/* Output should be safe for common template engines.
|
|
648
|
-
* This means, DOMPurify removes data attributes, mustaches and ERB
|
|
649
|
-
*/
|
|
650
|
-
|
|
651
|
-
let SAFE_FOR_TEMPLATES = false;
|
|
652
|
-
/* Decide if document with <html>... should be returned */
|
|
653
|
-
|
|
654
|
-
let WHOLE_DOCUMENT = false;
|
|
655
|
-
/* Track whether config is already set on this instance of DOMPurify. */
|
|
656
|
-
|
|
657
|
-
let SET_CONFIG = false;
|
|
658
|
-
/* Decide if all elements (e.g. style, script) must be children of
|
|
659
|
-
* document.body. By default, browsers might move them to document.head */
|
|
660
|
-
|
|
661
|
-
let FORCE_BODY = false;
|
|
662
|
-
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
663
|
-
* string (or a TrustedHTML object if Trusted Types are supported).
|
|
664
|
-
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
|
665
|
-
*/
|
|
666
|
-
|
|
667
|
-
let RETURN_DOM = false;
|
|
668
|
-
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
669
|
-
* string (or a TrustedHTML object if Trusted Types are supported) */
|
|
670
|
-
|
|
671
|
-
let RETURN_DOM_FRAGMENT = false;
|
|
672
|
-
/* Try to return a Trusted Type object instead of a string, return a string in
|
|
673
|
-
* case Trusted Types are not supported */
|
|
674
|
-
|
|
675
|
-
let RETURN_TRUSTED_TYPE = false;
|
|
676
|
-
/* Output should be free from DOM clobbering attacks?
|
|
677
|
-
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
|
678
|
-
*/
|
|
495
|
+
return found;
|
|
496
|
+
},
|
|
497
|
+
cacheUserLanguage: function cacheUserLanguage(lng, options) {
|
|
498
|
+
if (options.lookupSessionStorage && sessionStorageAvailable()) {
|
|
499
|
+
window.sessionStorage.setItem(options.lookupSessionStorage, lng);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
};
|
|
679
503
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
504
|
+
var navigator$1 = {
|
|
505
|
+
name: 'navigator',
|
|
506
|
+
lookup: function lookup(options) {
|
|
507
|
+
var found = [];
|
|
508
|
+
if (typeof navigator !== 'undefined') {
|
|
509
|
+
if (navigator.languages) {
|
|
510
|
+
// chrome only; not an array, so can't use .push.apply instead of iterating
|
|
511
|
+
for (var i = 0; i < navigator.languages.length; i++) {
|
|
512
|
+
found.push(navigator.languages[i]);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (navigator.userLanguage) {
|
|
516
|
+
found.push(navigator.userLanguage);
|
|
517
|
+
}
|
|
518
|
+
if (navigator.language) {
|
|
519
|
+
found.push(navigator.language);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return found.length > 0 ? found : undefined;
|
|
523
|
+
}
|
|
524
|
+
};
|
|
694
525
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
526
|
+
var htmlTag = {
|
|
527
|
+
name: 'htmlTag',
|
|
528
|
+
lookup: function lookup(options) {
|
|
529
|
+
var found;
|
|
530
|
+
var htmlTag = options.htmlTag || (typeof document !== 'undefined' ? document.documentElement : null);
|
|
531
|
+
if (htmlTag && typeof htmlTag.getAttribute === 'function') {
|
|
532
|
+
found = htmlTag.getAttribute('lang');
|
|
533
|
+
}
|
|
534
|
+
return found;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
698
537
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
538
|
+
var path = {
|
|
539
|
+
name: 'path',
|
|
540
|
+
lookup: function lookup(options) {
|
|
541
|
+
var found;
|
|
542
|
+
if (typeof window !== 'undefined') {
|
|
543
|
+
var language = window.location.pathname.match(/\/([a-zA-Z-]*)/g);
|
|
544
|
+
if (language instanceof Array) {
|
|
545
|
+
if (typeof options.lookupFromPathIndex === 'number') {
|
|
546
|
+
if (typeof language[options.lookupFromPathIndex] !== 'string') {
|
|
547
|
+
return undefined;
|
|
548
|
+
}
|
|
549
|
+
found = language[options.lookupFromPathIndex].replace('/', '');
|
|
550
|
+
} else {
|
|
551
|
+
found = language[0].replace('/', '');
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return found;
|
|
556
|
+
}
|
|
557
|
+
};
|
|
702
558
|
|
|
703
|
-
|
|
704
|
-
|
|
559
|
+
var subdomain = {
|
|
560
|
+
name: 'subdomain',
|
|
561
|
+
lookup: function lookup(options) {
|
|
562
|
+
// If given get the subdomain index else 1
|
|
563
|
+
var lookupFromSubdomainIndex = typeof options.lookupFromSubdomainIndex === 'number' ? options.lookupFromSubdomainIndex + 1 : 1;
|
|
564
|
+
// get all matches if window.location. is existing
|
|
565
|
+
// first item of match is the match itself and the second is the first group macht which sould be the first subdomain match
|
|
566
|
+
// is the hostname no public domain get the or option of localhost
|
|
567
|
+
var language = typeof window !== 'undefined' && window.location && window.location.hostname && window.location.hostname.match(/^(\w{2,5})\.(([a-z0-9-]{1,63}\.[a-z]{2,6})|localhost)/i);
|
|
705
568
|
|
|
706
|
-
|
|
707
|
-
|
|
569
|
+
// if there is no match (null) return undefined
|
|
570
|
+
if (!language) return undefined;
|
|
571
|
+
// return the given group match
|
|
572
|
+
return language[lookupFromSubdomainIndex];
|
|
573
|
+
}
|
|
574
|
+
};
|
|
708
575
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
576
|
+
function getDefaults() {
|
|
577
|
+
return {
|
|
578
|
+
order: ['querystring', 'cookie', 'localStorage', 'sessionStorage', 'navigator', 'htmlTag'],
|
|
579
|
+
lookupQuerystring: 'lng',
|
|
580
|
+
lookupCookie: 'i18next',
|
|
581
|
+
lookupLocalStorage: 'i18nextLng',
|
|
582
|
+
lookupSessionStorage: 'i18nextLng',
|
|
583
|
+
// cache user language
|
|
584
|
+
caches: ['localStorage'],
|
|
585
|
+
excludeCacheFor: ['cimode'],
|
|
586
|
+
// cookieMinutes: 10,
|
|
587
|
+
// cookieDomain: 'myDomain'
|
|
712
588
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
589
|
+
convertDetectedLanguage: function convertDetectedLanguage(l) {
|
|
590
|
+
return l;
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
var Browser = /*#__PURE__*/function () {
|
|
595
|
+
function Browser(services) {
|
|
596
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
597
|
+
_classCallCheck(this, Browser);
|
|
598
|
+
this.type = 'languageDetector';
|
|
599
|
+
this.detectors = {};
|
|
600
|
+
this.init(services, options);
|
|
601
|
+
}
|
|
602
|
+
_createClass(Browser, [{
|
|
603
|
+
key: "init",
|
|
604
|
+
value: function init(services) {
|
|
605
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
606
|
+
var i18nOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
607
|
+
this.services = services || {
|
|
608
|
+
languageUtils: {}
|
|
609
|
+
}; // this way the language detector can be used without i18next
|
|
610
|
+
this.options = defaults(options, this.options || {}, getDefaults());
|
|
611
|
+
if (typeof this.options.convertDetectedLanguage === 'string' && this.options.convertDetectedLanguage.indexOf('15897') > -1) {
|
|
612
|
+
this.options.convertDetectedLanguage = function (l) {
|
|
613
|
+
return l.replace('-', '_');
|
|
614
|
+
};
|
|
615
|
+
}
|
|
716
616
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
617
|
+
// backwards compatibility
|
|
618
|
+
if (this.options.lookupFromUrlIndex) this.options.lookupFromPathIndex = this.options.lookupFromUrlIndex;
|
|
619
|
+
this.i18nOptions = i18nOptions;
|
|
620
|
+
this.addDetector(cookie$1);
|
|
621
|
+
this.addDetector(querystring);
|
|
622
|
+
this.addDetector(localStorage);
|
|
623
|
+
this.addDetector(sessionStorage);
|
|
624
|
+
this.addDetector(navigator$1);
|
|
625
|
+
this.addDetector(htmlTag);
|
|
626
|
+
this.addDetector(path);
|
|
627
|
+
this.addDetector(subdomain);
|
|
628
|
+
}
|
|
629
|
+
}, {
|
|
630
|
+
key: "addDetector",
|
|
631
|
+
value: function addDetector(detector) {
|
|
632
|
+
this.detectors[detector.name] = detector;
|
|
633
|
+
}
|
|
634
|
+
}, {
|
|
635
|
+
key: "detect",
|
|
636
|
+
value: function detect(detectionOrder) {
|
|
637
|
+
var _this = this;
|
|
638
|
+
if (!detectionOrder) detectionOrder = this.options.order;
|
|
639
|
+
var detected = [];
|
|
640
|
+
detectionOrder.forEach(function (detectorName) {
|
|
641
|
+
if (_this.detectors[detectorName]) {
|
|
642
|
+
var lookup = _this.detectors[detectorName].lookup(_this.options);
|
|
643
|
+
if (lookup && typeof lookup === 'string') lookup = [lookup];
|
|
644
|
+
if (lookup) detected = detected.concat(lookup);
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
detected = detected.map(function (d) {
|
|
648
|
+
return _this.options.convertDetectedLanguage(d);
|
|
649
|
+
});
|
|
650
|
+
if (this.services.languageUtils.getBestMatchFromCodes) return detected; // new i18next v19.5.0
|
|
651
|
+
return detected.length > 0 ? detected[0] : null; // a little backward compatibility
|
|
652
|
+
}
|
|
653
|
+
}, {
|
|
654
|
+
key: "cacheUserLanguage",
|
|
655
|
+
value: function cacheUserLanguage(lng, caches) {
|
|
656
|
+
var _this2 = this;
|
|
657
|
+
if (!caches) caches = this.options.caches;
|
|
658
|
+
if (!caches) return;
|
|
659
|
+
if (this.options.excludeCacheFor && this.options.excludeCacheFor.indexOf(lng) > -1) return;
|
|
660
|
+
caches.forEach(function (cacheName) {
|
|
661
|
+
if (_this2.detectors[cacheName]) _this2.detectors[cacheName].cacheUserLanguage(lng, _this2.options);
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
}]);
|
|
665
|
+
return Browser;
|
|
666
|
+
}();
|
|
667
|
+
Browser.type = 'languageDetector';
|
|
723
668
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
669
|
+
function _arrayWithHoles(arr) {
|
|
670
|
+
if (Array.isArray(arr)) return arr;
|
|
671
|
+
}
|
|
727
672
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
673
|
+
function _iterableToArrayLimit(arr, i) {
|
|
674
|
+
var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"];
|
|
675
|
+
if (null != _i) {
|
|
676
|
+
var _s,
|
|
677
|
+
_e,
|
|
678
|
+
_x,
|
|
679
|
+
_r,
|
|
680
|
+
_arr = [],
|
|
681
|
+
_n = !0,
|
|
682
|
+
_d = !1;
|
|
683
|
+
try {
|
|
684
|
+
if (_x = (_i = _i.call(arr)).next, 0 === i) {
|
|
685
|
+
if (Object(_i) !== _i) return;
|
|
686
|
+
_n = !1;
|
|
687
|
+
} else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0);
|
|
688
|
+
} catch (err) {
|
|
689
|
+
_d = !0, _e = err;
|
|
690
|
+
} finally {
|
|
691
|
+
try {
|
|
692
|
+
if (!_n && null != _i["return"] && (_r = _i["return"](), Object(_r) !== _r)) return;
|
|
693
|
+
} finally {
|
|
694
|
+
if (_d) throw _e;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
return _arr;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
731
700
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
701
|
+
function _arrayLikeToArray(arr, len) {
|
|
702
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
703
|
+
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
|
704
|
+
return arr2;
|
|
705
|
+
}
|
|
737
706
|
|
|
738
|
-
|
|
739
|
-
|
|
707
|
+
function _unsupportedIterableToArray(o, minLen) {
|
|
708
|
+
if (!o) return;
|
|
709
|
+
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
|
710
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
711
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
712
|
+
if (n === "Map" || n === "Set") return Array.from(o);
|
|
713
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
714
|
+
}
|
|
740
715
|
|
|
741
|
-
|
|
716
|
+
function _nonIterableRest() {
|
|
717
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
718
|
+
}
|
|
742
719
|
|
|
743
|
-
|
|
720
|
+
function _slicedToArray(arr, i) {
|
|
721
|
+
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
|
722
|
+
}
|
|
744
723
|
|
|
745
|
-
|
|
746
|
-
|
|
724
|
+
var getter = function getter(key) {
|
|
725
|
+
return function () {
|
|
726
|
+
return i18n__default["default"].t("taxonomyDefaultLabels.".concat(key));
|
|
747
727
|
};
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
if (
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
728
|
+
};
|
|
729
|
+
var replaceNullValuesWithGetter = function replaceNullValuesWithGetter(inputObject) {
|
|
730
|
+
var parentKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
|
|
731
|
+
var result = {};
|
|
732
|
+
for (var _i = 0, _Object$entries = Object.entries(inputObject); _i < _Object$entries.length; _i++) {
|
|
733
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
734
|
+
key = _Object$entries$_i[0],
|
|
735
|
+
value = _Object$entries$_i[1];
|
|
736
|
+
var transKey = parentKey ? "".concat(parentKey, ".").concat(key) : key;
|
|
737
|
+
if (value === null) {
|
|
738
|
+
Object.defineProperty(result, key, {
|
|
739
|
+
get: getter(transKey)
|
|
740
|
+
});
|
|
741
|
+
} else if (_typeof$1(value) === "object") {
|
|
742
|
+
result[key] = replaceNullValuesWithGetter(value, transKey);
|
|
743
|
+
} else {
|
|
744
|
+
result[key] = value;
|
|
765
745
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
cfg = clone(cfg);
|
|
770
|
-
PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes
|
|
771
|
-
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
772
|
-
|
|
773
|
-
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
|
774
|
-
/* Set configuration parameters */
|
|
746
|
+
}
|
|
747
|
+
return result;
|
|
748
|
+
};
|
|
775
749
|
|
|
776
|
-
|
|
777
|
-
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
|
778
|
-
ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
|
779
|
-
URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent
|
|
780
|
-
cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent
|
|
781
|
-
transformCaseFunc // eslint-disable-line indent
|
|
782
|
-
) // eslint-disable-line indent
|
|
783
|
-
: DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
784
|
-
DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent
|
|
785
|
-
cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent
|
|
786
|
-
transformCaseFunc // eslint-disable-line indent
|
|
787
|
-
) // eslint-disable-line indent
|
|
788
|
-
: DEFAULT_DATA_URI_TAGS;
|
|
789
|
-
FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
|
790
|
-
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
|
|
791
|
-
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
|
792
|
-
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
|
|
793
|
-
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
750
|
+
/*! @license DOMPurify 3.0.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.0.3/LICENSE */
|
|
794
751
|
|
|
795
|
-
|
|
752
|
+
const {
|
|
753
|
+
entries,
|
|
754
|
+
setPrototypeOf,
|
|
755
|
+
isFrozen,
|
|
756
|
+
getPrototypeOf,
|
|
757
|
+
getOwnPropertyDescriptor
|
|
758
|
+
} = Object;
|
|
759
|
+
let {
|
|
760
|
+
freeze,
|
|
761
|
+
seal,
|
|
762
|
+
create
|
|
763
|
+
} = Object; // eslint-disable-line import/no-mutable-exports
|
|
796
764
|
|
|
797
|
-
|
|
765
|
+
let {
|
|
766
|
+
apply,
|
|
767
|
+
construct
|
|
768
|
+
} = typeof Reflect !== 'undefined' && Reflect;
|
|
798
769
|
|
|
799
|
-
|
|
770
|
+
if (!apply) {
|
|
771
|
+
apply = function apply(fun, thisValue, args) {
|
|
772
|
+
return fun.apply(thisValue, args);
|
|
773
|
+
};
|
|
774
|
+
}
|
|
800
775
|
|
|
801
|
-
|
|
776
|
+
if (!freeze) {
|
|
777
|
+
freeze = function freeze(x) {
|
|
778
|
+
return x;
|
|
779
|
+
};
|
|
780
|
+
}
|
|
802
781
|
|
|
803
|
-
|
|
782
|
+
if (!seal) {
|
|
783
|
+
seal = function seal(x) {
|
|
784
|
+
return x;
|
|
785
|
+
};
|
|
786
|
+
}
|
|
804
787
|
|
|
805
|
-
|
|
788
|
+
if (!construct) {
|
|
789
|
+
construct = function construct(Func, args) {
|
|
790
|
+
return new Func(...args);
|
|
791
|
+
};
|
|
792
|
+
}
|
|
806
793
|
|
|
807
|
-
|
|
794
|
+
const arrayForEach = unapply(Array.prototype.forEach);
|
|
795
|
+
const arrayPop = unapply(Array.prototype.pop);
|
|
796
|
+
const arrayPush = unapply(Array.prototype.push);
|
|
797
|
+
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
|
798
|
+
const stringToString = unapply(String.prototype.toString);
|
|
799
|
+
const stringMatch = unapply(String.prototype.match);
|
|
800
|
+
const stringReplace = unapply(String.prototype.replace);
|
|
801
|
+
const stringIndexOf = unapply(String.prototype.indexOf);
|
|
802
|
+
const stringTrim = unapply(String.prototype.trim);
|
|
803
|
+
const regExpTest = unapply(RegExp.prototype.test);
|
|
804
|
+
const typeErrorCreate = unconstruct(TypeError);
|
|
805
|
+
function unapply(func) {
|
|
806
|
+
return function (thisArg) {
|
|
807
|
+
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
808
|
+
args[_key - 1] = arguments[_key];
|
|
809
|
+
}
|
|
808
810
|
|
|
809
|
-
|
|
811
|
+
return apply(func, thisArg, args);
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
function unconstruct(func) {
|
|
815
|
+
return function () {
|
|
816
|
+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
817
|
+
args[_key2] = arguments[_key2];
|
|
818
|
+
}
|
|
810
819
|
|
|
811
|
-
|
|
820
|
+
return construct(func, args);
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
/* Add properties to a lookup table */
|
|
812
824
|
|
|
813
|
-
|
|
825
|
+
function addToSet(set, array, transformCaseFunc) {
|
|
826
|
+
var _transformCaseFunc;
|
|
814
827
|
|
|
815
|
-
|
|
828
|
+
transformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;
|
|
816
829
|
|
|
817
|
-
|
|
830
|
+
if (setPrototypeOf) {
|
|
831
|
+
// Make 'in' and truthy checks like Boolean(set.constructor)
|
|
832
|
+
// independent of any properties defined on Object.prototype.
|
|
833
|
+
// Prevent prototype setters from intercepting set as a this value.
|
|
834
|
+
setPrototypeOf(set, null);
|
|
835
|
+
}
|
|
818
836
|
|
|
819
|
-
|
|
837
|
+
let l = array.length;
|
|
820
838
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
|
839
|
+
while (l--) {
|
|
840
|
+
let element = array[l];
|
|
824
841
|
|
|
825
|
-
if (
|
|
826
|
-
|
|
827
|
-
}
|
|
842
|
+
if (typeof element === 'string') {
|
|
843
|
+
const lcElement = transformCaseFunc(element);
|
|
828
844
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
845
|
+
if (lcElement !== element) {
|
|
846
|
+
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
|
847
|
+
if (!isFrozen(array)) {
|
|
848
|
+
array[l] = lcElement;
|
|
849
|
+
}
|
|
832
850
|
|
|
833
|
-
|
|
834
|
-
|
|
851
|
+
element = lcElement;
|
|
852
|
+
}
|
|
835
853
|
}
|
|
836
854
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
}
|
|
855
|
+
set[element] = true;
|
|
856
|
+
}
|
|
840
857
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
/* Parse profile info */
|
|
858
|
+
return set;
|
|
859
|
+
}
|
|
860
|
+
/* Shallow clone an object */
|
|
845
861
|
|
|
862
|
+
function clone(object) {
|
|
863
|
+
const newObject = create(null);
|
|
846
864
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
865
|
+
for (const [property, value] of entries(object)) {
|
|
866
|
+
newObject[property] = value;
|
|
867
|
+
}
|
|
850
868
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
869
|
+
return newObject;
|
|
870
|
+
}
|
|
871
|
+
/* This method automatically checks if the prop is function
|
|
872
|
+
* or getter and behaves accordingly. */
|
|
855
873
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
addToSet(ALLOWED_ATTR, xml);
|
|
860
|
-
}
|
|
874
|
+
function lookupGetter(object, prop) {
|
|
875
|
+
while (object !== null) {
|
|
876
|
+
const desc = getOwnPropertyDescriptor(object, prop);
|
|
861
877
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
addToSet(ALLOWED_ATTR, xml);
|
|
878
|
+
if (desc) {
|
|
879
|
+
if (desc.get) {
|
|
880
|
+
return unapply(desc.get);
|
|
866
881
|
}
|
|
867
882
|
|
|
868
|
-
if (
|
|
869
|
-
|
|
870
|
-
addToSet(ALLOWED_ATTR, mathMl);
|
|
871
|
-
addToSet(ALLOWED_ATTR, xml);
|
|
883
|
+
if (typeof desc.value === 'function') {
|
|
884
|
+
return unapply(desc.value);
|
|
872
885
|
}
|
|
873
886
|
}
|
|
874
|
-
/* Merge configuration parameters */
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
if (cfg.ADD_TAGS) {
|
|
878
|
-
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
879
|
-
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
880
|
-
}
|
|
881
887
|
|
|
882
|
-
|
|
883
|
-
|
|
888
|
+
object = getPrototypeOf(object);
|
|
889
|
+
}
|
|
884
890
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
891
|
+
function fallbackValue(element) {
|
|
892
|
+
console.warn('fallback value for', element);
|
|
893
|
+
return null;
|
|
894
|
+
}
|
|
889
895
|
|
|
890
|
-
|
|
891
|
-
|
|
896
|
+
return fallbackValue;
|
|
897
|
+
}
|
|
892
898
|
|
|
893
|
-
|
|
894
|
-
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
895
|
-
}
|
|
899
|
+
const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']); // SVG
|
|
896
900
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
+
const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
|
|
902
|
+
const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']); // List of SVG elements that are disallowed by default.
|
|
903
|
+
// We still need to know them so that we can do namespace
|
|
904
|
+
// checks properly in case one wants to add them to
|
|
905
|
+
// allow-list.
|
|
901
906
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
907
|
+
const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', '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']);
|
|
908
|
+
const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']); // Similarly to SVG, we want to know all MathML elements,
|
|
909
|
+
// even those that we disallow by default.
|
|
905
910
|
|
|
911
|
+
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
|
912
|
+
const text = freeze(['#text']);
|
|
906
913
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
914
|
+
const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);
|
|
915
|
+
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
|
916
|
+
const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
|
|
917
|
+
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
911
918
|
|
|
919
|
+
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
|
912
920
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
|
|
921
|
+
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
|
922
|
+
const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
|
|
923
|
+
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
|
|
917
924
|
|
|
925
|
+
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
|
918
926
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
927
|
+
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
|
|
928
|
+
);
|
|
929
|
+
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
|
930
|
+
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
|
931
|
+
);
|
|
932
|
+
const DOCTYPE_NAME = seal(/^html$/i);
|
|
923
933
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
934
|
+
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
|
935
|
+
__proto__: null,
|
|
936
|
+
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
|
937
|
+
ERB_EXPR: ERB_EXPR,
|
|
938
|
+
TMPLIT_EXPR: TMPLIT_EXPR,
|
|
939
|
+
DATA_ATTR: DATA_ATTR,
|
|
940
|
+
ARIA_ATTR: ARIA_ATTR,
|
|
941
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
|
942
|
+
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
|
943
|
+
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
|
944
|
+
DOCTYPE_NAME: DOCTYPE_NAME
|
|
945
|
+
});
|
|
928
946
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
947
|
+
const getGlobal = () => typeof window === 'undefined' ? null : window;
|
|
948
|
+
/**
|
|
949
|
+
* Creates a no-op policy for internal use only.
|
|
950
|
+
* Don't export this function outside this module!
|
|
951
|
+
* @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
|
|
952
|
+
* @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
|
|
953
|
+
* @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
|
|
954
|
+
* are not supported or creating the policy failed).
|
|
955
|
+
*/
|
|
932
956
|
|
|
933
957
|
|
|
934
|
-
|
|
958
|
+
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
|
|
959
|
+
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
|
960
|
+
return null;
|
|
961
|
+
} // Allow the callers to control the unique policy name
|
|
962
|
+
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
|
963
|
+
// Policy creation with duplicate names throws in Trusted Types.
|
|
935
964
|
|
|
936
|
-
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
937
|
-
} else {
|
|
938
|
-
// Uninitialized policy, attempt to initialize the internal dompurify policy.
|
|
939
|
-
if (trustedTypesPolicy === undefined) {
|
|
940
|
-
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
|
941
|
-
} // If creating the internal policy succeeded sign internal variables.
|
|
942
965
|
|
|
966
|
+
let suffix = null;
|
|
967
|
+
const ATTR_NAME = 'data-tt-policy-suffix';
|
|
943
968
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
} // Prevent further manipulation of configuration.
|
|
948
|
-
// Not available in IE8, Safari 5, etc.
|
|
969
|
+
if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
|
|
970
|
+
suffix = purifyHostElement.getAttribute(ATTR_NAME);
|
|
971
|
+
}
|
|
949
972
|
|
|
973
|
+
const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
|
|
950
974
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
975
|
+
try {
|
|
976
|
+
return trustedTypes.createPolicy(policyName, {
|
|
977
|
+
createHTML(html) {
|
|
978
|
+
return html;
|
|
979
|
+
},
|
|
954
980
|
|
|
955
|
-
|
|
956
|
-
|
|
981
|
+
createScriptURL(scriptUrl) {
|
|
982
|
+
return scriptUrl;
|
|
983
|
+
}
|
|
957
984
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
985
|
+
});
|
|
986
|
+
} catch (_) {
|
|
987
|
+
// Policy creation failed (most likely another DOMPurify script has
|
|
988
|
+
// already run). Skip creating the policy, as this will only cause errors
|
|
989
|
+
// if TT are enforced.
|
|
990
|
+
console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
};
|
|
963
994
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
* so that we can perform the namespace checks
|
|
967
|
-
* correctly. */
|
|
995
|
+
function createDOMPurify() {
|
|
996
|
+
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
968
997
|
|
|
969
|
-
const
|
|
970
|
-
addToSet(ALL_SVG_TAGS, svgFilters);
|
|
971
|
-
addToSet(ALL_SVG_TAGS, svgDisallowed);
|
|
972
|
-
const ALL_MATHML_TAGS = addToSet({}, mathMl$1);
|
|
973
|
-
addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
|
|
998
|
+
const DOMPurify = root => createDOMPurify(root);
|
|
974
999
|
/**
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
|
-
* @param {Element} element a DOM element whose namespace is being checked
|
|
978
|
-
* @returns {boolean} Return false if the element has a
|
|
979
|
-
* namespace that a spec-compliant parser would never
|
|
980
|
-
* return. Return true otherwise.
|
|
1000
|
+
* Version label, exposed for easier checks
|
|
1001
|
+
* if DOMPurify is up to date or not
|
|
981
1002
|
*/
|
|
982
1003
|
|
|
983
|
-
const _checkValidNamespace = function _checkValidNamespace(element) {
|
|
984
|
-
let parent = getParentNode(element); // In JSDOM, if we're inside shadow DOM, then parentNode
|
|
985
|
-
// can be null. We just simulate parent in this case.
|
|
986
|
-
|
|
987
|
-
if (!parent || !parent.tagName) {
|
|
988
|
-
parent = {
|
|
989
|
-
namespaceURI: NAMESPACE,
|
|
990
|
-
tagName: 'template'
|
|
991
|
-
};
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
const tagName = stringToLowerCase(element.tagName);
|
|
995
|
-
const parentTagName = stringToLowerCase(parent.tagName);
|
|
996
1004
|
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1005
|
+
DOMPurify.version = '3.0.3';
|
|
1006
|
+
/**
|
|
1007
|
+
* Array of elements that DOMPurify removed during sanitation.
|
|
1008
|
+
* Empty if nothing was removed.
|
|
1009
|
+
*/
|
|
1000
1010
|
|
|
1001
|
-
|
|
1002
|
-
// The only way to switch from HTML namespace to SVG
|
|
1003
|
-
// is via <svg>. If it happens via any other tag, then
|
|
1004
|
-
// it should be killed.
|
|
1005
|
-
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
1006
|
-
return tagName === 'svg';
|
|
1007
|
-
} // The only way to switch from MathML to SVG is via`
|
|
1008
|
-
// svg if parent is either <annotation-xml> or MathML
|
|
1009
|
-
// text integration points.
|
|
1011
|
+
DOMPurify.removed = [];
|
|
1010
1012
|
|
|
1013
|
+
if (!window || !window.document || window.document.nodeType !== 9) {
|
|
1014
|
+
// Not running in a browser, provide a factory function
|
|
1015
|
+
// so that you can pass your own Window
|
|
1016
|
+
DOMPurify.isSupported = false;
|
|
1017
|
+
return DOMPurify;
|
|
1018
|
+
}
|
|
1011
1019
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1020
|
+
const originalDocument = window.document;
|
|
1021
|
+
const currentScript = originalDocument.currentScript;
|
|
1022
|
+
let {
|
|
1023
|
+
document
|
|
1024
|
+
} = window;
|
|
1025
|
+
const {
|
|
1026
|
+
DocumentFragment,
|
|
1027
|
+
HTMLTemplateElement,
|
|
1028
|
+
Node,
|
|
1029
|
+
Element,
|
|
1030
|
+
NodeFilter,
|
|
1031
|
+
NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
|
|
1032
|
+
HTMLFormElement,
|
|
1033
|
+
DOMParser,
|
|
1034
|
+
trustedTypes
|
|
1035
|
+
} = window;
|
|
1036
|
+
const ElementPrototype = Element.prototype;
|
|
1037
|
+
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
|
1038
|
+
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
|
1039
|
+
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
|
1040
|
+
const getParentNode = lookupGetter(ElementPrototype, 'parentNode'); // As per issue #47, the web-components registry is inherited by a
|
|
1041
|
+
// new document created via createHTMLDocument. As per the spec
|
|
1042
|
+
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
1043
|
+
// a new empty registry is used when creating a template contents owner
|
|
1044
|
+
// document, so we use that as our parent document to ensure nothing
|
|
1045
|
+
// is inherited.
|
|
1016
1046
|
|
|
1047
|
+
if (typeof HTMLTemplateElement === 'function') {
|
|
1048
|
+
const template = document.createElement('template');
|
|
1017
1049
|
|
|
1018
|
-
|
|
1050
|
+
if (template.content && template.content.ownerDocument) {
|
|
1051
|
+
document = template.content.ownerDocument;
|
|
1019
1052
|
}
|
|
1053
|
+
}
|
|
1020
1054
|
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1055
|
+
let trustedTypesPolicy;
|
|
1056
|
+
let emptyHTML = '';
|
|
1057
|
+
const {
|
|
1058
|
+
implementation,
|
|
1059
|
+
createNodeIterator,
|
|
1060
|
+
createDocumentFragment,
|
|
1061
|
+
getElementsByTagName
|
|
1062
|
+
} = document;
|
|
1063
|
+
const {
|
|
1064
|
+
importNode
|
|
1065
|
+
} = originalDocument;
|
|
1066
|
+
let hooks = {};
|
|
1067
|
+
/**
|
|
1068
|
+
* Expose whether this browser supports running the full DOMPurify.
|
|
1069
|
+
*/
|
|
1029
1070
|
|
|
1071
|
+
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
|
|
1072
|
+
const {
|
|
1073
|
+
MUSTACHE_EXPR,
|
|
1074
|
+
ERB_EXPR,
|
|
1075
|
+
TMPLIT_EXPR,
|
|
1076
|
+
DATA_ATTR,
|
|
1077
|
+
ARIA_ATTR,
|
|
1078
|
+
IS_SCRIPT_OR_DATA,
|
|
1079
|
+
ATTR_WHITESPACE
|
|
1080
|
+
} = EXPRESSIONS;
|
|
1081
|
+
let {
|
|
1082
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
|
1083
|
+
} = EXPRESSIONS;
|
|
1084
|
+
/**
|
|
1085
|
+
* We consider the elements and attributes below to be safe. Ideally
|
|
1086
|
+
* don't add any new ones but feel free to remove unwanted ones.
|
|
1087
|
+
*/
|
|
1030
1088
|
|
|
1031
|
-
|
|
1032
|
-
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
|
1033
|
-
} // We only allow elements that are defined in MathML
|
|
1034
|
-
// spec. All others are disallowed in MathML namespace.
|
|
1089
|
+
/* allowed element names */
|
|
1035
1090
|
|
|
1091
|
+
let ALLOWED_TAGS = null;
|
|
1092
|
+
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
|
|
1093
|
+
/* Allowed attribute names */
|
|
1036
1094
|
|
|
1037
|
-
|
|
1095
|
+
let ALLOWED_ATTR = null;
|
|
1096
|
+
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
|
1097
|
+
/*
|
|
1098
|
+
* Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
|
|
1099
|
+
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
|
1100
|
+
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
|
|
1101
|
+
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
|
1102
|
+
*/
|
|
1103
|
+
|
|
1104
|
+
let CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
|
|
1105
|
+
tagNameCheck: {
|
|
1106
|
+
writable: true,
|
|
1107
|
+
configurable: false,
|
|
1108
|
+
enumerable: true,
|
|
1109
|
+
value: null
|
|
1110
|
+
},
|
|
1111
|
+
attributeNameCheck: {
|
|
1112
|
+
writable: true,
|
|
1113
|
+
configurable: false,
|
|
1114
|
+
enumerable: true,
|
|
1115
|
+
value: null
|
|
1116
|
+
},
|
|
1117
|
+
allowCustomizedBuiltInElements: {
|
|
1118
|
+
writable: true,
|
|
1119
|
+
configurable: false,
|
|
1120
|
+
enumerable: true,
|
|
1121
|
+
value: false
|
|
1038
1122
|
}
|
|
1123
|
+
}));
|
|
1124
|
+
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
|
1039
1125
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
// HTML integration points, and from MathML to HTML
|
|
1043
|
-
// is via MathML text integration points
|
|
1044
|
-
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
|
|
1045
|
-
return false;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
|
1049
|
-
return false;
|
|
1050
|
-
} // We disallow tags that are specific for MathML
|
|
1051
|
-
// or SVG and should never appear in HTML namespace
|
|
1052
|
-
|
|
1126
|
+
let FORBID_TAGS = null;
|
|
1127
|
+
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
|
1053
1128
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1129
|
+
let FORBID_ATTR = null;
|
|
1130
|
+
/* Decide if ARIA attributes are okay */
|
|
1056
1131
|
|
|
1132
|
+
let ALLOW_ARIA_ATTR = true;
|
|
1133
|
+
/* Decide if custom data attributes are okay */
|
|
1057
1134
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
} // The code should never reach this place (this means
|
|
1061
|
-
// that the element somehow got namespace that is not
|
|
1062
|
-
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
|
|
1063
|
-
// Return false just in case.
|
|
1135
|
+
let ALLOW_DATA_ATTR = true;
|
|
1136
|
+
/* Decide if unknown protocols are okay */
|
|
1064
1137
|
|
|
1138
|
+
let ALLOW_UNKNOWN_PROTOCOLS = false;
|
|
1139
|
+
/* Decide if self-closing tags in attributes are allowed.
|
|
1140
|
+
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
|
1065
1141
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
* _forceRemove
|
|
1070
|
-
*
|
|
1071
|
-
* @param {Node} node a DOM node
|
|
1142
|
+
let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
|
1143
|
+
/* Output should be safe for common template engines.
|
|
1144
|
+
* This means, DOMPurify removes data attributes, mustaches and ERB
|
|
1072
1145
|
*/
|
|
1073
1146
|
|
|
1147
|
+
let SAFE_FOR_TEMPLATES = false;
|
|
1148
|
+
/* Decide if document with <html>... should be returned */
|
|
1074
1149
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
element: node
|
|
1078
|
-
});
|
|
1150
|
+
let WHOLE_DOCUMENT = false;
|
|
1151
|
+
/* Track whether config is already set on this instance of DOMPurify. */
|
|
1079
1152
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
* _removeAttribute
|
|
1089
|
-
*
|
|
1090
|
-
* @param {String} name an Attribute name
|
|
1091
|
-
* @param {Node} node a DOM node
|
|
1153
|
+
let SET_CONFIG = false;
|
|
1154
|
+
/* Decide if all elements (e.g. style, script) must be children of
|
|
1155
|
+
* document.body. By default, browsers might move them to document.head */
|
|
1156
|
+
|
|
1157
|
+
let FORCE_BODY = false;
|
|
1158
|
+
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
|
1159
|
+
* string (or a TrustedHTML object if Trusted Types are supported).
|
|
1160
|
+
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
|
1092
1161
|
*/
|
|
1093
1162
|
|
|
1163
|
+
let RETURN_DOM = false;
|
|
1164
|
+
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
|
1165
|
+
* string (or a TrustedHTML object if Trusted Types are supported) */
|
|
1094
1166
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
attribute: node.getAttributeNode(name),
|
|
1099
|
-
from: node
|
|
1100
|
-
});
|
|
1101
|
-
} catch (_) {
|
|
1102
|
-
arrayPush(DOMPurify.removed, {
|
|
1103
|
-
attribute: null,
|
|
1104
|
-
from: node
|
|
1105
|
-
});
|
|
1106
|
-
}
|
|
1167
|
+
let RETURN_DOM_FRAGMENT = false;
|
|
1168
|
+
/* Try to return a Trusted Type object instead of a string, return a string in
|
|
1169
|
+
* case Trusted Types are not supported */
|
|
1107
1170
|
|
|
1108
|
-
|
|
1171
|
+
let RETURN_TRUSTED_TYPE = false;
|
|
1172
|
+
/* Output should be free from DOM clobbering attacks?
|
|
1173
|
+
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
|
1174
|
+
*/
|
|
1109
1175
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
_forceRemove(node);
|
|
1114
|
-
} catch (_) {}
|
|
1115
|
-
} else {
|
|
1116
|
-
try {
|
|
1117
|
-
node.setAttribute(name, '');
|
|
1118
|
-
} catch (_) {}
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
};
|
|
1122
|
-
/**
|
|
1123
|
-
* _initDocument
|
|
1176
|
+
let SANITIZE_DOM = true;
|
|
1177
|
+
/* Achieve full DOM Clobbering protection by isolating the namespace of named
|
|
1178
|
+
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
|
|
1124
1179
|
*
|
|
1125
|
-
*
|
|
1126
|
-
*
|
|
1180
|
+
* HTML/DOM spec rules that enable DOM Clobbering:
|
|
1181
|
+
* - Named Access on Window (§7.3.3)
|
|
1182
|
+
* - DOM Tree Accessors (§3.1.5)
|
|
1183
|
+
* - Form Element Parent-Child Relations (§4.10.3)
|
|
1184
|
+
* - Iframe srcdoc / Nested WindowProxies (§4.8.5)
|
|
1185
|
+
* - HTMLCollection (§4.2.10.2)
|
|
1186
|
+
*
|
|
1187
|
+
* Namespace isolation is implemented by prefixing `id` and `name` attributes
|
|
1188
|
+
* with a constant string, i.e., `user-content-`
|
|
1127
1189
|
*/
|
|
1128
1190
|
|
|
1191
|
+
let SANITIZE_NAMED_PROPS = false;
|
|
1192
|
+
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
|
1193
|
+
/* Keep element content when removing element? */
|
|
1129
1194
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
let leadingWhitespace;
|
|
1195
|
+
let KEEP_CONTENT = true;
|
|
1196
|
+
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
|
|
1197
|
+
* of importing it into a new Document and returning a sanitized copy */
|
|
1134
1198
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
} else {
|
|
1138
|
-
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
|
1139
|
-
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
|
|
1140
|
-
leadingWhitespace = matches && matches[0];
|
|
1141
|
-
}
|
|
1199
|
+
let IN_PLACE = false;
|
|
1200
|
+
/* Allow usage of profiles like html, svg and mathMl */
|
|
1142
1201
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
1146
|
-
}
|
|
1202
|
+
let USE_PROFILES = {};
|
|
1203
|
+
/* Tags to ignore content of when KEEP_CONTENT is true */
|
|
1147
1204
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
* DOMParser not work for svg when has multiple root element.
|
|
1152
|
-
*/
|
|
1205
|
+
let FORBID_CONTENTS = null;
|
|
1206
|
+
const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
|
|
1207
|
+
/* Tags that are safe for data: URIs */
|
|
1153
1208
|
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
} catch (_) {}
|
|
1158
|
-
}
|
|
1159
|
-
/* Use createHTMLDocument in case DOMParser is not available */
|
|
1209
|
+
let DATA_URI_TAGS = null;
|
|
1210
|
+
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
|
1211
|
+
/* Attributes safe for values like "javascript:" */
|
|
1160
1212
|
|
|
1213
|
+
let URI_SAFE_ATTRIBUTES = null;
|
|
1214
|
+
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
|
1215
|
+
const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
|
1216
|
+
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
1217
|
+
const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
|
1218
|
+
/* Document namespace */
|
|
1161
1219
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1220
|
+
let NAMESPACE = HTML_NAMESPACE;
|
|
1221
|
+
let IS_EMPTY_INPUT = false;
|
|
1222
|
+
/* Allowed XHTML+XML namespaces */
|
|
1164
1223
|
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1224
|
+
let ALLOWED_NAMESPACES = null;
|
|
1225
|
+
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
|
1226
|
+
/* Parsing of strict XHTML documents */
|
|
1170
1227
|
|
|
1171
|
-
|
|
1228
|
+
let PARSER_MEDIA_TYPE;
|
|
1229
|
+
const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
|
1230
|
+
const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
|
1231
|
+
let transformCaseFunc;
|
|
1232
|
+
/* Keep a reference to config to pass to hooks */
|
|
1172
1233
|
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
}
|
|
1176
|
-
/* Work on whole document or just its body */
|
|
1234
|
+
let CONFIG = null;
|
|
1235
|
+
/* Ideally, do not touch anything below this line */
|
|
1177
1236
|
|
|
1237
|
+
/* ______________________________________________ */
|
|
1178
1238
|
|
|
1179
|
-
|
|
1180
|
-
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
|
1181
|
-
}
|
|
1239
|
+
const formElement = document.createElement('form');
|
|
1182
1240
|
|
|
1183
|
-
|
|
1241
|
+
const isRegexOrFunction = function isRegexOrFunction(testValue) {
|
|
1242
|
+
return testValue instanceof RegExp || testValue instanceof Function;
|
|
1184
1243
|
};
|
|
1185
1244
|
/**
|
|
1186
|
-
*
|
|
1245
|
+
* _parseConfig
|
|
1187
1246
|
*
|
|
1188
|
-
* @param {
|
|
1189
|
-
* @return {Iterator} iterator instance
|
|
1247
|
+
* @param {Object} cfg optional config literal
|
|
1190
1248
|
*/
|
|
1249
|
+
// eslint-disable-next-line complexity
|
|
1191
1250
|
|
|
1192
1251
|
|
|
1193
|
-
const
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1252
|
+
const _parseConfig = function _parseConfig(cfg) {
|
|
1253
|
+
if (CONFIG && CONFIG === cfg) {
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
/* Shield configuration object from tampering */
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
if (!cfg || typeof cfg !== 'object') {
|
|
1260
|
+
cfg = {};
|
|
1261
|
+
}
|
|
1262
|
+
/* Shield configuration object from prototype pollution */
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
cfg = clone(cfg);
|
|
1266
|
+
PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes
|
|
1267
|
+
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
|
1268
|
+
|
|
1269
|
+
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
|
1270
|
+
/* Set configuration parameters */
|
|
1271
|
+
|
|
1272
|
+
ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
|
1273
|
+
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
|
1274
|
+
ALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
|
1275
|
+
URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent
|
|
1276
|
+
cfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent
|
|
1277
|
+
transformCaseFunc // eslint-disable-line indent
|
|
1278
|
+
) // eslint-disable-line indent
|
|
1279
|
+
: DEFAULT_URI_SAFE_ATTRIBUTES;
|
|
1280
|
+
DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent
|
|
1281
|
+
cfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent
|
|
1282
|
+
transformCaseFunc // eslint-disable-line indent
|
|
1283
|
+
) // eslint-disable-line indent
|
|
1284
|
+
: DEFAULT_DATA_URI_TAGS;
|
|
1285
|
+
FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
|
1286
|
+
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
|
|
1287
|
+
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
|
1288
|
+
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
|
|
1289
|
+
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
|
1203
1290
|
|
|
1291
|
+
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
|
1204
1292
|
|
|
1205
|
-
|
|
1206
|
-
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');
|
|
1207
|
-
};
|
|
1208
|
-
/**
|
|
1209
|
-
* _isNode
|
|
1210
|
-
*
|
|
1211
|
-
* @param {Node} obj object to check whether it's a DOM node
|
|
1212
|
-
* @return {Boolean} true is object is a DOM node
|
|
1213
|
-
*/
|
|
1293
|
+
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
|
|
1214
1294
|
|
|
1295
|
+
ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
|
|
1215
1296
|
|
|
1216
|
-
|
|
1217
|
-
return typeof Node === 'object' ? object instanceof Node : object && typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
|
|
1218
|
-
};
|
|
1219
|
-
/**
|
|
1220
|
-
* _executeHook
|
|
1221
|
-
* Execute user configurable hooks
|
|
1222
|
-
*
|
|
1223
|
-
* @param {String} entryPoint Name of the hook's entry point
|
|
1224
|
-
* @param {Node} currentNode node to work on with the hook
|
|
1225
|
-
* @param {Object} data additional hook parameters
|
|
1226
|
-
*/
|
|
1297
|
+
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
|
|
1227
1298
|
|
|
1299
|
+
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
|
|
1228
1300
|
|
|
1229
|
-
|
|
1230
|
-
if (!hooks[entryPoint]) {
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1301
|
+
RETURN_DOM = cfg.RETURN_DOM || false; // Default false
|
|
1233
1302
|
|
|
1234
|
-
|
|
1235
|
-
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
1236
|
-
});
|
|
1237
|
-
};
|
|
1238
|
-
/**
|
|
1239
|
-
* _sanitizeElements
|
|
1240
|
-
*
|
|
1241
|
-
* @protect nodeName
|
|
1242
|
-
* @protect textContent
|
|
1243
|
-
* @protect removeChild
|
|
1244
|
-
*
|
|
1245
|
-
* @param {Node} currentNode to check for permission to exist
|
|
1246
|
-
* @return {Boolean} true if node was killed, false if left alive
|
|
1247
|
-
*/
|
|
1303
|
+
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
|
|
1248
1304
|
|
|
1305
|
+
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
|
|
1249
1306
|
|
|
1250
|
-
|
|
1251
|
-
let content;
|
|
1252
|
-
/* Execute a hook if present */
|
|
1307
|
+
FORCE_BODY = cfg.FORCE_BODY || false; // Default false
|
|
1253
1308
|
|
|
1254
|
-
|
|
1255
|
-
/* Check if element is clobbered or can clobber */
|
|
1309
|
+
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
|
|
1256
1310
|
|
|
1311
|
+
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
|
|
1257
1312
|
|
|
1258
|
-
|
|
1259
|
-
_forceRemove(currentNode);
|
|
1313
|
+
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
|
1260
1314
|
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1263
|
-
/* Now let's check the element's type and name */
|
|
1315
|
+
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
|
1264
1316
|
|
|
1317
|
+
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
|
1318
|
+
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
|
1319
|
+
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
|
1265
1320
|
|
|
1266
|
-
|
|
1267
|
-
|
|
1321
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
|
|
1322
|
+
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
|
|
1323
|
+
}
|
|
1268
1324
|
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
});
|
|
1273
|
-
/* Detect mXSS attempts abusing namespace confusion */
|
|
1325
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
|
|
1326
|
+
CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
|
|
1327
|
+
}
|
|
1274
1328
|
|
|
1329
|
+
if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
|
|
1330
|
+
CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
|
|
1331
|
+
}
|
|
1275
1332
|
|
|
1276
|
-
if (
|
|
1277
|
-
|
|
1333
|
+
if (SAFE_FOR_TEMPLATES) {
|
|
1334
|
+
ALLOW_DATA_ATTR = false;
|
|
1335
|
+
}
|
|
1278
1336
|
|
|
1279
|
-
|
|
1337
|
+
if (RETURN_DOM_FRAGMENT) {
|
|
1338
|
+
RETURN_DOM = true;
|
|
1280
1339
|
}
|
|
1281
|
-
/*
|
|
1340
|
+
/* Parse profile info */
|
|
1282
1341
|
|
|
1283
1342
|
|
|
1284
|
-
if (
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
|
|
1288
|
-
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
|
|
1289
|
-
}
|
|
1290
|
-
/* Keep content except for bad-listed elements */
|
|
1343
|
+
if (USE_PROFILES) {
|
|
1344
|
+
ALLOWED_TAGS = addToSet({}, [...text]);
|
|
1345
|
+
ALLOWED_ATTR = [];
|
|
1291
1346
|
|
|
1347
|
+
if (USE_PROFILES.html === true) {
|
|
1348
|
+
addToSet(ALLOWED_TAGS, html$1);
|
|
1349
|
+
addToSet(ALLOWED_ATTR, html);
|
|
1350
|
+
}
|
|
1292
1351
|
|
|
1293
|
-
if (
|
|
1294
|
-
|
|
1295
|
-
|
|
1352
|
+
if (USE_PROFILES.svg === true) {
|
|
1353
|
+
addToSet(ALLOWED_TAGS, svg$1);
|
|
1354
|
+
addToSet(ALLOWED_ATTR, svg);
|
|
1355
|
+
addToSet(ALLOWED_ATTR, xml);
|
|
1356
|
+
}
|
|
1296
1357
|
|
|
1297
|
-
|
|
1298
|
-
|
|
1358
|
+
if (USE_PROFILES.svgFilters === true) {
|
|
1359
|
+
addToSet(ALLOWED_TAGS, svgFilters);
|
|
1360
|
+
addToSet(ALLOWED_ATTR, svg);
|
|
1361
|
+
addToSet(ALLOWED_ATTR, xml);
|
|
1362
|
+
}
|
|
1299
1363
|
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1364
|
+
if (USE_PROFILES.mathMl === true) {
|
|
1365
|
+
addToSet(ALLOWED_TAGS, mathMl$1);
|
|
1366
|
+
addToSet(ALLOWED_ATTR, mathMl);
|
|
1367
|
+
addToSet(ALLOWED_ATTR, xml);
|
|
1304
1368
|
}
|
|
1369
|
+
}
|
|
1370
|
+
/* Merge configuration parameters */
|
|
1305
1371
|
|
|
1306
|
-
_forceRemove(currentNode);
|
|
1307
1372
|
|
|
1308
|
-
|
|
1373
|
+
if (cfg.ADD_TAGS) {
|
|
1374
|
+
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
|
1375
|
+
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
|
|
1309
1379
|
}
|
|
1310
|
-
/* Check whether element has a valid namespace */
|
|
1311
1380
|
|
|
1381
|
+
if (cfg.ADD_ATTR) {
|
|
1382
|
+
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
|
|
1383
|
+
ALLOWED_ATTR = clone(ALLOWED_ATTR);
|
|
1384
|
+
}
|
|
1312
1385
|
|
|
1313
|
-
|
|
1314
|
-
|
|
1386
|
+
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
1387
|
+
}
|
|
1315
1388
|
|
|
1316
|
-
|
|
1389
|
+
if (cfg.ADD_URI_SAFE_ATTR) {
|
|
1390
|
+
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
1317
1391
|
}
|
|
1318
|
-
/* Make sure that older browsers don't get noscript mXSS */
|
|
1319
1392
|
|
|
1393
|
+
if (cfg.FORBID_CONTENTS) {
|
|
1394
|
+
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
1395
|
+
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
1396
|
+
}
|
|
1320
1397
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1398
|
+
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
1399
|
+
}
|
|
1400
|
+
/* Add #text in case KEEP_CONTENT is set to true */
|
|
1323
1401
|
|
|
1324
|
-
|
|
1402
|
+
|
|
1403
|
+
if (KEEP_CONTENT) {
|
|
1404
|
+
ALLOWED_TAGS['#text'] = true;
|
|
1325
1405
|
}
|
|
1326
|
-
/*
|
|
1406
|
+
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
|
|
1327
1407
|
|
|
1328
1408
|
|
|
1329
|
-
if (
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
content = stringReplace(content, ERB_EXPR, ' ');
|
|
1334
|
-
content = stringReplace(content, TMPLIT_EXPR, ' ');
|
|
1409
|
+
if (WHOLE_DOCUMENT) {
|
|
1410
|
+
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
|
|
1411
|
+
}
|
|
1412
|
+
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
|
|
1335
1413
|
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
currentNode.textContent = content;
|
|
1341
|
-
}
|
|
1414
|
+
|
|
1415
|
+
if (ALLOWED_TAGS.table) {
|
|
1416
|
+
addToSet(ALLOWED_TAGS, ['tbody']);
|
|
1417
|
+
delete FORBID_TAGS.tbody;
|
|
1342
1418
|
}
|
|
1343
|
-
/* Execute a hook if present */
|
|
1344
1419
|
|
|
1420
|
+
if (cfg.TRUSTED_TYPES_POLICY) {
|
|
1421
|
+
if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
|
|
1422
|
+
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
|
|
1423
|
+
}
|
|
1345
1424
|
|
|
1346
|
-
|
|
1425
|
+
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
|
|
1426
|
+
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
|
1427
|
+
} // Overwrite existing TrustedTypes policy.
|
|
1347
1428
|
|
|
1348
|
-
return false;
|
|
1349
|
-
};
|
|
1350
|
-
/**
|
|
1351
|
-
* _isValidAttribute
|
|
1352
|
-
*
|
|
1353
|
-
* @param {string} lcTag Lowercase tag name of containing element.
|
|
1354
|
-
* @param {string} lcName Lowercase attribute name.
|
|
1355
|
-
* @param {string} value Attribute value.
|
|
1356
|
-
* @return {Boolean} Returns true if `value` is valid, otherwise false.
|
|
1357
|
-
*/
|
|
1358
|
-
// eslint-disable-next-line complexity
|
|
1359
1429
|
|
|
1430
|
+
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; // Sign local variables required by `sanitize`.
|
|
1360
1431
|
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
1368
|
-
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
1369
|
-
We don't need to check the value; it's always URI safe. */
|
|
1432
|
+
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
1433
|
+
} else {
|
|
1434
|
+
// Uninitialized policy, attempt to initialize the internal dompurify policy.
|
|
1435
|
+
if (trustedTypesPolicy === undefined) {
|
|
1436
|
+
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
|
1437
|
+
} // If creating the internal policy succeeded sign internal variables.
|
|
1370
1438
|
|
|
1371
1439
|
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1375
|
-
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
1376
|
-
_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)) || // Alternative, second condition checks if it's an `is`-attribute, AND
|
|
1377
|
-
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1378
|
-
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 {
|
|
1379
|
-
return false;
|
|
1440
|
+
if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
|
|
1441
|
+
emptyHTML = trustedTypesPolicy.createHTML('');
|
|
1380
1442
|
}
|
|
1381
|
-
|
|
1443
|
+
} // Prevent further manipulation of configuration.
|
|
1444
|
+
// Not available in IE8, Safari 5, etc.
|
|
1382
1445
|
|
|
1383
|
-
} 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) {
|
|
1384
|
-
return false;
|
|
1385
|
-
} else ;
|
|
1386
1446
|
|
|
1387
|
-
|
|
1447
|
+
if (freeze) {
|
|
1448
|
+
freeze(cfg);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
CONFIG = cfg;
|
|
1388
1452
|
};
|
|
1389
|
-
/**
|
|
1390
|
-
* _basicCustomElementCheck
|
|
1391
|
-
* checks if at least one dash is included in tagName, and it's not the first char
|
|
1392
|
-
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
|
1393
|
-
* @param {string} tagName name of the tag of the node to sanitize
|
|
1394
|
-
*/
|
|
1395
1453
|
|
|
1454
|
+
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
1455
|
+
const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']); // Certain elements are allowed in both SVG and HTML
|
|
1456
|
+
// namespace. We need to specify them explicitly
|
|
1457
|
+
// so that they don't get erroneously deleted from
|
|
1458
|
+
// HTML namespace.
|
|
1459
|
+
|
|
1460
|
+
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
|
1461
|
+
/* Keep track of all possible SVG and MathML tags
|
|
1462
|
+
* so that we can perform the namespace checks
|
|
1463
|
+
* correctly. */
|
|
1396
1464
|
|
|
1397
|
-
const
|
|
1398
|
-
|
|
1399
|
-
|
|
1465
|
+
const ALL_SVG_TAGS = addToSet({}, svg$1);
|
|
1466
|
+
addToSet(ALL_SVG_TAGS, svgFilters);
|
|
1467
|
+
addToSet(ALL_SVG_TAGS, svgDisallowed);
|
|
1468
|
+
const ALL_MATHML_TAGS = addToSet({}, mathMl$1);
|
|
1469
|
+
addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
|
|
1400
1470
|
/**
|
|
1401
|
-
* _sanitizeAttributes
|
|
1402
1471
|
*
|
|
1403
|
-
* @protect attributes
|
|
1404
|
-
* @protect nodeName
|
|
1405
|
-
* @protect removeAttribute
|
|
1406
|
-
* @protect setAttribute
|
|
1407
1472
|
*
|
|
1408
|
-
* @param {
|
|
1473
|
+
* @param {Element} element a DOM element whose namespace is being checked
|
|
1474
|
+
* @returns {boolean} Return false if the element has a
|
|
1475
|
+
* namespace that a spec-compliant parser would never
|
|
1476
|
+
* return. Return true otherwise.
|
|
1409
1477
|
*/
|
|
1410
1478
|
|
|
1479
|
+
const _checkValidNamespace = function _checkValidNamespace(element) {
|
|
1480
|
+
let parent = getParentNode(element); // In JSDOM, if we're inside shadow DOM, then parentNode
|
|
1481
|
+
// can be null. We just simulate parent in this case.
|
|
1411
1482
|
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
_executeHook('beforeSanitizeAttributes', currentNode, null);
|
|
1483
|
+
if (!parent || !parent.tagName) {
|
|
1484
|
+
parent = {
|
|
1485
|
+
namespaceURI: NAMESPACE,
|
|
1486
|
+
tagName: 'template'
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1420
1489
|
|
|
1421
|
-
const
|
|
1422
|
-
|
|
1423
|
-
} = currentNode;
|
|
1424
|
-
/* Check if we have attributes; if not we might have a text node */
|
|
1490
|
+
const tagName = stringToLowerCase(element.tagName);
|
|
1491
|
+
const parentTagName = stringToLowerCase(parent.tagName);
|
|
1425
1492
|
|
|
1426
|
-
if (!
|
|
1427
|
-
return;
|
|
1493
|
+
if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
1494
|
+
return false;
|
|
1428
1495
|
}
|
|
1429
1496
|
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1497
|
+
if (element.namespaceURI === SVG_NAMESPACE) {
|
|
1498
|
+
// The only way to switch from HTML namespace to SVG
|
|
1499
|
+
// is via <svg>. If it happens via any other tag, then
|
|
1500
|
+
// it should be killed.
|
|
1501
|
+
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
1502
|
+
return tagName === 'svg';
|
|
1503
|
+
} // The only way to switch from MathML to SVG is via`
|
|
1504
|
+
// svg if parent is either <annotation-xml> or MathML
|
|
1505
|
+
// text integration points.
|
|
1438
1506
|
|
|
1439
|
-
while (l--) {
|
|
1440
|
-
attr = attributes[l];
|
|
1441
|
-
const {
|
|
1442
|
-
name,
|
|
1443
|
-
namespaceURI
|
|
1444
|
-
} = attr;
|
|
1445
|
-
value = name === 'value' ? attr.value : stringTrim(attr.value);
|
|
1446
|
-
lcName = transformCaseFunc(name);
|
|
1447
|
-
/* Execute a hook if present */
|
|
1448
1507
|
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1508
|
+
if (parent.namespaceURI === MATHML_NAMESPACE) {
|
|
1509
|
+
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
|
1510
|
+
} // We only allow elements that are defined in SVG
|
|
1511
|
+
// spec. All others are disallowed in SVG namespace.
|
|
1453
1512
|
|
|
1454
|
-
_executeHook('uponSanitizeAttribute', currentNode, hookEvent);
|
|
1455
1513
|
|
|
1456
|
-
|
|
1457
|
-
|
|
1514
|
+
return Boolean(ALL_SVG_TAGS[tagName]);
|
|
1515
|
+
}
|
|
1458
1516
|
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1517
|
+
if (element.namespaceURI === MATHML_NAMESPACE) {
|
|
1518
|
+
// The only way to switch from HTML namespace to MathML
|
|
1519
|
+
// is via <math>. If it happens via any other tag, then
|
|
1520
|
+
// it should be killed.
|
|
1521
|
+
if (parent.namespaceURI === HTML_NAMESPACE) {
|
|
1522
|
+
return tagName === 'math';
|
|
1523
|
+
} // The only way to switch from SVG to MathML is via
|
|
1524
|
+
// <math> and HTML integration points
|
|
1463
1525
|
|
|
1464
1526
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1527
|
+
if (parent.namespaceURI === SVG_NAMESPACE) {
|
|
1528
|
+
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
|
1529
|
+
} // We only allow elements that are defined in MathML
|
|
1530
|
+
// spec. All others are disallowed in MathML namespace.
|
|
1467
1531
|
|
|
1468
1532
|
|
|
1469
|
-
|
|
1470
|
-
|
|
1533
|
+
return Boolean(ALL_MATHML_TAGS[tagName]);
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
if (element.namespaceURI === HTML_NAMESPACE) {
|
|
1537
|
+
// The only way to switch from SVG to HTML is via
|
|
1538
|
+
// HTML integration points, and from MathML to HTML
|
|
1539
|
+
// is via MathML text integration points
|
|
1540
|
+
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
|
|
1541
|
+
return false;
|
|
1471
1542
|
}
|
|
1472
|
-
/* Work around a security issue in jQuery 3.0 */
|
|
1473
1543
|
|
|
1544
|
+
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
|
1545
|
+
return false;
|
|
1546
|
+
} // We disallow tags that are specific for MathML
|
|
1547
|
+
// or SVG and should never appear in HTML namespace
|
|
1474
1548
|
|
|
1475
|
-
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
|
1476
|
-
_removeAttribute(name, currentNode);
|
|
1477
1549
|
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
/* Sanitize attribute content to be template-safe */
|
|
1550
|
+
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
|
1551
|
+
} // For XHTML and XML documents that support custom namespaces
|
|
1481
1552
|
|
|
1482
1553
|
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1554
|
+
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
|
|
1555
|
+
return true;
|
|
1556
|
+
} // The code should never reach this place (this means
|
|
1557
|
+
// that the element somehow got namespace that is not
|
|
1558
|
+
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
|
|
1559
|
+
// Return false just in case.
|
|
1489
1560
|
|
|
1490
1561
|
|
|
1491
|
-
|
|
1562
|
+
return false;
|
|
1563
|
+
};
|
|
1564
|
+
/**
|
|
1565
|
+
* _forceRemove
|
|
1566
|
+
*
|
|
1567
|
+
* @param {Node} node a DOM node
|
|
1568
|
+
*/
|
|
1492
1569
|
|
|
1493
|
-
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1494
|
-
continue;
|
|
1495
|
-
}
|
|
1496
|
-
/* Full DOM Clobbering protection via namespace isolation,
|
|
1497
|
-
* Prefix id and name attributes with `user-content-`
|
|
1498
|
-
*/
|
|
1499
1570
|
|
|
1571
|
+
const _forceRemove = function _forceRemove(node) {
|
|
1572
|
+
arrayPush(DOMPurify.removed, {
|
|
1573
|
+
element: node
|
|
1574
|
+
});
|
|
1575
|
+
|
|
1576
|
+
try {
|
|
1577
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
|
1578
|
+
node.parentNode.removeChild(node);
|
|
1579
|
+
} catch (_) {
|
|
1580
|
+
node.remove();
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
/**
|
|
1584
|
+
* _removeAttribute
|
|
1585
|
+
*
|
|
1586
|
+
* @param {String} name an Attribute name
|
|
1587
|
+
* @param {Node} node a DOM node
|
|
1588
|
+
*/
|
|
1500
1589
|
|
|
1501
|
-
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
1502
|
-
// Remove the attribute with this value
|
|
1503
|
-
_removeAttribute(name, currentNode); // Prefix the value and later re-create the attribute with the sanitized value
|
|
1504
1590
|
|
|
1591
|
+
const _removeAttribute = function _removeAttribute(name, node) {
|
|
1592
|
+
try {
|
|
1593
|
+
arrayPush(DOMPurify.removed, {
|
|
1594
|
+
attribute: node.getAttributeNode(name),
|
|
1595
|
+
from: node
|
|
1596
|
+
});
|
|
1597
|
+
} catch (_) {
|
|
1598
|
+
arrayPush(DOMPurify.removed, {
|
|
1599
|
+
attribute: null,
|
|
1600
|
+
from: node
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1505
1603
|
|
|
1506
|
-
|
|
1604
|
+
node.removeAttribute(name); // We void attribute values for unremovable "is"" attributes
|
|
1605
|
+
|
|
1606
|
+
if (name === 'is' && !ALLOWED_ATTR[name]) {
|
|
1607
|
+
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
|
1608
|
+
try {
|
|
1609
|
+
_forceRemove(node);
|
|
1610
|
+
} catch (_) {}
|
|
1611
|
+
} else {
|
|
1612
|
+
try {
|
|
1613
|
+
node.setAttribute(name, '');
|
|
1614
|
+
} catch (_) {}
|
|
1507
1615
|
}
|
|
1508
|
-
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
/**
|
|
1619
|
+
* _initDocument
|
|
1620
|
+
*
|
|
1621
|
+
* @param {String} dirty a string of dirty markup
|
|
1622
|
+
* @return {Document} a DOM, filled with the dirty markup
|
|
1623
|
+
*/
|
|
1509
1624
|
|
|
1510
1625
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
{
|
|
1516
|
-
value = trustedTypesPolicy.createHTML(value);
|
|
1517
|
-
break;
|
|
1518
|
-
}
|
|
1626
|
+
const _initDocument = function _initDocument(dirty) {
|
|
1627
|
+
/* Create a HTML document */
|
|
1628
|
+
let doc;
|
|
1629
|
+
let leadingWhitespace;
|
|
1519
1630
|
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1631
|
+
if (FORCE_BODY) {
|
|
1632
|
+
dirty = '<remove></remove>' + dirty;
|
|
1633
|
+
} else {
|
|
1634
|
+
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
|
1635
|
+
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
|
|
1636
|
+
leadingWhitespace = matches && matches[0];
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
|
|
1640
|
+
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
|
|
1641
|
+
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
1645
|
+
/*
|
|
1646
|
+
* Use the DOMParser API by default, fallback later if needs be
|
|
1647
|
+
* DOMParser not work for svg when has multiple root element.
|
|
1648
|
+
*/
|
|
1649
|
+
|
|
1650
|
+
if (NAMESPACE === HTML_NAMESPACE) {
|
|
1651
|
+
try {
|
|
1652
|
+
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
|
1653
|
+
} catch (_) {}
|
|
1654
|
+
}
|
|
1655
|
+
/* Use createHTMLDocument in case DOMParser is not available */
|
|
1529
1656
|
|
|
1530
1657
|
|
|
1658
|
+
if (!doc || !doc.documentElement) {
|
|
1659
|
+
doc = implementation.createDocument(NAMESPACE, 'template', null);
|
|
1660
|
+
|
|
1531
1661
|
try {
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
currentNode.setAttribute(name, value);
|
|
1537
|
-
}
|
|
1662
|
+
doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
|
|
1663
|
+
} catch (_) {// Syntax error if dirtyPayload is invalid xml
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1538
1666
|
|
|
1539
|
-
|
|
1540
|
-
|
|
1667
|
+
const body = doc.body || doc.documentElement;
|
|
1668
|
+
|
|
1669
|
+
if (dirty && leadingWhitespace) {
|
|
1670
|
+
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
|
1541
1671
|
}
|
|
1542
|
-
/*
|
|
1672
|
+
/* Work on whole document or just its body */
|
|
1543
1673
|
|
|
1544
1674
|
|
|
1545
|
-
|
|
1675
|
+
if (NAMESPACE === HTML_NAMESPACE) {
|
|
1676
|
+
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
return WHOLE_DOCUMENT ? doc.documentElement : body;
|
|
1546
1680
|
};
|
|
1547
1681
|
/**
|
|
1548
|
-
*
|
|
1682
|
+
* _createIterator
|
|
1549
1683
|
*
|
|
1550
|
-
* @param {
|
|
1684
|
+
* @param {Document} root document/fragment to create iterator for
|
|
1685
|
+
* @return {Iterator} iterator instance
|
|
1551
1686
|
*/
|
|
1552
1687
|
|
|
1553
1688
|
|
|
1554
|
-
const
|
|
1555
|
-
|
|
1689
|
+
const _createIterator = function _createIterator(root) {
|
|
1690
|
+
return createNodeIterator.call(root.ownerDocument || root, root, // eslint-disable-next-line no-bitwise
|
|
1691
|
+
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
|
|
1692
|
+
};
|
|
1693
|
+
/**
|
|
1694
|
+
* _isClobbered
|
|
1695
|
+
*
|
|
1696
|
+
* @param {Node} elm element to check for clobbering attacks
|
|
1697
|
+
* @return {Boolean} true if clobbered, false if safe
|
|
1698
|
+
*/
|
|
1556
1699
|
|
|
1557
|
-
const shadowIterator = _createIterator(fragment);
|
|
1558
|
-
/* Execute a hook if present */
|
|
1559
1700
|
|
|
1701
|
+
const _isClobbered = function _isClobbered(elm) {
|
|
1702
|
+
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');
|
|
1703
|
+
};
|
|
1704
|
+
/**
|
|
1705
|
+
* _isNode
|
|
1706
|
+
*
|
|
1707
|
+
* @param {Node} obj object to check whether it's a DOM node
|
|
1708
|
+
* @return {Boolean} true is object is a DOM node
|
|
1709
|
+
*/
|
|
1560
1710
|
|
|
1561
|
-
_executeHook('beforeSanitizeShadowDOM', fragment, null);
|
|
1562
1711
|
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1712
|
+
const _isNode = function _isNode(object) {
|
|
1713
|
+
return typeof Node === 'object' ? object instanceof Node : object && typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
|
|
1714
|
+
};
|
|
1715
|
+
/**
|
|
1716
|
+
* _executeHook
|
|
1717
|
+
* Execute user configurable hooks
|
|
1718
|
+
*
|
|
1719
|
+
* @param {String} entryPoint Name of the hook's entry point
|
|
1720
|
+
* @param {Node} currentNode node to work on with the hook
|
|
1721
|
+
* @param {Object} data additional hook parameters
|
|
1722
|
+
*/
|
|
1567
1723
|
|
|
1568
1724
|
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1725
|
+
const _executeHook = function _executeHook(entryPoint, currentNode, data) {
|
|
1726
|
+
if (!hooks[entryPoint]) {
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1573
1729
|
|
|
1730
|
+
arrayForEach(hooks[entryPoint], hook => {
|
|
1731
|
+
hook.call(DOMPurify, currentNode, data, CONFIG);
|
|
1732
|
+
});
|
|
1733
|
+
};
|
|
1734
|
+
/**
|
|
1735
|
+
* _sanitizeElements
|
|
1736
|
+
*
|
|
1737
|
+
* @protect nodeName
|
|
1738
|
+
* @protect textContent
|
|
1739
|
+
* @protect removeChild
|
|
1740
|
+
*
|
|
1741
|
+
* @param {Node} currentNode to check for permission to exist
|
|
1742
|
+
* @return {Boolean} true if node was killed, false if left alive
|
|
1743
|
+
*/
|
|
1574
1744
|
|
|
1575
|
-
if (shadowNode.content instanceof DocumentFragment) {
|
|
1576
|
-
_sanitizeShadowDOM(shadowNode.content);
|
|
1577
|
-
}
|
|
1578
|
-
/* Check attributes, sanitize if necessary */
|
|
1579
1745
|
|
|
1746
|
+
const _sanitizeElements = function _sanitizeElements(currentNode) {
|
|
1747
|
+
let content;
|
|
1748
|
+
/* Execute a hook if present */
|
|
1580
1749
|
|
|
1581
|
-
|
|
1750
|
+
_executeHook('beforeSanitizeElements', currentNode, null);
|
|
1751
|
+
/* Check if element is clobbered or can clobber */
|
|
1752
|
+
|
|
1753
|
+
|
|
1754
|
+
if (_isClobbered(currentNode)) {
|
|
1755
|
+
_forceRemove(currentNode);
|
|
1756
|
+
|
|
1757
|
+
return true;
|
|
1582
1758
|
}
|
|
1583
|
-
/*
|
|
1759
|
+
/* Now let's check the element's type and name */
|
|
1584
1760
|
|
|
1585
1761
|
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
/**
|
|
1589
|
-
* Sanitize
|
|
1590
|
-
* Public method providing core sanitation functionality
|
|
1591
|
-
*
|
|
1592
|
-
* @param {String|Node} dirty string or DOM node
|
|
1593
|
-
* @param {Object} configuration object
|
|
1594
|
-
*/
|
|
1595
|
-
// eslint-disable-next-line complexity
|
|
1762
|
+
const tagName = transformCaseFunc(currentNode.nodeName);
|
|
1763
|
+
/* Execute a hook if present */
|
|
1596
1764
|
|
|
1765
|
+
_executeHook('uponSanitizeElement', currentNode, {
|
|
1766
|
+
tagName,
|
|
1767
|
+
allowedTags: ALLOWED_TAGS
|
|
1768
|
+
});
|
|
1769
|
+
/* Detect mXSS attempts abusing namespace confusion */
|
|
1597
1770
|
|
|
1598
|
-
DOMPurify.sanitize = function (dirty) {
|
|
1599
|
-
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1600
|
-
let body;
|
|
1601
|
-
let importedNode;
|
|
1602
|
-
let currentNode;
|
|
1603
|
-
let returnNode;
|
|
1604
|
-
/* Make sure we have a string to sanitize.
|
|
1605
|
-
DO NOT return early, as this will return the wrong type if
|
|
1606
|
-
the user has requested a DOM object rather than a string */
|
|
1607
1771
|
|
|
1608
|
-
|
|
1772
|
+
if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
|
|
1773
|
+
_forceRemove(currentNode);
|
|
1609
1774
|
|
|
1610
|
-
|
|
1611
|
-
dirty = '<!-->';
|
|
1775
|
+
return true;
|
|
1612
1776
|
}
|
|
1613
|
-
/*
|
|
1777
|
+
/* Remove element if anything forbids its presence */
|
|
1614
1778
|
|
|
1615
1779
|
|
|
1616
|
-
if (
|
|
1617
|
-
if
|
|
1618
|
-
|
|
1780
|
+
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
1781
|
+
/* Check if we have a custom element to handle */
|
|
1782
|
+
if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
|
|
1783
|
+
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
|
|
1784
|
+
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
|
|
1785
|
+
}
|
|
1786
|
+
/* Keep content except for bad-listed elements */
|
|
1619
1787
|
|
|
1620
|
-
|
|
1621
|
-
|
|
1788
|
+
|
|
1789
|
+
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
1790
|
+
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
|
1791
|
+
const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
|
1792
|
+
|
|
1793
|
+
if (childNodes && parentNode) {
|
|
1794
|
+
const childCount = childNodes.length;
|
|
1795
|
+
|
|
1796
|
+
for (let i = childCount - 1; i >= 0; --i) {
|
|
1797
|
+
parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
|
|
1798
|
+
}
|
|
1622
1799
|
}
|
|
1623
|
-
} else {
|
|
1624
|
-
throw typeErrorCreate('toString is not a function');
|
|
1625
1800
|
}
|
|
1626
|
-
}
|
|
1627
|
-
/* Return dirty HTML if DOMPurify cannot run */
|
|
1628
1801
|
|
|
1802
|
+
_forceRemove(currentNode);
|
|
1629
1803
|
|
|
1630
|
-
|
|
1631
|
-
return dirty;
|
|
1804
|
+
return true;
|
|
1632
1805
|
}
|
|
1633
|
-
/*
|
|
1806
|
+
/* Check whether element has a valid namespace */
|
|
1634
1807
|
|
|
1635
1808
|
|
|
1636
|
-
if (!
|
|
1637
|
-
|
|
1809
|
+
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
|
|
1810
|
+
_forceRemove(currentNode);
|
|
1811
|
+
|
|
1812
|
+
return true;
|
|
1638
1813
|
}
|
|
1639
|
-
/*
|
|
1814
|
+
/* Make sure that older browsers don't get noscript mXSS */
|
|
1640
1815
|
|
|
1641
1816
|
|
|
1642
|
-
|
|
1643
|
-
|
|
1817
|
+
if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
|
|
1818
|
+
_forceRemove(currentNode);
|
|
1644
1819
|
|
|
1645
|
-
|
|
1646
|
-
IN_PLACE = false;
|
|
1820
|
+
return true;
|
|
1647
1821
|
}
|
|
1822
|
+
/* Sanitize element content to be template-safe */
|
|
1648
1823
|
|
|
1649
|
-
if (IN_PLACE) {
|
|
1650
|
-
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
|
1651
|
-
if (dirty.nodeName) {
|
|
1652
|
-
const tagName = transformCaseFunc(dirty.nodeName);
|
|
1653
1824
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
elements being stripped by the parser */
|
|
1661
|
-
body = _initDocument('<!---->');
|
|
1662
|
-
importedNode = body.ownerDocument.importNode(dirty, true);
|
|
1825
|
+
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
|
|
1826
|
+
/* Get the element's text content */
|
|
1827
|
+
content = currentNode.textContent;
|
|
1828
|
+
content = stringReplace(content, MUSTACHE_EXPR, ' ');
|
|
1829
|
+
content = stringReplace(content, ERB_EXPR, ' ');
|
|
1830
|
+
content = stringReplace(content, TMPLIT_EXPR, ' ');
|
|
1663
1831
|
|
|
1664
|
-
if (
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
} else {
|
|
1670
|
-
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
1671
|
-
body.appendChild(importedNode);
|
|
1672
|
-
}
|
|
1673
|
-
} else {
|
|
1674
|
-
/* Exit directly if we have nothing to do */
|
|
1675
|
-
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && // eslint-disable-next-line unicorn/prefer-includes
|
|
1676
|
-
dirty.indexOf('<') === -1) {
|
|
1677
|
-
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
1832
|
+
if (currentNode.textContent !== content) {
|
|
1833
|
+
arrayPush(DOMPurify.removed, {
|
|
1834
|
+
element: currentNode.cloneNode()
|
|
1835
|
+
});
|
|
1836
|
+
currentNode.textContent = content;
|
|
1678
1837
|
}
|
|
1679
|
-
|
|
1838
|
+
}
|
|
1839
|
+
/* Execute a hook if present */
|
|
1840
|
+
|
|
1841
|
+
|
|
1842
|
+
_executeHook('afterSanitizeElements', currentNode, null);
|
|
1680
1843
|
|
|
1844
|
+
return false;
|
|
1845
|
+
};
|
|
1846
|
+
/**
|
|
1847
|
+
* _isValidAttribute
|
|
1848
|
+
*
|
|
1849
|
+
* @param {string} lcTag Lowercase tag name of containing element.
|
|
1850
|
+
* @param {string} lcName Lowercase attribute name.
|
|
1851
|
+
* @param {string} value Attribute value.
|
|
1852
|
+
* @return {Boolean} Returns true if `value` is valid, otherwise false.
|
|
1853
|
+
*/
|
|
1854
|
+
// eslint-disable-next-line complexity
|
|
1855
|
+
|
|
1856
|
+
|
|
1857
|
+
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
1858
|
+
/* Make sure attribute cannot clobber */
|
|
1859
|
+
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1860
|
+
return false;
|
|
1861
|
+
}
|
|
1862
|
+
/* Allow valid data-* attributes: At least one character after "-"
|
|
1863
|
+
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
|
1864
|
+
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
|
1865
|
+
We don't need to check the value; it's always URI safe. */
|
|
1681
1866
|
|
|
1682
|
-
body = _initDocument(dirty);
|
|
1683
|
-
/* Check we have a DOM node from the data */
|
|
1684
1867
|
|
|
1685
|
-
|
|
1686
|
-
|
|
1868
|
+
if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
|
|
1869
|
+
if ( // First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
|
1870
|
+
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1871
|
+
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
|
1872
|
+
_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)) || // Alternative, second condition checks if it's an `is`-attribute, AND
|
|
1873
|
+
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
|
1874
|
+
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 {
|
|
1875
|
+
return false;
|
|
1687
1876
|
}
|
|
1688
|
-
|
|
1689
|
-
/* Remove first element node (ours) if FORCE_BODY is set */
|
|
1690
|
-
|
|
1877
|
+
/* Check value is safe. First, is attr inert? If so, is safe */
|
|
1691
1878
|
|
|
1692
|
-
if (
|
|
1693
|
-
|
|
1694
|
-
}
|
|
1695
|
-
/* Get node iterator */
|
|
1879
|
+
} 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) {
|
|
1880
|
+
return false;
|
|
1881
|
+
} else ;
|
|
1696
1882
|
|
|
1883
|
+
return true;
|
|
1884
|
+
};
|
|
1885
|
+
/**
|
|
1886
|
+
* _basicCustomElementCheck
|
|
1887
|
+
* checks if at least one dash is included in tagName, and it's not the first char
|
|
1888
|
+
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
|
1889
|
+
* @param {string} tagName name of the tag of the node to sanitize
|
|
1890
|
+
*/
|
|
1697
1891
|
|
|
1698
|
-
const nodeIterator = _createIterator(IN_PLACE ? dirty : body);
|
|
1699
|
-
/* Now start iterating over the created document */
|
|
1700
1892
|
|
|
1893
|
+
const _basicCustomElementTest = function _basicCustomElementTest(tagName) {
|
|
1894
|
+
return tagName.indexOf('-') > 0;
|
|
1895
|
+
};
|
|
1896
|
+
/**
|
|
1897
|
+
* _sanitizeAttributes
|
|
1898
|
+
*
|
|
1899
|
+
* @protect attributes
|
|
1900
|
+
* @protect nodeName
|
|
1901
|
+
* @protect removeAttribute
|
|
1902
|
+
* @protect setAttribute
|
|
1903
|
+
*
|
|
1904
|
+
* @param {Node} currentNode to sanitize
|
|
1905
|
+
*/
|
|
1701
1906
|
|
|
1702
|
-
while (currentNode = nodeIterator.nextNode()) {
|
|
1703
|
-
/* Sanitize tags and elements */
|
|
1704
|
-
if (_sanitizeElements(currentNode)) {
|
|
1705
|
-
continue;
|
|
1706
|
-
}
|
|
1707
|
-
/* Shadow DOM detected, sanitize it */
|
|
1708
1907
|
|
|
1908
|
+
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
|
1909
|
+
let attr;
|
|
1910
|
+
let value;
|
|
1911
|
+
let lcName;
|
|
1912
|
+
let l;
|
|
1913
|
+
/* Execute a hook if present */
|
|
1709
1914
|
|
|
1710
|
-
|
|
1711
|
-
_sanitizeShadowDOM(currentNode.content);
|
|
1712
|
-
}
|
|
1713
|
-
/* Check attributes, sanitize if necessary */
|
|
1915
|
+
_executeHook('beforeSanitizeAttributes', currentNode, null);
|
|
1714
1916
|
|
|
1917
|
+
const {
|
|
1918
|
+
attributes
|
|
1919
|
+
} = currentNode;
|
|
1920
|
+
/* Check if we have attributes; if not we might have a text node */
|
|
1715
1921
|
|
|
1716
|
-
|
|
1922
|
+
if (!attributes) {
|
|
1923
|
+
return;
|
|
1717
1924
|
}
|
|
1718
|
-
/* If we sanitized `dirty` in-place, return it. */
|
|
1719
1925
|
|
|
1926
|
+
const hookEvent = {
|
|
1927
|
+
attrName: '',
|
|
1928
|
+
attrValue: '',
|
|
1929
|
+
keepAttr: true,
|
|
1930
|
+
allowedAttributes: ALLOWED_ATTR
|
|
1931
|
+
};
|
|
1932
|
+
l = attributes.length;
|
|
1933
|
+
/* Go backwards over all attributes; safely remove bad ones */
|
|
1720
1934
|
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1935
|
+
while (l--) {
|
|
1936
|
+
attr = attributes[l];
|
|
1937
|
+
const {
|
|
1938
|
+
name,
|
|
1939
|
+
namespaceURI
|
|
1940
|
+
} = attr;
|
|
1941
|
+
value = name === 'value' ? attr.value : stringTrim(attr.value);
|
|
1942
|
+
lcName = transformCaseFunc(name);
|
|
1943
|
+
/* Execute a hook if present */
|
|
1725
1944
|
|
|
1945
|
+
hookEvent.attrName = lcName;
|
|
1946
|
+
hookEvent.attrValue = value;
|
|
1947
|
+
hookEvent.keepAttr = true;
|
|
1948
|
+
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
|
1726
1949
|
|
|
1727
|
-
|
|
1728
|
-
if (RETURN_DOM_FRAGMENT) {
|
|
1729
|
-
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
1950
|
+
_executeHook('uponSanitizeAttribute', currentNode, hookEvent);
|
|
1730
1951
|
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
returnNode.appendChild(body.firstChild);
|
|
1734
|
-
}
|
|
1735
|
-
} else {
|
|
1736
|
-
returnNode = body;
|
|
1737
|
-
}
|
|
1952
|
+
value = hookEvent.attrValue;
|
|
1953
|
+
/* Did the hooks approve of the attribute? */
|
|
1738
1954
|
|
|
1739
|
-
if (
|
|
1740
|
-
|
|
1741
|
-
AdoptNode() is not used because internal state is not reset
|
|
1742
|
-
(e.g. the past names map of a HTMLFormElement), this is safe
|
|
1743
|
-
in theory but we would rather not risk another attack vector.
|
|
1744
|
-
The state that is cloned by importNode() is explicitly defined
|
|
1745
|
-
by the specs.
|
|
1746
|
-
*/
|
|
1747
|
-
returnNode = importNode.call(originalDocument, returnNode, true);
|
|
1955
|
+
if (hookEvent.forceKeepAttr) {
|
|
1956
|
+
continue;
|
|
1748
1957
|
}
|
|
1958
|
+
/* Remove attribute */
|
|
1749
1959
|
|
|
1750
|
-
return returnNode;
|
|
1751
|
-
}
|
|
1752
1960
|
|
|
1753
|
-
|
|
1754
|
-
|
|
1961
|
+
_removeAttribute(name, currentNode);
|
|
1962
|
+
/* Did the hooks approve of the attribute? */
|
|
1755
1963
|
|
|
1756
|
-
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
|
1757
|
-
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
|
1758
|
-
}
|
|
1759
|
-
/* Sanitize final string template-safe */
|
|
1760
1964
|
|
|
1965
|
+
if (!hookEvent.keepAttr) {
|
|
1966
|
+
continue;
|
|
1967
|
+
}
|
|
1968
|
+
/* Work around a security issue in jQuery 3.0 */
|
|
1761
1969
|
|
|
1762
|
-
if (SAFE_FOR_TEMPLATES) {
|
|
1763
|
-
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR, ' ');
|
|
1764
|
-
serializedHTML = stringReplace(serializedHTML, ERB_EXPR, ' ');
|
|
1765
|
-
serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR, ' ');
|
|
1766
|
-
}
|
|
1767
1970
|
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
/**
|
|
1771
|
-
* Public method to set the configuration once
|
|
1772
|
-
* setConfig
|
|
1773
|
-
*
|
|
1774
|
-
* @param {Object} cfg configuration object
|
|
1775
|
-
*/
|
|
1971
|
+
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
|
1972
|
+
_removeAttribute(name, currentNode);
|
|
1776
1973
|
|
|
1974
|
+
continue;
|
|
1975
|
+
}
|
|
1976
|
+
/* Sanitize attribute content to be template-safe */
|
|
1777
1977
|
|
|
1778
|
-
DOMPurify.setConfig = function (cfg) {
|
|
1779
|
-
_parseConfig(cfg);
|
|
1780
1978
|
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
*/
|
|
1979
|
+
if (SAFE_FOR_TEMPLATES) {
|
|
1980
|
+
value = stringReplace(value, MUSTACHE_EXPR, ' ');
|
|
1981
|
+
value = stringReplace(value, ERB_EXPR, ' ');
|
|
1982
|
+
value = stringReplace(value, TMPLIT_EXPR, ' ');
|
|
1983
|
+
}
|
|
1984
|
+
/* Is `value` valid for this attribute? */
|
|
1788
1985
|
|
|
1789
1986
|
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
*
|
|
1799
|
-
* @param {string} tag Tag name of containing element.
|
|
1800
|
-
* @param {string} attr Attribute name.
|
|
1801
|
-
* @param {string} value Attribute value.
|
|
1802
|
-
* @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
|
|
1803
|
-
*/
|
|
1987
|
+
const lcTag = transformCaseFunc(currentNode.nodeName);
|
|
1988
|
+
|
|
1989
|
+
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
1990
|
+
continue;
|
|
1991
|
+
}
|
|
1992
|
+
/* Full DOM Clobbering protection via namespace isolation,
|
|
1993
|
+
* Prefix id and name attributes with `user-content-`
|
|
1994
|
+
*/
|
|
1804
1995
|
|
|
1805
1996
|
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
_parseConfig({});
|
|
1810
|
-
}
|
|
1997
|
+
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
|
1998
|
+
// Remove the attribute with this value
|
|
1999
|
+
_removeAttribute(name, currentNode); // Prefix the value and later re-create the attribute with the sanitized value
|
|
1811
2000
|
|
|
1812
|
-
const lcTag = transformCaseFunc(tag);
|
|
1813
|
-
const lcName = transformCaseFunc(attr);
|
|
1814
|
-
return _isValidAttribute(lcTag, lcName, value);
|
|
1815
|
-
};
|
|
1816
|
-
/**
|
|
1817
|
-
* AddHook
|
|
1818
|
-
* Public method to add DOMPurify hooks
|
|
1819
|
-
*
|
|
1820
|
-
* @param {String} entryPoint entry point for the hook to add
|
|
1821
|
-
* @param {Function} hookFunction function to execute
|
|
1822
|
-
*/
|
|
1823
2001
|
|
|
2002
|
+
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
2003
|
+
}
|
|
2004
|
+
/* Handle attributes that require Trusted Types */
|
|
1824
2005
|
|
|
1825
|
-
DOMPurify.addHook = function (entryPoint, hookFunction) {
|
|
1826
|
-
if (typeof hookFunction !== 'function') {
|
|
1827
|
-
return;
|
|
1828
|
-
}
|
|
1829
2006
|
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
2007
|
+
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
|
2008
|
+
if (namespaceURI) ; else {
|
|
2009
|
+
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
|
2010
|
+
case 'TrustedHTML':
|
|
2011
|
+
{
|
|
2012
|
+
value = trustedTypesPolicy.createHTML(value);
|
|
2013
|
+
break;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
case 'TrustedScriptURL':
|
|
2017
|
+
{
|
|
2018
|
+
value = trustedTypesPolicy.createScriptURL(value);
|
|
2019
|
+
break;
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
/* Handle invalid data-* attribute set by try-catching it */
|
|
2025
|
+
|
|
1841
2026
|
|
|
2027
|
+
try {
|
|
2028
|
+
if (namespaceURI) {
|
|
2029
|
+
currentNode.setAttributeNS(namespaceURI, name, value);
|
|
2030
|
+
} else {
|
|
2031
|
+
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
|
2032
|
+
currentNode.setAttribute(name, value);
|
|
2033
|
+
}
|
|
1842
2034
|
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
return arrayPop(hooks[entryPoint]);
|
|
2035
|
+
arrayPop(DOMPurify.removed);
|
|
2036
|
+
} catch (_) {}
|
|
1846
2037
|
}
|
|
1847
|
-
|
|
1848
|
-
/**
|
|
1849
|
-
* RemoveHooks
|
|
1850
|
-
* Public method to remove all DOMPurify hooks at a given entryPoint
|
|
1851
|
-
*
|
|
1852
|
-
* @param {String} entryPoint entry point for the hooks to remove
|
|
1853
|
-
*/
|
|
2038
|
+
/* Execute a hook if present */
|
|
1854
2039
|
|
|
1855
2040
|
|
|
1856
|
-
|
|
1857
|
-
if (hooks[entryPoint]) {
|
|
1858
|
-
hooks[entryPoint] = [];
|
|
1859
|
-
}
|
|
2041
|
+
_executeHook('afterSanitizeAttributes', currentNode, null);
|
|
1860
2042
|
};
|
|
1861
2043
|
/**
|
|
1862
|
-
*
|
|
1863
|
-
* Public method to remove all DOMPurify hooks
|
|
2044
|
+
* _sanitizeShadowDOM
|
|
1864
2045
|
*
|
|
2046
|
+
* @param {DocumentFragment} fragment to iterate over recursively
|
|
1865
2047
|
*/
|
|
1866
2048
|
|
|
1867
2049
|
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
};
|
|
1871
|
-
|
|
1872
|
-
return DOMPurify;
|
|
1873
|
-
}
|
|
2050
|
+
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
|
2051
|
+
let shadowNode;
|
|
1874
2052
|
|
|
1875
|
-
|
|
2053
|
+
const shadowIterator = _createIterator(fragment);
|
|
2054
|
+
/* Execute a hook if present */
|
|
1876
2055
|
|
|
1877
|
-
function _classCallCheck(instance, Constructor) {
|
|
1878
|
-
if (!(instance instanceof Constructor)) {
|
|
1879
|
-
throw new TypeError("Cannot call a class as a function");
|
|
1880
|
-
}
|
|
1881
|
-
}
|
|
1882
2056
|
|
|
1883
|
-
|
|
1884
|
-
"@babel/helpers - typeof";
|
|
2057
|
+
_executeHook('beforeSanitizeShadowDOM', fragment, null);
|
|
1885
2058
|
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
}, _typeof(obj);
|
|
1891
|
-
}
|
|
2059
|
+
while (shadowNode = shadowIterator.nextNode()) {
|
|
2060
|
+
/* Execute a hook if present */
|
|
2061
|
+
_executeHook('uponSanitizeShadowNode', shadowNode, null);
|
|
2062
|
+
/* Sanitize tags and elements */
|
|
1892
2063
|
|
|
1893
|
-
function _toPrimitive(input, hint) {
|
|
1894
|
-
if (_typeof(input) !== "object" || input === null) return input;
|
|
1895
|
-
var prim = input[Symbol.toPrimitive];
|
|
1896
|
-
if (prim !== undefined) {
|
|
1897
|
-
var res = prim.call(input, hint || "default");
|
|
1898
|
-
if (_typeof(res) !== "object") return res;
|
|
1899
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
1900
|
-
}
|
|
1901
|
-
return (hint === "string" ? String : Number)(input);
|
|
1902
|
-
}
|
|
1903
2064
|
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
2065
|
+
if (_sanitizeElements(shadowNode)) {
|
|
2066
|
+
continue;
|
|
2067
|
+
}
|
|
2068
|
+
/* Deep shadow DOM detected */
|
|
1908
2069
|
|
|
1909
|
-
function _defineProperties(target, props) {
|
|
1910
|
-
for (var i = 0; i < props.length; i++) {
|
|
1911
|
-
var descriptor = props[i];
|
|
1912
|
-
descriptor.enumerable = descriptor.enumerable || false;
|
|
1913
|
-
descriptor.configurable = true;
|
|
1914
|
-
if ("value" in descriptor) descriptor.writable = true;
|
|
1915
|
-
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
function _createClass(Constructor, protoProps, staticProps) {
|
|
1919
|
-
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
1920
|
-
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
1921
|
-
Object.defineProperty(Constructor, "prototype", {
|
|
1922
|
-
writable: false
|
|
1923
|
-
});
|
|
1924
|
-
return Constructor;
|
|
1925
|
-
}
|
|
1926
2070
|
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
var slice = arr.slice;
|
|
1930
|
-
function defaults(obj) {
|
|
1931
|
-
each.call(slice.call(arguments, 1), function (source) {
|
|
1932
|
-
if (source) {
|
|
1933
|
-
for (var prop in source) {
|
|
1934
|
-
if (obj[prop] === undefined) obj[prop] = source[prop];
|
|
2071
|
+
if (shadowNode.content instanceof DocumentFragment) {
|
|
2072
|
+
_sanitizeShadowDOM(shadowNode.content);
|
|
1935
2073
|
}
|
|
1936
|
-
|
|
1937
|
-
});
|
|
1938
|
-
return obj;
|
|
1939
|
-
}
|
|
2074
|
+
/* Check attributes, sanitize if necessary */
|
|
1940
2075
|
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
var serializeCookie = function serializeCookie(name, val, options) {
|
|
1944
|
-
var opt = options || {};
|
|
1945
|
-
opt.path = opt.path || '/';
|
|
1946
|
-
var value = encodeURIComponent(val);
|
|
1947
|
-
var str = "".concat(name, "=").concat(value);
|
|
1948
|
-
if (opt.maxAge > 0) {
|
|
1949
|
-
var maxAge = opt.maxAge - 0;
|
|
1950
|
-
if (Number.isNaN(maxAge)) throw new Error('maxAge should be a Number');
|
|
1951
|
-
str += "; Max-Age=".concat(Math.floor(maxAge));
|
|
1952
|
-
}
|
|
1953
|
-
if (opt.domain) {
|
|
1954
|
-
if (!fieldContentRegExp.test(opt.domain)) {
|
|
1955
|
-
throw new TypeError('option domain is invalid');
|
|
1956
|
-
}
|
|
1957
|
-
str += "; Domain=".concat(opt.domain);
|
|
1958
|
-
}
|
|
1959
|
-
if (opt.path) {
|
|
1960
|
-
if (!fieldContentRegExp.test(opt.path)) {
|
|
1961
|
-
throw new TypeError('option path is invalid');
|
|
1962
|
-
}
|
|
1963
|
-
str += "; Path=".concat(opt.path);
|
|
1964
|
-
}
|
|
1965
|
-
if (opt.expires) {
|
|
1966
|
-
if (typeof opt.expires.toUTCString !== 'function') {
|
|
1967
|
-
throw new TypeError('option expires is invalid');
|
|
1968
|
-
}
|
|
1969
|
-
str += "; Expires=".concat(opt.expires.toUTCString());
|
|
1970
|
-
}
|
|
1971
|
-
if (opt.httpOnly) str += '; HttpOnly';
|
|
1972
|
-
if (opt.secure) str += '; Secure';
|
|
1973
|
-
if (opt.sameSite) {
|
|
1974
|
-
var sameSite = typeof opt.sameSite === 'string' ? opt.sameSite.toLowerCase() : opt.sameSite;
|
|
1975
|
-
switch (sameSite) {
|
|
1976
|
-
case true:
|
|
1977
|
-
str += '; SameSite=Strict';
|
|
1978
|
-
break;
|
|
1979
|
-
case 'lax':
|
|
1980
|
-
str += '; SameSite=Lax';
|
|
1981
|
-
break;
|
|
1982
|
-
case 'strict':
|
|
1983
|
-
str += '; SameSite=Strict';
|
|
1984
|
-
break;
|
|
1985
|
-
case 'none':
|
|
1986
|
-
str += '; SameSite=None';
|
|
1987
|
-
break;
|
|
1988
|
-
default:
|
|
1989
|
-
throw new TypeError('option sameSite is invalid');
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
return str;
|
|
1993
|
-
};
|
|
1994
|
-
var cookie = {
|
|
1995
|
-
create: function create(name, value, minutes, domain) {
|
|
1996
|
-
var cookieOptions = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {
|
|
1997
|
-
path: '/',
|
|
1998
|
-
sameSite: 'strict'
|
|
1999
|
-
};
|
|
2000
|
-
if (minutes) {
|
|
2001
|
-
cookieOptions.expires = new Date();
|
|
2002
|
-
cookieOptions.expires.setTime(cookieOptions.expires.getTime() + minutes * 60 * 1000);
|
|
2003
|
-
}
|
|
2004
|
-
if (domain) cookieOptions.domain = domain;
|
|
2005
|
-
document.cookie = serializeCookie(name, encodeURIComponent(value), cookieOptions);
|
|
2006
|
-
},
|
|
2007
|
-
read: function read(name) {
|
|
2008
|
-
var nameEQ = "".concat(name, "=");
|
|
2009
|
-
var ca = document.cookie.split(';');
|
|
2010
|
-
for (var i = 0; i < ca.length; i++) {
|
|
2011
|
-
var c = ca[i];
|
|
2012
|
-
while (c.charAt(0) === ' ') {
|
|
2013
|
-
c = c.substring(1, c.length);
|
|
2014
|
-
}
|
|
2015
|
-
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
|
|
2016
|
-
}
|
|
2017
|
-
return null;
|
|
2018
|
-
},
|
|
2019
|
-
remove: function remove(name) {
|
|
2020
|
-
this.create(name, '', -1);
|
|
2021
|
-
}
|
|
2022
|
-
};
|
|
2023
|
-
var cookie$1 = {
|
|
2024
|
-
name: 'cookie',
|
|
2025
|
-
lookup: function lookup(options) {
|
|
2026
|
-
var found;
|
|
2027
|
-
if (options.lookupCookie && typeof document !== 'undefined') {
|
|
2028
|
-
var c = cookie.read(options.lookupCookie);
|
|
2029
|
-
if (c) found = c;
|
|
2076
|
+
|
|
2077
|
+
_sanitizeAttributes(shadowNode);
|
|
2030
2078
|
}
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2079
|
+
/* Execute a hook if present */
|
|
2080
|
+
|
|
2081
|
+
|
|
2082
|
+
_executeHook('afterSanitizeShadowDOM', fragment, null);
|
|
2083
|
+
};
|
|
2084
|
+
/**
|
|
2085
|
+
* Sanitize
|
|
2086
|
+
* Public method providing core sanitation functionality
|
|
2087
|
+
*
|
|
2088
|
+
* @param {String|Node} dirty string or DOM node
|
|
2089
|
+
* @param {Object} configuration object
|
|
2090
|
+
*/
|
|
2091
|
+
// eslint-disable-next-line complexity
|
|
2092
|
+
|
|
2093
|
+
|
|
2094
|
+
DOMPurify.sanitize = function (dirty) {
|
|
2095
|
+
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
2096
|
+
let body;
|
|
2097
|
+
let importedNode;
|
|
2098
|
+
let currentNode;
|
|
2099
|
+
let returnNode;
|
|
2100
|
+
/* Make sure we have a string to sanitize.
|
|
2101
|
+
DO NOT return early, as this will return the wrong type if
|
|
2102
|
+
the user has requested a DOM object rather than a string */
|
|
2103
|
+
|
|
2104
|
+
IS_EMPTY_INPUT = !dirty;
|
|
2105
|
+
|
|
2106
|
+
if (IS_EMPTY_INPUT) {
|
|
2107
|
+
dirty = '<!-->';
|
|
2036
2108
|
}
|
|
2037
|
-
|
|
2038
|
-
};
|
|
2109
|
+
/* Stringify, in case dirty is an object */
|
|
2039
2110
|
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
search = window.location.hash.substring(window.location.hash.indexOf('?'));
|
|
2048
|
-
}
|
|
2049
|
-
var query = search.substring(1);
|
|
2050
|
-
var params = query.split('&');
|
|
2051
|
-
for (var i = 0; i < params.length; i++) {
|
|
2052
|
-
var pos = params[i].indexOf('=');
|
|
2053
|
-
if (pos > 0) {
|
|
2054
|
-
var key = params[i].substring(0, pos);
|
|
2055
|
-
if (key === options.lookupQuerystring) {
|
|
2056
|
-
found = params[i].substring(pos + 1);
|
|
2057
|
-
}
|
|
2111
|
+
|
|
2112
|
+
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
|
2113
|
+
if (typeof dirty.toString === 'function') {
|
|
2114
|
+
dirty = dirty.toString();
|
|
2115
|
+
|
|
2116
|
+
if (typeof dirty !== 'string') {
|
|
2117
|
+
throw typeErrorCreate('dirty is not a string, aborting');
|
|
2058
2118
|
}
|
|
2119
|
+
} else {
|
|
2120
|
+
throw typeErrorCreate('toString is not a function');
|
|
2059
2121
|
}
|
|
2060
2122
|
}
|
|
2061
|
-
|
|
2062
|
-
}
|
|
2063
|
-
};
|
|
2123
|
+
/* Return dirty HTML if DOMPurify cannot run */
|
|
2064
2124
|
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
try {
|
|
2069
|
-
hasLocalStorageSupport = window !== 'undefined' && window.localStorage !== null;
|
|
2070
|
-
var testKey = 'i18next.translate.boo';
|
|
2071
|
-
window.localStorage.setItem(testKey, 'foo');
|
|
2072
|
-
window.localStorage.removeItem(testKey);
|
|
2073
|
-
} catch (e) {
|
|
2074
|
-
hasLocalStorageSupport = false;
|
|
2075
|
-
}
|
|
2076
|
-
return hasLocalStorageSupport;
|
|
2077
|
-
};
|
|
2078
|
-
var localStorage = {
|
|
2079
|
-
name: 'localStorage',
|
|
2080
|
-
lookup: function lookup(options) {
|
|
2081
|
-
var found;
|
|
2082
|
-
if (options.lookupLocalStorage && localStorageAvailable()) {
|
|
2083
|
-
var lng = window.localStorage.getItem(options.lookupLocalStorage);
|
|
2084
|
-
if (lng) found = lng;
|
|
2085
|
-
}
|
|
2086
|
-
return found;
|
|
2087
|
-
},
|
|
2088
|
-
cacheUserLanguage: function cacheUserLanguage(lng, options) {
|
|
2089
|
-
if (options.lookupLocalStorage && localStorageAvailable()) {
|
|
2090
|
-
window.localStorage.setItem(options.lookupLocalStorage, lng);
|
|
2125
|
+
|
|
2126
|
+
if (!DOMPurify.isSupported) {
|
|
2127
|
+
return dirty;
|
|
2091
2128
|
}
|
|
2092
|
-
|
|
2093
|
-
};
|
|
2129
|
+
/* Assign config vars */
|
|
2094
2130
|
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
try {
|
|
2099
|
-
hasSessionStorageSupport = window !== 'undefined' && window.sessionStorage !== null;
|
|
2100
|
-
var testKey = 'i18next.translate.boo';
|
|
2101
|
-
window.sessionStorage.setItem(testKey, 'foo');
|
|
2102
|
-
window.sessionStorage.removeItem(testKey);
|
|
2103
|
-
} catch (e) {
|
|
2104
|
-
hasSessionStorageSupport = false;
|
|
2105
|
-
}
|
|
2106
|
-
return hasSessionStorageSupport;
|
|
2107
|
-
};
|
|
2108
|
-
var sessionStorage = {
|
|
2109
|
-
name: 'sessionStorage',
|
|
2110
|
-
lookup: function lookup(options) {
|
|
2111
|
-
var found;
|
|
2112
|
-
if (options.lookupSessionStorage && sessionStorageAvailable()) {
|
|
2113
|
-
var lng = window.sessionStorage.getItem(options.lookupSessionStorage);
|
|
2114
|
-
if (lng) found = lng;
|
|
2131
|
+
|
|
2132
|
+
if (!SET_CONFIG) {
|
|
2133
|
+
_parseConfig(cfg);
|
|
2115
2134
|
}
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2135
|
+
/* Clean up removed elements */
|
|
2136
|
+
|
|
2137
|
+
|
|
2138
|
+
DOMPurify.removed = [];
|
|
2139
|
+
/* Check if dirty is correctly typed for IN_PLACE */
|
|
2140
|
+
|
|
2141
|
+
if (typeof dirty === 'string') {
|
|
2142
|
+
IN_PLACE = false;
|
|
2121
2143
|
}
|
|
2122
|
-
}
|
|
2123
|
-
};
|
|
2124
2144
|
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
for (var i = 0; i < navigator.languages.length; i++) {
|
|
2133
|
-
found.push(navigator.languages[i]);
|
|
2145
|
+
if (IN_PLACE) {
|
|
2146
|
+
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
|
2147
|
+
if (dirty.nodeName) {
|
|
2148
|
+
const tagName = transformCaseFunc(dirty.nodeName);
|
|
2149
|
+
|
|
2150
|
+
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
2151
|
+
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
2134
2152
|
}
|
|
2135
2153
|
}
|
|
2136
|
-
|
|
2137
|
-
|
|
2154
|
+
} else if (dirty instanceof Node) {
|
|
2155
|
+
/* If dirty is a DOM element, append to an empty document to avoid
|
|
2156
|
+
elements being stripped by the parser */
|
|
2157
|
+
body = _initDocument('<!---->');
|
|
2158
|
+
importedNode = body.ownerDocument.importNode(dirty, true);
|
|
2159
|
+
|
|
2160
|
+
if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
|
|
2161
|
+
/* Node is already a body, use as is */
|
|
2162
|
+
body = importedNode;
|
|
2163
|
+
} else if (importedNode.nodeName === 'HTML') {
|
|
2164
|
+
body = importedNode;
|
|
2165
|
+
} else {
|
|
2166
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
2167
|
+
body.appendChild(importedNode);
|
|
2138
2168
|
}
|
|
2139
|
-
|
|
2140
|
-
|
|
2169
|
+
} else {
|
|
2170
|
+
/* Exit directly if we have nothing to do */
|
|
2171
|
+
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && // eslint-disable-next-line unicorn/prefer-includes
|
|
2172
|
+
dirty.indexOf('<') === -1) {
|
|
2173
|
+
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
|
2174
|
+
}
|
|
2175
|
+
/* Initialize the document to work on */
|
|
2176
|
+
|
|
2177
|
+
|
|
2178
|
+
body = _initDocument(dirty);
|
|
2179
|
+
/* Check we have a DOM node from the data */
|
|
2180
|
+
|
|
2181
|
+
if (!body) {
|
|
2182
|
+
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
|
|
2141
2183
|
}
|
|
2142
2184
|
}
|
|
2143
|
-
|
|
2144
|
-
}
|
|
2145
|
-
};
|
|
2185
|
+
/* Remove first element node (ours) if FORCE_BODY is set */
|
|
2146
2186
|
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
var found;
|
|
2151
|
-
var htmlTag = options.htmlTag || (typeof document !== 'undefined' ? document.documentElement : null);
|
|
2152
|
-
if (htmlTag && typeof htmlTag.getAttribute === 'function') {
|
|
2153
|
-
found = htmlTag.getAttribute('lang');
|
|
2187
|
+
|
|
2188
|
+
if (body && FORCE_BODY) {
|
|
2189
|
+
_forceRemove(body.firstChild);
|
|
2154
2190
|
}
|
|
2155
|
-
|
|
2156
|
-
}
|
|
2157
|
-
};
|
|
2191
|
+
/* Get node iterator */
|
|
2158
2192
|
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2193
|
+
|
|
2194
|
+
const nodeIterator = _createIterator(IN_PLACE ? dirty : body);
|
|
2195
|
+
/* Now start iterating over the created document */
|
|
2196
|
+
|
|
2197
|
+
|
|
2198
|
+
while (currentNode = nodeIterator.nextNode()) {
|
|
2199
|
+
/* Sanitize tags and elements */
|
|
2200
|
+
if (_sanitizeElements(currentNode)) {
|
|
2201
|
+
continue;
|
|
2202
|
+
}
|
|
2203
|
+
/* Shadow DOM detected, sanitize it */
|
|
2204
|
+
|
|
2205
|
+
|
|
2206
|
+
if (currentNode.content instanceof DocumentFragment) {
|
|
2207
|
+
_sanitizeShadowDOM(currentNode.content);
|
|
2208
|
+
}
|
|
2209
|
+
/* Check attributes, sanitize if necessary */
|
|
2210
|
+
|
|
2211
|
+
|
|
2212
|
+
_sanitizeAttributes(currentNode);
|
|
2213
|
+
}
|
|
2214
|
+
/* If we sanitized `dirty` in-place, return it. */
|
|
2215
|
+
|
|
2216
|
+
|
|
2217
|
+
if (IN_PLACE) {
|
|
2218
|
+
return dirty;
|
|
2219
|
+
}
|
|
2220
|
+
/* Return sanitized string or DOM */
|
|
2221
|
+
|
|
2222
|
+
|
|
2223
|
+
if (RETURN_DOM) {
|
|
2224
|
+
if (RETURN_DOM_FRAGMENT) {
|
|
2225
|
+
returnNode = createDocumentFragment.call(body.ownerDocument);
|
|
2226
|
+
|
|
2227
|
+
while (body.firstChild) {
|
|
2228
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
|
2229
|
+
returnNode.appendChild(body.firstChild);
|
|
2173
2230
|
}
|
|
2231
|
+
} else {
|
|
2232
|
+
returnNode = body;
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmod) {
|
|
2236
|
+
/*
|
|
2237
|
+
AdoptNode() is not used because internal state is not reset
|
|
2238
|
+
(e.g. the past names map of a HTMLFormElement), this is safe
|
|
2239
|
+
in theory but we would rather not risk another attack vector.
|
|
2240
|
+
The state that is cloned by importNode() is explicitly defined
|
|
2241
|
+
by the specs.
|
|
2242
|
+
*/
|
|
2243
|
+
returnNode = importNode.call(originalDocument, returnNode, true);
|
|
2174
2244
|
}
|
|
2245
|
+
|
|
2246
|
+
return returnNode;
|
|
2175
2247
|
}
|
|
2176
|
-
return found;
|
|
2177
|
-
}
|
|
2178
|
-
};
|
|
2179
2248
|
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2249
|
+
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
|
2250
|
+
/* Serialize doctype if allowed */
|
|
2251
|
+
|
|
2252
|
+
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
|
2253
|
+
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
|
2254
|
+
}
|
|
2255
|
+
/* Sanitize final string template-safe */
|
|
2256
|
+
|
|
2257
|
+
|
|
2258
|
+
if (SAFE_FOR_TEMPLATES) {
|
|
2259
|
+
serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR, ' ');
|
|
2260
|
+
serializedHTML = stringReplace(serializedHTML, ERB_EXPR, ' ');
|
|
2261
|
+
serializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR, ' ');
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
|
2265
|
+
};
|
|
2266
|
+
/**
|
|
2267
|
+
* Public method to set the configuration once
|
|
2268
|
+
* setConfig
|
|
2269
|
+
*
|
|
2270
|
+
* @param {Object} cfg configuration object
|
|
2271
|
+
*/
|
|
2272
|
+
|
|
2273
|
+
|
|
2274
|
+
DOMPurify.setConfig = function (cfg) {
|
|
2275
|
+
_parseConfig(cfg);
|
|
2276
|
+
|
|
2277
|
+
SET_CONFIG = true;
|
|
2278
|
+
};
|
|
2279
|
+
/**
|
|
2280
|
+
* Public method to remove the configuration
|
|
2281
|
+
* clearConfig
|
|
2282
|
+
*
|
|
2283
|
+
*/
|
|
2189
2284
|
|
|
2190
|
-
// if there is no match (null) return undefined
|
|
2191
|
-
if (!language) return undefined;
|
|
2192
|
-
// return the given group match
|
|
2193
|
-
return language[lookupFromSubdomainIndex];
|
|
2194
|
-
}
|
|
2195
|
-
};
|
|
2196
2285
|
|
|
2197
|
-
function
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2286
|
+
DOMPurify.clearConfig = function () {
|
|
2287
|
+
CONFIG = null;
|
|
2288
|
+
SET_CONFIG = false;
|
|
2289
|
+
};
|
|
2290
|
+
/**
|
|
2291
|
+
* Public method to check if an attribute value is valid.
|
|
2292
|
+
* Uses last set config, if any. Otherwise, uses config defaults.
|
|
2293
|
+
* isValidAttribute
|
|
2294
|
+
*
|
|
2295
|
+
* @param {string} tag Tag name of containing element.
|
|
2296
|
+
* @param {string} attr Attribute name.
|
|
2297
|
+
* @param {string} value Attribute value.
|
|
2298
|
+
* @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
|
|
2299
|
+
*/
|
|
2209
2300
|
|
|
2210
|
-
|
|
2211
|
-
|
|
2301
|
+
|
|
2302
|
+
DOMPurify.isValidAttribute = function (tag, attr, value) {
|
|
2303
|
+
/* Initialize shared config vars if necessary. */
|
|
2304
|
+
if (!CONFIG) {
|
|
2305
|
+
_parseConfig({});
|
|
2212
2306
|
}
|
|
2307
|
+
|
|
2308
|
+
const lcTag = transformCaseFunc(tag);
|
|
2309
|
+
const lcName = transformCaseFunc(attr);
|
|
2310
|
+
return _isValidAttribute(lcTag, lcName, value);
|
|
2213
2311
|
};
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
this.init(services, options);
|
|
2222
|
-
}
|
|
2223
|
-
_createClass(Browser, [{
|
|
2224
|
-
key: "init",
|
|
2225
|
-
value: function init(services) {
|
|
2226
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
2227
|
-
var i18nOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
2228
|
-
this.services = services || {
|
|
2229
|
-
languageUtils: {}
|
|
2230
|
-
}; // this way the language detector can be used without i18next
|
|
2231
|
-
this.options = defaults(options, this.options || {}, getDefaults());
|
|
2232
|
-
if (typeof this.options.convertDetectedLanguage === 'string' && this.options.convertDetectedLanguage.indexOf('15897') > -1) {
|
|
2233
|
-
this.options.convertDetectedLanguage = function (l) {
|
|
2234
|
-
return l.replace('-', '_');
|
|
2235
|
-
};
|
|
2236
|
-
}
|
|
2312
|
+
/**
|
|
2313
|
+
* AddHook
|
|
2314
|
+
* Public method to add DOMPurify hooks
|
|
2315
|
+
*
|
|
2316
|
+
* @param {String} entryPoint entry point for the hook to add
|
|
2317
|
+
* @param {Function} hookFunction function to execute
|
|
2318
|
+
*/
|
|
2237
2319
|
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
this.addDetector(querystring);
|
|
2243
|
-
this.addDetector(localStorage);
|
|
2244
|
-
this.addDetector(sessionStorage);
|
|
2245
|
-
this.addDetector(navigator$1);
|
|
2246
|
-
this.addDetector(htmlTag);
|
|
2247
|
-
this.addDetector(path);
|
|
2248
|
-
this.addDetector(subdomain);
|
|
2249
|
-
}
|
|
2250
|
-
}, {
|
|
2251
|
-
key: "addDetector",
|
|
2252
|
-
value: function addDetector(detector) {
|
|
2253
|
-
this.detectors[detector.name] = detector;
|
|
2254
|
-
}
|
|
2255
|
-
}, {
|
|
2256
|
-
key: "detect",
|
|
2257
|
-
value: function detect(detectionOrder) {
|
|
2258
|
-
var _this = this;
|
|
2259
|
-
if (!detectionOrder) detectionOrder = this.options.order;
|
|
2260
|
-
var detected = [];
|
|
2261
|
-
detectionOrder.forEach(function (detectorName) {
|
|
2262
|
-
if (_this.detectors[detectorName]) {
|
|
2263
|
-
var lookup = _this.detectors[detectorName].lookup(_this.options);
|
|
2264
|
-
if (lookup && typeof lookup === 'string') lookup = [lookup];
|
|
2265
|
-
if (lookup) detected = detected.concat(lookup);
|
|
2266
|
-
}
|
|
2267
|
-
});
|
|
2268
|
-
detected = detected.map(function (d) {
|
|
2269
|
-
return _this.options.convertDetectedLanguage(d);
|
|
2270
|
-
});
|
|
2271
|
-
if (this.services.languageUtils.getBestMatchFromCodes) return detected; // new i18next v19.5.0
|
|
2272
|
-
return detected.length > 0 ? detected[0] : null; // a little backward compatibility
|
|
2320
|
+
|
|
2321
|
+
DOMPurify.addHook = function (entryPoint, hookFunction) {
|
|
2322
|
+
if (typeof hookFunction !== 'function') {
|
|
2323
|
+
return;
|
|
2273
2324
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2325
|
+
|
|
2326
|
+
hooks[entryPoint] = hooks[entryPoint] || [];
|
|
2327
|
+
arrayPush(hooks[entryPoint], hookFunction);
|
|
2328
|
+
};
|
|
2329
|
+
/**
|
|
2330
|
+
* RemoveHook
|
|
2331
|
+
* Public method to remove a DOMPurify hook at a given entryPoint
|
|
2332
|
+
* (pops it from the stack of hooks if more are present)
|
|
2333
|
+
*
|
|
2334
|
+
* @param {String} entryPoint entry point for the hook to remove
|
|
2335
|
+
* @return {Function} removed(popped) hook
|
|
2336
|
+
*/
|
|
2337
|
+
|
|
2338
|
+
|
|
2339
|
+
DOMPurify.removeHook = function (entryPoint) {
|
|
2340
|
+
if (hooks[entryPoint]) {
|
|
2341
|
+
return arrayPop(hooks[entryPoint]);
|
|
2284
2342
|
}
|
|
2285
|
-
}
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2343
|
+
};
|
|
2344
|
+
/**
|
|
2345
|
+
* RemoveHooks
|
|
2346
|
+
* Public method to remove all DOMPurify hooks at a given entryPoint
|
|
2347
|
+
*
|
|
2348
|
+
* @param {String} entryPoint entry point for the hooks to remove
|
|
2349
|
+
*/
|
|
2289
2350
|
|
|
2290
|
-
function _arrayWithHoles(arr) {
|
|
2291
|
-
if (Array.isArray(arr)) return arr;
|
|
2292
|
-
}
|
|
2293
2351
|
|
|
2294
|
-
function
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
var _s,
|
|
2298
|
-
_e,
|
|
2299
|
-
_x,
|
|
2300
|
-
_r,
|
|
2301
|
-
_arr = [],
|
|
2302
|
-
_n = !0,
|
|
2303
|
-
_d = !1;
|
|
2304
|
-
try {
|
|
2305
|
-
if (_x = (_i = _i.call(arr)).next, 0 === i) {
|
|
2306
|
-
if (Object(_i) !== _i) return;
|
|
2307
|
-
_n = !1;
|
|
2308
|
-
} else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0);
|
|
2309
|
-
} catch (err) {
|
|
2310
|
-
_d = !0, _e = err;
|
|
2311
|
-
} finally {
|
|
2312
|
-
try {
|
|
2313
|
-
if (!_n && null != _i["return"] && (_r = _i["return"](), Object(_r) !== _r)) return;
|
|
2314
|
-
} finally {
|
|
2315
|
-
if (_d) throw _e;
|
|
2316
|
-
}
|
|
2352
|
+
DOMPurify.removeHooks = function (entryPoint) {
|
|
2353
|
+
if (hooks[entryPoint]) {
|
|
2354
|
+
hooks[entryPoint] = [];
|
|
2317
2355
|
}
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2356
|
+
};
|
|
2357
|
+
/**
|
|
2358
|
+
* RemoveAllHooks
|
|
2359
|
+
* Public method to remove all DOMPurify hooks
|
|
2360
|
+
*
|
|
2361
|
+
*/
|
|
2321
2362
|
|
|
2322
|
-
function _arrayLikeToArray(arr, len) {
|
|
2323
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
2324
|
-
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
|
2325
|
-
return arr2;
|
|
2326
|
-
}
|
|
2327
2363
|
|
|
2328
|
-
function
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
2332
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
2333
|
-
if (n === "Map" || n === "Set") return Array.from(o);
|
|
2334
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
2335
|
-
}
|
|
2364
|
+
DOMPurify.removeAllHooks = function () {
|
|
2365
|
+
hooks = {};
|
|
2366
|
+
};
|
|
2336
2367
|
|
|
2337
|
-
|
|
2338
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
2368
|
+
return DOMPurify;
|
|
2339
2369
|
}
|
|
2340
2370
|
|
|
2341
|
-
|
|
2342
|
-
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
|
|
2343
|
-
}
|
|
2371
|
+
var purify = createDOMPurify();
|
|
2344
2372
|
|
|
2345
|
-
var
|
|
2346
|
-
return
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
};
|
|
2350
|
-
var replaceNullValuesWithGetter = function replaceNullValuesWithGetter(inputObject) {
|
|
2351
|
-
var parentKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
|
|
2352
|
-
var result = {};
|
|
2353
|
-
for (var _i = 0, _Object$entries = Object.entries(inputObject); _i < _Object$entries.length; _i++) {
|
|
2354
|
-
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
2355
|
-
key = _Object$entries$_i[0],
|
|
2356
|
-
value = _Object$entries$_i[1];
|
|
2357
|
-
var transKey = parentKey ? "".concat(parentKey, ".").concat(key) : key;
|
|
2358
|
-
if (value === null) {
|
|
2359
|
-
Object.defineProperty(result, key, {
|
|
2360
|
-
get: getter(transKey)
|
|
2361
|
-
});
|
|
2362
|
-
} else if (_typeof$1(value) === "object") {
|
|
2363
|
-
result[key] = replaceNullValuesWithGetter(value, transKey);
|
|
2364
|
-
} else {
|
|
2365
|
-
result[key] = value;
|
|
2373
|
+
var sanitizer = function sanitizer(array) {
|
|
2374
|
+
return purify.sanitize(array, {
|
|
2375
|
+
USE_PROFILES: {
|
|
2376
|
+
html: true
|
|
2366
2377
|
}
|
|
2367
|
-
}
|
|
2368
|
-
return result;
|
|
2378
|
+
});
|
|
2369
2379
|
};
|
|
2370
|
-
var
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2380
|
+
var cacheStore = new Map();
|
|
2381
|
+
var fetchCachedOrInvoke = function fetchCachedOrInvoke(func, lng, options) {
|
|
2382
|
+
var _cacheStore$get;
|
|
2383
|
+
var cache = (_cacheStore$get = cacheStore.get(lng)) === null || _cacheStore$get === void 0 ? void 0 : _cacheStore$get.get(options);
|
|
2384
|
+
if (cache) return cache;
|
|
2385
|
+
cache = func(lng, options);
|
|
2386
|
+
var lngCache = cacheStore.get(lng);
|
|
2387
|
+
if (lngCache) lngCache.set(options, cache);else cacheStore.set(lng, new Map([[options, cache]]));
|
|
2388
|
+
return cache;
|
|
2389
|
+
};
|
|
2390
|
+
var lowerCaseDynamicTextFormatter = function lowerCaseDynamicTextFormatter(value, format) {
|
|
2391
|
+
if (!value || format === ANY_CASE || typeof value !== "string") return value;
|
|
2392
|
+
return LOWERCASED + value.toLocaleLowerCase();
|
|
2393
|
+
};
|
|
2394
|
+
var boldListFormatter = function boldListFormatter(array, lng, options) {
|
|
2395
|
+
var formatter = fetchCachedOrInvoke(function (lng, options) {
|
|
2396
|
+
return new Intl.ListFormat(lng, options);
|
|
2397
|
+
}, lng, options);
|
|
2398
|
+
var boldItems = array.map(function (item) {
|
|
2399
|
+
return "<strong>".concat(item, "</strong>");
|
|
2400
|
+
});
|
|
2401
|
+
var sanitizedItems = sanitizer(boldItems).split(",");
|
|
2402
|
+
return formatter.format(sanitizedItems);
|
|
2403
|
+
};
|
|
2404
|
+
|
|
2405
|
+
var sentenceCase = function sentenceCase(value) {
|
|
2406
|
+
return value.charAt(0).toLocaleUpperCase() + value.slice(1);
|
|
2407
|
+
};
|
|
2408
|
+
var sentenceCaseProcessor = {
|
|
2409
|
+
type: "postProcessor",
|
|
2410
|
+
name: "sentenceCaseProcessor",
|
|
2411
|
+
process: function process(value) {
|
|
2412
|
+
var shouldSentenceCase = value.startsWith(LOWERCASED);
|
|
2413
|
+
value = value.replaceAll(LOWERCASED, "");
|
|
2414
|
+
return shouldSentenceCase ? sentenceCase(value) : value;
|
|
2415
|
+
}
|
|
2383
2416
|
};
|
|
2384
2417
|
|
|
2385
2418
|
var generic = {
|
|
@@ -2500,7 +2533,7 @@ var commonsEn = {
|
|
|
2500
2533
|
// eslint-disable-next-line import/no-mutable-exports
|
|
2501
2534
|
exports.taxonomies = {};
|
|
2502
2535
|
var initializeI18n = function initializeI18n(hostTranslations) {
|
|
2503
|
-
var _window$globalProps
|
|
2536
|
+
var _window$globalProps;
|
|
2504
2537
|
var packageTranslations = preval.require("./configs/scripts/getPkgTranslations.js");
|
|
2505
2538
|
var commonsTranslations = {
|
|
2506
2539
|
en: {
|
|
@@ -2508,10 +2541,16 @@ var initializeI18n = function initializeI18n(hostTranslations) {
|
|
|
2508
2541
|
}
|
|
2509
2542
|
};
|
|
2510
2543
|
var resources = [hostTranslations, commonsTranslations, packageTranslations].reduce(ramda.mergeDeepLeft);
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2544
|
+
var defaultTaxonomyKeys = Object.keys(resources.en.translation.taxonomyDefaultLabels || {});
|
|
2545
|
+
var defaultTaxonomies = Object.fromEntries(defaultTaxonomyKeys.map(function (key) {
|
|
2546
|
+
return [key, {
|
|
2547
|
+
singular: null,
|
|
2548
|
+
plural: null
|
|
2549
|
+
}];
|
|
2550
|
+
}));
|
|
2551
|
+
var hostTaxonomies = ((_window$globalProps = window.globalProps) === null || _window$globalProps === void 0 ? void 0 : _window$globalProps.taxonomies) || {};
|
|
2552
|
+
exports.taxonomies = replaceNullValuesWithGetter(ramda.mergeDeepLeft(hostTaxonomies, defaultTaxonomies));
|
|
2553
|
+
i18n__default["default"].use(Browser).use(reactI18next.initReactI18next).use(sentenceCaseProcessor).init({
|
|
2515
2554
|
resources: resources,
|
|
2516
2555
|
fallbackLng: "en",
|
|
2517
2556
|
interpolation: {
|
|
@@ -2519,9 +2558,17 @@ var initializeI18n = function initializeI18n(hostTranslations) {
|
|
|
2519
2558
|
taxonomies: exports.taxonomies
|
|
2520
2559
|
},
|
|
2521
2560
|
escapeValue: false,
|
|
2522
|
-
skipOnVariables: false
|
|
2561
|
+
skipOnVariables: false,
|
|
2562
|
+
alwaysFormat: true,
|
|
2563
|
+
format: function format(value, _format, lng, options) {
|
|
2564
|
+
var newValue = value;
|
|
2565
|
+
if (_format === "boldList") {
|
|
2566
|
+
newValue = boldListFormatter(newValue, lng, options);
|
|
2567
|
+
}
|
|
2568
|
+
return lowerCaseDynamicTextFormatter(newValue, _format);
|
|
2569
|
+
}
|
|
2523
2570
|
},
|
|
2524
|
-
postProcess: [
|
|
2571
|
+
postProcess: [sentenceCaseProcessor.name],
|
|
2525
2572
|
detection: {
|
|
2526
2573
|
order: ["querystring", "cookie", "navigator", "path"],
|
|
2527
2574
|
caches: ["cookie"],
|
|
@@ -2529,23 +2576,6 @@ var initializeI18n = function initializeI18n(hostTranslations) {
|
|
|
2529
2576
|
lookupCookie: "lang"
|
|
2530
2577
|
}
|
|
2531
2578
|
});
|
|
2532
|
-
(_i18n$services$format = i18n__default["default"].services.formatter) === null || _i18n$services$format === void 0 ? void 0 : _i18n$services$format.addCached("boldList", function (language, options) {
|
|
2533
|
-
var formatter = new Intl.ListFormat(language, options);
|
|
2534
|
-
var sanitizer = function sanitizer(array) {
|
|
2535
|
-
return purify.sanitize(array, {
|
|
2536
|
-
USE_PROFILES: {
|
|
2537
|
-
html: true
|
|
2538
|
-
}
|
|
2539
|
-
});
|
|
2540
|
-
};
|
|
2541
|
-
return function (array) {
|
|
2542
|
-
var boldItems = array.map(function (item) {
|
|
2543
|
-
return "<strong>".concat(item, "</strong>");
|
|
2544
|
-
});
|
|
2545
|
-
var sanitizedItems = sanitizer(boldItems).split(",");
|
|
2546
|
-
return formatter.format(sanitizedItems);
|
|
2547
|
-
};
|
|
2548
|
-
});
|
|
2549
2579
|
};
|
|
2550
2580
|
|
|
2551
2581
|
function initializeLogger() {
|