tinymce-rails 7.4.0 → 7.4.1
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.
- checksums.yaml +4 -4
- data/app/assets/source/tinymce/tinymce.js +891 -867
- data/lib/tinymce/rails/version.rb +2 -2
- data/vendor/assets/javascripts/tinymce/models/dom/model.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/accordion/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/advlist/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autosave/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/code/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/codesample/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/emoticons/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/fullscreen/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/help/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/importcss/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/lists/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/nonbreaking/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/pagebreak/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/preview/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/quickbars/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/visualblocks/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/visualchars/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/wordcount/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/themes/silver/theme.js +384 -2
- data/vendor/assets/javascripts/tinymce/tinymce.js +383 -2
- metadata +2 -2
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* TinyMCE version 7.4.
|
2
|
+
* TinyMCE version 7.4.1 (TBD)
|
3
3
|
*/
|
4
4
|
|
5
5
|
(function () {
|
@@ -15274,14 +15274,24 @@
|
|
15274
15274
|
}
|
15275
15275
|
};
|
15276
15276
|
|
15277
|
-
|
15278
|
-
|
15279
|
-
|
15280
|
-
|
15281
|
-
|
15282
|
-
|
15283
|
-
|
15284
|
-
|
15277
|
+
/*! @license DOMPurify 3.1.7 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.7/LICENSE */
|
15278
|
+
|
15279
|
+
const {
|
15280
|
+
entries,
|
15281
|
+
setPrototypeOf,
|
15282
|
+
isFrozen,
|
15283
|
+
getPrototypeOf,
|
15284
|
+
getOwnPropertyDescriptor
|
15285
|
+
} = Object;
|
15286
|
+
let {
|
15287
|
+
freeze,
|
15288
|
+
seal,
|
15289
|
+
create: create$7
|
15290
|
+
} = Object; // eslint-disable-line import/no-mutable-exports
|
15291
|
+
let {
|
15292
|
+
apply,
|
15293
|
+
construct
|
15294
|
+
} = typeof Reflect !== 'undefined' && Reflect;
|
15285
15295
|
if (!freeze) {
|
15286
15296
|
freeze = function freeze(x) {
|
15287
15297
|
return x;
|
@@ -15292,6 +15302,11 @@
|
|
15292
15302
|
return x;
|
15293
15303
|
};
|
15294
15304
|
}
|
15305
|
+
if (!apply) {
|
15306
|
+
apply = function apply(fun, thisValue, args) {
|
15307
|
+
return fun.apply(thisValue, args);
|
15308
|
+
};
|
15309
|
+
}
|
15295
15310
|
if (!construct) {
|
15296
15311
|
construct = function construct(Func, args) {
|
15297
15312
|
return new Func(...args);
|
@@ -15306,8 +15321,16 @@
|
|
15306
15321
|
const stringReplace = unapply(String.prototype.replace);
|
15307
15322
|
const stringIndexOf = unapply(String.prototype.indexOf);
|
15308
15323
|
const stringTrim = unapply(String.prototype.trim);
|
15324
|
+
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
15309
15325
|
const regExpTest = unapply(RegExp.prototype.test);
|
15310
15326
|
const typeErrorCreate = unconstruct(TypeError);
|
15327
|
+
|
15328
|
+
/**
|
15329
|
+
* Creates a new function that calls the given function with a specified thisArg and arguments.
|
15330
|
+
*
|
15331
|
+
* @param {Function} func - The function to be wrapped and called.
|
15332
|
+
* @returns {Function} A new function that calls the given function with a specified thisArg and arguments.
|
15333
|
+
*/
|
15311
15334
|
function unapply(func) {
|
15312
15335
|
return function (thisArg) {
|
15313
15336
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
@@ -15316,6 +15339,13 @@
|
|
15316
15339
|
return apply(func, thisArg, args);
|
15317
15340
|
};
|
15318
15341
|
}
|
15342
|
+
|
15343
|
+
/**
|
15344
|
+
* Creates a new function that constructs an instance of the given constructor function with the provided arguments.
|
15345
|
+
*
|
15346
|
+
* @param {Function} func - The constructor function to be wrapped and called.
|
15347
|
+
* @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.
|
15348
|
+
*/
|
15319
15349
|
function unconstruct(func) {
|
15320
15350
|
return function () {
|
15321
15351
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
@@ -15324,10 +15354,21 @@
|
|
15324
15354
|
return construct(func, args);
|
15325
15355
|
};
|
15326
15356
|
}
|
15327
|
-
|
15328
|
-
|
15329
|
-
|
15357
|
+
|
15358
|
+
/**
|
15359
|
+
* Add properties to a lookup table
|
15360
|
+
*
|
15361
|
+
* @param {Object} set - The set to which elements will be added.
|
15362
|
+
* @param {Array} array - The array containing elements to be added to the set.
|
15363
|
+
* @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.
|
15364
|
+
* @returns {Object} The modified set with added elements.
|
15365
|
+
*/
|
15366
|
+
function addToSet(set, array) {
|
15367
|
+
let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
|
15330
15368
|
if (setPrototypeOf) {
|
15369
|
+
// Make 'in' and truthy checks like Boolean(set.constructor)
|
15370
|
+
// independent of any properties defined on Object.prototype.
|
15371
|
+
// Prevent prototype setters from intercepting set as a this value.
|
15331
15372
|
setPrototypeOf(set, null);
|
15332
15373
|
}
|
15333
15374
|
let l = array.length;
|
@@ -15336,6 +15377,7 @@
|
|
15336
15377
|
if (typeof element === 'string') {
|
15337
15378
|
const lcElement = transformCaseFunc(element);
|
15338
15379
|
if (lcElement !== element) {
|
15380
|
+
// Config presets (e.g. tags.js, attrs.js) are immutable.
|
15339
15381
|
if (!isFrozen(array)) {
|
15340
15382
|
array[l] = lcElement;
|
15341
15383
|
}
|
@@ -15346,13 +15388,53 @@
|
|
15346
15388
|
}
|
15347
15389
|
return set;
|
15348
15390
|
}
|
15391
|
+
|
15392
|
+
/**
|
15393
|
+
* Clean up an array to harden against CSPP
|
15394
|
+
*
|
15395
|
+
* @param {Array} array - The array to be cleaned.
|
15396
|
+
* @returns {Array} The cleaned version of the array
|
15397
|
+
*/
|
15398
|
+
function cleanArray(array) {
|
15399
|
+
for (let index = 0; index < array.length; index++) {
|
15400
|
+
const isPropertyExist = objectHasOwnProperty(array, index);
|
15401
|
+
if (!isPropertyExist) {
|
15402
|
+
array[index] = null;
|
15403
|
+
}
|
15404
|
+
}
|
15405
|
+
return array;
|
15406
|
+
}
|
15407
|
+
|
15408
|
+
/**
|
15409
|
+
* Shallow clone an object
|
15410
|
+
*
|
15411
|
+
* @param {Object} object - The object to be cloned.
|
15412
|
+
* @returns {Object} A new object that copies the original.
|
15413
|
+
*/
|
15349
15414
|
function clone(object) {
|
15350
15415
|
const newObject = create$7(null);
|
15351
15416
|
for (const [property, value] of entries(object)) {
|
15352
|
-
|
15417
|
+
const isPropertyExist = objectHasOwnProperty(object, property);
|
15418
|
+
if (isPropertyExist) {
|
15419
|
+
if (Array.isArray(value)) {
|
15420
|
+
newObject[property] = cleanArray(value);
|
15421
|
+
} else if (value && typeof value === 'object' && value.constructor === Object) {
|
15422
|
+
newObject[property] = clone(value);
|
15423
|
+
} else {
|
15424
|
+
newObject[property] = value;
|
15425
|
+
}
|
15426
|
+
}
|
15353
15427
|
}
|
15354
15428
|
return newObject;
|
15355
15429
|
}
|
15430
|
+
|
15431
|
+
/**
|
15432
|
+
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
15433
|
+
*
|
15434
|
+
* @param {Object} object - The object to look up the getter function in its prototype chain.
|
15435
|
+
* @param {String} prop - The property name for which to find the getter function.
|
15436
|
+
* @returns {Function} The getter function found in the prototype chain or a fallback function.
|
15437
|
+
*/
|
15356
15438
|
function lookupGetter(object, prop) {
|
15357
15439
|
while (object !== null) {
|
15358
15440
|
const desc = getOwnPropertyDescriptor(object, prop);
|
@@ -15366,644 +15448,50 @@
|
|
15366
15448
|
}
|
15367
15449
|
object = getPrototypeOf(object);
|
15368
15450
|
}
|
15369
|
-
function fallbackValue(
|
15370
|
-
console.warn('fallback value for', element);
|
15451
|
+
function fallbackValue() {
|
15371
15452
|
return null;
|
15372
15453
|
}
|
15373
15454
|
return fallbackValue;
|
15374
15455
|
}
|
15375
|
-
|
15376
|
-
|
15377
|
-
|
15378
|
-
|
15379
|
-
|
15380
|
-
|
15381
|
-
|
15382
|
-
|
15383
|
-
|
15384
|
-
|
15385
|
-
|
15386
|
-
|
15387
|
-
|
15388
|
-
|
15389
|
-
|
15390
|
-
|
15391
|
-
|
15392
|
-
'button',
|
15393
|
-
'canvas',
|
15394
|
-
'caption',
|
15395
|
-
'center',
|
15396
|
-
'cite',
|
15397
|
-
'code',
|
15398
|
-
'col',
|
15399
|
-
'colgroup',
|
15400
|
-
'content',
|
15401
|
-
'data',
|
15402
|
-
'datalist',
|
15403
|
-
'dd',
|
15404
|
-
'decorator',
|
15405
|
-
'del',
|
15406
|
-
'details',
|
15407
|
-
'dfn',
|
15408
|
-
'dialog',
|
15409
|
-
'dir',
|
15410
|
-
'div',
|
15411
|
-
'dl',
|
15412
|
-
'dt',
|
15413
|
-
'element',
|
15414
|
-
'em',
|
15415
|
-
'fieldset',
|
15416
|
-
'figcaption',
|
15417
|
-
'figure',
|
15418
|
-
'font',
|
15419
|
-
'footer',
|
15420
|
-
'form',
|
15421
|
-
'h1',
|
15422
|
-
'h2',
|
15423
|
-
'h3',
|
15424
|
-
'h4',
|
15425
|
-
'h5',
|
15426
|
-
'h6',
|
15427
|
-
'head',
|
15428
|
-
'header',
|
15429
|
-
'hgroup',
|
15430
|
-
'hr',
|
15431
|
-
'html',
|
15432
|
-
'i',
|
15433
|
-
'img',
|
15434
|
-
'input',
|
15435
|
-
'ins',
|
15436
|
-
'kbd',
|
15437
|
-
'label',
|
15438
|
-
'legend',
|
15439
|
-
'li',
|
15440
|
-
'main',
|
15441
|
-
'map',
|
15442
|
-
'mark',
|
15443
|
-
'marquee',
|
15444
|
-
'menu',
|
15445
|
-
'menuitem',
|
15446
|
-
'meter',
|
15447
|
-
'nav',
|
15448
|
-
'nobr',
|
15449
|
-
'ol',
|
15450
|
-
'optgroup',
|
15451
|
-
'option',
|
15452
|
-
'output',
|
15453
|
-
'p',
|
15454
|
-
'picture',
|
15455
|
-
'pre',
|
15456
|
-
'progress',
|
15457
|
-
'q',
|
15458
|
-
'rp',
|
15459
|
-
'rt',
|
15460
|
-
'ruby',
|
15461
|
-
's',
|
15462
|
-
'samp',
|
15463
|
-
'section',
|
15464
|
-
'select',
|
15465
|
-
'shadow',
|
15466
|
-
'small',
|
15467
|
-
'source',
|
15468
|
-
'spacer',
|
15469
|
-
'span',
|
15470
|
-
'strike',
|
15471
|
-
'strong',
|
15472
|
-
'style',
|
15473
|
-
'sub',
|
15474
|
-
'summary',
|
15475
|
-
'sup',
|
15476
|
-
'table',
|
15477
|
-
'tbody',
|
15478
|
-
'td',
|
15479
|
-
'template',
|
15480
|
-
'textarea',
|
15481
|
-
'tfoot',
|
15482
|
-
'th',
|
15483
|
-
'thead',
|
15484
|
-
'time',
|
15485
|
-
'tr',
|
15486
|
-
'track',
|
15487
|
-
'tt',
|
15488
|
-
'u',
|
15489
|
-
'ul',
|
15490
|
-
'var',
|
15491
|
-
'video',
|
15492
|
-
'wbr'
|
15493
|
-
]);
|
15494
|
-
const svg$1 = freeze([
|
15495
|
-
'svg',
|
15496
|
-
'a',
|
15497
|
-
'altglyph',
|
15498
|
-
'altglyphdef',
|
15499
|
-
'altglyphitem',
|
15500
|
-
'animatecolor',
|
15501
|
-
'animatemotion',
|
15502
|
-
'animatetransform',
|
15503
|
-
'circle',
|
15504
|
-
'clippath',
|
15505
|
-
'defs',
|
15506
|
-
'desc',
|
15507
|
-
'ellipse',
|
15508
|
-
'filter',
|
15509
|
-
'font',
|
15510
|
-
'g',
|
15511
|
-
'glyph',
|
15512
|
-
'glyphref',
|
15513
|
-
'hkern',
|
15514
|
-
'image',
|
15515
|
-
'line',
|
15516
|
-
'lineargradient',
|
15517
|
-
'marker',
|
15518
|
-
'mask',
|
15519
|
-
'metadata',
|
15520
|
-
'mpath',
|
15521
|
-
'path',
|
15522
|
-
'pattern',
|
15523
|
-
'polygon',
|
15524
|
-
'polyline',
|
15525
|
-
'radialgradient',
|
15526
|
-
'rect',
|
15527
|
-
'stop',
|
15528
|
-
'style',
|
15529
|
-
'switch',
|
15530
|
-
'symbol',
|
15531
|
-
'text',
|
15532
|
-
'textpath',
|
15533
|
-
'title',
|
15534
|
-
'tref',
|
15535
|
-
'tspan',
|
15536
|
-
'view',
|
15537
|
-
'vkern'
|
15538
|
-
]);
|
15539
|
-
const svgFilters = freeze([
|
15540
|
-
'feBlend',
|
15541
|
-
'feColorMatrix',
|
15542
|
-
'feComponentTransfer',
|
15543
|
-
'feComposite',
|
15544
|
-
'feConvolveMatrix',
|
15545
|
-
'feDiffuseLighting',
|
15546
|
-
'feDisplacementMap',
|
15547
|
-
'feDistantLight',
|
15548
|
-
'feDropShadow',
|
15549
|
-
'feFlood',
|
15550
|
-
'feFuncA',
|
15551
|
-
'feFuncB',
|
15552
|
-
'feFuncG',
|
15553
|
-
'feFuncR',
|
15554
|
-
'feGaussianBlur',
|
15555
|
-
'feImage',
|
15556
|
-
'feMerge',
|
15557
|
-
'feMergeNode',
|
15558
|
-
'feMorphology',
|
15559
|
-
'feOffset',
|
15560
|
-
'fePointLight',
|
15561
|
-
'feSpecularLighting',
|
15562
|
-
'feSpotLight',
|
15563
|
-
'feTile',
|
15564
|
-
'feTurbulence'
|
15565
|
-
]);
|
15566
|
-
const svgDisallowed = freeze([
|
15567
|
-
'animate',
|
15568
|
-
'color-profile',
|
15569
|
-
'cursor',
|
15570
|
-
'discard',
|
15571
|
-
'font-face',
|
15572
|
-
'font-face-format',
|
15573
|
-
'font-face-name',
|
15574
|
-
'font-face-src',
|
15575
|
-
'font-face-uri',
|
15576
|
-
'foreignobject',
|
15577
|
-
'hatch',
|
15578
|
-
'hatchpath',
|
15579
|
-
'mesh',
|
15580
|
-
'meshgradient',
|
15581
|
-
'meshpatch',
|
15582
|
-
'meshrow',
|
15583
|
-
'missing-glyph',
|
15584
|
-
'script',
|
15585
|
-
'set',
|
15586
|
-
'solidcolor',
|
15587
|
-
'unknown',
|
15588
|
-
'use'
|
15589
|
-
]);
|
15590
|
-
const mathMl$1 = freeze([
|
15591
|
-
'math',
|
15592
|
-
'menclose',
|
15593
|
-
'merror',
|
15594
|
-
'mfenced',
|
15595
|
-
'mfrac',
|
15596
|
-
'mglyph',
|
15597
|
-
'mi',
|
15598
|
-
'mlabeledtr',
|
15599
|
-
'mmultiscripts',
|
15600
|
-
'mn',
|
15601
|
-
'mo',
|
15602
|
-
'mover',
|
15603
|
-
'mpadded',
|
15604
|
-
'mphantom',
|
15605
|
-
'mroot',
|
15606
|
-
'mrow',
|
15607
|
-
'ms',
|
15608
|
-
'mspace',
|
15609
|
-
'msqrt',
|
15610
|
-
'mstyle',
|
15611
|
-
'msub',
|
15612
|
-
'msup',
|
15613
|
-
'msubsup',
|
15614
|
-
'mtable',
|
15615
|
-
'mtd',
|
15616
|
-
'mtext',
|
15617
|
-
'mtr',
|
15618
|
-
'munder',
|
15619
|
-
'munderover',
|
15620
|
-
'mprescripts'
|
15621
|
-
]);
|
15622
|
-
const mathMlDisallowed = freeze([
|
15623
|
-
'maction',
|
15624
|
-
'maligngroup',
|
15625
|
-
'malignmark',
|
15626
|
-
'mlongdiv',
|
15627
|
-
'mscarries',
|
15628
|
-
'mscarry',
|
15629
|
-
'msgroup',
|
15630
|
-
'mstack',
|
15631
|
-
'msline',
|
15632
|
-
'msrow',
|
15633
|
-
'semantics',
|
15634
|
-
'annotation',
|
15635
|
-
'annotation-xml',
|
15636
|
-
'mprescripts',
|
15637
|
-
'none'
|
15638
|
-
]);
|
15456
|
+
|
15457
|
+
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']);
|
15458
|
+
|
15459
|
+
// SVG
|
15460
|
+
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']);
|
15461
|
+
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']);
|
15462
|
+
|
15463
|
+
// List of SVG elements that are disallowed by default.
|
15464
|
+
// We still need to know them so that we can do namespace
|
15465
|
+
// checks properly in case one wants to add them to
|
15466
|
+
// allow-list.
|
15467
|
+
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']);
|
15468
|
+
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']);
|
15469
|
+
|
15470
|
+
// Similarly to SVG, we want to know all MathML elements,
|
15471
|
+
// even those that we disallow by default.
|
15472
|
+
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
15639
15473
|
const text = freeze(['#text']);
|
15640
|
-
|
15641
|
-
|
15642
|
-
|
15643
|
-
|
15644
|
-
|
15645
|
-
|
15646
|
-
|
15647
|
-
|
15648
|
-
'autoplay',
|
15649
|
-
'background',
|
15650
|
-
'bgcolor',
|
15651
|
-
'border',
|
15652
|
-
'capture',
|
15653
|
-
'cellpadding',
|
15654
|
-
'cellspacing',
|
15655
|
-
'checked',
|
15656
|
-
'cite',
|
15657
|
-
'class',
|
15658
|
-
'clear',
|
15659
|
-
'color',
|
15660
|
-
'cols',
|
15661
|
-
'colspan',
|
15662
|
-
'controls',
|
15663
|
-
'controlslist',
|
15664
|
-
'coords',
|
15665
|
-
'crossorigin',
|
15666
|
-
'datetime',
|
15667
|
-
'decoding',
|
15668
|
-
'default',
|
15669
|
-
'dir',
|
15670
|
-
'disabled',
|
15671
|
-
'disablepictureinpicture',
|
15672
|
-
'disableremoteplayback',
|
15673
|
-
'download',
|
15674
|
-
'draggable',
|
15675
|
-
'enctype',
|
15676
|
-
'enterkeyhint',
|
15677
|
-
'face',
|
15678
|
-
'for',
|
15679
|
-
'headers',
|
15680
|
-
'height',
|
15681
|
-
'hidden',
|
15682
|
-
'high',
|
15683
|
-
'href',
|
15684
|
-
'hreflang',
|
15685
|
-
'id',
|
15686
|
-
'inputmode',
|
15687
|
-
'integrity',
|
15688
|
-
'ismap',
|
15689
|
-
'kind',
|
15690
|
-
'label',
|
15691
|
-
'lang',
|
15692
|
-
'list',
|
15693
|
-
'loading',
|
15694
|
-
'loop',
|
15695
|
-
'low',
|
15696
|
-
'max',
|
15697
|
-
'maxlength',
|
15698
|
-
'media',
|
15699
|
-
'method',
|
15700
|
-
'min',
|
15701
|
-
'minlength',
|
15702
|
-
'multiple',
|
15703
|
-
'muted',
|
15704
|
-
'name',
|
15705
|
-
'nonce',
|
15706
|
-
'noshade',
|
15707
|
-
'novalidate',
|
15708
|
-
'nowrap',
|
15709
|
-
'open',
|
15710
|
-
'optimum',
|
15711
|
-
'pattern',
|
15712
|
-
'placeholder',
|
15713
|
-
'playsinline',
|
15714
|
-
'poster',
|
15715
|
-
'preload',
|
15716
|
-
'pubdate',
|
15717
|
-
'radiogroup',
|
15718
|
-
'readonly',
|
15719
|
-
'rel',
|
15720
|
-
'required',
|
15721
|
-
'rev',
|
15722
|
-
'reversed',
|
15723
|
-
'role',
|
15724
|
-
'rows',
|
15725
|
-
'rowspan',
|
15726
|
-
'spellcheck',
|
15727
|
-
'scope',
|
15728
|
-
'selected',
|
15729
|
-
'shape',
|
15730
|
-
'size',
|
15731
|
-
'sizes',
|
15732
|
-
'span',
|
15733
|
-
'srclang',
|
15734
|
-
'start',
|
15735
|
-
'src',
|
15736
|
-
'srcset',
|
15737
|
-
'step',
|
15738
|
-
'style',
|
15739
|
-
'summary',
|
15740
|
-
'tabindex',
|
15741
|
-
'title',
|
15742
|
-
'translate',
|
15743
|
-
'type',
|
15744
|
-
'usemap',
|
15745
|
-
'valign',
|
15746
|
-
'value',
|
15747
|
-
'width',
|
15748
|
-
'xmlns',
|
15749
|
-
'slot'
|
15750
|
-
]);
|
15751
|
-
const svg = freeze([
|
15752
|
-
'accent-height',
|
15753
|
-
'accumulate',
|
15754
|
-
'additive',
|
15755
|
-
'alignment-baseline',
|
15756
|
-
'ascent',
|
15757
|
-
'attributename',
|
15758
|
-
'attributetype',
|
15759
|
-
'azimuth',
|
15760
|
-
'basefrequency',
|
15761
|
-
'baseline-shift',
|
15762
|
-
'begin',
|
15763
|
-
'bias',
|
15764
|
-
'by',
|
15765
|
-
'class',
|
15766
|
-
'clip',
|
15767
|
-
'clippathunits',
|
15768
|
-
'clip-path',
|
15769
|
-
'clip-rule',
|
15770
|
-
'color',
|
15771
|
-
'color-interpolation',
|
15772
|
-
'color-interpolation-filters',
|
15773
|
-
'color-profile',
|
15774
|
-
'color-rendering',
|
15775
|
-
'cx',
|
15776
|
-
'cy',
|
15777
|
-
'd',
|
15778
|
-
'dx',
|
15779
|
-
'dy',
|
15780
|
-
'diffuseconstant',
|
15781
|
-
'direction',
|
15782
|
-
'display',
|
15783
|
-
'divisor',
|
15784
|
-
'dur',
|
15785
|
-
'edgemode',
|
15786
|
-
'elevation',
|
15787
|
-
'end',
|
15788
|
-
'fill',
|
15789
|
-
'fill-opacity',
|
15790
|
-
'fill-rule',
|
15791
|
-
'filter',
|
15792
|
-
'filterunits',
|
15793
|
-
'flood-color',
|
15794
|
-
'flood-opacity',
|
15795
|
-
'font-family',
|
15796
|
-
'font-size',
|
15797
|
-
'font-size-adjust',
|
15798
|
-
'font-stretch',
|
15799
|
-
'font-style',
|
15800
|
-
'font-variant',
|
15801
|
-
'font-weight',
|
15802
|
-
'fx',
|
15803
|
-
'fy',
|
15804
|
-
'g1',
|
15805
|
-
'g2',
|
15806
|
-
'glyph-name',
|
15807
|
-
'glyphref',
|
15808
|
-
'gradientunits',
|
15809
|
-
'gradienttransform',
|
15810
|
-
'height',
|
15811
|
-
'href',
|
15812
|
-
'id',
|
15813
|
-
'image-rendering',
|
15814
|
-
'in',
|
15815
|
-
'in2',
|
15816
|
-
'k',
|
15817
|
-
'k1',
|
15818
|
-
'k2',
|
15819
|
-
'k3',
|
15820
|
-
'k4',
|
15821
|
-
'kerning',
|
15822
|
-
'keypoints',
|
15823
|
-
'keysplines',
|
15824
|
-
'keytimes',
|
15825
|
-
'lang',
|
15826
|
-
'lengthadjust',
|
15827
|
-
'letter-spacing',
|
15828
|
-
'kernelmatrix',
|
15829
|
-
'kernelunitlength',
|
15830
|
-
'lighting-color',
|
15831
|
-
'local',
|
15832
|
-
'marker-end',
|
15833
|
-
'marker-mid',
|
15834
|
-
'marker-start',
|
15835
|
-
'markerheight',
|
15836
|
-
'markerunits',
|
15837
|
-
'markerwidth',
|
15838
|
-
'maskcontentunits',
|
15839
|
-
'maskunits',
|
15840
|
-
'max',
|
15841
|
-
'mask',
|
15842
|
-
'media',
|
15843
|
-
'method',
|
15844
|
-
'mode',
|
15845
|
-
'min',
|
15846
|
-
'name',
|
15847
|
-
'numoctaves',
|
15848
|
-
'offset',
|
15849
|
-
'operator',
|
15850
|
-
'opacity',
|
15851
|
-
'order',
|
15852
|
-
'orient',
|
15853
|
-
'orientation',
|
15854
|
-
'origin',
|
15855
|
-
'overflow',
|
15856
|
-
'paint-order',
|
15857
|
-
'path',
|
15858
|
-
'pathlength',
|
15859
|
-
'patterncontentunits',
|
15860
|
-
'patterntransform',
|
15861
|
-
'patternunits',
|
15862
|
-
'points',
|
15863
|
-
'preservealpha',
|
15864
|
-
'preserveaspectratio',
|
15865
|
-
'primitiveunits',
|
15866
|
-
'r',
|
15867
|
-
'rx',
|
15868
|
-
'ry',
|
15869
|
-
'radius',
|
15870
|
-
'refx',
|
15871
|
-
'refy',
|
15872
|
-
'repeatcount',
|
15873
|
-
'repeatdur',
|
15874
|
-
'restart',
|
15875
|
-
'result',
|
15876
|
-
'rotate',
|
15877
|
-
'scale',
|
15878
|
-
'seed',
|
15879
|
-
'shape-rendering',
|
15880
|
-
'specularconstant',
|
15881
|
-
'specularexponent',
|
15882
|
-
'spreadmethod',
|
15883
|
-
'startoffset',
|
15884
|
-
'stddeviation',
|
15885
|
-
'stitchtiles',
|
15886
|
-
'stop-color',
|
15887
|
-
'stop-opacity',
|
15888
|
-
'stroke-dasharray',
|
15889
|
-
'stroke-dashoffset',
|
15890
|
-
'stroke-linecap',
|
15891
|
-
'stroke-linejoin',
|
15892
|
-
'stroke-miterlimit',
|
15893
|
-
'stroke-opacity',
|
15894
|
-
'stroke',
|
15895
|
-
'stroke-width',
|
15896
|
-
'style',
|
15897
|
-
'surfacescale',
|
15898
|
-
'systemlanguage',
|
15899
|
-
'tabindex',
|
15900
|
-
'targetx',
|
15901
|
-
'targety',
|
15902
|
-
'transform',
|
15903
|
-
'transform-origin',
|
15904
|
-
'text-anchor',
|
15905
|
-
'text-decoration',
|
15906
|
-
'text-rendering',
|
15907
|
-
'textlength',
|
15908
|
-
'type',
|
15909
|
-
'u1',
|
15910
|
-
'u2',
|
15911
|
-
'unicode',
|
15912
|
-
'values',
|
15913
|
-
'viewbox',
|
15914
|
-
'visibility',
|
15915
|
-
'version',
|
15916
|
-
'vert-adv-y',
|
15917
|
-
'vert-origin-x',
|
15918
|
-
'vert-origin-y',
|
15919
|
-
'width',
|
15920
|
-
'word-spacing',
|
15921
|
-
'wrap',
|
15922
|
-
'writing-mode',
|
15923
|
-
'xchannelselector',
|
15924
|
-
'ychannelselector',
|
15925
|
-
'x',
|
15926
|
-
'x1',
|
15927
|
-
'x2',
|
15928
|
-
'xmlns',
|
15929
|
-
'y',
|
15930
|
-
'y1',
|
15931
|
-
'y2',
|
15932
|
-
'z',
|
15933
|
-
'zoomandpan'
|
15934
|
-
]);
|
15935
|
-
const mathMl = freeze([
|
15936
|
-
'accent',
|
15937
|
-
'accentunder',
|
15938
|
-
'align',
|
15939
|
-
'bevelled',
|
15940
|
-
'close',
|
15941
|
-
'columnsalign',
|
15942
|
-
'columnlines',
|
15943
|
-
'columnspan',
|
15944
|
-
'denomalign',
|
15945
|
-
'depth',
|
15946
|
-
'dir',
|
15947
|
-
'display',
|
15948
|
-
'displaystyle',
|
15949
|
-
'encoding',
|
15950
|
-
'fence',
|
15951
|
-
'frame',
|
15952
|
-
'height',
|
15953
|
-
'href',
|
15954
|
-
'id',
|
15955
|
-
'largeop',
|
15956
|
-
'length',
|
15957
|
-
'linethickness',
|
15958
|
-
'lspace',
|
15959
|
-
'lquote',
|
15960
|
-
'mathbackground',
|
15961
|
-
'mathcolor',
|
15962
|
-
'mathsize',
|
15963
|
-
'mathvariant',
|
15964
|
-
'maxsize',
|
15965
|
-
'minsize',
|
15966
|
-
'movablelimits',
|
15967
|
-
'notation',
|
15968
|
-
'numalign',
|
15969
|
-
'open',
|
15970
|
-
'rowalign',
|
15971
|
-
'rowlines',
|
15972
|
-
'rowspacing',
|
15973
|
-
'rowspan',
|
15974
|
-
'rspace',
|
15975
|
-
'rquote',
|
15976
|
-
'scriptlevel',
|
15977
|
-
'scriptminsize',
|
15978
|
-
'scriptsizemultiplier',
|
15979
|
-
'selection',
|
15980
|
-
'separator',
|
15981
|
-
'separators',
|
15982
|
-
'stretchy',
|
15983
|
-
'subscriptshift',
|
15984
|
-
'supscriptshift',
|
15985
|
-
'symmetric',
|
15986
|
-
'voffset',
|
15987
|
-
'width',
|
15988
|
-
'xmlns'
|
15989
|
-
]);
|
15990
|
-
const xml = freeze([
|
15991
|
-
'xlink:href',
|
15992
|
-
'xml:id',
|
15993
|
-
'xlink:title',
|
15994
|
-
'xml:space',
|
15995
|
-
'xmlns:xlink'
|
15996
|
-
]);
|
15997
|
-
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);
|
15474
|
+
|
15475
|
+
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', 'popover', 'popovertarget', 'popovertargetaction', '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', 'wrap', 'xmlns', 'slot']);
|
15476
|
+
const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
|
15477
|
+
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']);
|
15478
|
+
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
15479
|
+
|
15480
|
+
// eslint-disable-next-line unicorn/better-regex
|
15481
|
+
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
15998
15482
|
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
15999
15483
|
const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
|
16000
|
-
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/);
|
16001
|
-
const ARIA_ATTR = seal(/^aria-[\-\w]+$/);
|
16002
|
-
const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i
|
15484
|
+
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
|
15485
|
+
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
15486
|
+
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
|
15487
|
+
);
|
16003
15488
|
const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
|
16004
|
-
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g
|
15489
|
+
const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
|
15490
|
+
);
|
16005
15491
|
const DOCTYPE_NAME = seal(/^html$/i);
|
16006
|
-
|
15492
|
+
const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
|
15493
|
+
|
15494
|
+
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
16007
15495
|
__proto__: null,
|
16008
15496
|
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
16009
15497
|
ERB_EXPR: ERB_EXPR,
|
@@ -16013,13 +15501,47 @@
|
|
16013
15501
|
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
16014
15502
|
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
16015
15503
|
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
16016
|
-
DOCTYPE_NAME: DOCTYPE_NAME
|
15504
|
+
DOCTYPE_NAME: DOCTYPE_NAME,
|
15505
|
+
CUSTOM_ELEMENT: CUSTOM_ELEMENT
|
16017
15506
|
});
|
16018
|
-
|
15507
|
+
|
15508
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
15509
|
+
const NODE_TYPE = {
|
15510
|
+
element: 1,
|
15511
|
+
attribute: 2,
|
15512
|
+
text: 3,
|
15513
|
+
cdataSection: 4,
|
15514
|
+
entityReference: 5,
|
15515
|
+
// Deprecated
|
15516
|
+
entityNode: 6,
|
15517
|
+
// Deprecated
|
15518
|
+
progressingInstruction: 7,
|
15519
|
+
comment: 8,
|
15520
|
+
document: 9,
|
15521
|
+
documentType: 10,
|
15522
|
+
documentFragment: 11,
|
15523
|
+
notation: 12 // Deprecated
|
15524
|
+
};
|
15525
|
+
const getGlobal = function getGlobal() {
|
15526
|
+
return typeof window === 'undefined' ? null : window;
|
15527
|
+
};
|
15528
|
+
|
15529
|
+
/**
|
15530
|
+
* Creates a no-op policy for internal use only.
|
15531
|
+
* Don't export this function outside this module!
|
15532
|
+
* @param {TrustedTypePolicyFactory} trustedTypes The policy factory.
|
15533
|
+
* @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
|
15534
|
+
* @return {TrustedTypePolicy} The policy created (or null, if Trusted Types
|
15535
|
+
* are not supported or creating the policy failed).
|
15536
|
+
*/
|
16019
15537
|
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
|
16020
15538
|
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
16021
15539
|
return null;
|
16022
15540
|
}
|
15541
|
+
|
15542
|
+
// Allow the callers to control the unique policy name
|
15543
|
+
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
15544
|
+
// Policy creation with duplicate names throws in Trusted Types.
|
16023
15545
|
let suffix = null;
|
16024
15546
|
const ATTR_NAME = 'data-tt-policy-suffix';
|
16025
15547
|
if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
|
@@ -16036,6 +15558,9 @@
|
|
16036
15558
|
}
|
16037
15559
|
});
|
16038
15560
|
} catch (_) {
|
15561
|
+
// Policy creation failed (most likely another DOMPurify script has
|
15562
|
+
// already run). Skip creating the policy, as this will only cause errors
|
15563
|
+
// if TT are enforced.
|
16039
15564
|
console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
|
16040
15565
|
return null;
|
16041
15566
|
}
|
@@ -16043,21 +15568,53 @@
|
|
16043
15568
|
function createDOMPurify() {
|
16044
15569
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
16045
15570
|
const DOMPurify = root => createDOMPurify(root);
|
16046
|
-
|
15571
|
+
|
15572
|
+
/**
|
15573
|
+
* Version label, exposed for easier checks
|
15574
|
+
* if DOMPurify is up to date or not
|
15575
|
+
*/
|
15576
|
+
DOMPurify.version = '3.1.7';
|
15577
|
+
|
15578
|
+
/**
|
15579
|
+
* Array of elements that DOMPurify removed during sanitation.
|
15580
|
+
* Empty if nothing was removed.
|
15581
|
+
*/
|
16047
15582
|
DOMPurify.removed = [];
|
16048
|
-
if (!window || !window.document || window.document.nodeType !==
|
15583
|
+
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
|
15584
|
+
// Not running in a browser, provide a factory function
|
15585
|
+
// so that you can pass your own Window
|
16049
15586
|
DOMPurify.isSupported = false;
|
16050
15587
|
return DOMPurify;
|
16051
15588
|
}
|
16052
|
-
|
15589
|
+
let {
|
15590
|
+
document
|
15591
|
+
} = window;
|
15592
|
+
const originalDocument = document;
|
16053
15593
|
const currentScript = originalDocument.currentScript;
|
16054
|
-
|
16055
|
-
|
15594
|
+
const {
|
15595
|
+
DocumentFragment,
|
15596
|
+
HTMLTemplateElement,
|
15597
|
+
Node,
|
15598
|
+
Element,
|
15599
|
+
NodeFilter,
|
15600
|
+
NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
|
15601
|
+
HTMLFormElement,
|
15602
|
+
DOMParser,
|
15603
|
+
trustedTypes
|
15604
|
+
} = window;
|
16056
15605
|
const ElementPrototype = Element.prototype;
|
16057
15606
|
const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
|
15607
|
+
const remove = lookupGetter(ElementPrototype, 'remove');
|
16058
15608
|
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
16059
15609
|
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
16060
15610
|
const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
|
15611
|
+
|
15612
|
+
// As per issue #47, the web-components registry is inherited by a
|
15613
|
+
// new document created via createHTMLDocument. As per the spec
|
15614
|
+
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
15615
|
+
// a new empty registry is used when creating a template contents owner
|
15616
|
+
// document, so we use that as our parent document to ensure nothing
|
15617
|
+
// is inherited.
|
16061
15618
|
if (typeof HTMLTemplateElement === 'function') {
|
16062
15619
|
const template = document.createElement('template');
|
16063
15620
|
if (template.content && template.content.ownerDocument) {
|
@@ -16066,28 +15623,55 @@
|
|
16066
15623
|
}
|
16067
15624
|
let trustedTypesPolicy;
|
16068
15625
|
let emptyHTML = '';
|
16069
|
-
const {
|
16070
|
-
|
15626
|
+
const {
|
15627
|
+
implementation,
|
15628
|
+
createNodeIterator,
|
15629
|
+
createDocumentFragment,
|
15630
|
+
getElementsByTagName
|
15631
|
+
} = document;
|
15632
|
+
const {
|
15633
|
+
importNode
|
15634
|
+
} = originalDocument;
|
16071
15635
|
let hooks = {};
|
15636
|
+
|
15637
|
+
/**
|
15638
|
+
* Expose whether this browser supports running the full DOMPurify.
|
15639
|
+
*/
|
16072
15640
|
DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
|
16073
|
-
const {
|
16074
|
-
|
15641
|
+
const {
|
15642
|
+
MUSTACHE_EXPR,
|
15643
|
+
ERB_EXPR,
|
15644
|
+
TMPLIT_EXPR,
|
15645
|
+
DATA_ATTR,
|
15646
|
+
ARIA_ATTR,
|
15647
|
+
IS_SCRIPT_OR_DATA,
|
15648
|
+
ATTR_WHITESPACE,
|
15649
|
+
CUSTOM_ELEMENT
|
15650
|
+
} = EXPRESSIONS;
|
15651
|
+
let {
|
15652
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
15653
|
+
} = EXPRESSIONS;
|
15654
|
+
|
15655
|
+
/**
|
15656
|
+
* We consider the elements and attributes below to be safe. Ideally
|
15657
|
+
* don't add any new ones but feel free to remove unwanted ones.
|
15658
|
+
*/
|
15659
|
+
|
15660
|
+
/* allowed element names */
|
16075
15661
|
let ALLOWED_TAGS = null;
|
16076
|
-
const DEFAULT_ALLOWED_TAGS = addToSet({}, [
|
16077
|
-
|
16078
|
-
|
16079
|
-
...svgFilters,
|
16080
|
-
...mathMl$1,
|
16081
|
-
...text
|
16082
|
-
]);
|
15662
|
+
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
|
15663
|
+
|
15664
|
+
/* Allowed attribute names */
|
16083
15665
|
let ALLOWED_ATTR = null;
|
16084
|
-
const DEFAULT_ALLOWED_ATTR = addToSet({}, [
|
16085
|
-
|
16086
|
-
|
16087
|
-
|
16088
|
-
|
16089
|
-
|
16090
|
-
|
15666
|
+
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
15667
|
+
|
15668
|
+
/*
|
15669
|
+
* Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
|
15670
|
+
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
15671
|
+
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
|
15672
|
+
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
15673
|
+
*/
|
15674
|
+
let CUSTOM_ELEMENT_HANDLING = Object.seal(create$7(null, {
|
16091
15675
|
tagNameCheck: {
|
16092
15676
|
writable: true,
|
16093
15677
|
configurable: false,
|
@@ -16107,135 +15691,193 @@
|
|
16107
15691
|
value: false
|
16108
15692
|
}
|
16109
15693
|
}));
|
15694
|
+
|
15695
|
+
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
16110
15696
|
let FORBID_TAGS = null;
|
15697
|
+
|
15698
|
+
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
16111
15699
|
let FORBID_ATTR = null;
|
15700
|
+
|
15701
|
+
/* Decide if ARIA attributes are okay */
|
16112
15702
|
let ALLOW_ARIA_ATTR = true;
|
15703
|
+
|
15704
|
+
/* Decide if custom data attributes are okay */
|
16113
15705
|
let ALLOW_DATA_ATTR = true;
|
15706
|
+
|
15707
|
+
/* Decide if unknown protocols are okay */
|
16114
15708
|
let ALLOW_UNKNOWN_PROTOCOLS = false;
|
15709
|
+
|
15710
|
+
/* Decide if self-closing tags in attributes are allowed.
|
15711
|
+
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
16115
15712
|
let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
15713
|
+
|
15714
|
+
/* Output should be safe for common template engines.
|
15715
|
+
* This means, DOMPurify removes data attributes, mustaches and ERB
|
15716
|
+
*/
|
16116
15717
|
let SAFE_FOR_TEMPLATES = false;
|
15718
|
+
|
15719
|
+
/* Output should be safe even for XML used within HTML and alike.
|
15720
|
+
* This means, DOMPurify removes comments when containing risky content.
|
15721
|
+
*/
|
15722
|
+
let SAFE_FOR_XML = true;
|
15723
|
+
|
15724
|
+
/* Decide if document with <html>... should be returned */
|
16117
15725
|
let WHOLE_DOCUMENT = false;
|
15726
|
+
|
15727
|
+
/* Track whether config is already set on this instance of DOMPurify. */
|
16118
15728
|
let SET_CONFIG = false;
|
15729
|
+
|
15730
|
+
/* Decide if all elements (e.g. style, script) must be children of
|
15731
|
+
* document.body. By default, browsers might move them to document.head */
|
16119
15732
|
let FORCE_BODY = false;
|
15733
|
+
|
15734
|
+
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
15735
|
+
* string (or a TrustedHTML object if Trusted Types are supported).
|
15736
|
+
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
15737
|
+
*/
|
16120
15738
|
let RETURN_DOM = false;
|
15739
|
+
|
15740
|
+
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
15741
|
+
* string (or a TrustedHTML object if Trusted Types are supported) */
|
16121
15742
|
let RETURN_DOM_FRAGMENT = false;
|
15743
|
+
|
15744
|
+
/* Try to return a Trusted Type object instead of a string, return a string in
|
15745
|
+
* case Trusted Types are not supported */
|
16122
15746
|
let RETURN_TRUSTED_TYPE = false;
|
15747
|
+
|
15748
|
+
/* Output should be free from DOM clobbering attacks?
|
15749
|
+
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
15750
|
+
*/
|
16123
15751
|
let SANITIZE_DOM = true;
|
15752
|
+
|
15753
|
+
/* Achieve full DOM Clobbering protection by isolating the namespace of named
|
15754
|
+
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
|
15755
|
+
*
|
15756
|
+
* HTML/DOM spec rules that enable DOM Clobbering:
|
15757
|
+
* - Named Access on Window (§7.3.3)
|
15758
|
+
* - DOM Tree Accessors (§3.1.5)
|
15759
|
+
* - Form Element Parent-Child Relations (§4.10.3)
|
15760
|
+
* - Iframe srcdoc / Nested WindowProxies (§4.8.5)
|
15761
|
+
* - HTMLCollection (§4.2.10.2)
|
15762
|
+
*
|
15763
|
+
* Namespace isolation is implemented by prefixing `id` and `name` attributes
|
15764
|
+
* with a constant string, i.e., `user-content-`
|
15765
|
+
*/
|
16124
15766
|
let SANITIZE_NAMED_PROPS = false;
|
16125
15767
|
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
15768
|
+
|
15769
|
+
/* Keep element content when removing element? */
|
16126
15770
|
let KEEP_CONTENT = true;
|
15771
|
+
|
15772
|
+
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
|
15773
|
+
* of importing it into a new Document and returning a sanitized copy */
|
16127
15774
|
let IN_PLACE = false;
|
15775
|
+
|
15776
|
+
/* Allow usage of profiles like html, svg and mathMl */
|
16128
15777
|
let USE_PROFILES = {};
|
15778
|
+
|
15779
|
+
/* Tags to ignore content of when KEEP_CONTENT is true */
|
16129
15780
|
let FORBID_CONTENTS = null;
|
16130
|
-
const DEFAULT_FORBID_CONTENTS = addToSet({}, [
|
16131
|
-
|
16132
|
-
|
16133
|
-
'colgroup',
|
16134
|
-
'desc',
|
16135
|
-
'foreignobject',
|
16136
|
-
'head',
|
16137
|
-
'iframe',
|
16138
|
-
'math',
|
16139
|
-
'mi',
|
16140
|
-
'mn',
|
16141
|
-
'mo',
|
16142
|
-
'ms',
|
16143
|
-
'mtext',
|
16144
|
-
'noembed',
|
16145
|
-
'noframes',
|
16146
|
-
'noscript',
|
16147
|
-
'plaintext',
|
16148
|
-
'script',
|
16149
|
-
'style',
|
16150
|
-
'svg',
|
16151
|
-
'template',
|
16152
|
-
'thead',
|
16153
|
-
'title',
|
16154
|
-
'video',
|
16155
|
-
'xmp'
|
16156
|
-
]);
|
15781
|
+
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']);
|
15782
|
+
|
15783
|
+
/* Tags that are safe for data: URIs */
|
16157
15784
|
let DATA_URI_TAGS = null;
|
16158
|
-
const DEFAULT_DATA_URI_TAGS = addToSet({}, [
|
16159
|
-
|
16160
|
-
|
16161
|
-
'img',
|
16162
|
-
'source',
|
16163
|
-
'image',
|
16164
|
-
'track'
|
16165
|
-
]);
|
15785
|
+
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
15786
|
+
|
15787
|
+
/* Attributes safe for values like "javascript:" */
|
16166
15788
|
let URI_SAFE_ATTRIBUTES = null;
|
16167
|
-
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
|
16168
|
-
'alt',
|
16169
|
-
'class',
|
16170
|
-
'for',
|
16171
|
-
'id',
|
16172
|
-
'label',
|
16173
|
-
'name',
|
16174
|
-
'pattern',
|
16175
|
-
'placeholder',
|
16176
|
-
'role',
|
16177
|
-
'summary',
|
16178
|
-
'title',
|
16179
|
-
'value',
|
16180
|
-
'style',
|
16181
|
-
'xmlns'
|
16182
|
-
]);
|
15789
|
+
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
16183
15790
|
const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
|
16184
15791
|
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
16185
15792
|
const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
|
15793
|
+
/* Document namespace */
|
16186
15794
|
let NAMESPACE = HTML_NAMESPACE;
|
16187
15795
|
let IS_EMPTY_INPUT = false;
|
15796
|
+
|
15797
|
+
/* Allowed XHTML+XML namespaces */
|
16188
15798
|
let ALLOWED_NAMESPACES = null;
|
16189
|
-
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [
|
16190
|
-
|
16191
|
-
|
16192
|
-
|
16193
|
-
|
16194
|
-
let PARSER_MEDIA_TYPE;
|
16195
|
-
const SUPPORTED_PARSER_MEDIA_TYPES = [
|
16196
|
-
'application/xhtml+xml',
|
16197
|
-
'text/html'
|
16198
|
-
];
|
15799
|
+
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
15800
|
+
|
15801
|
+
/* Parsing of strict XHTML documents */
|
15802
|
+
let PARSER_MEDIA_TYPE = null;
|
15803
|
+
const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
16199
15804
|
const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
16200
|
-
let transformCaseFunc;
|
15805
|
+
let transformCaseFunc = null;
|
15806
|
+
|
15807
|
+
/* Keep a reference to config to pass to hooks */
|
16201
15808
|
let CONFIG = null;
|
15809
|
+
|
15810
|
+
/* Ideally, do not touch anything below this line */
|
15811
|
+
/* ______________________________________________ */
|
15812
|
+
|
16202
15813
|
const formElement = document.createElement('form');
|
16203
15814
|
const isRegexOrFunction = function isRegexOrFunction(testValue) {
|
16204
15815
|
return testValue instanceof RegExp || testValue instanceof Function;
|
16205
15816
|
};
|
16206
|
-
|
15817
|
+
|
15818
|
+
/**
|
15819
|
+
* _parseConfig
|
15820
|
+
*
|
15821
|
+
* @param {Object} cfg optional config literal
|
15822
|
+
*/
|
15823
|
+
// eslint-disable-next-line complexity
|
15824
|
+
const _parseConfig = function _parseConfig() {
|
15825
|
+
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
16207
15826
|
if (CONFIG && CONFIG === cfg) {
|
16208
15827
|
return;
|
16209
15828
|
}
|
15829
|
+
|
15830
|
+
/* Shield configuration object from tampering */
|
16210
15831
|
if (!cfg || typeof cfg !== 'object') {
|
16211
15832
|
cfg = {};
|
16212
15833
|
}
|
15834
|
+
|
15835
|
+
/* Shield configuration object from prototype pollution */
|
16213
15836
|
cfg = clone(cfg);
|
16214
|
-
PARSER_MEDIA_TYPE =
|
15837
|
+
PARSER_MEDIA_TYPE =
|
15838
|
+
// eslint-disable-next-line unicorn/prefer-includes
|
15839
|
+
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
|
15840
|
+
|
15841
|
+
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
16215
15842
|
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
16216
|
-
|
16217
|
-
|
16218
|
-
|
16219
|
-
|
16220
|
-
|
16221
|
-
|
16222
|
-
|
16223
|
-
|
16224
|
-
|
16225
|
-
|
16226
|
-
|
16227
|
-
|
16228
|
-
|
16229
|
-
|
16230
|
-
|
16231
|
-
|
16232
|
-
|
16233
|
-
|
16234
|
-
|
16235
|
-
|
16236
|
-
|
16237
|
-
|
16238
|
-
|
15843
|
+
|
15844
|
+
/* Set configuration parameters */
|
15845
|
+
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
15846
|
+
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
15847
|
+
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
15848
|
+
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),
|
15849
|
+
// eslint-disable-line indent
|
15850
|
+
cfg.ADD_URI_SAFE_ATTR,
|
15851
|
+
// eslint-disable-line indent
|
15852
|
+
transformCaseFunc // eslint-disable-line indent
|
15853
|
+
) // eslint-disable-line indent
|
15854
|
+
: DEFAULT_URI_SAFE_ATTRIBUTES;
|
15855
|
+
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS),
|
15856
|
+
// eslint-disable-line indent
|
15857
|
+
cfg.ADD_DATA_URI_TAGS,
|
15858
|
+
// eslint-disable-line indent
|
15859
|
+
transformCaseFunc // eslint-disable-line indent
|
15860
|
+
) // eslint-disable-line indent
|
15861
|
+
: DEFAULT_DATA_URI_TAGS;
|
15862
|
+
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
15863
|
+
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
|
15864
|
+
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
15865
|
+
USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
|
15866
|
+
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
|
15867
|
+
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
|
15868
|
+
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
|
15869
|
+
ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
|
15870
|
+
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
|
15871
|
+
SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
|
15872
|
+
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
|
15873
|
+
RETURN_DOM = cfg.RETURN_DOM || false; // Default false
|
15874
|
+
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
|
15875
|
+
RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
|
15876
|
+
FORCE_BODY = cfg.FORCE_BODY || false; // Default false
|
15877
|
+
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
|
15878
|
+
SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
|
15879
|
+
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
|
15880
|
+
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
16239
15881
|
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
16240
15882
|
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
16241
15883
|
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
@@ -16254,8 +15896,10 @@
|
|
16254
15896
|
if (RETURN_DOM_FRAGMENT) {
|
16255
15897
|
RETURN_DOM = true;
|
16256
15898
|
}
|
15899
|
+
|
15900
|
+
/* Parse profile info */
|
16257
15901
|
if (USE_PROFILES) {
|
16258
|
-
ALLOWED_TAGS = addToSet({},
|
15902
|
+
ALLOWED_TAGS = addToSet({}, text);
|
16259
15903
|
ALLOWED_ATTR = [];
|
16260
15904
|
if (USE_PROFILES.html === true) {
|
16261
15905
|
addToSet(ALLOWED_TAGS, html$1);
|
@@ -16277,6 +15921,8 @@
|
|
16277
15921
|
addToSet(ALLOWED_ATTR, xml);
|
16278
15922
|
}
|
16279
15923
|
}
|
15924
|
+
|
15925
|
+
/* Merge configuration parameters */
|
16280
15926
|
if (cfg.ADD_TAGS) {
|
16281
15927
|
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
16282
15928
|
ALLOWED_TAGS = clone(ALLOWED_TAGS);
|
@@ -16298,16 +15944,18 @@
|
|
16298
15944
|
}
|
16299
15945
|
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
16300
15946
|
}
|
15947
|
+
|
15948
|
+
/* Add #text in case KEEP_CONTENT is set to true */
|
16301
15949
|
if (KEEP_CONTENT) {
|
16302
15950
|
ALLOWED_TAGS['#text'] = true;
|
16303
15951
|
}
|
15952
|
+
|
15953
|
+
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
|
16304
15954
|
if (WHOLE_DOCUMENT) {
|
16305
|
-
addToSet(ALLOWED_TAGS, [
|
16306
|
-
'html',
|
16307
|
-
'head',
|
16308
|
-
'body'
|
16309
|
-
]);
|
15955
|
+
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
|
16310
15956
|
}
|
15957
|
+
|
15958
|
+
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
|
16311
15959
|
if (ALLOWED_TAGS.table) {
|
16312
15960
|
addToSet(ALLOWED_TAGS, ['tbody']);
|
16313
15961
|
delete FORBID_TAGS.tbody;
|
@@ -16319,48 +15967,57 @@
|
|
16319
15967
|
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
|
16320
15968
|
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
16321
15969
|
}
|
15970
|
+
|
15971
|
+
// Overwrite existing TrustedTypes policy.
|
16322
15972
|
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
|
15973
|
+
|
15974
|
+
// Sign local variables required by `sanitize`.
|
16323
15975
|
emptyHTML = trustedTypesPolicy.createHTML('');
|
16324
15976
|
} else {
|
15977
|
+
// Uninitialized policy, attempt to initialize the internal dompurify policy.
|
16325
15978
|
if (trustedTypesPolicy === undefined) {
|
16326
15979
|
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
16327
15980
|
}
|
15981
|
+
|
15982
|
+
// If creating the internal policy succeeded sign internal variables.
|
16328
15983
|
if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
|
16329
15984
|
emptyHTML = trustedTypesPolicy.createHTML('');
|
16330
15985
|
}
|
16331
15986
|
}
|
15987
|
+
|
15988
|
+
// Prevent further manipulation of configuration.
|
15989
|
+
// Not available in IE8, Safari 5, etc.
|
16332
15990
|
if (freeze) {
|
16333
15991
|
freeze(cfg);
|
16334
15992
|
}
|
16335
15993
|
CONFIG = cfg;
|
16336
15994
|
};
|
16337
|
-
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [
|
16338
|
-
|
16339
|
-
|
16340
|
-
|
16341
|
-
|
16342
|
-
|
16343
|
-
|
16344
|
-
const
|
16345
|
-
|
16346
|
-
|
16347
|
-
|
16348
|
-
|
16349
|
-
]);
|
16350
|
-
const
|
16351
|
-
|
16352
|
-
|
16353
|
-
|
16354
|
-
|
16355
|
-
|
16356
|
-
|
16357
|
-
|
16358
|
-
addToSet(ALL_SVG_TAGS, svgFilters);
|
16359
|
-
addToSet(ALL_SVG_TAGS, svgDisallowed);
|
16360
|
-
const ALL_MATHML_TAGS = addToSet({}, mathMl$1);
|
16361
|
-
addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
|
15995
|
+
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
15996
|
+
const HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
|
15997
|
+
|
15998
|
+
// Certain elements are allowed in both SVG and HTML
|
15999
|
+
// namespace. We need to specify them explicitly
|
16000
|
+
// so that they don't get erroneously deleted from
|
16001
|
+
// HTML namespace.
|
16002
|
+
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
16003
|
+
|
16004
|
+
/* Keep track of all possible SVG and MathML tags
|
16005
|
+
* so that we can perform the namespace checks
|
16006
|
+
* correctly. */
|
16007
|
+
const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
|
16008
|
+
const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
|
16009
|
+
|
16010
|
+
/**
|
16011
|
+
* @param {Element} element a DOM element whose namespace is being checked
|
16012
|
+
* @returns {boolean} Return false if the element has a
|
16013
|
+
* namespace that a spec-compliant parser would never
|
16014
|
+
* return. Return true otherwise.
|
16015
|
+
*/
|
16362
16016
|
const _checkValidNamespace = function _checkValidNamespace(element) {
|
16363
16017
|
let parent = getParentNode(element);
|
16018
|
+
|
16019
|
+
// In JSDOM, if we're inside shadow DOM, then parentNode
|
16020
|
+
// can be null. We just simulate parent in this case.
|
16364
16021
|
if (!parent || !parent.tagName) {
|
16365
16022
|
parent = {
|
16366
16023
|
namespaceURI: NAMESPACE,
|
@@ -16373,45 +16030,93 @@
|
|
16373
16030
|
return false;
|
16374
16031
|
}
|
16375
16032
|
if (element.namespaceURI === SVG_NAMESPACE) {
|
16033
|
+
// The only way to switch from HTML namespace to SVG
|
16034
|
+
// is via <svg>. If it happens via any other tag, then
|
16035
|
+
// it should be killed.
|
16376
16036
|
if (parent.namespaceURI === HTML_NAMESPACE) {
|
16377
16037
|
return tagName === 'svg';
|
16378
16038
|
}
|
16039
|
+
|
16040
|
+
// The only way to switch from MathML to SVG is via`
|
16041
|
+
// svg if parent is either <annotation-xml> or MathML
|
16042
|
+
// text integration points.
|
16379
16043
|
if (parent.namespaceURI === MATHML_NAMESPACE) {
|
16380
16044
|
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
16381
16045
|
}
|
16046
|
+
|
16047
|
+
// We only allow elements that are defined in SVG
|
16048
|
+
// spec. All others are disallowed in SVG namespace.
|
16382
16049
|
return Boolean(ALL_SVG_TAGS[tagName]);
|
16383
16050
|
}
|
16384
16051
|
if (element.namespaceURI === MATHML_NAMESPACE) {
|
16052
|
+
// The only way to switch from HTML namespace to MathML
|
16053
|
+
// is via <math>. If it happens via any other tag, then
|
16054
|
+
// it should be killed.
|
16385
16055
|
if (parent.namespaceURI === HTML_NAMESPACE) {
|
16386
16056
|
return tagName === 'math';
|
16387
16057
|
}
|
16058
|
+
|
16059
|
+
// The only way to switch from SVG to MathML is via
|
16060
|
+
// <math> and HTML integration points
|
16388
16061
|
if (parent.namespaceURI === SVG_NAMESPACE) {
|
16389
16062
|
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
16390
16063
|
}
|
16064
|
+
|
16065
|
+
// We only allow elements that are defined in MathML
|
16066
|
+
// spec. All others are disallowed in MathML namespace.
|
16391
16067
|
return Boolean(ALL_MATHML_TAGS[tagName]);
|
16392
16068
|
}
|
16393
16069
|
if (element.namespaceURI === HTML_NAMESPACE) {
|
16070
|
+
// The only way to switch from SVG to HTML is via
|
16071
|
+
// HTML integration points, and from MathML to HTML
|
16072
|
+
// is via MathML text integration points
|
16394
16073
|
if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
|
16395
16074
|
return false;
|
16396
16075
|
}
|
16397
16076
|
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
16398
16077
|
return false;
|
16399
16078
|
}
|
16079
|
+
|
16080
|
+
// We disallow tags that are specific for MathML
|
16081
|
+
// or SVG and should never appear in HTML namespace
|
16400
16082
|
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
16401
16083
|
}
|
16084
|
+
|
16085
|
+
// For XHTML and XML documents that support custom namespaces
|
16402
16086
|
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
|
16403
16087
|
return true;
|
16404
16088
|
}
|
16089
|
+
|
16090
|
+
// The code should never reach this place (this means
|
16091
|
+
// that the element somehow got namespace that is not
|
16092
|
+
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
|
16093
|
+
// Return false just in case.
|
16405
16094
|
return false;
|
16406
16095
|
};
|
16096
|
+
|
16097
|
+
/**
|
16098
|
+
* _forceRemove
|
16099
|
+
*
|
16100
|
+
* @param {Node} node a DOM node
|
16101
|
+
*/
|
16407
16102
|
const _forceRemove = function _forceRemove(node) {
|
16408
|
-
arrayPush(DOMPurify.removed, {
|
16103
|
+
arrayPush(DOMPurify.removed, {
|
16104
|
+
element: node
|
16105
|
+
});
|
16409
16106
|
try {
|
16410
|
-
node
|
16107
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-remove
|
16108
|
+
getParentNode(node).removeChild(node);
|
16411
16109
|
} catch (_) {
|
16412
|
-
|
16110
|
+
remove(node);
|
16413
16111
|
}
|
16414
16112
|
};
|
16113
|
+
|
16114
|
+
/**
|
16115
|
+
* _removeAttribute
|
16116
|
+
*
|
16117
|
+
* @param {String} name an Attribute name
|
16118
|
+
* @param {Node} node a DOM node
|
16119
|
+
*/
|
16415
16120
|
const _removeAttribute = function _removeAttribute(name, node) {
|
16416
16121
|
try {
|
16417
16122
|
arrayPush(DOMPurify.removed, {
|
@@ -16425,64 +16130,114 @@
|
|
16425
16130
|
});
|
16426
16131
|
}
|
16427
16132
|
node.removeAttribute(name);
|
16133
|
+
|
16134
|
+
// We void attribute values for unremovable "is"" attributes
|
16428
16135
|
if (name === 'is' && !ALLOWED_ATTR[name]) {
|
16429
16136
|
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
16430
16137
|
try {
|
16431
16138
|
_forceRemove(node);
|
16432
|
-
} catch (_) {
|
16433
|
-
}
|
16139
|
+
} catch (_) {}
|
16434
16140
|
} else {
|
16435
16141
|
try {
|
16436
16142
|
node.setAttribute(name, '');
|
16437
|
-
} catch (_) {
|
16438
|
-
}
|
16143
|
+
} catch (_) {}
|
16439
16144
|
}
|
16440
16145
|
}
|
16441
16146
|
};
|
16147
|
+
|
16148
|
+
/**
|
16149
|
+
* _initDocument
|
16150
|
+
*
|
16151
|
+
* @param {String} dirty a string of dirty markup
|
16152
|
+
* @return {Document} a DOM, filled with the dirty markup
|
16153
|
+
*/
|
16442
16154
|
const _initDocument = function _initDocument(dirty) {
|
16443
|
-
|
16444
|
-
let
|
16155
|
+
/* Create a HTML document */
|
16156
|
+
let doc = null;
|
16157
|
+
let leadingWhitespace = null;
|
16445
16158
|
if (FORCE_BODY) {
|
16446
16159
|
dirty = '<remove></remove>' + dirty;
|
16447
16160
|
} else {
|
16161
|
+
/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
|
16448
16162
|
const matches = stringMatch(dirty, /^[\r\n\t ]+/);
|
16449
16163
|
leadingWhitespace = matches && matches[0];
|
16450
16164
|
}
|
16451
16165
|
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
|
16166
|
+
// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
|
16452
16167
|
dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
|
16453
16168
|
}
|
16454
16169
|
const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
16170
|
+
/*
|
16171
|
+
* Use the DOMParser API by default, fallback later if needs be
|
16172
|
+
* DOMParser not work for svg when has multiple root element.
|
16173
|
+
*/
|
16455
16174
|
if (NAMESPACE === HTML_NAMESPACE) {
|
16456
16175
|
try {
|
16457
16176
|
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
16458
|
-
} catch (_) {
|
16459
|
-
}
|
16177
|
+
} catch (_) {}
|
16460
16178
|
}
|
16179
|
+
|
16180
|
+
/* Use createHTMLDocument in case DOMParser is not available */
|
16461
16181
|
if (!doc || !doc.documentElement) {
|
16462
16182
|
doc = implementation.createDocument(NAMESPACE, 'template', null);
|
16463
16183
|
try {
|
16464
16184
|
doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
|
16465
16185
|
} catch (_) {
|
16186
|
+
// Syntax error if dirtyPayload is invalid xml
|
16466
16187
|
}
|
16467
16188
|
}
|
16468
16189
|
const body = doc.body || doc.documentElement;
|
16469
16190
|
if (dirty && leadingWhitespace) {
|
16470
16191
|
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
16471
16192
|
}
|
16193
|
+
|
16194
|
+
/* Work on whole document or just its body */
|
16472
16195
|
if (NAMESPACE === HTML_NAMESPACE) {
|
16473
16196
|
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
16474
16197
|
}
|
16475
16198
|
return WHOLE_DOCUMENT ? doc.documentElement : body;
|
16476
16199
|
};
|
16477
|
-
|
16478
|
-
|
16479
|
-
|
16200
|
+
|
16201
|
+
/**
|
16202
|
+
* Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
|
16203
|
+
*
|
16204
|
+
* @param {Node} root The root element or node to start traversing on.
|
16205
|
+
* @return {NodeIterator} The created NodeIterator
|
16206
|
+
*/
|
16207
|
+
const _createNodeIterator = function _createNodeIterator(root) {
|
16208
|
+
return createNodeIterator.call(root.ownerDocument || root, root,
|
16209
|
+
// eslint-disable-next-line no-bitwise
|
16210
|
+
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
|
16211
|
+
};
|
16212
|
+
|
16213
|
+
/**
|
16214
|
+
* _isClobbered
|
16215
|
+
*
|
16216
|
+
* @param {Node} elm element to check for clobbering attacks
|
16217
|
+
* @return {Boolean} true if clobbered, false if safe
|
16218
|
+
*/
|
16480
16219
|
const _isClobbered = function _isClobbered(elm) {
|
16481
16220
|
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');
|
16482
16221
|
};
|
16222
|
+
|
16223
|
+
/**
|
16224
|
+
* Checks whether the given object is a DOM node.
|
16225
|
+
*
|
16226
|
+
* @param {Node} object object to check whether it's a DOM node
|
16227
|
+
* @return {Boolean} true is object is a DOM node
|
16228
|
+
*/
|
16483
16229
|
const _isNode = function _isNode(object) {
|
16484
|
-
return typeof Node === '
|
16230
|
+
return typeof Node === 'function' && object instanceof Node;
|
16485
16231
|
};
|
16232
|
+
|
16233
|
+
/**
|
16234
|
+
* _executeHook
|
16235
|
+
* Execute user configurable hooks
|
16236
|
+
*
|
16237
|
+
* @param {String} entryPoint Name of the hook's entry point
|
16238
|
+
* @param {Node} currentNode node to work on with the hook
|
16239
|
+
* @param {Object} data additional hook parameters
|
16240
|
+
*/
|
16486
16241
|
const _executeHook = function _executeHook(entryPoint, currentNode, data) {
|
16487
16242
|
if (!hooks[entryPoint]) {
|
16488
16243
|
return;
|
@@ -16491,93 +16246,184 @@
|
|
16491
16246
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
16492
16247
|
});
|
16493
16248
|
};
|
16249
|
+
|
16250
|
+
/**
|
16251
|
+
* _sanitizeElements
|
16252
|
+
*
|
16253
|
+
* @protect nodeName
|
16254
|
+
* @protect textContent
|
16255
|
+
* @protect removeChild
|
16256
|
+
*
|
16257
|
+
* @param {Node} currentNode to check for permission to exist
|
16258
|
+
* @return {Boolean} true if node was killed, false if left alive
|
16259
|
+
*/
|
16494
16260
|
const _sanitizeElements = function _sanitizeElements(currentNode) {
|
16495
|
-
let content;
|
16261
|
+
let content = null;
|
16262
|
+
|
16263
|
+
/* Execute a hook if present */
|
16496
16264
|
_executeHook('beforeSanitizeElements', currentNode, null);
|
16265
|
+
|
16266
|
+
/* Check if element is clobbered or can clobber */
|
16497
16267
|
if (_isClobbered(currentNode)) {
|
16498
16268
|
_forceRemove(currentNode);
|
16499
16269
|
return true;
|
16500
16270
|
}
|
16271
|
+
|
16272
|
+
/* Now let's check the element's type and name */
|
16501
16273
|
const tagName = transformCaseFunc(currentNode.nodeName);
|
16274
|
+
|
16275
|
+
/* Execute a hook if present */
|
16502
16276
|
_executeHook('uponSanitizeElement', currentNode, {
|
16503
16277
|
tagName,
|
16504
16278
|
allowedTags: ALLOWED_TAGS
|
16505
16279
|
});
|
16506
|
-
|
16280
|
+
|
16281
|
+
/* Detect mXSS attempts abusing namespace confusion */
|
16282
|
+
if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
|
16507
16283
|
_forceRemove(currentNode);
|
16508
16284
|
return true;
|
16509
16285
|
}
|
16286
|
+
|
16287
|
+
/* Remove any occurrence of processing instructions */
|
16288
|
+
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
|
16289
|
+
_forceRemove(currentNode);
|
16290
|
+
return true;
|
16291
|
+
}
|
16292
|
+
|
16293
|
+
/* Remove any kind of possibly harmful comments */
|
16294
|
+
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
|
16295
|
+
_forceRemove(currentNode);
|
16296
|
+
return true;
|
16297
|
+
}
|
16298
|
+
|
16299
|
+
/* Remove element if anything forbids its presence */
|
16510
16300
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
16511
|
-
if
|
16512
|
-
|
16301
|
+
/* Check if we have a custom element to handle */
|
16302
|
+
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
16303
|
+
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
16513
16304
|
return false;
|
16514
|
-
|
16305
|
+
}
|
16306
|
+
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
|
16515
16307
|
return false;
|
16308
|
+
}
|
16516
16309
|
}
|
16310
|
+
|
16311
|
+
/* Keep content except for bad-listed elements */
|
16517
16312
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
16518
16313
|
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
16519
16314
|
const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
|
16520
16315
|
if (childNodes && parentNode) {
|
16521
16316
|
const childCount = childNodes.length;
|
16522
16317
|
for (let i = childCount - 1; i >= 0; --i) {
|
16523
|
-
|
16318
|
+
const childClone = cloneNode(childNodes[i], true);
|
16319
|
+
childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
|
16320
|
+
parentNode.insertBefore(childClone, getNextSibling(currentNode));
|
16524
16321
|
}
|
16525
16322
|
}
|
16526
16323
|
}
|
16527
16324
|
_forceRemove(currentNode);
|
16528
16325
|
return true;
|
16529
16326
|
}
|
16327
|
+
|
16328
|
+
/* Check whether element has a valid namespace */
|
16530
16329
|
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
|
16531
16330
|
_forceRemove(currentNode);
|
16532
16331
|
return true;
|
16533
16332
|
}
|
16333
|
+
|
16334
|
+
/* Make sure that older browsers don't get fallback-tag mXSS */
|
16534
16335
|
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
|
16535
16336
|
_forceRemove(currentNode);
|
16536
16337
|
return true;
|
16537
16338
|
}
|
16538
|
-
|
16339
|
+
|
16340
|
+
/* Sanitize element content to be template-safe */
|
16341
|
+
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
|
16342
|
+
/* Get the element's text content */
|
16539
16343
|
content = currentNode.textContent;
|
16540
|
-
|
16541
|
-
|
16542
|
-
|
16344
|
+
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
16345
|
+
content = stringReplace(content, expr, ' ');
|
16346
|
+
});
|
16543
16347
|
if (currentNode.textContent !== content) {
|
16544
|
-
arrayPush(DOMPurify.removed, {
|
16348
|
+
arrayPush(DOMPurify.removed, {
|
16349
|
+
element: currentNode.cloneNode()
|
16350
|
+
});
|
16545
16351
|
currentNode.textContent = content;
|
16546
16352
|
}
|
16547
16353
|
}
|
16354
|
+
|
16355
|
+
/* Execute a hook if present */
|
16548
16356
|
_executeHook('afterSanitizeElements', currentNode, null);
|
16549
16357
|
return false;
|
16550
16358
|
};
|
16359
|
+
|
16360
|
+
/**
|
16361
|
+
* _isValidAttribute
|
16362
|
+
*
|
16363
|
+
* @param {string} lcTag Lowercase tag name of containing element.
|
16364
|
+
* @param {string} lcName Lowercase attribute name.
|
16365
|
+
* @param {string} value Attribute value.
|
16366
|
+
* @return {Boolean} Returns true if `value` is valid, otherwise false.
|
16367
|
+
*/
|
16368
|
+
// eslint-disable-next-line complexity
|
16551
16369
|
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
16370
|
+
/* Make sure attribute cannot clobber */
|
16552
16371
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
16553
16372
|
return false;
|
16554
16373
|
}
|
16555
|
-
|
16556
|
-
|
16557
|
-
|
16558
|
-
|
16559
|
-
|
16374
|
+
|
16375
|
+
/* Allow valid data-* attributes: At least one character after "-"
|
16376
|
+
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
16377
|
+
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
16378
|
+
We don't need to check the value; it's always URI safe. */
|
16379
|
+
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]) {
|
16380
|
+
if (
|
16381
|
+
// First condition does a very basic check if a) it's basically a valid custom element tagname AND
|
16382
|
+
// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
16383
|
+
// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
|
16384
|
+
_isBasicCustomElement(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)) ||
|
16385
|
+
// Alternative, second condition checks if it's an `is`-attribute, AND
|
16386
|
+
// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
|
16387
|
+
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 {
|
16560
16388
|
return false;
|
16561
16389
|
}
|
16562
|
-
|
16563
|
-
else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, '')));
|
16564
|
-
else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]);
|
16565
|
-
else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, '')));
|
16566
|
-
else if (value) {
|
16390
|
+
/* Check value is safe. First, is attr inert? If so, is safe */
|
16391
|
+
} 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) {
|
16567
16392
|
return false;
|
16568
16393
|
} else ;
|
16569
16394
|
return true;
|
16570
16395
|
};
|
16571
|
-
|
16572
|
-
|
16573
|
-
|
16396
|
+
|
16397
|
+
/**
|
16398
|
+
* _isBasicCustomElement
|
16399
|
+
* checks if at least one dash is included in tagName, and it's not the first char
|
16400
|
+
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
16401
|
+
*
|
16402
|
+
* @param {string} tagName name of the tag of the node to sanitize
|
16403
|
+
* @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
|
16404
|
+
*/
|
16405
|
+
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
|
16406
|
+
return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
|
16407
|
+
};
|
16408
|
+
|
16409
|
+
/**
|
16410
|
+
* _sanitizeAttributes
|
16411
|
+
*
|
16412
|
+
* @protect attributes
|
16413
|
+
* @protect nodeName
|
16414
|
+
* @protect removeAttribute
|
16415
|
+
* @protect setAttribute
|
16416
|
+
*
|
16417
|
+
* @param {Node} currentNode to sanitize
|
16418
|
+
*/
|
16574
16419
|
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
16575
|
-
|
16576
|
-
let value;
|
16577
|
-
let lcName;
|
16578
|
-
let l;
|
16420
|
+
/* Execute a hook if present */
|
16579
16421
|
_executeHook('beforeSanitizeAttributes', currentNode, null);
|
16580
|
-
const {
|
16422
|
+
const {
|
16423
|
+
attributes
|
16424
|
+
} = currentNode;
|
16425
|
+
|
16426
|
+
/* Check if we have attributes; if not we might have a text node */
|
16581
16427
|
if (!attributes) {
|
16582
16428
|
return;
|
16583
16429
|
}
|
@@ -16587,99 +16433,174 @@
|
|
16587
16433
|
keepAttr: true,
|
16588
16434
|
allowedAttributes: ALLOWED_ATTR
|
16589
16435
|
};
|
16590
|
-
l = attributes.length;
|
16436
|
+
let l = attributes.length;
|
16437
|
+
|
16438
|
+
/* Go backwards over all attributes; safely remove bad ones */
|
16591
16439
|
while (l--) {
|
16592
|
-
attr = attributes[l];
|
16593
|
-
const {
|
16594
|
-
|
16440
|
+
const attr = attributes[l];
|
16441
|
+
const {
|
16442
|
+
name,
|
16443
|
+
namespaceURI,
|
16444
|
+
value: attrValue
|
16445
|
+
} = attr;
|
16446
|
+
const lcName = transformCaseFunc(name);
|
16447
|
+
let value = name === 'value' ? attrValue : stringTrim(attrValue);
|
16595
16448
|
const initValue = value;
|
16596
|
-
|
16449
|
+
|
16450
|
+
/* Execute a hook if present */
|
16597
16451
|
hookEvent.attrName = lcName;
|
16598
16452
|
hookEvent.attrValue = value;
|
16599
16453
|
hookEvent.keepAttr = true;
|
16600
|
-
hookEvent.forceKeepAttr = undefined;
|
16454
|
+
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
16601
16455
|
_executeHook('uponSanitizeAttribute', currentNode, hookEvent);
|
16602
16456
|
value = hookEvent.attrValue;
|
16457
|
+
|
16458
|
+
/* Did the hooks approve of the attribute? */
|
16603
16459
|
if (hookEvent.forceKeepAttr) {
|
16604
16460
|
continue;
|
16605
16461
|
}
|
16462
|
+
|
16463
|
+
/* Remove attribute */
|
16464
|
+
|
16465
|
+
/* Did the hooks approve of the attribute? */
|
16606
16466
|
if (!hookEvent.keepAttr) {
|
16607
16467
|
_removeAttribute(name, currentNode);
|
16608
16468
|
continue;
|
16609
16469
|
}
|
16470
|
+
|
16471
|
+
/* Work around a security issue in jQuery 3.0 */
|
16610
16472
|
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
16611
16473
|
_removeAttribute(name, currentNode);
|
16612
16474
|
continue;
|
16613
16475
|
}
|
16476
|
+
|
16477
|
+
/* Sanitize attribute content to be template-safe */
|
16614
16478
|
if (SAFE_FOR_TEMPLATES) {
|
16615
|
-
|
16616
|
-
|
16617
|
-
|
16479
|
+
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
16480
|
+
value = stringReplace(value, expr, ' ');
|
16481
|
+
});
|
16618
16482
|
}
|
16483
|
+
|
16484
|
+
/* Is `value` valid for this attribute? */
|
16619
16485
|
const lcTag = transformCaseFunc(currentNode.nodeName);
|
16620
16486
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
16621
16487
|
_removeAttribute(name, currentNode);
|
16622
16488
|
continue;
|
16623
16489
|
}
|
16490
|
+
|
16491
|
+
/* Full DOM Clobbering protection via namespace isolation,
|
16492
|
+
* Prefix id and name attributes with `user-content-`
|
16493
|
+
*/
|
16624
16494
|
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
16495
|
+
// Remove the attribute with this value
|
16625
16496
|
_removeAttribute(name, currentNode);
|
16497
|
+
|
16498
|
+
// Prefix the value and later re-create the attribute with the sanitized value
|
16626
16499
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
16627
16500
|
}
|
16501
|
+
|
16502
|
+
/* Work around a security issue with comments inside attributes */
|
16503
|
+
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
|
16504
|
+
_removeAttribute(name, currentNode);
|
16505
|
+
continue;
|
16506
|
+
}
|
16507
|
+
|
16508
|
+
/* Handle attributes that require Trusted Types */
|
16628
16509
|
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
16629
|
-
if (namespaceURI);
|
16630
|
-
else {
|
16510
|
+
if (namespaceURI) ; else {
|
16631
16511
|
switch (trustedTypes.getAttributeType(lcTag, lcName)) {
|
16632
|
-
|
16633
|
-
|
16634
|
-
|
16635
|
-
|
16636
|
-
|
16637
|
-
|
16638
|
-
|
16639
|
-
|
16512
|
+
case 'TrustedHTML':
|
16513
|
+
{
|
16514
|
+
value = trustedTypesPolicy.createHTML(value);
|
16515
|
+
break;
|
16516
|
+
}
|
16517
|
+
case 'TrustedScriptURL':
|
16518
|
+
{
|
16519
|
+
value = trustedTypesPolicy.createScriptURL(value);
|
16520
|
+
break;
|
16521
|
+
}
|
16640
16522
|
}
|
16641
16523
|
}
|
16642
16524
|
}
|
16525
|
+
|
16526
|
+
/* Handle invalid data-* attribute set by try-catching it */
|
16643
16527
|
if (value !== initValue) {
|
16644
16528
|
try {
|
16645
16529
|
if (namespaceURI) {
|
16646
16530
|
currentNode.setAttributeNS(namespaceURI, name, value);
|
16647
16531
|
} else {
|
16532
|
+
/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
|
16648
16533
|
currentNode.setAttribute(name, value);
|
16649
16534
|
}
|
16650
|
-
|
16651
|
-
|
16652
|
-
|
16535
|
+
if (_isClobbered(currentNode)) {
|
16536
|
+
_forceRemove(currentNode);
|
16537
|
+
} else {
|
16538
|
+
arrayPop(DOMPurify.removed);
|
16539
|
+
}
|
16540
|
+
} catch (_) {}
|
16653
16541
|
}
|
16654
16542
|
}
|
16543
|
+
|
16544
|
+
/* Execute a hook if present */
|
16655
16545
|
_executeHook('afterSanitizeAttributes', currentNode, null);
|
16656
16546
|
};
|
16547
|
+
|
16548
|
+
/**
|
16549
|
+
* _sanitizeShadowDOM
|
16550
|
+
*
|
16551
|
+
* @param {DocumentFragment} fragment to iterate over recursively
|
16552
|
+
*/
|
16657
16553
|
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
16658
|
-
let shadowNode;
|
16659
|
-
const shadowIterator =
|
16554
|
+
let shadowNode = null;
|
16555
|
+
const shadowIterator = _createNodeIterator(fragment);
|
16556
|
+
|
16557
|
+
/* Execute a hook if present */
|
16660
16558
|
_executeHook('beforeSanitizeShadowDOM', fragment, null);
|
16661
16559
|
while (shadowNode = shadowIterator.nextNode()) {
|
16560
|
+
/* Execute a hook if present */
|
16662
16561
|
_executeHook('uponSanitizeShadowNode', shadowNode, null);
|
16562
|
+
|
16563
|
+
/* Sanitize tags and elements */
|
16663
16564
|
if (_sanitizeElements(shadowNode)) {
|
16664
16565
|
continue;
|
16665
16566
|
}
|
16567
|
+
|
16568
|
+
/* Deep shadow DOM detected */
|
16666
16569
|
if (shadowNode.content instanceof DocumentFragment) {
|
16667
16570
|
_sanitizeShadowDOM(shadowNode.content);
|
16668
16571
|
}
|
16572
|
+
|
16573
|
+
/* Check attributes, sanitize if necessary */
|
16669
16574
|
_sanitizeAttributes(shadowNode);
|
16670
16575
|
}
|
16576
|
+
|
16577
|
+
/* Execute a hook if present */
|
16671
16578
|
_executeHook('afterSanitizeShadowDOM', fragment, null);
|
16672
16579
|
};
|
16580
|
+
|
16581
|
+
/**
|
16582
|
+
* Sanitize
|
16583
|
+
* Public method providing core sanitation functionality
|
16584
|
+
*
|
16585
|
+
* @param {String|Node} dirty string or DOM node
|
16586
|
+
* @param {Object} cfg object
|
16587
|
+
*/
|
16588
|
+
// eslint-disable-next-line complexity
|
16673
16589
|
DOMPurify.sanitize = function (dirty) {
|
16674
16590
|
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
16675
|
-
let body;
|
16676
|
-
let importedNode;
|
16677
|
-
let currentNode;
|
16678
|
-
let returnNode;
|
16591
|
+
let body = null;
|
16592
|
+
let importedNode = null;
|
16593
|
+
let currentNode = null;
|
16594
|
+
let returnNode = null;
|
16595
|
+
/* Make sure we have a string to sanitize.
|
16596
|
+
DO NOT return early, as this will return the wrong type if
|
16597
|
+
the user has requested a DOM object rather than a string */
|
16679
16598
|
IS_EMPTY_INPUT = !dirty;
|
16680
16599
|
if (IS_EMPTY_INPUT) {
|
16681
16600
|
dirty = '<!-->';
|
16682
16601
|
}
|
16602
|
+
|
16603
|
+
/* Stringify, in case dirty is an object */
|
16683
16604
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
16684
16605
|
if (typeof dirty.toString === 'function') {
|
16685
16606
|
dirty = dirty.toString();
|
@@ -16690,17 +16611,26 @@
|
|
16690
16611
|
throw typeErrorCreate('toString is not a function');
|
16691
16612
|
}
|
16692
16613
|
}
|
16614
|
+
|
16615
|
+
/* Return dirty HTML if DOMPurify cannot run */
|
16693
16616
|
if (!DOMPurify.isSupported) {
|
16694
16617
|
return dirty;
|
16695
16618
|
}
|
16619
|
+
|
16620
|
+
/* Assign config vars */
|
16696
16621
|
if (!SET_CONFIG) {
|
16697
16622
|
_parseConfig(cfg);
|
16698
16623
|
}
|
16624
|
+
|
16625
|
+
/* Clean up removed elements */
|
16699
16626
|
DOMPurify.removed = [];
|
16627
|
+
|
16628
|
+
/* Check if dirty is correctly typed for IN_PLACE */
|
16700
16629
|
if (typeof dirty === 'string') {
|
16701
16630
|
IN_PLACE = false;
|
16702
16631
|
}
|
16703
16632
|
if (IN_PLACE) {
|
16633
|
+
/* Do some early pre-sanitization to avoid unsafe root nodes */
|
16704
16634
|
if (dirty.nodeName) {
|
16705
16635
|
const tagName = transformCaseFunc(dirty.nodeName);
|
16706
16636
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
@@ -16708,74 +16638,138 @@
|
|
16708
16638
|
}
|
16709
16639
|
}
|
16710
16640
|
} else if (dirty instanceof Node) {
|
16641
|
+
/* If dirty is a DOM element, append to an empty document to avoid
|
16642
|
+
elements being stripped by the parser */
|
16711
16643
|
body = _initDocument('<!---->');
|
16712
16644
|
importedNode = body.ownerDocument.importNode(dirty, true);
|
16713
|
-
if (importedNode.nodeType ===
|
16645
|
+
if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
|
16646
|
+
/* Node is already a body, use as is */
|
16714
16647
|
body = importedNode;
|
16715
16648
|
} else if (importedNode.nodeName === 'HTML') {
|
16716
16649
|
body = importedNode;
|
16717
16650
|
} else {
|
16651
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
16718
16652
|
body.appendChild(importedNode);
|
16719
16653
|
}
|
16720
16654
|
} else {
|
16721
|
-
|
16655
|
+
/* Exit directly if we have nothing to do */
|
16656
|
+
if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
|
16657
|
+
// eslint-disable-next-line unicorn/prefer-includes
|
16658
|
+
dirty.indexOf('<') === -1) {
|
16722
16659
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
16723
16660
|
}
|
16661
|
+
|
16662
|
+
/* Initialize the document to work on */
|
16724
16663
|
body = _initDocument(dirty);
|
16664
|
+
|
16665
|
+
/* Check we have a DOM node from the data */
|
16725
16666
|
if (!body) {
|
16726
16667
|
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
|
16727
16668
|
}
|
16728
16669
|
}
|
16670
|
+
|
16671
|
+
/* Remove first element node (ours) if FORCE_BODY is set */
|
16729
16672
|
if (body && FORCE_BODY) {
|
16730
16673
|
_forceRemove(body.firstChild);
|
16731
16674
|
}
|
16732
|
-
|
16675
|
+
|
16676
|
+
/* Get node iterator */
|
16677
|
+
const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
|
16678
|
+
|
16679
|
+
/* Now start iterating over the created document */
|
16733
16680
|
while (currentNode = nodeIterator.nextNode()) {
|
16681
|
+
/* Sanitize tags and elements */
|
16734
16682
|
if (_sanitizeElements(currentNode)) {
|
16735
16683
|
continue;
|
16736
16684
|
}
|
16685
|
+
|
16686
|
+
/* Shadow DOM detected, sanitize it */
|
16737
16687
|
if (currentNode.content instanceof DocumentFragment) {
|
16738
16688
|
_sanitizeShadowDOM(currentNode.content);
|
16739
16689
|
}
|
16690
|
+
|
16691
|
+
/* Check attributes, sanitize if necessary */
|
16740
16692
|
_sanitizeAttributes(currentNode);
|
16741
16693
|
}
|
16694
|
+
|
16695
|
+
/* If we sanitized `dirty` in-place, return it. */
|
16742
16696
|
if (IN_PLACE) {
|
16743
16697
|
return dirty;
|
16744
16698
|
}
|
16699
|
+
|
16700
|
+
/* Return sanitized string or DOM */
|
16745
16701
|
if (RETURN_DOM) {
|
16746
16702
|
if (RETURN_DOM_FRAGMENT) {
|
16747
16703
|
returnNode = createDocumentFragment.call(body.ownerDocument);
|
16748
16704
|
while (body.firstChild) {
|
16705
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-append
|
16749
16706
|
returnNode.appendChild(body.firstChild);
|
16750
16707
|
}
|
16751
16708
|
} else {
|
16752
16709
|
returnNode = body;
|
16753
16710
|
}
|
16754
16711
|
if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
|
16712
|
+
/*
|
16713
|
+
AdoptNode() is not used because internal state is not reset
|
16714
|
+
(e.g. the past names map of a HTMLFormElement), this is safe
|
16715
|
+
in theory but we would rather not risk another attack vector.
|
16716
|
+
The state that is cloned by importNode() is explicitly defined
|
16717
|
+
by the specs.
|
16718
|
+
*/
|
16755
16719
|
returnNode = importNode.call(originalDocument, returnNode, true);
|
16756
16720
|
}
|
16757
16721
|
return returnNode;
|
16758
16722
|
}
|
16759
16723
|
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
16724
|
+
|
16725
|
+
/* Serialize doctype if allowed */
|
16760
16726
|
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
16761
16727
|
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
16762
16728
|
}
|
16729
|
+
|
16730
|
+
/* Sanitize final string template-safe */
|
16763
16731
|
if (SAFE_FOR_TEMPLATES) {
|
16764
|
-
|
16765
|
-
|
16766
|
-
|
16732
|
+
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
16733
|
+
serializedHTML = stringReplace(serializedHTML, expr, ' ');
|
16734
|
+
});
|
16767
16735
|
}
|
16768
16736
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
16769
16737
|
};
|
16770
|
-
|
16738
|
+
|
16739
|
+
/**
|
16740
|
+
* Public method to set the configuration once
|
16741
|
+
* setConfig
|
16742
|
+
*
|
16743
|
+
* @param {Object} cfg configuration object
|
16744
|
+
*/
|
16745
|
+
DOMPurify.setConfig = function () {
|
16746
|
+
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
16771
16747
|
_parseConfig(cfg);
|
16772
16748
|
SET_CONFIG = true;
|
16773
16749
|
};
|
16750
|
+
|
16751
|
+
/**
|
16752
|
+
* Public method to remove the configuration
|
16753
|
+
* clearConfig
|
16754
|
+
*
|
16755
|
+
*/
|
16774
16756
|
DOMPurify.clearConfig = function () {
|
16775
16757
|
CONFIG = null;
|
16776
16758
|
SET_CONFIG = false;
|
16777
16759
|
};
|
16760
|
+
|
16761
|
+
/**
|
16762
|
+
* Public method to check if an attribute value is valid.
|
16763
|
+
* Uses last set config, if any. Otherwise, uses config defaults.
|
16764
|
+
* isValidAttribute
|
16765
|
+
*
|
16766
|
+
* @param {String} tag Tag name of containing element.
|
16767
|
+
* @param {String} attr Attribute name.
|
16768
|
+
* @param {String} value Attribute value.
|
16769
|
+
* @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
|
16770
|
+
*/
|
16778
16771
|
DOMPurify.isValidAttribute = function (tag, attr, value) {
|
16772
|
+
/* Initialize shared config vars if necessary. */
|
16779
16773
|
if (!CONFIG) {
|
16780
16774
|
_parseConfig({});
|
16781
16775
|
}
|
@@ -16783,6 +16777,14 @@
|
|
16783
16777
|
const lcName = transformCaseFunc(attr);
|
16784
16778
|
return _isValidAttribute(lcTag, lcName, value);
|
16785
16779
|
};
|
16780
|
+
|
16781
|
+
/**
|
16782
|
+
* AddHook
|
16783
|
+
* Public method to add DOMPurify hooks
|
16784
|
+
*
|
16785
|
+
* @param {String} entryPoint entry point for the hook to add
|
16786
|
+
* @param {Function} hookFunction function to execute
|
16787
|
+
*/
|
16786
16788
|
DOMPurify.addHook = function (entryPoint, hookFunction) {
|
16787
16789
|
if (typeof hookFunction !== 'function') {
|
16788
16790
|
return;
|
@@ -16790,16 +16792,37 @@
|
|
16790
16792
|
hooks[entryPoint] = hooks[entryPoint] || [];
|
16791
16793
|
arrayPush(hooks[entryPoint], hookFunction);
|
16792
16794
|
};
|
16795
|
+
|
16796
|
+
/**
|
16797
|
+
* RemoveHook
|
16798
|
+
* Public method to remove a DOMPurify hook at a given entryPoint
|
16799
|
+
* (pops it from the stack of hooks if more are present)
|
16800
|
+
*
|
16801
|
+
* @param {String} entryPoint entry point for the hook to remove
|
16802
|
+
* @return {Function} removed(popped) hook
|
16803
|
+
*/
|
16793
16804
|
DOMPurify.removeHook = function (entryPoint) {
|
16794
16805
|
if (hooks[entryPoint]) {
|
16795
16806
|
return arrayPop(hooks[entryPoint]);
|
16796
16807
|
}
|
16797
16808
|
};
|
16809
|
+
|
16810
|
+
/**
|
16811
|
+
* RemoveHooks
|
16812
|
+
* Public method to remove all DOMPurify hooks at a given entryPoint
|
16813
|
+
*
|
16814
|
+
* @param {String} entryPoint entry point for the hooks to remove
|
16815
|
+
*/
|
16798
16816
|
DOMPurify.removeHooks = function (entryPoint) {
|
16799
16817
|
if (hooks[entryPoint]) {
|
16800
16818
|
hooks[entryPoint] = [];
|
16801
16819
|
}
|
16802
16820
|
};
|
16821
|
+
|
16822
|
+
/**
|
16823
|
+
* RemoveAllHooks
|
16824
|
+
* Public method to remove all DOMPurify hooks
|
16825
|
+
*/
|
16803
16826
|
DOMPurify.removeAllHooks = function () {
|
16804
16827
|
hooks = {};
|
16805
16828
|
};
|
@@ -17235,7 +17258,8 @@
|
|
17235
17258
|
'#cdata-section',
|
17236
17259
|
'body'
|
17237
17260
|
],
|
17238
|
-
ALLOWED_ATTR: []
|
17261
|
+
ALLOWED_ATTR: [],
|
17262
|
+
SAFE_FOR_XML: false
|
17239
17263
|
};
|
17240
17264
|
const config = { ...basePurifyConfig };
|
17241
17265
|
config.PARSER_MEDIA_TYPE = mimeType;
|
@@ -31592,8 +31616,8 @@
|
|
31592
31616
|
documentBaseURL: null,
|
31593
31617
|
suffix: null,
|
31594
31618
|
majorVersion: '7',
|
31595
|
-
minorVersion: '4.
|
31596
|
-
releaseDate: '
|
31619
|
+
minorVersion: '4.1',
|
31620
|
+
releaseDate: 'TBD',
|
31597
31621
|
i18n: I18n,
|
31598
31622
|
activeEditor: null,
|
31599
31623
|
focusedEditor: null,
|