Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,19 @@

ARG GEOLIBRE_APP_BASE=/
ARG VITE_GEE_OAUTH_CLIENT_ID=
ARG VITE_MAPILLARY_ACCESS_TOKEN=

Check warning on line 26 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build and publish container image

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "VITE_MAPILLARY_ACCESS_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
# Set to 1 (or true) to disable the first-launch welcome wizard for the whole
# deployment; visitors land straight on the map.
ARG VITE_WELCOME_DISABLED=
# Comma-separated origins allowed to drive a framed app over the embed
# postMessage API. Usually set at RUN time instead (-e GEOLIBRE_EMBED_ORIGINS=…),
# which the entrypoint writes into the runtime config without a rebuild.
ARG VITE_GEOLIBRE_EMBED_ORIGINS=
ENV GEOLIBRE_APP_BASE=${GEOLIBRE_APP_BASE}
ENV VITE_GEE_OAUTH_CLIENT_ID=${VITE_GEE_OAUTH_CLIENT_ID}
ENV VITE_MAPILLARY_ACCESS_TOKEN=${VITE_MAPILLARY_ACCESS_TOKEN}

Check warning on line 36 in Dockerfile

View workflow job for this annotation

GitHub Actions / Build and publish container image

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "VITE_MAPILLARY_ACCESS_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ENV VITE_WELCOME_DISABLED=${VITE_WELCOME_DISABLED}
ENV VITE_GEOLIBRE_EMBED_ORIGINS=${VITE_GEOLIBRE_EMBED_ORIGINS}

RUN npm run build

Expand Down
5 changes: 5 additions & 0 deletions apps/geolibre-desktop/src/components/layout/DesktopShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
import { MapGrid } from "./MapGrid";
import { RemoteCursorsOverlay } from "./RemoteCursorsOverlay";
import { useCommandBridge } from "../../hooks/useCommandBridge";
import { useEmbedApi } from "../../hooks/useEmbedApi";
import { useJupyterRelay } from "../../hooks/useJupyterRelay";
import { appendDiagnostic, useDiagnosticsSnapshot } from "../../lib/diagnostics";
import { SectionErrorBoundary, SilentErrorBoundary } from "../common/error-boundaries";
Expand Down Expand Up @@ -748,6 +749,10 @@
// Request/reply + event channel backing the Python scripting API (live
// queries, processing, map events). Also inert when not embedded.
useCommandBridge(mapControllerRef);
// Runtime postMessage API for a third-party host page that frames the app
// (fly to a record, highlight it, open a tool; selection/view/tool events back
// out). Off unless the deployment configured GEOLIBRE_EMBED_ORIGINS.
useEmbedApi(mapControllerRef);
// Same scripting surface, reached over the desktop Jupyter server's relay, so
// a kernel driven from an EXTERNAL client (VS Code's Jupyter extension) can
// control the map too. Inert until that server is running.
Expand Down Expand Up @@ -1466,7 +1471,7 @@
disposed = true;
unlisten?.();
};
}, [clearDropMessageLater, finishDrop, addDroppedRasters, addDroppedPhotos, addGeoJsonLayer]);

Check warning on line 1474 in apps/geolibre-desktop/src/components/layout/DesktopShell.tsx

View workflow job for this annotation

GitHub Actions / Build and test

React Hook useEffect has a missing dependency: 't'. Either include it or remove the dependency array

const handleDragEnter = useCallback((event: DragEvent<HTMLDivElement>) => {
if (!hasDroppedFiles(event)) return;
Expand Down Expand Up @@ -1592,7 +1597,7 @@
clearDropMessageLater();
}
},
[clearDropMessageLater, finishDrop, addDroppedRasters, addDroppedPhotos, addGeoJsonLayer],

Check warning on line 1600 in apps/geolibre-desktop/src/components/layout/DesktopShell.tsx

View workflow job for this annotation

GitHub Actions / Build and test

React Hook useCallback has a missing dependency: 't'. Either include it or remove the dependency array
);

const startLayerPanelResize = useCallback(
Expand Down
30 changes: 29 additions & 1 deletion apps/geolibre-desktop/src/hooks/embedHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// (useCommandBridge) talk to the SAME host window and must apply the SAME trust
// rules, so the detection and origin handshake live here once.

import { EMBED_ORIGIN_WILDCARD, isEmbedOriginAllowed, readEmbedOrigins } from "../lib/embed-api";

/**
* Detects whether the app is running inside the GeoLibre Jupyter/embed host.
*
Expand All @@ -21,7 +23,10 @@
* broadcasts full project state to it. Because the legitimate hosts (the Jupyter
* widget, Colab's proxy) have arbitrary, unknowable origins, an origin allowlist
* is not viable here; instead the deployment constraint is: an `?embed=1`
* export must only be served from a trusted context, never a public URL.
* export must only be served from a trusted context, never a public URL. A
* deployment that *can* name its hosts (a web build framed by a portal) should
* set `GEOLIBRE_EMBED_ORIGINS`, which both enables the embed API
* (`hooks/useEmbedApi.ts`) and narrows these bridges to those origins.
*
* @returns True when the postMessage bridges should be active.
*/
Expand Down Expand Up @@ -64,6 +69,11 @@ export interface EmbedHost {
readonly handshakeComplete: boolean;
/** Origin to scope outbound posts to (`"*"` until the host is identified). */
targetOrigin(): string;
/**
* Origins a pre-handshake broadcast (the `ready` ping) may go to: the known
* host origin, else every allowlisted origin, else `["*"]`.
*/
broadcastTargets(): string[];
/**
* Record an inbound message from the host: marks the handshake complete and
* learns the host's origin. Returns true when the message actually came from
Expand All @@ -77,9 +87,17 @@ export interface EmbedHost {
* always defined; when the app is the top-level document (the `?embed=1`
* self-test) it is `window` itself, so the bridge naturally posts to and
* receives from itself.
*
* When the deployment configured an embed-API origin allowlist
* (`GEOLIBRE_EMBED_ORIGINS`), it applies here too: a host whose origin is not
* listed never completes the handshake, so an operator who names their trusted
* hosts also narrows the `?embed=1` project/scripting bridges to them. With no
* allowlist configured nothing changes (the Jupyter widget's host origin is
* arbitrary and unknowable, so it cannot be listed in advance).
*/
export function createEmbedHost(): EmbedHost {
const host = window.parent;
const allowedOrigins = readEmbedOrigins();
let hostOrigin: string | null = null;
let handshakeComplete = false;
return {
Expand All @@ -88,8 +106,18 @@ export function createEmbedHost(): EmbedHost {
return handshakeComplete;
},
targetOrigin: () => hostOrigin ?? "*",
broadcastTargets: () => {
if (hostOrigin) return [hostOrigin];
if (allowedOrigins.length === 0 || allowedOrigins.includes(EMBED_ORIGIN_WILDCARD)) {
return [EMBED_ORIGIN_WILDCARD];
}
return allowedOrigins;
},
note(event: MessageEvent): boolean {
if (event.source !== host) return false;
if (allowedOrigins.length > 0 && !isEmbedOriginAllowed(event.origin, allowedOrigins)) {
return false;
}
handshakeComplete = true;
// "null" (opaque/file origins) stays "*".
if (event.origin && event.origin !== "null") hostOrigin = event.origin;
Expand Down
Loading
Loading