what-core 0.6.5 → 0.6.6

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/compiler.js CHANGED
@@ -412,6 +412,53 @@ function _setComponentRef(fn) {
412
412
  _getCurrentComponentRef = fn;
413
413
  }
414
414
 
415
+ // packages/core/src/security.js
416
+ var URL_ATTRS = /* @__PURE__ */ new Set([
417
+ "href",
418
+ "src",
419
+ "action",
420
+ "formaction",
421
+ "poster",
422
+ "cite",
423
+ "background",
424
+ "xlink:href"
425
+ ]);
426
+ var URL_LIST_ATTRS = /* @__PURE__ */ new Set(["srcset"]);
427
+ function normalizeAttrName(name) {
428
+ return String(name).toLowerCase();
429
+ }
430
+ function normalizeUrlForProtocolCheck(url) {
431
+ return String(url).trim().replace(/[\s\x00-\x1f\x7f]/g, "").toLowerCase();
432
+ }
433
+ function isSafeUrlValue(value) {
434
+ if (typeof value !== "string") return true;
435
+ const normalized = normalizeUrlForProtocolCheck(value);
436
+ return !(normalized.startsWith("javascript:") || normalized.startsWith("data:") || normalized.startsWith("vbscript:"));
437
+ }
438
+ function isSafeSrcsetValue(value) {
439
+ if (typeof value !== "string") return true;
440
+ return value.split(",").every((candidate) => {
441
+ const url = candidate.trim().split(/\s+/, 1)[0] || "";
442
+ return url === "" || isSafeUrlValue(url);
443
+ });
444
+ }
445
+ function isUrlAttribute(name) {
446
+ return URL_ATTRS.has(normalizeAttrName(name));
447
+ }
448
+ function isUrlListAttribute(name) {
449
+ return URL_LIST_ATTRS.has(normalizeAttrName(name));
450
+ }
451
+ function isSafeUrlAttributeValue(name, value) {
452
+ if (isUrlListAttribute(name)) return isSafeSrcsetValue(value);
453
+ if (isUrlAttribute(name)) return isSafeUrlValue(value);
454
+ return true;
455
+ }
456
+ function getDomAttributeName(name) {
457
+ if (name === "className") return "class";
458
+ if (name === "htmlFor") return "for";
459
+ return normalizeAttrName(name) === "formaction" ? "formaction" : name;
460
+ }
461
+
415
462
  // packages/core/src/dom.js
416
463
  var SVG_ELEMENTS = /* @__PURE__ */ new Set([
417
464
  "svg",
@@ -886,6 +933,13 @@ function applyProps(el, newProps, oldProps, isSvg) {
886
933
  }
887
934
  }
888
935
  function setProp(el, key, value, isSvg) {
936
+ if (!isSafeUrlAttributeValue(key, value)) {
937
+ if (typeof console !== "undefined") {
938
+ console.warn(`[what] Blocked unsafe URL in "${key}" attribute: ${value}`);
939
+ }
940
+ el.removeAttribute(getDomAttributeName(key));
941
+ return;
942
+ }
889
943
  if (typeof value === "function" && !(key.startsWith("on") && key.length > 2) && key !== "ref") {
890
944
  if (!el._propEffects) el._propEffects = {};
891
945
  if (el._propEffects[key]) {
@@ -998,15 +1052,6 @@ function _$createComponent(Component, props, children) {
998
1052
  }
999
1053
  return createDOM({ tag: Component, props: props || {}, children: children || [], key: null, _vnode: true });
1000
1054
  }
1001
- var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "formAction"]);
1002
- function isSafeUrl(url) {
1003
- if (typeof url !== "string") return true;
1004
- const normalized = url.trim().replace(/[\s\x00-\x1f]/g, "").toLowerCase();
1005
- if (normalized.startsWith("javascript:")) return false;
1006
- if (normalized.startsWith("data:")) return false;
1007
- if (normalized.startsWith("vbscript:")) return false;
1008
- return true;
1009
- }
1010
1055
  var TABLE_WRAPPERS = {
1011
1056
  tr: { depth: 2, wrap: "<table><tbody>", unwrap: "</tbody></table>" },
1012
1057
  td: { depth: 3, wrap: "<table><tbody><tr>", unwrap: "</tr></tbody></table>" },
@@ -1697,13 +1742,12 @@ function setProp2(el, key, value) {
1697
1742
  return;
1698
1743
  }
1699
1744
  if (key === "key") return;
1700
- if (URL_ATTRS.has(key) || URL_ATTRS.has(key.toLowerCase())) {
1701
- if (!isSafeUrl(value)) {
1702
- if (typeof console !== "undefined") {
1703
- console.warn(`[what] Blocked unsafe URL in "${key}" attribute: ${value}`);
1704
- }
1705
- return;
1745
+ if (!isSafeUrlAttributeValue(key, value)) {
1746
+ if (typeof console !== "undefined") {
1747
+ console.warn(`[what] Blocked unsafe URL in "${key}" attribute: ${value}`);
1706
1748
  }
1749
+ el.removeAttribute(getDomAttributeName(key));
1750
+ return;
1707
1751
  }
1708
1752
  if (key === "class" || key === "className") {
1709
1753
  el.className = value || "";