Skip to content
This repository was archived by the owner on Apr 25, 2026. It is now read-only.

Add download command for browser-accessible resources#5

Merged
4fuu merged 3 commits into
mainfrom
feature/download-command
Mar 28, 2026
Merged

Add download command for browser-accessible resources#5
4fuu merged 3 commits into
mainfrom
feature/download-command

Conversation

@4fuu
Copy link
Copy Markdown
Owner

@4fuu 4fuu commented Mar 28, 2026

Summary

  • Adds a browser-cli download <session-id> <target> [--output <path>] command that downloads browser-accessible images and files using the session's cookies/auth
  • Target can be an element ID (e.g. e3) which resolves its src/href, or a direct URL
  • Downloads are fetched in the extension background context, base64-encoded, and decoded on the CLI side to save locally

Changes

  • src/protocol/messages.rs: Added DOWNLOAD action constant
  • src/main.rs: Added Download variant to CLI command enum with dispatch
  • src/cli/commands.rs: Added download() handler (sends request, decodes base64, writes file)
  • extension/src/background/service-worker.ts: Added handleDownload() (resolves target URL, fetches with session cookies, returns base64 data + metadata)
  • extension/src/content/content-script.ts: Added handleResolveUrl() to resolve element ref IDs to absolute URLs
  • extension/src/shared/types.ts: Added resolve_url to ContentRequest type union
  • Cargo.toml: Added base64 crate dependency

Test plan

  • Verify browser-cli download <session> <url> downloads a file from a direct URL
  • Verify browser-cli download <session> e3 resolves element src/href and downloads
  • Verify --output flag saves to custom path
  • Verify --json outputs structured JSON with path, content_type, size
  • Verify auto-filename detection from Content-Disposition and URL path
  • Verify error handling for missing elements, failed fetches, invalid targets

Closes #3

@4fuu
Copy link
Copy Markdown
Owner Author

4fuu commented Mar 28, 2026

@codex review this pr

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37a017a4d6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

try {
const response = await fetch(url);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include session credentials in download fetches

The download request uses plain fetch(url) from the extension service worker, which defaults to credentials: "same-origin"; because the request origin is the extension, cookies for normal http(s) targets are not sent. In practice, authenticated resources (the main reason for this feature) will often return 401/redirect even with a live browser session. Please fetch with explicit credentials (and related request context as needed) so session-auth downloads work reliably.

Useful? React with 👍 / 👎.

Comment thread src/cli/commands.rs Outdated

let out_path = match output {
Some(p) => PathBuf::from(p),
None => PathBuf::from(filename),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Sanitize server-provided filenames before writing

When --output is not provided, the code writes directly to PathBuf::from(filename) where filename comes from remote Content-Disposition/URL data. A malicious filename like ../../target, /absolute/path, or percent-encoded separators can cause writes outside the working directory and overwrite unintended files. The auto filename should be reduced to a safe basename and path traversal components should be rejected.

Useful? React with 👍 / 👎.

return {
id: req.id,
ok: true,
data: { data, filename, content_type: contentType, size },
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Chunk download payloads to stay under native message limits

This returns the entire base64 file in one native-messaging response object, but Chrome native messaging has a per-message size limit (64 MiB to the host). Because base64 expands payload size, larger downloads will fail once the encoded JSON exceeds that cap. The payload should be streamed/chunked (similar to page chunks) rather than sent in a single response.

Useful? React with 👍 / 👎.

@4fuu
Copy link
Copy Markdown
Owner Author

4fuu commented Mar 28, 2026

I checked this branch locally, and there is still one blocking issue here before merge.

Blocking issue: the CLI help text and the PR description both promise support for browser-cli download <session> e3, but the current implementation passes the user input e3 through target unchanged to the extension. On the extension side, handleResolveUrl() passes that value directly into resolveTarget(refId). However, the content script's elementMap stores low-level snapshot refs (rN), not structured page element IDs (eN).

That means:

  • direct URL downloads can work
  • but downloading by page element ID will fail at runtime, which does not match the core promise of this PR

I suggest reusing the existing click/type resolution path for eN -> ref_id on the Rust side before sending the request to the extension, or explicitly changing the protocol so page element IDs are translated before resolveTarget() is used. After that, please add a minimal test that covers the eN download path.

  • Codex

Mule added 3 commits March 28, 2026 17:07
Implement a `download` subcommand that fetches a browser-accessible
resource using the session's cookies/auth and saves it locally.

- Add DOWNLOAD action constant to protocol messages
- Add Download CLI subcommand with session_id, target, output, json args
- Add download handler in commands.rs: sends request, decodes base64, writes file
- Add handleDownload in background service-worker: resolves URL (direct or via
  element ref), fetches with session cookies, returns base64-encoded content
- Add resolve_url content script handler to resolve element src/href to absolute URL
- Add 'resolve_url' to ContentRequest type union
- Add base64 crate dependency for decoding in Rust

Closes #3
@4fuu 4fuu force-pushed the feature/download-command branch from 099b1c8 to a78c46b Compare March 28, 2026 17:07
@4fuu 4fuu merged commit 03904ec into main Mar 28, 2026
2 checks passed
@4fuu 4fuu deleted the feature/download-command branch March 28, 2026 17:15
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a download command for browser-accessible images and files

1 participant