[DEMO] Sottodominio: DEMO_BASE -> nis2.dimostrazione.agile.software + origin allowlist postMessage

AgileHub ha consegnato il reverse-proxy nis2.dimostrazione.agile.software -> nis2.agile.software.
- DemoController.DEMO_BASE default = sottodominio (spa_iframe_url/manifest/credentials lì); env DEMO_BASE_URL override.
- demo-mode.js: origin-check ora ALLOWLIST (dimostrazione + nis2.dimostrazione) robusto alla topologia widget;
  outbound postMessage mirato all'origin reale del parent (ancestorOrigins/captured).
This commit is contained in:
DevEnv nis2-agile
2026-06-13 10:31:46 +02:00
parent 460d435a47
commit 3e8a90f969
2 changed files with 16 additions and 5 deletions
+3 -1
View File
@@ -18,7 +18,9 @@ class DemoController extends BaseController
private const DEMO_ORG_ID = 996001; private const DEMO_ORG_ID = 996001;
private const DEMO_RANGE = [996000, 996999]; private const DEMO_RANGE = [996000, 996999];
private const JWT_TTL_SEC = 1800; // 30 min private const JWT_TTL_SEC = 1800; // 30 min
private const DEMO_BASE = 'https://dimostrazione.agile.software'; // SPA demo servita sul sottodominio per-prodotto (reverse-proxy AgileHub → nis2.agile.software).
// Override via env DEMO_BASE_URL (vedi demoBase()). Il widget/hub resta su dimostrazione.agile.software.
private const DEMO_BASE = 'https://nis2.dimostrazione.agile.software';
private const RL_DIR = '/tmp/nis2_demo_rl'; private const RL_DIR = '/tmp/nis2_demo_rl';
// ── 1) POST /api/demo/session-start ────────────────────────────────────── // ── 1) POST /api/demo/session-start ──────────────────────────────────────
+13 -4
View File
@@ -23,7 +23,15 @@
(function (w, d) { (function (w, d) {
'use strict'; 'use strict';
var IFRAME_ORIGIN = 'https://dimostrazione.agile.software'; // Origin del widget/parent AgileHub. Allowlist robusta a entrambe le topologie:
// widget sull'hub (dimostrazione.agile.software) o sul sottodominio prodotto. Da
// confermare al collaudo E2E; intanto accettiamo entrambi (e l'origin reale viene
// bloccato comunque all'allowlist).
var ALLOWED_ORIGINS = ['https://dimostrazione.agile.software', 'https://nis2.dimostrazione.agile.software'];
function parentOrigin() {
try { var ao = w.location.ancestorOrigins; if (ao && ao.length && ALLOWED_ORIGINS.indexOf(ao[0]) >= 0) return ao[0]; } catch (e) {}
return state.parentOrigin || ALLOWED_ORIGINS[0];
}
var PROTOCOL = 'agilehub.product-demo.v1'; var PROTOCOL = 'agilehub.product-demo.v1';
// Canale = RUNTIME AVATAR (postMessage widget→SPA), NON external/v1. Chiarimento AgileHub // Canale = RUNTIME AVATAR (postMessage widget→SPA), NON external/v1. Chiarimento AgileHub
// 2026-06-13: il runtime avatar NON usa HMAC per-messaggio (server-to-server = X-Internal-Key, // 2026-06-13: il runtime avatar NON usa HMAC per-messaggio (server-to-server = X-Internal-Key,
@@ -37,7 +45,7 @@
var sessionId = qs.get('demo'); var sessionId = qs.get('demo');
if (!sessionId) return; // non in demo-mode → no-op if (!sessionId) return; // non in demo-mode → no-op
var state = { jwt: null, seed: null, channelKeyRaw: null, seen: {}, ready: false }; var state = { jwt: null, seed: null, channelKeyRaw: null, seen: {}, ready: false, parentOrigin: null };
// ── util crypto ────────────────────────────────────────────────────────── // ── util crypto ──────────────────────────────────────────────────────────
function enc(s) { return new TextEncoder().encode(s); } function enc(s) { return new TextEncoder().encode(s); }
@@ -64,7 +72,7 @@
// ── outbound ───────────────────────────────────────────────────────────── // ── outbound ─────────────────────────────────────────────────────────────
function send(type, payload) { function send(type, payload) {
try { w.parent.postMessage({ protocol: PROTOCOL, type: type, payload: payload || {}, message_id: 'spa-' + Date.now() + '-' + Math.floor(performance.now()), ts: new Date().toISOString() }, IFRAME_ORIGIN); } catch (e) { /* noop */ } try { w.parent.postMessage({ protocol: PROTOCOL, type: type, payload: payload || {}, message_id: 'spa-' + Date.now() + '-' + Math.floor(performance.now()), ts: new Date().toISOString() }, parentOrigin()); } catch (e) { /* noop */ }
} }
function currentView() { function currentView() {
var p = w.location.pathname.replace(/^\//, '').replace(/\.html$/, ''); var p = w.location.pathname.replace(/^\//, '').replace(/\.html$/, '');
@@ -128,7 +136,8 @@
} }
function onMessage(ev) { function onMessage(ev) {
if (ev.origin !== IFRAME_ORIGIN) return; if (ALLOWED_ORIGINS.indexOf(ev.origin) < 0) return;
state.parentOrigin = ev.origin; // origin reale del widget (per outbound mirati)
var msg = ev.data; var msg = ev.data;
if (!msg || msg.protocol !== PROTOCOL || !msg.type) return; if (!msg || msg.protocol !== PROTOCOL || !msg.type) return;
verifyHmac(msg).then(function (ok) { verifyHmac(msg).then(function (ok) {