Browser-extension download handoff
Status
Desktop Material now owns the Windows desktop surfaces, a checked-in unpacked browser-extension entry, and a bounded native-messaging contract for a browser-extension download handoff. The extension is not presented as installed: this repository still does not ship a native host executable or a registered host manifest, so the integration reports unavailable rather than pretending the in-app browser or a File Explorer shell extension can initiate this feature.
The existing Preferences → Integrations surface exposes this exact unavailable state. It is a real status card inside the current frozen interface, not a new destination or a browser-page mock.
Behaviour
The checked-in browser-extension/ package adds a
Manifest V3 service worker and a small options page. A user action on a
link is the only producer: it reads the locally configured Windows
destination, validates the request, and uses
chrome.runtime.connectNative to submit it. It does not
observe or replace the browser's ordinary download stream in the
background.
An installed native-messaging host may submit one strict JSON request with an HTTPS/HTTP source, suggested file name, chosen local destination, bounded id, and timestamp. Unknown fields, invalid paths, unsupported schemes, control characters, and unbounded payload values are rejected before a renderer can see them.
When a genuine request reaches the desktop owner, it renders three separate existing-dialog-system surfaces:
- Start download names the file, source, and destination and requires an explicit confirmation before any transfer.
- Downloading is a separate operation-progress surface showing truthful bytes, rate where available, pause, resume, and cancel controls.
- Completion is a distinct completion dialog/notification-ready state naming the output rather than a background-only table entry.
The desktop queue supplies the eventual native-host executor a unique same-volume temporary path, validates that it is a regular file, and atomically materializes only the approved destination. It refuses to overwrite an existing destination. A cancelled or failed transfer removes temporary output and never claims a completed file.
Security and boundaries
The handoff deliberately refuses to use either the app-hosted
internal browser download-blocked route or the File Explorer shell
extension as proof of browser extension integration. Renderer IPC is
also not a native-messaging substitute. The current code is a receiving
foundation plus an unpacked extension source tree, not an installed
browser integration or a mocked browser page.
app/src/lib/browser-extension-native-messaging.ts
implements native frame bounds, strict UTF-8/JSON decoding, response
framing, request validation, and host-manifest generation. It also emits
fixed reg.exe argv for the per-user Chrome/Edge registry
location; callers must execute that argv without a shell. Host-manifest
generation refuses wildcard origins and requires both an exact
32-character Chrome extension ID and an absolute Windows executable
path.
The remaining packaging blocker is concrete: Chrome's native-messaging host manifest must name a real executable and an exact extension ID. This unsigned project does not generate or store a browser-extension signing key, and its Windows package currently has no standalone native host executable. Therefore the host manifest is intentionally a pure builder used by a future packaging lane, not a checked-in manifest containing a guessed path or wildcard origin. The extension source can be loaded unpacked for contract review, but it cannot claim end-to-end delivery until a supported host executable and an owner- approved stable extension ID exist.
Verification
Focused tests cover strict request parsing, native-messaging framing, exact host-origin generation, and the three owned surface states. The extension has not been loaded into a browser, because no host executable is registered in this build. Native-host installation, real browser interaction, packaged runtime interaction, and captures therefore remain pending and are not claimed.