Skip to content

Add hubble.links.open so HTML Apps can open external links - #263

Closed
marcodlk wants to merge 2 commits into
bholmesdev:mainfrom
marcodlk:fm/hubble-links-open
Closed

Add hubble.links.open so HTML Apps can open external links#263
marcodlk wants to merge 2 commits into
bholmesdev:mainfrom
marcodlk:fm/hubble-links-open

Conversation

@marcodlk

Copy link
Copy Markdown

Pairs with #262. Opened as a draft per CONTRIBUTING until there's consensus on the approach in the issue.

What changed

HTML Apps render in a sandboxed iframe (sandbox="allow-scripts allow-forms", no allow-popups, no allow-top-navigation), so window.open() and target="_blank" are no-ops and an app has no way to send the user to an external URL.

This adds a links.open method to the HTML App runtime broker:

  • Runtime (packages/runtime/global.js): hubble.links.open(url) and hubble.links.safeOpen(url), matching the existing hubble.files.* / safe* style.
  • Renderer (IframeView.tsx): the hubble:request dispatch validates the URL — http/https only, mirroring the existing main-process guard — and forwards to the existing desktopApi.openExternalUrl, i.e. the same validated desktop:open-external-url IPC path the Markdown editor uses for note links. No new IPC surface. Non-http(s) URLs (file:, javascript:, scheme-less strings) are rejected with Only http(s) external URLs are allowed before ever reaching the desktop API. links.open is handled before the workspace guard since opening a link doesn't depend on workspace file access.
  • Docs: ADR-0007's API list now includes links.open, with a decision bullet explaining the sandbox limitation and the reuse of the external-URL path (following its "future APIs should extend the runtime broker" consequence).

Existing files.* methods and the unknown-method error are unchanged.

How I tested

  • New Vitest cases in IframeView.test.ts (exported handleHtmlAppRequest the same way resolveHtmlAppGlob already is): http(s) URLs resolve { ok: true, value: { url } } and reach openExternalUrl; file:/javascript:/scheme-less/non-string inputs return { ok: false } without calling the desktop API; unknown methods still throw the same error.
  • pnpm --filter @hubble.md/desktop test — 23 files, 208 tests pass.
  • pnpm build:desktop (Biome + tsc + electron-vite build) passes; React compiler audit passes for the desktop package.
  • Manually exercised in a packaged macOS arm64 build: a workspace note embedding a test HTML App, where hubble.links.safeOpen("https://example.com") returned { ok: true } and opened the system browser, safeOpen("file:///etc/passwd") and safeOpen("example.com") both returned { ok: false, error: { message: "Only http(s) external URLs are allowed" } } without reaching the desktop API, and hubble.files.safeList() kept working.

Changelog

Added under [Unreleased]Added.

HTML Apps render in a sandboxed iframe without allow-popups or
allow-top-navigation, so window.open and target="_blank" are no-ops
and apps have no way to send the user to an external URL.

Add a links.open method to the runtime broker: the injected runtime
exposes hubble.links.open(url) / hubble.links.safeOpen(url) in the
same style as files.*, and the renderer dispatch validates the URL
(http/https only, mirroring the main-process guard) before forwarding
to the existing desktop:open-external-url IPC handler. No new IPC
surface is added.

Closes bholmesdev#262
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

@marcodlk is attempting to deploy a commit to the bholmesdev's projects Team on Vercel.

A member of the Team first needs to authorize it.

@marcodlk

Copy link
Copy Markdown
Author

PR created by clanker by mistake. apologies.

@marcodlk marcodlk closed this Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant