openlearn-next 0.2.1 → 0.2.2

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/server.cjs CHANGED
@@ -18418,9 +18418,69 @@ var BRIDGE_SDK_CODE = `(function() {
18418
18418
  } catch (err) {}
18419
18419
  }
18420
18420
 
18421
+ // \u2500\u2500 Helper: create a safe postMessage wrapper that normalises 'null' \u2192 '*' \u2500\u2500
18422
+ function __makeSafePostMessage(realTarget, label) {
18423
+ return function(message, targetOrigin, transfer) {
18424
+ try {
18425
+ if (message && typeof message === 'object') {
18426
+ if (!message.attempt_id && window.__LMS_STUDENT__?.attempt_id) {
18427
+ message.attempt_id = window.__LMS_STUDENT__.attempt_id;
18428
+ }
18429
+ if (!message.uuid && window.__LMS_COURSEWARE__?.uuid) {
18430
+ message.uuid = window.__LMS_COURSEWARE__.uuid;
18431
+ }
18432
+ }
18433
+ } catch (e) {}
18434
+
18435
+ var origin = targetOrigin;
18436
+ if (origin === 'null' || origin === null || origin === undefined) {
18437
+ console.warn('[LMS Bridge Notice] Normalized invalid targetOrigin "' + origin + '" to "*" for ' + label);
18438
+ origin = '*';
18439
+ }
18440
+ try {
18441
+ return realTarget.postMessage.call(realTarget, message, origin, transfer);
18442
+ } catch (err) {
18443
+ if (err.name === 'SyntaxError' && origin !== '*') {
18444
+ console.warn('[LMS Bridge Notice] Recovered SyntaxError on ' + label + ', fallback to "*"', err);
18445
+ return realTarget.postMessage.call(realTarget, message, '*', transfer);
18446
+ }
18447
+ throw err;
18448
+ }
18449
+ };
18450
+ }
18451
+
18452
+ // \u2500\u2500 Helper: create a Proxy wrapper around a cross-origin WindowProxy \u2500\u2500
18453
+ // This is necessary because sandboxed iframes (without allow-same-origin)
18454
+ // cannot set properties on cross-origin WindowProxy objects.
18455
+ // We use Object.defineProperty to shadow window.parent / window.top
18456
+ // with a Proxy that intercepts the .postMessage() call.
18457
+ function __proxyWindow(realRef, propName) {
18458
+ try {
18459
+ var safePost = __makeSafePostMessage(realRef, propName + '.postMessage');
18460
+ var proxyObj = new Proxy(realRef, {
18461
+ get: function(target, prop) {
18462
+ if (prop === 'postMessage') return safePost;
18463
+ try {
18464
+ var val = target[prop];
18465
+ if (typeof val === 'function') return val.bind(target);
18466
+ return val;
18467
+ } catch (e) { return undefined; }
18468
+ }
18469
+ });
18470
+ Object.defineProperty(window, propName, {
18471
+ get: function() { return proxyObj; },
18472
+ configurable: true
18473
+ });
18474
+ } catch (e) {
18475
+ // Proxy or defineProperty not supported, fall back to direct override attempt
18476
+ try { realRef.postMessage = __makeSafePostMessage(realRef, propName + '.postMessage (fallback)'); } catch (_) {}
18477
+ }
18478
+ }
18479
+
18421
18480
  // Proxy postMessage calls to enrich them with attempt_id/uuid and normalize targetOrigin
18422
18481
  try {
18423
- const originalPostMessage = window.postMessage;
18482
+ // 1. Override window.postMessage (self-targeting, always works)
18483
+ var originalPostMessage = window.postMessage;
18424
18484
  window.postMessage = function(message, targetOrigin, transfer) {
18425
18485
  try {
18426
18486
  if (message && typeof message === 'object') {
@@ -18433,49 +18493,67 @@ var BRIDGE_SDK_CODE = `(function() {
18433
18493
  }
18434
18494
  } catch (e) {}
18435
18495
 
18436
- let origin = targetOrigin;
18437
- if (origin === 'null') {
18496
+ var origin = targetOrigin;
18497
+ if (origin === 'null' || origin === null || origin === undefined) {
18498
+ console.warn('[LMS Bridge Notice] Normalized invalid targetOrigin "null" to "*" for postMessage call');
18438
18499
  origin = '*';
18439
18500
  }
18440
18501
  try {
18441
18502
  return originalPostMessage.call(this, message, origin, transfer);
18442
18503
  } catch (err) {
18443
18504
  if (err.name === 'SyntaxError' && origin !== '*') {
18505
+ console.warn('[LMS Bridge Notice] Recovered SyntaxError on postMessage, fallback targetOrigin to "*"', err);
18444
18506
  return originalPostMessage.call(this, message, '*', transfer);
18445
18507
  }
18446
18508
  throw err;
18447
18509
  }
18448
18510
  };
