@mulmoclaude/core 4.5.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collection/core/schemaZ.d.ts +1 -1
- package/dist/collection/registry/server/index.cjs +1 -1
- package/dist/collection/registry/server/index.js +1 -1
- package/dist/collection/server/index.cjs +2 -1
- package/dist/collection/server/index.js +2 -2
- package/dist/collection/server/skillAssets.d.ts +20 -0
- package/dist/collection-watchers/index.cjs +1 -1
- package/dist/collection-watchers/index.js +1 -1
- package/dist/feeds/server/index.cjs +1 -1
- package/dist/feeds/server/index.js +1 -1
- package/dist/global-config/index.cjs +1 -1
- package/dist/google/index.cjs +1 -1
- package/dist/{paths-ClV946_f.cjs → paths-C8-jxR0s.cjs} +1 -2
- package/dist/{paths-ClV946_f.cjs.map → paths-C8-jxR0s.cjs.map} +1 -1
- package/dist/plugin-vue/index.cjs +214 -75
- package/dist/plugin-vue/index.cjs.map +1 -1
- package/dist/plugin-vue/index.js +214 -75
- package/dist/plugin-vue/index.js.map +1 -1
- package/dist/{server-Wz4_ALLl.cjs → server-DXUt34Rt.cjs} +79 -29
- package/dist/server-DXUt34Rt.cjs.map +1 -0
- package/dist/{server-BENtFplH.js → server-DyYwfNB6.js} +74 -30
- package/dist/server-DyYwfNB6.js.map +1 -0
- package/package.json +4 -4
- package/dist/server-BENtFplH.js.map +0 -1
- package/dist/server-Wz4_ALLl.cjs.map +0 -1
package/dist/plugin-vue/index.js
CHANGED
|
@@ -137,7 +137,7 @@ IconGlyph.props = {
|
|
|
137
137
|
};
|
|
138
138
|
//#endregion
|
|
139
139
|
//#region ../../node_modules/dompurify/dist/purify.es.mjs
|
|
140
|
-
/*! @license DOMPurify 3.4.
|
|
140
|
+
/*! @license DOMPurify 3.4.14 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.14/LICENSE */
|
|
141
141
|
function _arrayLikeToArray(r, a) {
|
|
142
142
|
(null == a || a > r.length) && (a = r.length);
|
|
143
143
|
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
@@ -296,9 +296,11 @@ function clone(object) {
|
|
|
296
296
|
var _ref3 = _slicedToArray(_ref2, 2);
|
|
297
297
|
const property = _ref3[0];
|
|
298
298
|
const value = _ref3[1];
|
|
299
|
-
if (objectHasOwnProperty(object, property))
|
|
300
|
-
|
|
301
|
-
|
|
299
|
+
if (objectHasOwnProperty(object, property)) {
|
|
300
|
+
if (arrayIsArray(value)) newObject[property] = cleanArray(value);
|
|
301
|
+
else if (value && typeof value === "object" && value.constructor === Object) newObject[property] = clone(value);
|
|
302
|
+
else newObject[property] = value;
|
|
303
|
+
}
|
|
302
304
|
}
|
|
303
305
|
return newObject;
|
|
304
306
|
}
|
|
@@ -866,6 +868,7 @@ var svg = freeze([
|
|
|
866
868
|
"patterncontentunits",
|
|
867
869
|
"patterntransform",
|
|
868
870
|
"patternunits",
|
|
871
|
+
"pointer-events",
|
|
869
872
|
"points",
|
|
870
873
|
"preservealpha",
|
|
871
874
|
"preserveaspectratio",
|
|
@@ -920,6 +923,7 @@ var svg = freeze([
|
|
|
920
923
|
"u2",
|
|
921
924
|
"unicode",
|
|
922
925
|
"values",
|
|
926
|
+
"vector-effect",
|
|
923
927
|
"viewbox",
|
|
924
928
|
"visibility",
|
|
925
929
|
"version",
|
|
@@ -1033,6 +1037,24 @@ var NODE_TYPE = {
|
|
|
1033
1037
|
documentFragment: 11,
|
|
1034
1038
|
notation: 12
|
|
1035
1039
|
};
|
|
1040
|
+
var LITERAL_TEXT_ELEMENT_NAMES = [
|
|
1041
|
+
"style",
|
|
1042
|
+
"script",
|
|
1043
|
+
"xmp",
|
|
1044
|
+
"iframe",
|
|
1045
|
+
"noembed",
|
|
1046
|
+
"noframes",
|
|
1047
|
+
"plaintext",
|
|
1048
|
+
"noscript"
|
|
1049
|
+
];
|
|
1050
|
+
var LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, LITERAL_TEXT_ELEMENT_NAMES));
|
|
1051
|
+
var LITERAL_TEXT_CLOSE = function() {
|
|
1052
|
+
const map = {};
|
|
1053
|
+
arrayForEach(LITERAL_TEXT_ELEMENT_NAMES, (name) => {
|
|
1054
|
+
map[name] = seal(new RegExp("</" + name + "(?=[\\t\\n\\f\\r />])", "i"));
|
|
1055
|
+
});
|
|
1056
|
+
return freeze(map);
|
|
1057
|
+
}();
|
|
1036
1058
|
var getGlobal = function getGlobal() {
|
|
1037
1059
|
return typeof window === "undefined" ? null : window;
|
|
1038
1060
|
};
|
|
@@ -1092,10 +1114,25 @@ var _createHooksMap = function _createHooksMap() {
|
|
|
1092
1114
|
var _resolveSetOption = function _resolveSetOption(cfg, key, fallback, options) {
|
|
1093
1115
|
return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
|
|
1094
1116
|
};
|
|
1117
|
+
/**
|
|
1118
|
+
* Resolve an object-valued configuration option: a prototype-free clone
|
|
1119
|
+
* of cfg[key] when it is an own, truthy object property, else a fresh
|
|
1120
|
+
* fallback built by makeFallback (fresh on every parse, so a previous
|
|
1121
|
+
* parse can never leak state into the next one).
|
|
1122
|
+
*
|
|
1123
|
+
* @param cfg the cloned, prototype-free configuration object
|
|
1124
|
+
* @param key the configuration property to read
|
|
1125
|
+
* @param makeFallback builds the fallback value when the option is absent
|
|
1126
|
+
* @returns the resolved object
|
|
1127
|
+
*/
|
|
1128
|
+
var _resolveObjectOption = function _resolveObjectOption(cfg, key, makeFallback) {
|
|
1129
|
+
const value = objectHasOwnProperty(cfg, key) ? cfg[key] : void 0;
|
|
1130
|
+
return value && typeof value === "object" ? clone(value) : makeFallback();
|
|
1131
|
+
};
|
|
1095
1132
|
function createDOMPurify() {
|
|
1096
1133
|
let window = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal();
|
|
1097
1134
|
const DOMPurify = (root) => createDOMPurify(root);
|
|
1098
|
-
DOMPurify.version = "3.4.
|
|
1135
|
+
DOMPurify.version = "3.4.14";
|
|
1099
1136
|
DOMPurify.removed = [];
|
|
1100
1137
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
1101
1138
|
DOMPurify.isSupported = false;
|
|
@@ -1120,6 +1157,12 @@ function createDOMPurify() {
|
|
|
1120
1157
|
const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeType") : null;
|
|
1121
1158
|
const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, "nodeName") : null;
|
|
1122
1159
|
const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, "ownerDocument") : null;
|
|
1160
|
+
const _readNodeType = function _readNodeType(node) {
|
|
1161
|
+
return getNodeType ? getNodeType(node) : node.nodeType;
|
|
1162
|
+
};
|
|
1163
|
+
const _readNodeName = function _readNodeName(node) {
|
|
1164
|
+
return getNodeName ? getNodeName(node) : node.nodeName;
|
|
1165
|
+
};
|
|
1123
1166
|
if (typeof HTMLTemplateElement === "function") {
|
|
1124
1167
|
const template = document.createElement("template");
|
|
1125
1168
|
if (template.content && template.content.ownerDocument) document = template.content.ownerDocument;
|
|
@@ -1377,9 +1420,9 @@ function createDOMPurify() {
|
|
|
1377
1420
|
IN_PLACE = cfg.IN_PLACE || false;
|
|
1378
1421
|
IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI;
|
|
1379
1422
|
NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE;
|
|
1380
|
-
MATHML_TEXT_INTEGRATION_POINTS =
|
|
1381
|
-
HTML_INTEGRATION_POINTS =
|
|
1382
|
-
const customElementHandling =
|
|
1423
|
+
MATHML_TEXT_INTEGRATION_POINTS = _resolveObjectOption(cfg, "MATHML_TEXT_INTEGRATION_POINTS", () => addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS));
|
|
1424
|
+
HTML_INTEGRATION_POINTS = _resolveObjectOption(cfg, "HTML_INTEGRATION_POINTS", () => addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS));
|
|
1425
|
+
const customElementHandling = _resolveObjectOption(cfg, "CUSTOM_ELEMENT_HANDLING", () => create(null));
|
|
1383
1426
|
CUSTOM_ELEMENT_HANDLING = create(null);
|
|
1384
1427
|
if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck;
|
|
1385
1428
|
if (objectHasOwnProperty(customElementHandling, "attributeNameCheck") && isRegexOrFunction(customElementHandling.attributeNameCheck)) CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck;
|
|
@@ -1426,11 +1469,6 @@ function createDOMPurify() {
|
|
|
1426
1469
|
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
|
|
1427
1470
|
}
|
|
1428
1471
|
}
|
|
1429
|
-
if (objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
1430
|
-
if (objectHasOwnProperty(cfg, "FORBID_CONTENTS") && arrayIsArray(cfg.FORBID_CONTENTS)) {
|
|
1431
|
-
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
1432
|
-
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
1433
|
-
}
|
|
1434
1472
|
if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
|
|
1435
1473
|
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
1436
1474
|
addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
|
|
@@ -1547,6 +1585,32 @@ function createDOMPurify() {
|
|
|
1547
1585
|
}
|
|
1548
1586
|
};
|
|
1549
1587
|
/**
|
|
1588
|
+
* _stripAttributeNode
|
|
1589
|
+
*
|
|
1590
|
+
* Remove a single Attr node case/namespace-exactly on an attribute-teardown
|
|
1591
|
+
* path. Name-based removeAttribute() ASCII-lowercases its lookup key for an
|
|
1592
|
+
* HTML element in an HTML document and so silently misses a case-preserved
|
|
1593
|
+
* handler (e.g. `ONERROR` off an XML/XHTML import) - the same defect
|
|
1594
|
+
* _removeAttribute() was fixed for, which a name-based call would reintroduce
|
|
1595
|
+
* on these IN_PLACE teardown paths. Unlike _removeAttribute this does not
|
|
1596
|
+
* record into DOMPurify.removed: the neutralize passes intentionally do not
|
|
1597
|
+
* book-keep. A clobbered/detached node falls back to best-effort name-based
|
|
1598
|
+
* removal.
|
|
1599
|
+
*
|
|
1600
|
+
* @param element the element to strip the attribute from
|
|
1601
|
+
* @param attribute the Attr node to remove
|
|
1602
|
+
* @param name the attribute's name, for the fallback path
|
|
1603
|
+
*/
|
|
1604
|
+
const _stripAttributeNode = function _stripAttributeNode(element, attribute, name) {
|
|
1605
|
+
try {
|
|
1606
|
+
element.removeAttributeNode(attribute);
|
|
1607
|
+
} catch (_) {
|
|
1608
|
+
try {
|
|
1609
|
+
element.removeAttribute(name);
|
|
1610
|
+
} catch (_) {}
|
|
1611
|
+
}
|
|
1612
|
+
};
|
|
1613
|
+
/**
|
|
1550
1614
|
* _neutralizeRoot
|
|
1551
1615
|
*
|
|
1552
1616
|
* Fail-closed teardown of an in-place root after the sanitize walk aborts
|
|
@@ -1580,36 +1644,53 @@ function createDOMPurify() {
|
|
|
1580
1644
|
if (attributes) for (let i = attributes.length - 1; i >= 0; --i) {
|
|
1581
1645
|
const attribute = attributes[i];
|
|
1582
1646
|
const name = attribute && attribute.name;
|
|
1583
|
-
if (typeof name === "string")
|
|
1584
|
-
root.removeAttribute(name);
|
|
1585
|
-
} catch (_) {}
|
|
1647
|
+
if (typeof name === "string") _stripAttributeNode(root, attribute, name);
|
|
1586
1648
|
}
|
|
1587
1649
|
};
|
|
1588
1650
|
/**
|
|
1589
1651
|
* _removeAttribute
|
|
1590
1652
|
*
|
|
1653
|
+
* Name-based getAttributeNode()/removeAttribute() ASCII-lowercase their
|
|
1654
|
+
* lookup key for HTML elements in an HTML document, so they silently miss an
|
|
1655
|
+
* attribute whose stored qualified name still contains uppercase ASCII
|
|
1656
|
+
* letters. That happens when the node came from a case-preserving source
|
|
1657
|
+
* (an XML/XHTML document imported via importNode(), or createAttributeNS()),
|
|
1658
|
+
* where e.g. `ONERROR` survives the walk: the policy check lowercases to
|
|
1659
|
+
* `onerror` and rejects it, but `removeAttribute('ONERROR')` looks up
|
|
1660
|
+
* `onerror` and finds nothing. Remove the exact Attr node instead, which is
|
|
1661
|
+
* case- and namespace-exact, and fall back to name-based removal only when
|
|
1662
|
+
* the caller could not supply the node.
|
|
1663
|
+
*
|
|
1591
1664
|
* @param name an Attribute name
|
|
1592
1665
|
* @param element a DOM node
|
|
1666
|
+
* @param attr the exact Attr node to remove, when the caller has it
|
|
1593
1667
|
*/
|
|
1594
|
-
const _removeAttribute = function _removeAttribute(name, element) {
|
|
1668
|
+
const _removeAttribute = function _removeAttribute(name, element, attr) {
|
|
1669
|
+
if (!attr) try {
|
|
1670
|
+
attr = element.getAttributeNode(name);
|
|
1671
|
+
} catch (_) {
|
|
1672
|
+
attr = null;
|
|
1673
|
+
}
|
|
1674
|
+
arrayPush(DOMPurify.removed, {
|
|
1675
|
+
attribute: attr || null,
|
|
1676
|
+
from: element
|
|
1677
|
+
});
|
|
1595
1678
|
try {
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
from: element
|
|
1599
|
-
});
|
|
1679
|
+
if (attr) element.removeAttributeNode(attr);
|
|
1680
|
+
else element.removeAttribute(name);
|
|
1600
1681
|
} catch (_) {
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1682
|
+
try {
|
|
1683
|
+
element.removeAttribute(name);
|
|
1684
|
+
} catch (_) {}
|
|
1685
|
+
}
|
|
1686
|
+
if (name === "is") {
|
|
1687
|
+
if (RETURN_DOM || RETURN_DOM_FRAGMENT) try {
|
|
1688
|
+
_forceRemove(element);
|
|
1689
|
+
} catch (_) {}
|
|
1690
|
+
else try {
|
|
1691
|
+
element.setAttribute(name, "");
|
|
1692
|
+
} catch (_) {}
|
|
1605
1693
|
}
|
|
1606
|
-
element.removeAttribute(name);
|
|
1607
|
-
if (name === "is") if (RETURN_DOM || RETURN_DOM_FRAGMENT) try {
|
|
1608
|
-
_forceRemove(element);
|
|
1609
|
-
} catch (_) {}
|
|
1610
|
-
else try {
|
|
1611
|
-
element.setAttribute(name, "");
|
|
1612
|
-
} catch (_) {}
|
|
1613
1694
|
};
|
|
1614
1695
|
/**
|
|
1615
1696
|
* _stripDisallowedAttributes
|
|
@@ -1628,9 +1709,7 @@ function createDOMPurify() {
|
|
|
1628
1709
|
const attribute = attributes[i];
|
|
1629
1710
|
const name = attribute && attribute.name;
|
|
1630
1711
|
if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) continue;
|
|
1631
|
-
|
|
1632
|
-
element.removeAttribute(name);
|
|
1633
|
-
} catch (_) {}
|
|
1712
|
+
_stripAttributeNode(element, attribute, name);
|
|
1634
1713
|
}
|
|
1635
1714
|
};
|
|
1636
1715
|
/**
|
|
@@ -1659,7 +1738,7 @@ function createDOMPurify() {
|
|
|
1659
1738
|
const stack = [root];
|
|
1660
1739
|
while (stack.length > 0) {
|
|
1661
1740
|
const node = stack.pop();
|
|
1662
|
-
if ((
|
|
1741
|
+
if (_readNodeType(node) === NODE_TYPE.element) _stripDisallowedAttributes(node);
|
|
1663
1742
|
const childNodes = getChildNodes(node);
|
|
1664
1743
|
if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push(childNodes[i]);
|
|
1665
1744
|
}
|
|
@@ -1699,12 +1778,28 @@ function createDOMPurify() {
|
|
|
1699
1778
|
*
|
|
1700
1779
|
* @param root the in-place root to sweep
|
|
1701
1780
|
*/
|
|
1781
|
+
/**
|
|
1782
|
+
* Central policy for declarative-partial-updates patch-linkage attributes,
|
|
1783
|
+
* shared by the _neutralizePatchLinkage pre-pass and _isValidAttribute so
|
|
1784
|
+
* the two sites cannot drift: `patchsrc` always links, `for` links
|
|
1785
|
+
* everywhere except on <label>/<output>, and the whole policy is gated on
|
|
1786
|
+
* SAFE_FOR_XML (see the rationale block in _isValidAttribute).
|
|
1787
|
+
*
|
|
1788
|
+
* @param lcName the transformCaseFunc'd attribute name
|
|
1789
|
+
* @param lcTag the transformCaseFunc'd tag name of the carrying element
|
|
1790
|
+
* @return true if the attribute is patch linkage and must be dropped
|
|
1791
|
+
*/
|
|
1792
|
+
const _isPatchLinkageAttribute = function _isPatchLinkageAttribute(lcName, lcTag) {
|
|
1793
|
+
if (!SAFE_FOR_XML) return false;
|
|
1794
|
+
if (lcName === "patchsrc") return true;
|
|
1795
|
+
return lcName === "for" && lcTag !== "label" && lcTag !== "output";
|
|
1796
|
+
};
|
|
1702
1797
|
const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) {
|
|
1703
1798
|
if (!SAFE_FOR_XML) return;
|
|
1704
1799
|
const stack = [root];
|
|
1705
1800
|
while (stack.length > 0) {
|
|
1706
1801
|
const node = stack.pop();
|
|
1707
|
-
const nodeType =
|
|
1802
|
+
const nodeType = _readNodeType(node);
|
|
1708
1803
|
if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
|
|
1709
1804
|
try {
|
|
1710
1805
|
remove(node);
|
|
@@ -1713,10 +1808,10 @@ function createDOMPurify() {
|
|
|
1713
1808
|
}
|
|
1714
1809
|
if (nodeType === NODE_TYPE.element) {
|
|
1715
1810
|
const element = node;
|
|
1716
|
-
const lcTag = transformCaseFunc(
|
|
1811
|
+
const lcTag = transformCaseFunc(_readNodeName(node));
|
|
1717
1812
|
try {
|
|
1718
1813
|
if (element.hasAttribute && element.hasAttribute("patchsrc")) element.removeAttribute("patchsrc");
|
|
1719
|
-
if (element.hasAttribute && element.hasAttribute("for") &&
|
|
1814
|
+
if (element.hasAttribute && element.hasAttribute("for") && _isPatchLinkageAttribute("for", lcTag)) element.removeAttribute("for");
|
|
1720
1815
|
} catch (_) {}
|
|
1721
1816
|
}
|
|
1722
1817
|
const childNodes = getChildNodes(node);
|
|
@@ -1885,12 +1980,32 @@ function createDOMPurify() {
|
|
|
1885
1980
|
*/
|
|
1886
1981
|
const _isUnsafeNode = function _isUnsafeNode(currentNode, tagName) {
|
|
1887
1982
|
if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) return true;
|
|
1888
|
-
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "
|
|
1983
|
+
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && LITERAL_TEXT_ELEMENTS[tagName] && (_isNode(currentNode.firstElementChild) || typeof currentNode.textContent === "string" && regExpTest(LITERAL_TEXT_CLOSE[tagName], currentNode.textContent))) return true;
|
|
1889
1984
|
if (currentNode.nodeType === NODE_TYPE.processingInstruction) return true;
|
|
1890
1985
|
if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) return true;
|
|
1891
1986
|
return false;
|
|
1892
1987
|
};
|
|
1893
1988
|
/**
|
|
1989
|
+
* Evaluate a CUSTOM_ELEMENT_HANDLING check (a RegExp or a predicate
|
|
1990
|
+
* function, per the validation in _parseConfig) against a name.
|
|
1991
|
+
* Additional arguments are forwarded to predicate functions - the
|
|
1992
|
+
* attributeNameCheck predicate receives the tag name as its second
|
|
1993
|
+
* argument. A null/absent check never matches.
|
|
1994
|
+
*
|
|
1995
|
+
* @param check the configured tagNameCheck / attributeNameCheck value
|
|
1996
|
+
* @param name the name to test
|
|
1997
|
+
* @param args extra arguments forwarded to a predicate function
|
|
1998
|
+
* @return true if the check matches the name
|
|
1999
|
+
*/
|
|
2000
|
+
const _matchesNameCheck = function _matchesNameCheck(check, name) {
|
|
2001
|
+
if (check instanceof RegExp) return regExpTest(check, name);
|
|
2002
|
+
if (check instanceof Function) {
|
|
2003
|
+
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) args[_key - 2] = arguments[_key];
|
|
2004
|
+
return Boolean(check(name, ...args));
|
|
2005
|
+
}
|
|
2006
|
+
return false;
|
|
2007
|
+
};
|
|
2008
|
+
/**
|
|
1894
2009
|
* Handle a node whose tag is forbidden or not allowlisted: keep
|
|
1895
2010
|
* allowed custom elements (false return exits _sanitizeElements
|
|
1896
2011
|
* early - the namespace and fallback-tag removal checks are
|
|
@@ -1908,10 +2023,7 @@ function createDOMPurify() {
|
|
|
1908
2023
|
* @return true if the node was removed, false if kept
|
|
1909
2024
|
*/
|
|
1910
2025
|
const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) {
|
|
1911
|
-
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName))
|
|
1912
|
-
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
|
|
1913
|
-
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
|
|
1914
|
-
}
|
|
2026
|
+
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
|
|
1915
2027
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
1916
2028
|
const parentNode = getParentNode(currentNode);
|
|
1917
2029
|
const childNodes = getChildNodes(currentNode);
|
|
@@ -1945,6 +2057,42 @@ function createDOMPurify() {
|
|
|
1945
2057
|
return set === defaultSet || set === setConfigSet ? clone(set) : set;
|
|
1946
2058
|
};
|
|
1947
2059
|
/**
|
|
2060
|
+
* Shared guard for a node that a hook has detached from the walk tree,
|
|
2061
|
+
* used after each element-hook site in _sanitizeElements. Detaching is a
|
|
2062
|
+
* long-standing user pattern (issue #469; draw.io-style foreignObject
|
|
2063
|
+
* filtering). Per the cached, unclobberable parentNode getter the node is
|
|
2064
|
+
* genuinely out of the tree, so it can reach neither the serialized
|
|
2065
|
+
* output nor an IN_PLACE live tree; treat it as removed and stop
|
|
2066
|
+
* processing it. Without this guard, the unsafe-node / namespace checks
|
|
2067
|
+
* would call _forceRemove on a parentless node and hit the REPORT-3
|
|
2068
|
+
* fail-closed throw — which exists for nodes DOMPurify wants gone but
|
|
2069
|
+
* *cannot* detach (clobbered / parentless roots), the opposite of a node
|
|
2070
|
+
* that is already safely gone. The walk root is exempt: a detached
|
|
2071
|
+
* IN_PLACE root is legitimate input and must still be fully sanitized,
|
|
2072
|
+
* and a kill-decision on it must keep hitting the REPORT-3 throw.
|
|
2073
|
+
*
|
|
2074
|
+
* Nodes detached by hooks stay the hook's responsibility for placement:
|
|
2075
|
+
* they are not recorded in DOMPurify.removed, so the post-walk IN_PLACE
|
|
2076
|
+
* pass (which iterates DOMPurify.removed) does not reach them. But a
|
|
2077
|
+
* hook-detached subtree can still hold a queued resource-event handler -
|
|
2078
|
+
* e.g. an <img onload> that began loading when the caller built the live
|
|
2079
|
+
* tree - which fires in page scope after sanitize returns even though the
|
|
2080
|
+
* handler never reached the returned tree. That is the audit-5 F1 hazard,
|
|
2081
|
+
* and the documented node.remove() hook pattern walks straight into it.
|
|
2082
|
+
* So on the IN_PLACE path we neutralize the detached subtree inline,
|
|
2083
|
+
* stripping its non-allow-listed attributes before returning, exactly as
|
|
2084
|
+
* the post-walk pass does for _forceRemove'd subtrees.
|
|
2085
|
+
*
|
|
2086
|
+
* @param currentNode the node a hook may have detached
|
|
2087
|
+
* @param root the current walk root
|
|
2088
|
+
* @return true if the node is detached and now handled, false otherwise
|
|
2089
|
+
*/
|
|
2090
|
+
const _handleHookDetachedNode = function _handleHookDetachedNode(currentNode, root) {
|
|
2091
|
+
if (currentNode === root || getParentNode(currentNode) !== null) return false;
|
|
2092
|
+
if (IN_PLACE) _neutralizeSubtree(currentNode);
|
|
2093
|
+
return true;
|
|
2094
|
+
};
|
|
2095
|
+
/**
|
|
1948
2096
|
* _sanitizeElements
|
|
1949
2097
|
*
|
|
1950
2098
|
* @protect nodeName
|
|
@@ -1955,24 +2103,18 @@ function createDOMPurify() {
|
|
|
1955
2103
|
*/
|
|
1956
2104
|
const _sanitizeElements = function _sanitizeElements(currentNode, root) {
|
|
1957
2105
|
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
|
|
1958
|
-
if (currentNode
|
|
1959
|
-
if (IN_PLACE) _neutralizeSubtree(currentNode);
|
|
1960
|
-
return true;
|
|
1961
|
-
}
|
|
2106
|
+
if (_handleHookDetachedNode(currentNode, root)) return true;
|
|
1962
2107
|
if (_isClobbered(currentNode)) {
|
|
1963
2108
|
_forceRemove(currentNode);
|
|
1964
2109
|
return true;
|
|
1965
2110
|
}
|
|
1966
|
-
const tagName = transformCaseFunc(
|
|
2111
|
+
const tagName = transformCaseFunc(_readNodeName(currentNode));
|
|
1967
2112
|
ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
|
|
1968
2113
|
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
|
1969
2114
|
tagName,
|
|
1970
2115
|
allowedTags: ALLOWED_TAGS
|
|
1971
2116
|
});
|
|
1972
|
-
if (currentNode
|
|
1973
|
-
if (IN_PLACE) _neutralizeSubtree(currentNode);
|
|
1974
|
-
return true;
|
|
1975
|
-
}
|
|
2117
|
+
if (_handleHookDetachedNode(currentNode, root)) return true;
|
|
1976
2118
|
if (_isUnsafeNode(currentNode, tagName)) {
|
|
1977
2119
|
_forceRemove(currentNode);
|
|
1978
2120
|
return true;
|
|
@@ -1982,7 +2124,7 @@ function createDOMPurify() {
|
|
|
1982
2124
|
if (removed === false) _executeHooks(hooks.afterSanitizeElements, currentNode, null);
|
|
1983
2125
|
return removed;
|
|
1984
2126
|
}
|
|
1985
|
-
if ((
|
|
2127
|
+
if (_readNodeType(currentNode) === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
|
|
1986
2128
|
_forceRemove(currentNode);
|
|
1987
2129
|
return true;
|
|
1988
2130
|
}
|
|
@@ -2010,20 +2152,17 @@ function createDOMPurify() {
|
|
|
2010
2152
|
*/
|
|
2011
2153
|
const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
|
|
2012
2154
|
if (FORBID_ATTR[lcName]) return false;
|
|
2013
|
-
if (
|
|
2014
|
-
if (SAFE_FOR_XML && lcName === "for" && lcTag !== "label" && lcTag !== "output") return false;
|
|
2155
|
+
if (_isPatchLinkageAttribute(lcName, lcTag)) return false;
|
|
2015
2156
|
if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document || value in formElement)) return false;
|
|
2016
2157
|
const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
|
|
2017
|
-
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName));
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
else if (value) return false;
|
|
2026
|
-
return true;
|
|
2158
|
+
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) return true;
|
|
2159
|
+
if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) return true;
|
|
2160
|
+
if (!nameIsPermitted) return _isBasicCustomElement(lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName, lcTag) || lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value);
|
|
2161
|
+
if (URI_SAFE_ATTRIBUTES[lcName]) return true;
|
|
2162
|
+
if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) return true;
|
|
2163
|
+
if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]) return true;
|
|
2164
|
+
if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) return true;
|
|
2165
|
+
return !value;
|
|
2027
2166
|
};
|
|
2028
2167
|
const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, [
|
|
2029
2168
|
"annotation-xml",
|
|
@@ -2125,29 +2264,29 @@ function createDOMPurify() {
|
|
|
2125
2264
|
_executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
|
|
2126
2265
|
value = hookEvent.attrValue;
|
|
2127
2266
|
if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
|
|
2128
|
-
_removeAttribute(name, currentNode);
|
|
2267
|
+
_removeAttribute(name, currentNode, attr);
|
|
2129
2268
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
2130
2269
|
}
|
|
2131
2270
|
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
|
|
2132
|
-
_removeAttribute(name, currentNode);
|
|
2271
|
+
_removeAttribute(name, currentNode, attr);
|
|
2133
2272
|
continue;
|
|
2134
2273
|
}
|
|
2135
2274
|
if (lcName === "attributename" && stringMatch(value, "href")) {
|
|
2136
|
-
_removeAttribute(name, currentNode);
|
|
2275
|
+
_removeAttribute(name, currentNode, attr);
|
|
2137
2276
|
continue;
|
|
2138
2277
|
}
|
|
2139
2278
|
if (hookEvent.forceKeepAttr) continue;
|
|
2140
2279
|
if (!hookEvent.keepAttr) {
|
|
2141
|
-
_removeAttribute(name, currentNode);
|
|
2280
|
+
_removeAttribute(name, currentNode, attr);
|
|
2142
2281
|
continue;
|
|
2143
2282
|
}
|
|
2144
2283
|
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
|
|
2145
|
-
_removeAttribute(name, currentNode);
|
|
2284
|
+
_removeAttribute(name, currentNode, attr);
|
|
2146
2285
|
continue;
|
|
2147
2286
|
}
|
|
2148
2287
|
if (SAFE_FOR_TEMPLATES) value = _stripTemplateExpressions(value);
|
|
2149
2288
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
2150
|
-
_removeAttribute(name, currentNode);
|
|
2289
|
+
_removeAttribute(name, currentNode, attr);
|
|
2151
2290
|
continue;
|
|
2152
2291
|
}
|
|
2153
2292
|
value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
|
|
@@ -2169,7 +2308,7 @@ function createDOMPurify() {
|
|
|
2169
2308
|
_sanitizeElements(shadowNode, fragment);
|
|
2170
2309
|
_sanitizeAttributes(shadowNode);
|
|
2171
2310
|
if (_isDocumentFragment(shadowNode.content)) _sanitizeShadowDOM2(shadowNode.content);
|
|
2172
|
-
if ((
|
|
2311
|
+
if (_readNodeType(shadowNode) === NODE_TYPE.element) {
|
|
2173
2312
|
const innerSr = getShadowRoot(shadowNode);
|
|
2174
2313
|
if (_isDocumentFragment(innerSr)) {
|
|
2175
2314
|
_sanitizeAttachedShadowRoots(innerSr);
|
|
@@ -2210,7 +2349,7 @@ function createDOMPurify() {
|
|
|
2210
2349
|
continue;
|
|
2211
2350
|
}
|
|
2212
2351
|
const node = item.node;
|
|
2213
|
-
const isElement = (
|
|
2352
|
+
const isElement = _readNodeType(node) === NODE_TYPE.element;
|
|
2214
2353
|
const childNodes = getChildNodes(node);
|
|
2215
2354
|
if (childNodes) for (let i = childNodes.length - 1; i >= 0; --i) stack.push({
|
|
2216
2355
|
node: childNodes[i],
|
|
@@ -2261,7 +2400,7 @@ function createDOMPurify() {
|
|
|
2261
2400
|
const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty);
|
|
2262
2401
|
if (inPlace) {
|
|
2263
2402
|
_neutralizePatchLinkage(dirty);
|
|
2264
|
-
const nn =
|
|
2403
|
+
const nn = _readNodeName(dirty);
|
|
2265
2404
|
if (typeof nn === "string") {
|
|
2266
2405
|
const tagName = transformCaseFunc(nn);
|
|
2267
2406
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|