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