Origin configuration

The webclient wire validates every inbound postMessage against a trusted origin before anything is trusted. This page covers both trust modes, the desktop-app origin group, and the extra defense layer (sender validation) that origin checks alone cannot provide.

1. The two trust modes

expectedOrigin (DashletOptions.expectedOrigin) is the origin of the webclient host that may send messages — configured per deployment, never hardcoded, and never "*".

1.1. Strict mode (configured origin)

With a usable value configured, the wire runs strict: the configured origin is the trust anchor from the very first message; every received message is validated against it (scheme + host + port must match; the file-origin group is matched as one group, below). Configuring an origin disables origin learning — and, as a consequence, breaks the desktop app in both directions (below). Use strict mode when the dashlet is served by one known webclient deployment.

1.2. Learning mode (no configured origin, the iframe default)

Without a configured origin and inside an iframe, the wire starts unanchored and learns the trusted origin from the first onInit message — the webclient and the desktop app both send onInit on dashlet load. Rules:

  • only an onInit may anchor (a pre-anchor onUpdate or response is ignored);

  • the anchor is the origin string as received and is immutable (no re-anchoring);

  • every subsequent message — onUpdate, method responses — is validated against the learned origin exactly as against a configured one.

A dashlet that is not inside an iframe (top-level window) never learns: it degrades to the standalone state after the detection cap (Standalone operation). This is what lets one dashlet definition serve the browser webclient and the desktop app without a per-deployment origin switch.

2. The "null" / file:// desktop-app origin group

The desktop-app host (Electron, opaque origin) presents the string "null" to the dashlet — the engine’s serialization of an opaque origin (measured on 12.0.28 / Electron 41; the commlib’s file:// handling is dead code from a legacy generation). The legacy serializations file://, file:/// and file are retained in the same group.

The matcher treats file://, file:///, file and "null" as one origin group, bidirectionally, for inbound validation — and every member is mapped to the target token "" on every outbound post. (Per the postMessage spec, "null" is never a valid target origin — it throws SyntaxError in every engine; only "", "/" and absolute URLs are valid target tokens. A concrete https target origin is delivered by the browser but silently dropped by the desktop host, which is why "*" is the only reliably delivered target for a dual-target post. The post still goes to the single parent window, and inbound validation is unchanged.)

Note: the "null" group member also covers non-file opaque origins (e.g. sandboxed iframes or data: frames without allow-same-origin). Strict mode with a concrete origin is the control if a deployment must exclude such senders.

3. Sender validation

Origin validation alone cannot stop a sibling frame of the host: it shares the host’s origin, but it is not the window the dashlet posts to. The wire therefore also checks the sender reference: an inbound postMessage whose event.source is present and is a different window than window.parent is dropped before any origin processing — no origin anchoring, no init, no update, no response correlation. A message without a sender reference may still be accepted (minimal test doubles and exotic engines omit it); real sibling frames always carry one.

4. Install-time rejections

"*" is rejected at install time with a TypeError, as is any expectedOrigin that is neither a valid absolute URL nor a file-origin group member — such a value could never be a valid postMessage target token. The rejection happens at install time, not at post time.

installDashletGlobal({
    expectedOrigin: 'https://enaio.example.com', // webclient host origin
    timeoutMs: 5000, // default host-reply timeout
    pollIntervalMs: 50, // rich-client bridge poll interval
    detectionTimeoutMs: 5000, // cap before the standalone state is reported
});

5. The documented security trade-off

In learning mode the trust anchor becomes "the first host that embeds us". This is acceptable in the enaio dashlet context (a dashlet URI is not a general web page; the embedding side is by definition the host); strict deployments keep the configured-origin path.