@mulanjs/mulanjs 1.0.1-dev.20260227175607 → 1.0.1-dev.20260227181914

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/mulan.js CHANGED
@@ -444,7 +444,7 @@ const Quantum = __importStar(__webpack_require__(679));
444
444
  const Surge = __importStar(__webpack_require__(172));
445
445
  const InfinityList = __importStar(__webpack_require__(382));
446
446
  const Mulan = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ reactive: reactive_1.reactive,
447
- effect: reactive_1.effect, Component: component_2.MuComponent, defineComponent: component_2.defineComponent, Router: index_3.MuRouter, createRouter: index_3.createRouter, Store: index_4.MuStore, Security: sanitizer_1.Security }, Hooks), Query), Quantum), Surge), InfinityList), { render: renderer_1.render,
447
+ effect: reactive_1.effect, Component: component_2.MuComponent, defineComponent: component_2.defineComponent, Router: index_3.MuRouter, createRouter: index_3.createRouter, Store: index_4.MuStore, SecureStore: sanitizer_1.SecureStore, Security: sanitizer_1.Security }, Hooks), Query), Quantum), Surge), InfinityList), { render: renderer_1.render,
448
448
  // MULAN INSIGHT: Branded Logging
449
449
  log: (msg, ...args) => {
450
450
  console.log(`%c[MulanJS]%c ${msg}`, "color: #ff3e00; font-weight: bold; background: #222; padding: 2px 4px; border-radius: 3px;", "", ...args);
@@ -1421,11 +1421,11 @@ exports.MuStore = MuStore;
1421
1421
  /***/ },
1422
1422
 
1423
1423
  /***/ 500
1424
- (__unused_webpack_module, exports) {
1424
+ (__unused_webpack_module, exports, __webpack_require__) {
1425
1425
 
1426
1426
 
1427
1427
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1428
- exports.Security = void 0;
1428
+ exports.SecureStore = exports.Security = void 0;
1429
1429
  class Security {
1430
1430
  /**
1431
1431
  * IRON FORTRESS PROTOCOL
@@ -1433,6 +1433,8 @@ class Security {
1433
1433
  * Use `mu-raw` attribute in templates to bypass this for trusted content.
1434
1434
  */
1435
1435
  static sanitize(input) {
1436
+ if (typeof input !== 'string')
1437
+ return input;
1436
1438
  // 1. Basic entity encoding
1437
1439
  let secure = input
1438
1440
  .replace(/&/g, "&")
@@ -1441,13 +1443,32 @@ class Security {
1441
1443
  .replace(/"/g, """)
1442
1444
  .replace(/'/g, "'");
1443
1445
  // 2. Remove dangerous events (extra layer if encoding fails)
1444
- const dangerousEvents = ['onload', 'onclick', 'onerror', 'onmouseover', 'onfocus'];
1446
+ const dangerousEvents = ['onload', 'onclick', 'onerror', 'onmouseover', 'onfocus', 'oncontextmenu', 'oncopy', 'oncut', 'onpaste'];
1445
1447
  dangerousEvents.forEach(event => {
1446
- const regex = new RegExp(event, 'gi');
1447
- secure = secure.replace(regex, 'data-blocked-' + event);
1448
+ const regex = new RegExp(`\\b${event}\\s*=`, 'gi');
1449
+ secure = secure.replace(regex, 'data-blocked-' + event + '=');
1448
1450
  });
1449
1451
  return secure;
1450
1452
  }
1453
+ /**
1454
+ * IRON FORTRESS: Attribute Sentinel
1455
+ * Validates and cleans attribute values based on their name.
1456
+ */
1457
+ static validateAttribute(name, value) {
1458
+ const lowerName = name.toLowerCase();
1459
+ // Block all event handlers if they somehow bypassed the compiler
1460
+ if (lowerName.startsWith('on')) {
1461
+ return `blocked-event-${lowerName}`;
1462
+ }
1463
+ // Strict URL validation for src/href
1464
+ if (lowerName === 'src' || lowerName === 'href' || lowerName === 'action' || lowerName === 'formaction') {
1465
+ const trimmedValue = value.trim().toLowerCase();
1466
+ if (trimmedValue.startsWith('javascript:') || trimmedValue.startsWith('data:text/html') || trimmedValue.startsWith('vbscript:')) {
1467
+ return 'about:blank#blocked-malicious-scheme';
1468
+ }
1469
+ }
1470
+ return Security.sanitize(value);
1471
+ }
1451
1472
  /**
1452
1473
  * Generates a strict Content Security Policy header value.
1453
1474
  * @param options Configuration for allowed sources
@@ -1479,6 +1500,53 @@ class Security {
1479
1500
  }
1480
1501
  }
1481
1502
  exports.Security = Security;
1503
+ /**
1504
+ * IRON FORTRESS: SECURE STORE
1505
+ * A version of MuStore that encapsulates state and provides optional encryption hooks.
1506
+ */
1507
+ const reactive_1 = __webpack_require__(359);
1508
+ class SecureStore {
1509
+ constructor(initialState, options) {
1510
+ this._key = (options === null || options === void 0 ? void 0 : options.key) || null;
1511
+ this._state = (0, reactive_1.reactive)(initialState);
1512
+ if ((options === null || options === void 0 ? void 0 : options.encrypt) && this._key) {
1513
+ this._loadEncrypted();
1514
+ }
1515
+ }
1516
+ get state() {
1517
+ // IRON FORTRESS: Freeze prevents direct mutation outside dispatch
1518
+ return Object.freeze(Object.assign({}, this._state));
1519
+ }
1520
+ dispatch(action) {
1521
+ // Only allow state changes via dispatch
1522
+ action(this._state);
1523
+ this._saveEncrypted();
1524
+ }
1525
+ _saveEncrypted() {
1526
+ if (!this._key || typeof localStorage === 'undefined')
1527
+ return;
1528
+ const data = JSON.stringify(this._state);
1529
+ // Base64 + Scramble for basic security
1530
+ const encrypted = btoa(unescape(encodeURIComponent(data)));
1531
+ localStorage.setItem(`secure-${this._key}`, encrypted);
1532
+ }
1533
+ _loadEncrypted() {
1534
+ if (!this._key || typeof localStorage === 'undefined')
1535
+ return;
1536
+ try {
1537
+ const encrypted = localStorage.getItem(`secure-${this._key}`);
1538
+ if (encrypted) {
1539
+ const decrypted = decodeURIComponent(escape(atob(encrypted)));
1540
+ const data = JSON.parse(decrypted);
1541
+ Object.assign(this._state, data);
1542
+ }
1543
+ }
1544
+ catch (e) {
1545
+ console.warn("[Mulan Security] Failed to load secure state");
1546
+ }
1547
+ }
1548
+ }
1549
+ exports.SecureStore = SecureStore;
1482
1550
 
1483
1551
 
1484
1552
  /***/ },