18449
18511
 
18512
+ // 2. Shadow window.parent with a Proxy that intercepts .postMessage()
18450
18513
  if (window.parent && window.parent !== window) {
18451
- const parentPostMessage = window.parent.postMessage;
18452
- try {
18453
- window.parent.postMessage = function(message, targetOrigin, transfer) {
18454
- try {
18455
- if (message && typeof message === 'object') {
18456
- if (!message.attempt_id && window.__LMS_STUDENT__?.attempt_id) {
18457
- message.attempt_id = window.__LMS_STUDENT__.attempt_id;
18458
- }
18459
- if (!message.uuid && window.__LMS_COURSEWARE__?.uuid) {
18460
- message.uuid = window.__LMS_COURSEWARE__.uuid;
18514
+ __proxyWindow(window.parent, 'parent');
18515
+ }
18516
+
18517
+ // 3. Shadow window.top with a Proxy that intercepts .postMessage()
18518
+ try {
18519
+ if (window.top && window.top !== window) {
18520
+ __proxyWindow(window.top, 'top');
18521
+ }
18522
+ } catch (e) {}
18523
+
18524
+ // 4. Intercept message event listeners to sanitize event.source.postMessage replies
18525
+ var origAddEventListener = window.addEventListener;
18526
+ if (typeof origAddEventListener === 'function') {
18527
+ window.addEventListener = function(type, listener, options) {
18528
+ if (type === 'message' && typeof listener === 'function') {
18529
+ var wrappedListener = function(event) {
18530
+ try {
18531
+ if (event && event.source && typeof event.source.postMessage === 'function') {
18532
+ var origSourcePostMessage = event.source.postMessage;
18533
+ event.source.postMessage = function(msg, targetOrigin, transfer) {
18534
+ var origin = targetOrigin;
18535
+ if (origin === 'null' || origin === null) {
18536
+ console.warn('[LMS Bridge Notice] Normalized invalid targetOrigin "null" to "*" on event.source.postMessage');
18537
+ origin = '*';
18538
+ }
18539
+ try {
18540
+ return origSourcePostMessage.call(event.source, msg, origin, transfer);
18541
+ } catch (err) {
18542
+ if (err.name === 'SyntaxError' && origin !== '*') {
18543
+ console.warn('[LMS Bridge Notice] Recovered SyntaxError on event.source.postMessage, fallback to "*"', err);
18544
+ return origSourcePostMessage.call(event.source, msg, '*', transfer);
18545
+ }
18546
+ throw err;
18547
+ }
18548
+ };
18461
18549
  }
18462
- }
18463
- } catch (e) {}
18464
-
18465
- let origin = targetOrigin;
18466
- if (origin === 'null') {
18467
- origin = '*';
18468
- }
18469
- try {
18470
- return parentPostMessage.call(window.parent, message, origin, transfer);
18471
- } catch (err) {
18472
- if (err.name === 'SyntaxError' && origin !== '*') {
18473
- return parentPostMessage.call(window.parent, message, '*', transfer);
18474
- }
18475
- throw err;
18476
- }
18477
- };
18478
- } catch (e) {}
18550
+ } catch (e) {}
18551
+ return listener.apply(this, arguments);
18552
+ };
18553
+ return origAddEventListener.call(this, type, wrappedListener, options);
18554
+ }
18555
+ return origAddEventListener.apply(this, arguments);
18556
+ };
18479
18557
  }
18480
18558
  } catch (e) {}
18481
18559
 
@@ -23877,7 +23955,7 @@ async function startServer() {
23877
23955
  imgSrc: ["'self'", "data:", "blob:", "https:"],
23878
23956
  connectSrc: ["'self'", "ws:", "wss:", "https:"],
23879
23957
  fontSrc: ["'self'", "data:", "https:", "https://fonts.gstatic.com"],
23880
- frameSrc: ["'self'"],
23958
+ frameSrc: ["'self'", "blob:", "data:", "http://localhost", "http://127.0.0.1", "http:", "https:"],
23881
23959
  objectSrc: ["'none'"]
23882
23960
  }
23883
23961
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openlearn-next",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "private": false,
5
5
  "description": "A plugin-driven Educational OS / LMS platform with AI agent teaching assistant",
6
6
  "keywords": [