tinymce-rails 7.7.0 → 7.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/source/tinymce/tinymce.js +144 -359
- data/lib/tinymce/rails/version.rb +2 -2
- data/vendor/assets/javascripts/tinymce/models/dom/model.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/accordion/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/advlist/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autosave/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/code/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/codesample/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/emoticons/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/fullscreen/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/help/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/importcss/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/lists/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/nonbreaking/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/pagebreak/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/preview/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/quickbars/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/visualblocks/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/visualchars/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/wordcount/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.min.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.min.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.min.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.min.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.min.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.min.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css +1 -3
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.min.css +1 -3
- data/vendor/assets/javascripts/tinymce/themes/silver/theme.js +126 -180
- data/vendor/assets/javascripts/tinymce/tinymce.js +122 -176
- metadata +2 -2
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* TinyMCE version 7.7.
|
2
|
+
* TinyMCE version 7.7.1 (2025-03-05)
|
3
3
|
*/
|
4
4
|
|
5
5
|
(function () {
|
@@ -15314,7 +15314,7 @@
|
|
15314
15314
|
}
|
15315
15315
|
};
|
15316
15316
|
|
15317
|
-
/*! @license DOMPurify 3.
|
15317
|
+
/*! @license DOMPurify 3.2.4 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.4/LICENSE */
|
15318
15318
|
|
15319
15319
|
const {
|
15320
15320
|
entries,
|
@@ -15353,8 +15353,10 @@
|
|
15353
15353
|
};
|
15354
15354
|
}
|
15355
15355
|
const arrayForEach = unapply(Array.prototype.forEach);
|
15356
|
+
const arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);
|
15356
15357
|
const arrayPop = unapply(Array.prototype.pop);
|
15357
15358
|
const arrayPush = unapply(Array.prototype.push);
|
15359
|
+
const arraySplice = unapply(Array.prototype.splice);
|
15358
15360
|
const stringToLowerCase = unapply(String.prototype.toLowerCase);
|
15359
15361
|
const stringToString = unapply(String.prototype.toString);
|
15360
15362
|
const stringMatch = unapply(String.prototype.match);
|
@@ -15364,12 +15366,11 @@
|
|
15364
15366
|
const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
|
15365
15367
|
const regExpTest = unapply(RegExp.prototype.test);
|
15366
15368
|
const typeErrorCreate = unconstruct(TypeError);
|
15367
|
-
|
15368
15369
|
/**
|
15369
15370
|
* Creates a new function that calls the given function with a specified thisArg and arguments.
|
15370
15371
|
*
|
15371
|
-
* @param
|
15372
|
-
* @returns
|
15372
|
+
* @param func - The function to be wrapped and called.
|
15373
|
+
* @returns A new function that calls the given function with a specified thisArg and arguments.
|
15373
15374
|
*/
|
15374
15375
|
function unapply(func) {
|
15375
15376
|
return function (thisArg) {
|
@@ -15379,12 +15380,11 @@
|
|
15379
15380
|
return apply(func, thisArg, args);
|
15380
15381
|
};
|
15381
15382
|
}
|
15382
|
-
|
15383
15383
|
/**
|
15384
15384
|
* Creates a new function that constructs an instance of the given constructor function with the provided arguments.
|
15385
15385
|
*
|
15386
|
-
* @param
|
15387
|
-
* @returns
|
15386
|
+
* @param func - The constructor function to be wrapped and called.
|
15387
|
+
* @returns A new function that constructs an instance of the given constructor function with the provided arguments.
|
15388
15388
|
*/
|
15389
15389
|
function unconstruct(func) {
|
15390
15390
|
return function () {
|
@@ -15394,14 +15394,13 @@
|
|
15394
15394
|
return construct(func, args);
|
15395
15395
|
};
|
15396
15396
|
}
|
15397
|
-
|
15398
15397
|
/**
|
15399
15398
|
* Add properties to a lookup table
|
15400
15399
|
*
|
15401
|
-
* @param
|
15402
|
-
* @param
|
15403
|
-
* @param
|
15404
|
-
* @returns
|
15400
|
+
* @param set - The set to which elements will be added.
|
15401
|
+
* @param array - The array containing elements to be added to the set.
|
15402
|
+
* @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
|
15403
|
+
* @returns The modified set with added elements.
|
15405
15404
|
*/
|
15406
15405
|
function addToSet(set, array) {
|
15407
15406
|
let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
|
@@ -15428,12 +15427,11 @@
|
|
15428
15427
|
}
|
15429
15428
|
return set;
|
15430
15429
|
}
|
15431
|
-
|
15432
15430
|
/**
|
15433
15431
|
* Clean up an array to harden against CSPP
|
15434
15432
|
*
|
15435
|
-
* @param
|
15436
|
-
* @returns
|
15433
|
+
* @param array - The array to be cleaned.
|
15434
|
+
* @returns The cleaned version of the array
|
15437
15435
|
*/
|
15438
15436
|
function cleanArray(array) {
|
15439
15437
|
for (let index = 0; index < array.length; index++) {
|
@@ -15444,12 +15442,11 @@
|
|
15444
15442
|
}
|
15445
15443
|
return array;
|
15446
15444
|
}
|
15447
|
-
|
15448
15445
|
/**
|
15449
15446
|
* Shallow clone an object
|
15450
15447
|
*
|
15451
|
-
* @param
|
15452
|
-
* @returns
|
15448
|
+
* @param object - The object to be cloned.
|
15449
|
+
* @returns A new object that copies the original.
|
15453
15450
|
*/
|
15454
15451
|
function clone(object) {
|
15455
15452
|
const newObject = create$7(null);
|
@@ -15467,13 +15464,12 @@
|
|
15467
15464
|
}
|
15468
15465
|
return newObject;
|
15469
15466
|
}
|
15470
|
-
|
15471
15467
|
/**
|
15472
15468
|
* This method automatically checks if the prop is function or getter and behaves accordingly.
|
15473
15469
|
*
|
15474
|
-
* @param
|
15475
|
-
* @param
|
15476
|
-
* @returns
|
15470
|
+
* @param object - The object to look up the getter function in its prototype chain.
|
15471
|
+
* @param prop - The property name for which to find the getter function.
|
15472
|
+
* @returns The getter function found in the prototype chain or a fallback function.
|
15477
15473
|
*/
|
15478
15474
|
function lookupGetter(object, prop) {
|
15479
15475
|
while (object !== null) {
|
@@ -15495,18 +15491,14 @@
|
|
15495
15491
|
}
|
15496
15492
|
|
15497
15493
|
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']);
|
15498
|
-
|
15499
|
-
// SVG
|
15500
15494
|
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']);
|
15501
15495
|
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']);
|
15502
|
-
|
15503
15496
|
// List of SVG elements that are disallowed by default.
|
15504
15497
|
// We still need to know them so that we can do namespace
|
15505
15498
|
// checks properly in case one wants to add them to
|
15506
15499
|
// allow-list.
|
15507
15500
|
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']);
|
15508
15501
|
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']);
|
15509
|
-
|
15510
15502
|
// Similarly to SVG, we want to know all MathML elements,
|
15511
15503
|
// even those that we disallow by default.
|
15512
15504
|
const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
|
@@ -15520,8 +15512,8 @@
|
|
15520
15512
|
// eslint-disable-next-line unicorn/better-regex
|
15521
15513
|
const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
|
15522
15514
|
const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
|
15523
|
-
const TMPLIT_EXPR = seal(
|
15524
|
-
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]
|
15515
|
+
const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
|
15516
|
+
const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
|
15525
15517
|
const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
|
15526
15518
|
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
|
15527
15519
|
);
|
@@ -15533,18 +15525,19 @@
|
|
15533
15525
|
|
15534
15526
|
var EXPRESSIONS = /*#__PURE__*/Object.freeze({
|
15535
15527
|
__proto__: null,
|
15536
|
-
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
15537
|
-
ERB_EXPR: ERB_EXPR,
|
15538
|
-
TMPLIT_EXPR: TMPLIT_EXPR,
|
15539
|
-
DATA_ATTR: DATA_ATTR,
|
15540
15528
|
ARIA_ATTR: ARIA_ATTR,
|
15541
|
-
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
15542
|
-
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
15543
15529
|
ATTR_WHITESPACE: ATTR_WHITESPACE,
|
15530
|
+
CUSTOM_ELEMENT: CUSTOM_ELEMENT,
|
15531
|
+
DATA_ATTR: DATA_ATTR,
|
15544
15532
|
DOCTYPE_NAME: DOCTYPE_NAME,
|
15545
|
-
|
15533
|
+
ERB_EXPR: ERB_EXPR,
|
15534
|
+
IS_ALLOWED_URI: IS_ALLOWED_URI,
|
15535
|
+
IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
|
15536
|
+
MUSTACHE_EXPR: MUSTACHE_EXPR,
|
15537
|
+
TMPLIT_EXPR: TMPLIT_EXPR
|
15546
15538
|
});
|
15547
15539
|
|
15540
|
+
/* eslint-disable @typescript-eslint/indent */
|
15548
15541
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
15549
15542
|
const NODE_TYPE = {
|
15550
15543
|
element: 1,
|
@@ -15565,20 +15558,18 @@
|
|
15565
15558
|
const getGlobal = function getGlobal() {
|
15566
15559
|
return typeof window === 'undefined' ? null : window;
|
15567
15560
|
};
|
15568
|
-
|
15569
15561
|
/**
|
15570
15562
|
* Creates a no-op policy for internal use only.
|
15571
15563
|
* Don't export this function outside this module!
|
15572
|
-
* @param
|
15573
|
-
* @param
|
15574
|
-
* @return
|
15564
|
+
* @param trustedTypes The policy factory.
|
15565
|
+
* @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
|
15566
|
+
* @return The policy created (or null, if Trusted Types
|
15575
15567
|
* are not supported or creating the policy failed).
|
15576
15568
|
*/
|
15577
15569
|
const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
|
15578
15570
|
if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
|
15579
15571
|
return null;
|
15580
15572
|
}
|
15581
|
-
|
15582
15573
|
// Allow the callers to control the unique policy name
|
15583
15574
|
// by adding a data-tt-policy-suffix to the script element with the DOMPurify.
|
15584
15575
|
// Policy creation with duplicate names throws in Trusted Types.
|
@@ -15605,22 +15596,25 @@
|
|
15605
15596
|
return null;
|
15606
15597
|
}
|
15607
15598
|
};
|
15599
|
+
const _createHooksMap = function _createHooksMap() {
|
15600
|
+
return {
|
15601
|
+
afterSanitizeAttributes: [],
|
15602
|
+
afterSanitizeElements: [],
|
15603
|
+
afterSanitizeShadowDOM: [],
|
15604
|
+
beforeSanitizeAttributes: [],
|
15605
|
+
beforeSanitizeElements: [],
|
15606
|
+
beforeSanitizeShadowDOM: [],
|
15607
|
+
uponSanitizeAttribute: [],
|
15608
|
+
uponSanitizeElement: [],
|
15609
|
+
uponSanitizeShadowNode: []
|
15610
|
+
};
|
15611
|
+
};
|
15608
15612
|
function createDOMPurify() {
|
15609
15613
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
15610
15614
|
const DOMPurify = root => createDOMPurify(root);
|
15611
|
-
|
15612
|
-
/**
|
15613
|
-
* Version label, exposed for easier checks
|
15614
|
-
* if DOMPurify is up to date or not
|
15615
|
-
*/
|
15616
|
-
DOMPurify.version = '3.1.7';
|
15617
|
-
|
15618
|
-
/**
|
15619
|
-
* Array of elements that DOMPurify removed during sanitation.
|
15620
|
-
* Empty if nothing was removed.
|
15621
|
-
*/
|
15615
|
+
DOMPurify.version = '3.2.4';
|
15622
15616
|
DOMPurify.removed = [];
|
15623
|
-
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
|
15617
|
+
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
15624
15618
|
// Not running in a browser, provide a factory function
|
15625
15619
|
// so that you can pass your own Window
|
15626
15620
|
DOMPurify.isSupported = false;
|
@@ -15648,7 +15642,6 @@
|
|
15648
15642
|
const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
|
15649
15643
|
const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
|
15650
15644
|
const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
|
15651
|
-
|
15652
15645
|
// As per issue #47, the web-components registry is inherited by a
|
15653
15646
|
// new document created via createHTMLDocument. As per the spec
|
15654
15647
|
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
@@ -15672,8 +15665,7 @@
|
|
15672
15665
|
const {
|
15673
15666
|
importNode
|
15674
15667
|
} = originalDocument;
|
15675
|
-
let hooks =
|
15676
|
-
|
15668
|
+
let hooks = _createHooksMap();
|
15677
15669
|
/**
|
15678
15670
|
* Expose whether this browser supports running the full DOMPurify.
|
15679
15671
|
*/
|
@@ -15691,22 +15683,18 @@
|
|
15691
15683
|
let {
|
15692
15684
|
IS_ALLOWED_URI: IS_ALLOWED_URI$1
|
15693
15685
|
} = EXPRESSIONS;
|
15694
|
-
|
15695
15686
|
/**
|
15696
15687
|
* We consider the elements and attributes below to be safe. Ideally
|
15697
15688
|
* don't add any new ones but feel free to remove unwanted ones.
|
15698
15689
|
*/
|
15699
|
-
|
15700
15690
|
/* allowed element names */
|
15701
15691
|
let ALLOWED_TAGS = null;
|
15702
15692
|
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
|
15703
|
-
|
15704
15693
|
/* Allowed attribute names */
|
15705
15694
|
let ALLOWED_ATTR = null;
|
15706
15695
|
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
15707
|
-
|
15708
15696
|
/*
|
15709
|
-
* Configure how
|
15697
|
+
* Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
|
15710
15698
|
* @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
|
15711
15699
|
* @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
|
15712
15700
|
* @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
|
@@ -15731,65 +15719,49 @@
|
|
15731
15719
|
value: false
|
15732
15720
|
}
|
15733
15721
|
}));
|
15734
|
-
|
15735
15722
|
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
|
15736
15723
|
let FORBID_TAGS = null;
|
15737
|
-
|
15738
15724
|
/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
|
15739
15725
|
let FORBID_ATTR = null;
|
15740
|
-
|
15741
15726
|
/* Decide if ARIA attributes are okay */
|
15742
15727
|
let ALLOW_ARIA_ATTR = true;
|
15743
|
-
|
15744
15728
|
/* Decide if custom data attributes are okay */
|
15745
15729
|
let ALLOW_DATA_ATTR = true;
|
15746
|
-
|
15747
15730
|
/* Decide if unknown protocols are okay */
|
15748
15731
|
let ALLOW_UNKNOWN_PROTOCOLS = false;
|
15749
|
-
|
15750
15732
|
/* Decide if self-closing tags in attributes are allowed.
|
15751
15733
|
* Usually removed due to a mXSS issue in jQuery 3.0 */
|
15752
15734
|
let ALLOW_SELF_CLOSE_IN_ATTR = true;
|
15753
|
-
|
15754
15735
|
/* Output should be safe for common template engines.
|
15755
15736
|
* This means, DOMPurify removes data attributes, mustaches and ERB
|
15756
15737
|
*/
|
15757
15738
|
let SAFE_FOR_TEMPLATES = false;
|
15758
|
-
|
15759
15739
|
/* Output should be safe even for XML used within HTML and alike.
|
15760
15740
|
* This means, DOMPurify removes comments when containing risky content.
|
15761
15741
|
*/
|
15762
15742
|
let SAFE_FOR_XML = true;
|
15763
|
-
|
15764
15743
|
/* Decide if document with <html>... should be returned */
|
15765
15744
|
let WHOLE_DOCUMENT = false;
|
15766
|
-
|
15767
15745
|
/* Track whether config is already set on this instance of DOMPurify. */
|
15768
15746
|
let SET_CONFIG = false;
|
15769
|
-
|
15770
15747
|
/* Decide if all elements (e.g. style, script) must be children of
|
15771
15748
|
* document.body. By default, browsers might move them to document.head */
|
15772
15749
|
let FORCE_BODY = false;
|
15773
|
-
|
15774
15750
|
/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
|
15775
15751
|
* string (or a TrustedHTML object if Trusted Types are supported).
|
15776
15752
|
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
|
15777
15753
|
*/
|
15778
15754
|
let RETURN_DOM = false;
|
15779
|
-
|
15780
15755
|
/* Decide if a DOM `DocumentFragment` should be returned, instead of a html
|
15781
15756
|
* string (or a TrustedHTML object if Trusted Types are supported) */
|
15782
15757
|
let RETURN_DOM_FRAGMENT = false;
|
15783
|
-
|
15784
15758
|
/* Try to return a Trusted Type object instead of a string, return a string in
|
15785
15759
|
* case Trusted Types are not supported */
|
15786
15760
|
let RETURN_TRUSTED_TYPE = false;
|
15787
|
-
|
15788
15761
|
/* Output should be free from DOM clobbering attacks?
|
15789
15762
|
* This sanitizes markups named with colliding, clobberable built-in DOM APIs.
|
15790
15763
|
*/
|
15791
15764
|
let SANITIZE_DOM = true;
|
15792
|
-
|
15793
15765
|
/* Achieve full DOM Clobbering protection by isolating the namespace of named
|
15794
15766
|
* properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
|
15795
15767
|
*
|
@@ -15805,25 +15777,19 @@
|
|
15805
15777
|
*/
|
15806
15778
|
let SANITIZE_NAMED_PROPS = false;
|
15807
15779
|
const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
|
15808
|
-
|
15809
15780
|
/* Keep element content when removing element? */
|
15810
15781
|
let KEEP_CONTENT = true;
|
15811
|
-
|
15812
15782
|
/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
|
15813
15783
|
* of importing it into a new Document and returning a sanitized copy */
|
15814
15784
|
let IN_PLACE = false;
|
15815
|
-
|
15816
15785
|
/* Allow usage of profiles like html, svg and mathMl */
|
15817
15786
|
let USE_PROFILES = {};
|
15818
|
-
|
15819
15787
|
/* Tags to ignore content of when KEEP_CONTENT is true */
|
15820
15788
|
let FORBID_CONTENTS = null;
|
15821
15789
|
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']);
|
15822
|
-
|
15823
15790
|
/* Tags that are safe for data: URIs */
|
15824
15791
|
let DATA_URI_TAGS = null;
|
15825
15792
|
const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
|
15826
|
-
|
15827
15793
|
/* Attributes safe for values like "javascript:" */
|
15828
15794
|
let URI_SAFE_ATTRIBUTES = null;
|
15829
15795
|
const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
|
@@ -15833,32 +15799,33 @@
|
|
15833
15799
|
/* Document namespace */
|
15834
15800
|
let NAMESPACE = HTML_NAMESPACE;
|
15835
15801
|
let IS_EMPTY_INPUT = false;
|
15836
|
-
|
15837
15802
|
/* Allowed XHTML+XML namespaces */
|
15838
15803
|
let ALLOWED_NAMESPACES = null;
|
15839
15804
|
const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
|
15840
|
-
|
15805
|
+
let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
15806
|
+
let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
|
15807
|
+
// Certain elements are allowed in both SVG and HTML
|
15808
|
+
// namespace. We need to specify them explicitly
|
15809
|
+
// so that they don't get erroneously deleted from
|
15810
|
+
// HTML namespace.
|
15811
|
+
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
15841
15812
|
/* Parsing of strict XHTML documents */
|
15842
15813
|
let PARSER_MEDIA_TYPE = null;
|
15843
15814
|
const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
|
15844
15815
|
const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
|
15845
15816
|
let transformCaseFunc = null;
|
15846
|
-
|
15847
15817
|
/* Keep a reference to config to pass to hooks */
|
15848
15818
|
let CONFIG = null;
|
15849
|
-
|
15850
15819
|
/* Ideally, do not touch anything below this line */
|
15851
15820
|
/* ______________________________________________ */
|
15852
|
-
|
15853
15821
|
const formElement = document.createElement('form');
|
15854
15822
|
const isRegexOrFunction = function isRegexOrFunction(testValue) {
|
15855
15823
|
return testValue instanceof RegExp || testValue instanceof Function;
|
15856
15824
|
};
|
15857
|
-
|
15858
15825
|
/**
|
15859
15826
|
* _parseConfig
|
15860
15827
|
*
|
15861
|
-
* @param
|
15828
|
+
* @param cfg optional config literal
|
15862
15829
|
*/
|
15863
15830
|
// eslint-disable-next-line complexity
|
15864
15831
|
const _parseConfig = function _parseConfig() {
|
@@ -15866,39 +15833,23 @@
|
|
15866
15833
|
if (CONFIG && CONFIG === cfg) {
|
15867
15834
|
return;
|
15868
15835
|
}
|
15869
|
-
|
15870
15836
|
/* Shield configuration object from tampering */
|
15871
15837
|
if (!cfg || typeof cfg !== 'object') {
|
15872
15838
|
cfg = {};
|
15873
15839
|
}
|
15874
|
-
|
15875
15840
|
/* Shield configuration object from prototype pollution */
|
15876
15841
|
cfg = clone(cfg);
|
15877
15842
|
PARSER_MEDIA_TYPE =
|
15878
15843
|
// eslint-disable-next-line unicorn/prefer-includes
|
15879
15844
|
SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
|
15880
|
-
|
15881
15845
|
// HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
|
15882
15846
|
transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
|
15883
|
-
|
15884
15847
|
/* Set configuration parameters */
|
15885
15848
|
ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
|
15886
15849
|
ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
|
15887
15850
|
ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
|
15888
|
-
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),
|
15889
|
-
|
15890
|
-
cfg.ADD_URI_SAFE_ATTR,
|
15891
|
-
// eslint-disable-line indent
|
15892
|
-
transformCaseFunc // eslint-disable-line indent
|
15893
|
-
) // eslint-disable-line indent
|
15894
|
-
: DEFAULT_URI_SAFE_ATTRIBUTES;
|
15895
|
-
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS),
|
15896
|
-
// eslint-disable-line indent
|
15897
|
-
cfg.ADD_DATA_URI_TAGS,
|
15898
|
-
// eslint-disable-line indent
|
15899
|
-
transformCaseFunc // eslint-disable-line indent
|
15900
|
-
) // eslint-disable-line indent
|
15901
|
-
: DEFAULT_DATA_URI_TAGS;
|
15851
|
+
URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
|
15852
|
+
DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
|
15902
15853
|
FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
|
15903
15854
|
FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
|
15904
15855
|
FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
|
@@ -15920,6 +15871,8 @@
|
|
15920
15871
|
IN_PLACE = cfg.IN_PLACE || false; // Default false
|
15921
15872
|
IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
|
15922
15873
|
NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
|
15874
|
+
MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
|
15875
|
+
HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
|
15923
15876
|
CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
|
15924
15877
|
if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
|
15925
15878
|
CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
|
@@ -15936,7 +15889,6 @@
|
|
15936
15889
|
if (RETURN_DOM_FRAGMENT) {
|
15937
15890
|
RETURN_DOM = true;
|
15938
15891
|
}
|
15939
|
-
|
15940
15892
|
/* Parse profile info */
|
15941
15893
|
if (USE_PROFILES) {
|
15942
15894
|
ALLOWED_TAGS = addToSet({}, text);
|
@@ -15961,7 +15913,6 @@
|
|
15961
15913
|
addToSet(ALLOWED_ATTR, xml);
|
15962
15914
|
}
|
15963
15915
|
}
|
15964
|
-
|
15965
15916
|
/* Merge configuration parameters */
|
15966
15917
|
if (cfg.ADD_TAGS) {
|
15967
15918
|
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
|
@@ -15984,17 +15935,14 @@
|
|
15984
15935
|
}
|
15985
15936
|
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
15986
15937
|
}
|
15987
|
-
|
15988
15938
|
/* Add #text in case KEEP_CONTENT is set to true */
|
15989
15939
|
if (KEEP_CONTENT) {
|
15990
15940
|
ALLOWED_TAGS['#text'] = true;
|
15991
15941
|
}
|
15992
|
-
|
15993
15942
|
/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
|
15994
15943
|
if (WHOLE_DOCUMENT) {
|
15995
15944
|
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
|
15996
15945
|
}
|
15997
|
-
|
15998
15946
|
/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
|
15999
15947
|
if (ALLOWED_TAGS.table) {
|
16000
15948
|
addToSet(ALLOWED_TAGS, ['tbody']);
|
@@ -16007,10 +15955,8 @@
|
|
16007
15955
|
if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
|
16008
15956
|
throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
|
16009
15957
|
}
|
16010
|
-
|
16011
15958
|
// Overwrite existing TrustedTypes policy.
|
16012
15959
|
trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
|
16013
|
-
|
16014
15960
|
// Sign local variables required by `sanitize`.
|
16015
15961
|
emptyHTML = trustedTypesPolicy.createHTML('');
|
16016
15962
|
} else {
|
@@ -16018,13 +15964,11 @@
|
|
16018
15964
|
if (trustedTypesPolicy === undefined) {
|
16019
15965
|
trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
|
16020
15966
|
}
|
16021
|
-
|
16022
15967
|
// If creating the internal policy succeeded sign internal variables.
|
16023
15968
|
if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
|
16024
15969
|
emptyHTML = trustedTypesPolicy.createHTML('');
|
16025
15970
|
}
|
16026
15971
|
}
|
16027
|
-
|
16028
15972
|
// Prevent further manipulation of configuration.
|
16029
15973
|
// Not available in IE8, Safari 5, etc.
|
16030
15974
|
if (freeze) {
|
@@ -16032,30 +15976,19 @@
|
|
16032
15976
|
}
|
16033
15977
|
CONFIG = cfg;
|
16034
15978
|
};
|
16035
|
-
const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
|
16036
|
-
const HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
|
16037
|
-
|
16038
|
-
// Certain elements are allowed in both SVG and HTML
|
16039
|
-
// namespace. We need to specify them explicitly
|
16040
|
-
// so that they don't get erroneously deleted from
|
16041
|
-
// HTML namespace.
|
16042
|
-
const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
|
16043
|
-
|
16044
15979
|
/* Keep track of all possible SVG and MathML tags
|
16045
15980
|
* so that we can perform the namespace checks
|
16046
15981
|
* correctly. */
|
16047
15982
|
const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
|
16048
15983
|
const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
|
16049
|
-
|
16050
15984
|
/**
|
16051
|
-
* @param
|
16052
|
-
* @returns
|
15985
|
+
* @param element a DOM element whose namespace is being checked
|
15986
|
+
* @returns Return false if the element has a
|
16053
15987
|
* namespace that a spec-compliant parser would never
|
16054
15988
|
* return. Return true otherwise.
|
16055
15989
|
*/
|
16056
15990
|
const _checkValidNamespace = function _checkValidNamespace(element) {
|
16057
15991
|
let parent = getParentNode(element);
|
16058
|
-
|
16059
15992
|
// In JSDOM, if we're inside shadow DOM, then parentNode
|
16060
15993
|
// can be null. We just simulate parent in this case.
|
16061
15994
|
if (!parent || !parent.tagName) {
|
@@ -16076,14 +16009,12 @@
|
|
16076
16009
|
if (parent.namespaceURI === HTML_NAMESPACE) {
|
16077
16010
|
return tagName === 'svg';
|
16078
16011
|
}
|
16079
|
-
|
16080
16012
|
// The only way to switch from MathML to SVG is via`
|
16081
16013
|
// svg if parent is either <annotation-xml> or MathML
|
16082
16014
|
// text integration points.
|
16083
16015
|
if (parent.namespaceURI === MATHML_NAMESPACE) {
|
16084
16016
|
return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
|
16085
16017
|
}
|
16086
|
-
|
16087
16018
|
// We only allow elements that are defined in SVG
|
16088
16019
|
// spec. All others are disallowed in SVG namespace.
|
16089
16020
|
return Boolean(ALL_SVG_TAGS[tagName]);
|
@@ -16095,13 +16026,11 @@
|
|
16095
16026
|
if (parent.namespaceURI === HTML_NAMESPACE) {
|
16096
16027
|
return tagName === 'math';
|
16097
16028
|
}
|
16098
|
-
|
16099
16029
|
// The only way to switch from SVG to MathML is via
|
16100
16030
|
// <math> and HTML integration points
|
16101
16031
|
if (parent.namespaceURI === SVG_NAMESPACE) {
|
16102
16032
|
return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
|
16103
16033
|
}
|
16104
|
-
|
16105
16034
|
// We only allow elements that are defined in MathML
|
16106
16035
|
// spec. All others are disallowed in MathML namespace.
|
16107
16036
|
return Boolean(ALL_MATHML_TAGS[tagName]);
|
@@ -16116,28 +16045,24 @@
|
|
16116
16045
|
if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
|
16117
16046
|
return false;
|
16118
16047
|
}
|
16119
|
-
|
16120
16048
|
// We disallow tags that are specific for MathML
|
16121
16049
|
// or SVG and should never appear in HTML namespace
|
16122
16050
|
return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
|
16123
16051
|
}
|
16124
|
-
|
16125
16052
|
// For XHTML and XML documents that support custom namespaces
|
16126
16053
|
if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
|
16127
16054
|
return true;
|
16128
16055
|
}
|
16129
|
-
|
16130
16056
|
// The code should never reach this place (this means
|
16131
16057
|
// that the element somehow got namespace that is not
|
16132
16058
|
// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
|
16133
16059
|
// Return false just in case.
|
16134
16060
|
return false;
|
16135
16061
|
};
|
16136
|
-
|
16137
16062
|
/**
|
16138
16063
|
* _forceRemove
|
16139
16064
|
*
|
16140
|
-
* @param
|
16065
|
+
* @param node a DOM node
|
16141
16066
|
*/
|
16142
16067
|
const _forceRemove = function _forceRemove(node) {
|
16143
16068
|
arrayPush(DOMPurify.removed, {
|
@@ -16150,46 +16075,43 @@
|
|
16150
16075
|
remove(node);
|
16151
16076
|
}
|
16152
16077
|
};
|
16153
|
-
|
16154
16078
|
/**
|
16155
16079
|
* _removeAttribute
|
16156
16080
|
*
|
16157
|
-
* @param
|
16158
|
-
* @param
|
16081
|
+
* @param name an Attribute name
|
16082
|
+
* @param element a DOM node
|
16159
16083
|
*/
|
16160
|
-
const _removeAttribute = function _removeAttribute(name,
|
16084
|
+
const _removeAttribute = function _removeAttribute(name, element) {
|
16161
16085
|
try {
|
16162
16086
|
arrayPush(DOMPurify.removed, {
|
16163
|
-
attribute:
|
16164
|
-
from:
|
16087
|
+
attribute: element.getAttributeNode(name),
|
16088
|
+
from: element
|
16165
16089
|
});
|
16166
16090
|
} catch (_) {
|
16167
16091
|
arrayPush(DOMPurify.removed, {
|
16168
16092
|
attribute: null,
|
16169
|
-
from:
|
16093
|
+
from: element
|
16170
16094
|
});
|
16171
16095
|
}
|
16172
|
-
|
16173
|
-
|
16174
|
-
|
16175
|
-
if (name === 'is' && !ALLOWED_ATTR[name]) {
|
16096
|
+
element.removeAttribute(name);
|
16097
|
+
// We void attribute values for unremovable "is" attributes
|
16098
|
+
if (name === 'is') {
|
16176
16099
|
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
16177
16100
|
try {
|
16178
|
-
_forceRemove(
|
16101
|
+
_forceRemove(element);
|
16179
16102
|
} catch (_) {}
|
16180
16103
|
} else {
|
16181
16104
|
try {
|
16182
|
-
|
16105
|
+
element.setAttribute(name, '');
|
16183
16106
|
} catch (_) {}
|
16184
16107
|
}
|
16185
16108
|
}
|
16186
16109
|
};
|
16187
|
-
|
16188
16110
|
/**
|
16189
16111
|
* _initDocument
|
16190
16112
|
*
|
16191
|
-
* @param
|
16192
|
-
* @return
|
16113
|
+
* @param dirty - a string of dirty markup
|
16114
|
+
* @return a DOM, filled with the dirty markup
|
16193
16115
|
*/
|
16194
16116
|
const _initDocument = function _initDocument(dirty) {
|
16195
16117
|
/* Create a HTML document */
|
@@ -16216,7 +16138,6 @@
|
|
16216
16138
|
doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
|
16217
16139
|
} catch (_) {}
|
16218
16140
|
}
|
16219
|
-
|
16220
16141
|
/* Use createHTMLDocument in case DOMParser is not available */
|
16221
16142
|
if (!doc || !doc.documentElement) {
|
16222
16143
|
doc = implementation.createDocument(NAMESPACE, 'template', null);
|
@@ -16230,112 +16151,86 @@
|
|
16230
16151
|
if (dirty && leadingWhitespace) {
|
16231
16152
|
body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
|
16232
16153
|
}
|
16233
|
-
|
16234
16154
|
/* Work on whole document or just its body */
|
16235
16155
|
if (NAMESPACE === HTML_NAMESPACE) {
|
16236
16156
|
return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
|
16237
16157
|
}
|
16238
16158
|
return WHOLE_DOCUMENT ? doc.documentElement : body;
|
16239
16159
|
};
|
16240
|
-
|
16241
16160
|
/**
|
16242
16161
|
* Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
|
16243
16162
|
*
|
16244
|
-
* @param
|
16245
|
-
* @return
|
16163
|
+
* @param root The root element or node to start traversing on.
|
16164
|
+
* @return The created NodeIterator
|
16246
16165
|
*/
|
16247
16166
|
const _createNodeIterator = function _createNodeIterator(root) {
|
16248
16167
|
return createNodeIterator.call(root.ownerDocument || root, root,
|
16249
16168
|
// eslint-disable-next-line no-bitwise
|
16250
16169
|
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
|
16251
16170
|
};
|
16252
|
-
|
16253
16171
|
/**
|
16254
16172
|
* _isClobbered
|
16255
16173
|
*
|
16256
|
-
* @param
|
16257
|
-
* @return
|
16174
|
+
* @param element element to check for clobbering attacks
|
16175
|
+
* @return true if clobbered, false if safe
|
16258
16176
|
*/
|
16259
|
-
const _isClobbered = function _isClobbered(
|
16260
|
-
return
|
16177
|
+
const _isClobbered = function _isClobbered(element) {
|
16178
|
+
return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
|
16261
16179
|
};
|
16262
|
-
|
16263
16180
|
/**
|
16264
16181
|
* Checks whether the given object is a DOM node.
|
16265
16182
|
*
|
16266
|
-
* @param
|
16267
|
-
* @return
|
16183
|
+
* @param value object to check whether it's a DOM node
|
16184
|
+
* @return true is object is a DOM node
|
16268
16185
|
*/
|
16269
|
-
const _isNode = function _isNode(
|
16270
|
-
return typeof Node === 'function' &&
|
16186
|
+
const _isNode = function _isNode(value) {
|
16187
|
+
return typeof Node === 'function' && value instanceof Node;
|
16271
16188
|
};
|
16272
|
-
|
16273
|
-
|
16274
|
-
* _executeHook
|
16275
|
-
* Execute user configurable hooks
|
16276
|
-
*
|
16277
|
-
* @param {String} entryPoint Name of the hook's entry point
|
16278
|
-
* @param {Node} currentNode node to work on with the hook
|
16279
|
-
* @param {Object} data additional hook parameters
|
16280
|
-
*/
|
16281
|
-
const _executeHook = function _executeHook(entryPoint, currentNode, data) {
|
16282
|
-
if (!hooks[entryPoint]) {
|
16283
|
-
return;
|
16284
|
-
}
|
16285
|
-
arrayForEach(hooks[entryPoint], hook => {
|
16189
|
+
function _executeHooks(hooks, currentNode, data) {
|
16190
|
+
arrayForEach(hooks, hook => {
|
16286
16191
|
hook.call(DOMPurify, currentNode, data, CONFIG);
|
16287
16192
|
});
|
16288
|
-
}
|
16289
|
-
|
16193
|
+
}
|
16290
16194
|
/**
|
16291
16195
|
* _sanitizeElements
|
16292
16196
|
*
|
16293
16197
|
* @protect nodeName
|
16294
16198
|
* @protect textContent
|
16295
16199
|
* @protect removeChild
|
16296
|
-
*
|
16297
|
-
* @
|
16298
|
-
* @return {Boolean} true if node was killed, false if left alive
|
16200
|
+
* @param currentNode to check for permission to exist
|
16201
|
+
* @return true if node was killed, false if left alive
|
16299
16202
|
*/
|
16300
16203
|
const _sanitizeElements = function _sanitizeElements(currentNode) {
|
16301
16204
|
let content = null;
|
16302
|
-
|
16303
16205
|
/* Execute a hook if present */
|
16304
|
-
|
16305
|
-
|
16206
|
+
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
|
16306
16207
|
/* Check if element is clobbered or can clobber */
|
16307
16208
|
if (_isClobbered(currentNode)) {
|
16308
16209
|
_forceRemove(currentNode);
|
16309
16210
|
return true;
|
16310
16211
|
}
|
16311
|
-
|
16312
16212
|
/* Now let's check the element's type and name */
|
16313
16213
|
const tagName = transformCaseFunc(currentNode.nodeName);
|
16314
|
-
|
16315
16214
|
/* Execute a hook if present */
|
16316
|
-
|
16215
|
+
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
16317
16216
|
tagName,
|
16318
16217
|
allowedTags: ALLOWED_TAGS
|
16319
16218
|
});
|
16320
|
-
|
16321
16219
|
/* Detect mXSS attempts abusing namespace confusion */
|
16322
16220
|
if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
|
16323
16221
|
_forceRemove(currentNode);
|
16324
16222
|
return true;
|
16325
16223
|
}
|
16326
|
-
|
16327
16224
|
/* Remove any occurrence of processing instructions */
|
16328
16225
|
if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
|
16329
16226
|
_forceRemove(currentNode);
|
16330
16227
|
return true;
|
16331
16228
|
}
|
16332
|
-
|
16333
16229
|
/* Remove any kind of possibly harmful comments */
|
16334
16230
|
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
|
16335
16231
|
_forceRemove(currentNode);
|
16336
16232
|
return true;
|
16337
16233
|
}
|
16338
|
-
|
16339
16234
|
/* Remove element if anything forbids its presence */
|
16340
16235
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
16341
16236
|
/* Check if we have a custom element to handle */
|
@@ -16347,7 +16242,6 @@
|
|
16347
16242
|
return false;
|
16348
16243
|
}
|
16349
16244
|
}
|
16350
|
-
|
16351
16245
|
/* Keep content except for bad-listed elements */
|
16352
16246
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
16353
16247
|
const parentNode = getParentNode(currentNode) || currentNode.parentNode;
|
@@ -16364,19 +16258,16 @@
|
|
16364
16258
|
_forceRemove(currentNode);
|
16365
16259
|
return true;
|
16366
16260
|
}
|
16367
|
-
|
16368
16261
|
/* Check whether element has a valid namespace */
|
16369
16262
|
if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
|
16370
16263
|
_forceRemove(currentNode);
|
16371
16264
|
return true;
|
16372
16265
|
}
|
16373
|
-
|
16374
16266
|
/* Make sure that older browsers don't get fallback-tag mXSS */
|
16375
16267
|
if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
|
16376
16268
|
_forceRemove(currentNode);
|
16377
16269
|
return true;
|
16378
16270
|
}
|
16379
|
-
|
16380
16271
|
/* Sanitize element content to be template-safe */
|
16381
16272
|
if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
|
16382
16273
|
/* Get the element's text content */
|
@@ -16391,19 +16282,17 @@
|
|
16391
16282
|
currentNode.textContent = content;
|
16392
16283
|
}
|
16393
16284
|
}
|
16394
|
-
|
16395
16285
|
/* Execute a hook if present */
|
16396
|
-
|
16286
|
+
_executeHooks(hooks.afterSanitizeElements, currentNode, null);
|
16397
16287
|
return false;
|
16398
16288
|
};
|
16399
|
-
|
16400
16289
|
/**
|
16401
16290
|
* _isValidAttribute
|
16402
16291
|
*
|
16403
|
-
* @param
|
16404
|
-
* @param
|
16405
|
-
* @param
|
16406
|
-
* @return
|
16292
|
+
* @param lcTag Lowercase tag name of containing element.
|
16293
|
+
* @param lcName Lowercase attribute name.
|
16294
|
+
* @param value Attribute value.
|
16295
|
+
* @return Returns true if `value` is valid, otherwise false.
|
16407
16296
|
*/
|
16408
16297
|
// eslint-disable-next-line complexity
|
16409
16298
|
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
@@ -16411,7 +16300,6 @@
|
|
16411
16300
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
16412
16301
|
return false;
|
16413
16302
|
}
|
16414
|
-
|
16415
16303
|
/* Allow valid data-* attributes: At least one character after "-"
|
16416
16304
|
(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
|
16417
16305
|
XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
|
@@ -16433,19 +16321,17 @@
|
|
16433
16321
|
} else ;
|
16434
16322
|
return true;
|
16435
16323
|
};
|
16436
|
-
|
16437
16324
|
/**
|
16438
16325
|
* _isBasicCustomElement
|
16439
16326
|
* checks if at least one dash is included in tagName, and it's not the first char
|
16440
16327
|
* for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
|
16441
16328
|
*
|
16442
|
-
* @param
|
16443
|
-
* @returns
|
16329
|
+
* @param tagName name of the tag of the node to sanitize
|
16330
|
+
* @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
|
16444
16331
|
*/
|
16445
16332
|
const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
|
16446
16333
|
return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
|
16447
16334
|
};
|
16448
|
-
|
16449
16335
|
/**
|
16450
16336
|
* _sanitizeAttributes
|
16451
16337
|
*
|
@@ -16454,27 +16340,26 @@
|
|
16454
16340
|
* @protect removeAttribute
|
16455
16341
|
* @protect setAttribute
|
16456
16342
|
*
|
16457
|
-
* @param
|
16343
|
+
* @param currentNode to sanitize
|
16458
16344
|
*/
|
16459
16345
|
const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
|
16460
16346
|
/* Execute a hook if present */
|
16461
|
-
|
16347
|
+
_executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
|
16462
16348
|
const {
|
16463
16349
|
attributes
|
16464
16350
|
} = currentNode;
|
16465
|
-
|
16466
16351
|
/* Check if we have attributes; if not we might have a text node */
|
16467
|
-
if (!attributes) {
|
16352
|
+
if (!attributes || _isClobbered(currentNode)) {
|
16468
16353
|
return;
|
16469
16354
|
}
|
16470
16355
|
const hookEvent = {
|
16471
16356
|
attrName: '',
|
16472
16357
|
attrValue: '',
|
16473
16358
|
keepAttr: true,
|
16474
|
-
allowedAttributes: ALLOWED_ATTR
|
16359
|
+
allowedAttributes: ALLOWED_ATTR,
|
16360
|
+
forceKeepAttr: undefined
|
16475
16361
|
};
|
16476
16362
|
let l = attributes.length;
|
16477
|
-
|
16478
16363
|
/* Go backwards over all attributes; safely remove bad ones */
|
16479
16364
|
while (l--) {
|
16480
16365
|
const attr = attributes[l];
|
@@ -16486,65 +16371,54 @@
|
|
16486
16371
|
const lcName = transformCaseFunc(name);
|
16487
16372
|
let value = name === 'value' ? attrValue : stringTrim(attrValue);
|
16488
16373
|
const initValue = value;
|
16489
|
-
|
16490
16374
|
/* Execute a hook if present */
|
16491
16375
|
hookEvent.attrName = lcName;
|
16492
16376
|
hookEvent.attrValue = value;
|
16493
16377
|
hookEvent.keepAttr = true;
|
16494
16378
|
hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
|
16495
|
-
|
16379
|
+
_executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
|
16496
16380
|
value = hookEvent.attrValue;
|
16497
|
-
|
16381
|
+
/* Full DOM Clobbering protection via namespace isolation,
|
16382
|
+
* Prefix id and name attributes with `user-content-`
|
16383
|
+
*/
|
16384
|
+
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
16385
|
+
// Remove the attribute with this value
|
16386
|
+
_removeAttribute(name, currentNode);
|
16387
|
+
// Prefix the value and later re-create the attribute with the sanitized value
|
16388
|
+
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
16389
|
+
}
|
16390
|
+
/* Work around a security issue with comments inside attributes */
|
16391
|
+
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
|
16392
|
+
_removeAttribute(name, currentNode);
|
16393
|
+
continue;
|
16394
|
+
}
|
16498
16395
|
/* Did the hooks approve of the attribute? */
|
16499
16396
|
if (hookEvent.forceKeepAttr) {
|
16500
16397
|
continue;
|
16501
16398
|
}
|
16502
|
-
|
16503
16399
|
/* Remove attribute */
|
16504
|
-
|
16505
16400
|
/* Did the hooks approve of the attribute? */
|
16506
16401
|
if (!hookEvent.keepAttr) {
|
16507
16402
|
_removeAttribute(name, currentNode);
|
16508
16403
|
continue;
|
16509
16404
|
}
|
16510
|
-
|
16511
16405
|
/* Work around a security issue in jQuery 3.0 */
|
16512
16406
|
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
|
16513
16407
|
_removeAttribute(name, currentNode);
|
16514
16408
|
continue;
|
16515
16409
|
}
|
16516
|
-
|
16517
16410
|
/* Sanitize attribute content to be template-safe */
|
16518
16411
|
if (SAFE_FOR_TEMPLATES) {
|
16519
16412
|
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
16520
16413
|
value = stringReplace(value, expr, ' ');
|
16521
16414
|
});
|
16522
16415
|
}
|
16523
|
-
|
16524
16416
|
/* Is `value` valid for this attribute? */
|
16525
16417
|
const lcTag = transformCaseFunc(currentNode.nodeName);
|
16526
16418
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
16527
16419
|
_removeAttribute(name, currentNode);
|
16528
16420
|
continue;
|
16529
16421
|
}
|
16530
|
-
|
16531
|
-
/* Full DOM Clobbering protection via namespace isolation,
|
16532
|
-
* Prefix id and name attributes with `user-content-`
|
16533
|
-
*/
|
16534
|
-
if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
|
16535
|
-
// Remove the attribute with this value
|
16536
|
-
_removeAttribute(name, currentNode);
|
16537
|
-
|
16538
|
-
// Prefix the value and later re-create the attribute with the sanitized value
|
16539
|
-
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
16540
|
-
}
|
16541
|
-
|
16542
|
-
/* Work around a security issue with comments inside attributes */
|
16543
|
-
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
|
16544
|
-
_removeAttribute(name, currentNode);
|
16545
|
-
continue;
|
16546
|
-
}
|
16547
|
-
|
16548
16422
|
/* Handle attributes that require Trusted Types */
|
16549
16423
|
if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
|
16550
16424
|
if (namespaceURI) ; else {
|
@@ -16562,7 +16436,6 @@
|
|
16562
16436
|
}
|
16563
16437
|
}
|
16564
16438
|
}
|
16565
|
-
|
16566
16439
|
/* Handle invalid data-* attribute set by try-catching it */
|
16567
16440
|
if (value !== initValue) {
|
16568
16441
|
try {
|
@@ -16580,51 +16453,34 @@
|
|
16580
16453
|
} catch (_) {}
|
16581
16454
|
}
|
16582
16455
|
}
|
16583
|
-
|
16584
16456
|
/* Execute a hook if present */
|
16585
|
-
|
16457
|
+
_executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
|
16586
16458
|
};
|
16587
|
-
|
16588
16459
|
/**
|
16589
16460
|
* _sanitizeShadowDOM
|
16590
16461
|
*
|
16591
|
-
* @param
|
16462
|
+
* @param fragment to iterate over recursively
|
16592
16463
|
*/
|
16593
16464
|
const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
|
16594
16465
|
let shadowNode = null;
|
16595
16466
|
const shadowIterator = _createNodeIterator(fragment);
|
16596
|
-
|
16597
16467
|
/* Execute a hook if present */
|
16598
|
-
|
16468
|
+
_executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
|
16599
16469
|
while (shadowNode = shadowIterator.nextNode()) {
|
16600
16470
|
/* Execute a hook if present */
|
16601
|
-
|
16602
|
-
|
16471
|
+
_executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
|
16603
16472
|
/* Sanitize tags and elements */
|
16604
|
-
|
16605
|
-
|
16606
|
-
|
16607
|
-
|
16473
|
+
_sanitizeElements(shadowNode);
|
16474
|
+
/* Check attributes next */
|
16475
|
+
_sanitizeAttributes(shadowNode);
|
16608
16476
|
/* Deep shadow DOM detected */
|
16609
16477
|
if (shadowNode.content instanceof DocumentFragment) {
|
16610
16478
|
_sanitizeShadowDOM(shadowNode.content);
|
16611
16479
|
}
|
16612
|
-
|
16613
|
-
/* Check attributes, sanitize if necessary */
|
16614
|
-
_sanitizeAttributes(shadowNode);
|
16615
16480
|
}
|
16616
|
-
|
16617
16481
|
/* Execute a hook if present */
|
16618
|
-
|
16482
|
+
_executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
|
16619
16483
|
};
|
16620
|
-
|
16621
|
-
/**
|
16622
|
-
* Sanitize
|
16623
|
-
* Public method providing core sanitation functionality
|
16624
|
-
*
|
16625
|
-
* @param {String|Node} dirty string or DOM node
|
16626
|
-
* @param {Object} cfg object
|
16627
|
-
*/
|
16628
16484
|
// eslint-disable-next-line complexity
|
16629
16485
|
DOMPurify.sanitize = function (dirty) {
|
16630
16486
|
let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
@@ -16639,7 +16495,6 @@
|
|
16639
16495
|
if (IS_EMPTY_INPUT) {
|
16640
16496
|
dirty = '<!-->';
|
16641
16497
|
}
|
16642
|
-
|
16643
16498
|
/* Stringify, in case dirty is an object */
|
16644
16499
|
if (typeof dirty !== 'string' && !_isNode(dirty)) {
|
16645
16500
|
if (typeof dirty.toString === 'function') {
|
@@ -16651,20 +16506,16 @@
|
|
16651
16506
|
throw typeErrorCreate('toString is not a function');
|
16652
16507
|
}
|
16653
16508
|
}
|
16654
|
-
|
16655
16509
|
/* Return dirty HTML if DOMPurify cannot run */
|
16656
16510
|
if (!DOMPurify.isSupported) {
|
16657
16511
|
return dirty;
|
16658
16512
|
}
|
16659
|
-
|
16660
16513
|
/* Assign config vars */
|
16661
16514
|
if (!SET_CONFIG) {
|
16662
16515
|
_parseConfig(cfg);
|
16663
16516
|
}
|
16664
|
-
|
16665
16517
|
/* Clean up removed elements */
|
16666
16518
|
DOMPurify.removed = [];
|
16667
|
-
|
16668
16519
|
/* Check if dirty is correctly typed for IN_PLACE */
|
16669
16520
|
if (typeof dirty === 'string') {
|
16670
16521
|
IN_PLACE = false;
|
@@ -16698,45 +16549,34 @@
|
|
16698
16549
|
dirty.indexOf('<') === -1) {
|
16699
16550
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
|
16700
16551
|
}
|
16701
|
-
|
16702
16552
|
/* Initialize the document to work on */
|
16703
16553
|
body = _initDocument(dirty);
|
16704
|
-
|
16705
16554
|
/* Check we have a DOM node from the data */
|
16706
16555
|
if (!body) {
|
16707
16556
|
return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
|
16708
16557
|
}
|
16709
16558
|
}
|
16710
|
-
|
16711
16559
|
/* Remove first element node (ours) if FORCE_BODY is set */
|
16712
16560
|
if (body && FORCE_BODY) {
|
16713
16561
|
_forceRemove(body.firstChild);
|
16714
16562
|
}
|
16715
|
-
|
16716
16563
|
/* Get node iterator */
|
16717
16564
|
const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
|
16718
|
-
|
16719
16565
|
/* Now start iterating over the created document */
|
16720
16566
|
while (currentNode = nodeIterator.nextNode()) {
|
16721
16567
|
/* Sanitize tags and elements */
|
16722
|
-
|
16723
|
-
|
16724
|
-
|
16725
|
-
|
16568
|
+
_sanitizeElements(currentNode);
|
16569
|
+
/* Check attributes next */
|
16570
|
+
_sanitizeAttributes(currentNode);
|
16726
16571
|
/* Shadow DOM detected, sanitize it */
|
16727
16572
|
if (currentNode.content instanceof DocumentFragment) {
|
16728
16573
|
_sanitizeShadowDOM(currentNode.content);
|
16729
16574
|
}
|
16730
|
-
|
16731
|
-
/* Check attributes, sanitize if necessary */
|
16732
|
-
_sanitizeAttributes(currentNode);
|
16733
16575
|
}
|
16734
|
-
|
16735
16576
|
/* If we sanitized `dirty` in-place, return it. */
|
16736
16577
|
if (IN_PLACE) {
|
16737
16578
|
return dirty;
|
16738
16579
|
}
|
16739
|
-
|
16740
16580
|
/* Return sanitized string or DOM */
|
16741
16581
|
if (RETURN_DOM) {
|
16742
16582
|
if (RETURN_DOM_FRAGMENT) {
|
@@ -16761,12 +16601,10 @@
|
|
16761
16601
|
return returnNode;
|
16762
16602
|
}
|
16763
16603
|
let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
|
16764
|
-
|
16765
16604
|
/* Serialize doctype if allowed */
|
16766
16605
|
if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
|
16767
16606
|
serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
|
16768
16607
|
}
|
16769
|
-
|
16770
16608
|
/* Sanitize final string template-safe */
|
16771
16609
|
if (SAFE_FOR_TEMPLATES) {
|
16772
16610
|
arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
|
@@ -16775,39 +16613,15 @@
|
|
16775
16613
|
}
|
16776
16614
|
return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
|
16777
16615
|
};
|
16778
|
-
|
16779
|
-
/**
|
16780
|
-
* Public method to set the configuration once
|
16781
|
-
* setConfig
|
16782
|
-
*
|
16783
|
-
* @param {Object} cfg configuration object
|
16784
|
-
*/
|
16785
16616
|
DOMPurify.setConfig = function () {
|
16786
16617
|
let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
16787
16618
|
_parseConfig(cfg);
|
16788
16619
|
SET_CONFIG = true;
|
16789
16620
|
};
|
16790
|
-
|
16791
|
-
/**
|
16792
|
-
* Public method to remove the configuration
|
16793
|
-
* clearConfig
|
16794
|
-
*
|
16795
|
-
*/
|
16796
16621
|
DOMPurify.clearConfig = function () {
|
16797
16622
|
CONFIG = null;
|
16798
16623
|
SET_CONFIG = false;
|
16799
16624
|
};
|
16800
|
-
|
16801
|
-
/**
|
16802
|
-
* Public method to check if an attribute value is valid.
|
16803
|
-
* Uses last set config, if any. Otherwise, uses config defaults.
|
16804
|
-
* isValidAttribute
|
16805
|
-
*
|
16806
|
-
* @param {String} tag Tag name of containing element.
|
16807
|
-
* @param {String} attr Attribute name.
|
16808
|
-
* @param {String} value Attribute value.
|
16809
|
-
* @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
|
16810
|
-
*/
|
16811
16625
|
DOMPurify.isValidAttribute = function (tag, attr, value) {
|
16812
16626
|
/* Initialize shared config vars if necessary. */
|
16813
16627
|
if (!CONFIG) {
|
@@ -16817,54 +16631,24 @@
|
|
16817
16631
|
const lcName = transformCaseFunc(attr);
|
16818
16632
|
return _isValidAttribute(lcTag, lcName, value);
|
16819
16633
|
};
|
16820
|
-
|
16821
|
-
/**
|
16822
|
-
* AddHook
|
16823
|
-
* Public method to add DOMPurify hooks
|
16824
|
-
*
|
16825
|
-
* @param {String} entryPoint entry point for the hook to add
|
16826
|
-
* @param {Function} hookFunction function to execute
|
16827
|
-
*/
|
16828
16634
|
DOMPurify.addHook = function (entryPoint, hookFunction) {
|
16829
16635
|
if (typeof hookFunction !== 'function') {
|
16830
16636
|
return;
|
16831
16637
|
}
|
16832
|
-
hooks[entryPoint] = hooks[entryPoint] || [];
|
16833
16638
|
arrayPush(hooks[entryPoint], hookFunction);
|
16834
16639
|
};
|
16835
|
-
|
16836
|
-
|
16837
|
-
|
16838
|
-
|
16839
|
-
* (pops it from the stack of hooks if more are present)
|
16840
|
-
*
|
16841
|
-
* @param {String} entryPoint entry point for the hook to remove
|
16842
|
-
* @return {Function} removed(popped) hook
|
16843
|
-
*/
|
16844
|
-
DOMPurify.removeHook = function (entryPoint) {
|
16845
|
-
if (hooks[entryPoint]) {
|
16846
|
-
return arrayPop(hooks[entryPoint]);
|
16640
|
+
DOMPurify.removeHook = function (entryPoint, hookFunction) {
|
16641
|
+
if (hookFunction !== undefined) {
|
16642
|
+
const index = arrayLastIndexOf(hooks[entryPoint], hookFunction);
|
16643
|
+
return index === -1 ? undefined : arraySplice(hooks[entryPoint], index, 1)[0];
|
16847
16644
|
}
|
16645
|
+
return arrayPop(hooks[entryPoint]);
|
16848
16646
|
};
|
16849
|
-
|
16850
|
-
/**
|
16851
|
-
* RemoveHooks
|
16852
|
-
* Public method to remove all DOMPurify hooks at a given entryPoint
|
16853
|
-
*
|
16854
|
-
* @param {String} entryPoint entry point for the hooks to remove
|
16855
|
-
*/
|
16856
16647
|
DOMPurify.removeHooks = function (entryPoint) {
|
16857
|
-
|
16858
|
-
hooks[entryPoint] = [];
|
16859
|
-
}
|
16648
|
+
hooks[entryPoint] = [];
|
16860
16649
|
};
|
16861
|
-
|
16862
|
-
/**
|
16863
|
-
* RemoveAllHooks
|
16864
|
-
* Public method to remove all DOMPurify hooks
|
16865
|
-
*/
|
16866
16650
|
DOMPurify.removeAllHooks = function () {
|
16867
|
-
hooks =
|
16651
|
+
hooks = _createHooksMap();
|
16868
16652
|
};
|
16869
16653
|
return DOMPurify;
|
16870
16654
|
}
|
@@ -17353,10 +17137,11 @@
|
|
17353
17137
|
evt.allowedTags[lcTagName] = true;
|
17354
17138
|
}
|
17355
17139
|
if (lcTagName === 'annotation') {
|
17356
|
-
const
|
17140
|
+
const elm = node;
|
17141
|
+
const keepElement = hasValidEncoding(elm);
|
17357
17142
|
evt.allowedTags[lcTagName] = keepElement;
|
17358
17143
|
if (!keepElement) {
|
17359
|
-
|
17144
|
+
elm.remove();
|
17360
17145
|
}
|
17361
17146
|
}
|
17362
17147
|
});
|
@@ -31853,8 +31638,8 @@
|
|
31853
31638
|
documentBaseURL: null,
|
31854
31639
|
suffix: null,
|
31855
31640
|
majorVersion: '7',
|
31856
|
-
minorVersion: '7.
|
31857
|
-
releaseDate: '
|
31641
|
+
minorVersion: '7.1',
|
31642
|
+
releaseDate: '2025-03-05',
|
31858
31643
|
i18n: I18n,
|
31859
31644
|
activeEditor: null,
|
31860
31645
|
focusedEditor: null,
|