{"id":48816594,"url":"https://github.com/ractive/ff-rdp","last_synced_at":"2026-04-14T11:04:44.023Z","repository":{"id":349440725,"uuid":"1202314032","full_name":"ractive/ff-rdp","owner":"ractive","description":"Use Firefox's Remote Dubugging Protocol via a CLI","archived":false,"fork":false,"pushed_at":"2026-04-06T01:21:38.000Z","size":74,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-06T01:22:23.675Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ractive.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-05T22:03:06.000Z","updated_at":"2026-04-06T00:37:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ractive/ff-rdp","commit_stats":null,"previous_names":["ractive/ff-rdp"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ractive/ff-rdp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fff-rdp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fff-rdp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fff-rdp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fff-rdp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ractive","download_url":"https://codeload.github.com/ractive/ff-rdp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ractive%2Fff-rdp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31793235,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T02:24:21.117Z","status":"ssl_error","status_checked_at":"2026-04-14T02:24:20.627Z","response_time":153,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-14T11:04:23.967Z","updated_at":"2026-04-14T11:04:44.007Z","avatar_url":"https://github.com/ractive.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ff-rdp\n\nA fast Rust CLI for the Firefox Remote Debugging Protocol. Communicates directly over TCP with Firefox's built-in debugger for minimal latency.\n\n## Status\n\n**Early development** — all planned commands working: `tabs`, `navigate`, `eval`, `dom`, `page-text`, `console`, `network`, `perf`, `click`, `type`, `wait`, `cookies`, `storage`, `screenshot`, `launch`, `inspect`, `sources`, `reload`, `back`, `forward`.\n\n## Requirements\n\n- Firefox with remote debugging enabled:\n  ```bash\n  firefox --start-debugger-server 6000\n  ```\n- Rust toolchain (for building from source)\n\n## Building\n\n```bash\ncargo build --release\n```\n\nThe binary is at `target/release/ff-rdp`.\n\n## Usage\n\n```\nff-rdp [OPTIONS] \u003cCOMMAND\u003e\n\nCommands:\n  tabs        List open browser tabs\n  navigate    Navigate to a URL (with --with-network for traffic capture)\n  eval        Evaluate JavaScript in the target tab\n  dom         Query DOM elements by CSS selector (--outer-html, --inner-html, --text, --attrs)\n  page-text   Extract visible page text (document.body.innerText)\n  console     Read console messages (with --level and --pattern filters)\n  network     Show network requests (with --filter, --method filters)\n  perf        Query Performance API entries and Core Web Vitals\n  click       Click an element matching a CSS selector\n  type        Type text into an input element matching a CSS selector\n  wait        Wait for a condition to become true (polls every 100ms)\n  cookies     List cookies via StorageActor (includes httpOnly, secure, sameSite)\n  storage     Read web storage (localStorage or sessionStorage)\n  screenshot  Capture a screenshot (requires Firefox drawWindow support)\n  inspect     Inspect a remote JavaScript object by its grip actor ID\n  sources     List JavaScript/WASM sources loaded on the page\n  launch      Launch Firefox with remote debugging enabled\n  reload      Reload the page\n  back        Go back in history\n  forward     Go forward in history\n\nOptions:\n  --host \u003cHOST\u003e              Firefox debug server host [default: localhost]\n  --port \u003cPORT\u003e              Firefox debug server port [default: 6000]\n  --tab \u003cTAB\u003e                Target tab by index (1-based) or URL substring\n  --tab-id \u003cTAB_ID\u003e          Target tab by exact actor ID\n  --jq \u003cJQ\u003e                  jq filter expression applied to output\n  --timeout \u003cTIMEOUT\u003e        Operation timeout in milliseconds [default: 5000]\n  --no-daemon                Don't use or start a daemon (direct Firefox connection)\n  --daemon-timeout \u003cSECS\u003e    Daemon idle timeout in seconds [default: 300]\n  --allow-unsafe-urls        Allow javascript: and data: URLs in navigate\n```\n\nAll output is JSON with a standard envelope (`results`, `total`, `meta`). Use `--jq` to filter:\n\n```bash\n# List tab URLs\nff-rdp tabs --jq '.results[].url'\n\n# Navigate to a URL\nff-rdp navigate https://example.com\n\n# Evaluate JavaScript and extract the result\nff-rdp eval 'document.title' --jq '.results'\n\n# Target a specific tab by URL substring\nff-rdp eval 'location.href' --tab example.com\n\n# Query DOM elements by CSS selector (default: outerHTML)\nff-rdp dom \"h1\"\n\n# Get text content of matching elements\nff-rdp dom \"ul li\" --text\n\n# Get element attributes as JSON\nff-rdp dom \"a\" --attrs\n\n# Extract all visible page text\nff-rdp page-text\n\n# Count characters in page text\nff-rdp page-text --jq '.results | length'\n\n# Read console messages (errors only)\nff-rdp console --level error\n\n# Filter console messages by pattern\nff-rdp console --pattern \"TypeError\"\n\n# Show network requests\nff-rdp network\n\n# Filter network by URL substring\nff-rdp network --filter api\n\n# Filter network by HTTP method\nff-rdp network --method POST\n\n# Navigate and capture all network traffic in one shot\nff-rdp navigate https://example.com --with-network\n\n# Find failed requests during navigation\nff-rdp navigate https://example.com --with-network \\\n  --jq '.results.network[] | select(.status \u003e= 400)'\n\n# Query Performance API resource timing entries (default: --type resource)\nff-rdp perf\n\n# Page load waterfall (DNS, TLS, TTFB, DOM timings)\nff-rdp perf --type navigation\n\n# First Paint and First Contentful Paint timestamps\nff-rdp perf --type paint\n\n# Largest Contentful Paint\nff-rdp perf --type lcp\n\n# Cumulative Layout Shift entries\nff-rdp perf --type cls\n\n# Long tasks (\u003e50ms)\nff-rdp perf --type longtask\n\n# Filter resource entries by URL substring\nff-rdp perf --filter \"api/\"\n\n# Core Web Vitals summary with ratings (LCP, CLS, TBT, FCP, TTFB)\nff-rdp perf vitals\n\n# Extract a single metric\nff-rdp perf vitals --jq '.results.lcp_ms'\n\n# Click a button\nff-rdp click \"button.submit\"\n\n# Type into an input (clear first with --clear)\nff-rdp type \"input[name=email]\" \"user@example.com\"\nff-rdp type \"input[name=email]\" \"new@example.com\" --clear\n\n# Wait for an element to appear (default timeout: 5000ms)\nff-rdp wait --selector \".results\"\n\n# Wait for text to appear on the page\nff-rdp wait --text \"Success\" --wait-timeout 10000\n\n# Wait for a JavaScript expression to become truthy\nff-rdp wait --eval \"document.readyState === 'complete'\"\n\n# List cookies\nff-rdp cookies\n\n# Filter cookies by name\nff-rdp cookies --name \"session_id\"\n\n# Dump all localStorage\nff-rdp storage local\n\n# Get a specific sessionStorage key\nff-rdp storage session --key \"token\"\n\n# Capture a screenshot (saves PNG)\nff-rdp screenshot --output page.png\n\n# Launch Firefox with debugging enabled\nff-rdp launch\n\n# Launch headless Firefox with temporary profile\nff-rdp launch --headless --temp-profile\n\n# Launch with a specific profile and debug port\nff-rdp launch --profile /path/to/profile --debug-port 9222\n\n# Inspect a remote object grip (from eval output)\nff-rdp inspect server1.conn0.child2/obj19\n\n# Recursive inspection (depth 2)\nff-rdp inspect server1.conn0.child2/obj19 --depth 2\n\n# List all loaded JavaScript sources\nff-rdp sources\n\n# Filter sources by URL substring\nff-rdp sources --filter vendor\n\n# Filter sources by regex pattern\nff-rdp sources --pattern \"cdn\\.example\\.com\"\n\n# Reload, go back, go forward\nff-rdp reload\nff-rdp back\nff-rdp forward\n```\n\n## Daemon Mode\n\nBy default, the first CLI invocation auto-starts a background daemon that holds a persistent Firefox RDP connection and buffers watcher events. Subsequent invocations connect through the daemon for faster execution and cross-command workflows.\n\n**How it works:**\n- First `ff-rdp` call spawns a daemon process (`ff-rdp _daemon`) in the background\n- The daemon connects to Firefox, subscribes to watcher resources (network, console, errors), and listens on a random TCP loopback port\n- Subsequent CLI calls connect to the daemon instead of Firefox directly\n- The daemon transparently proxies RDP frames and also exposes a `\"daemon\"` virtual actor for draining buffered events\n- Daemon exits automatically after 5 minutes of inactivity (configurable via `--daemon-timeout`)\n\n**Cross-command workflows (enabled by daemon):**\n```bash\n# Navigate, then inspect network traffic as separate commands\nff-rdp navigate https://example.com\nff-rdp network\n\n# Object grips from eval survive across invocations\nff-rdp eval 'document.querySelector(\"h1\")'\nff-rdp inspect server1.conn0.child2/obj19\n```\n\n**Disabling the daemon:**\n```bash\n# Connect directly to Firefox (original behavior)\nff-rdp --no-daemon eval \"1+1\"\n```\n\n**Registry and logs:**\n- Registry file: `~/.ff-rdp/daemon.json` (PID, port, Firefox target)\n- Log file: `~/.ff-rdp/daemon.log`\n- Stale registry files are cleaned up automatically when the daemon PID is dead\n\n**Troubleshooting:**\n- If the daemon seems stuck, delete `~/.ff-rdp/daemon.json` to force a fresh start\n- Use `--no-daemon` to bypass the daemon and test direct connectivity\n- Check `~/.ff-rdp/daemon.log` for daemon-side errors\n\n## Security\n\nff-rdp has the same power as Firefox DevTools — it can read httpOnly cookies, execute arbitrary JavaScript, capture screenshots, and navigate to URLs. The security model is \"same as opening DevTools\": the user is the operator.\n\n**Transport:** Firefox RDP uses plaintext TCP with no TLS. By default ff-rdp connects to `localhost` only. For remote debugging, use SSH tunneling (`ssh -L 6000:localhost:6000 remote-host`) rather than exposing the debug port directly.\n\n**URL validation:** The `navigate` command rejects `javascript:` and `data:` URLs by default to prevent accidental code execution in the page context. Allowed schemes are `http:`, `https:`, `file:`, and `about:`. Use `--allow-unsafe-urls` to bypass this check if needed.\n\n**Daemon trust model:** The daemon listens on `127.0.0.1` (loopback only). Any local process can connect and send RDP commands through it — the same trust boundary as Firefox DevTools. The registry file (`~/.ff-rdp/daemon.json`) is created with owner-only permissions (0600 on Unix).\n\n**Regex limits:** The `--pattern` flag (used by `console` and `sources` commands) applies a 1 MiB NFA size limit to prevent denial-of-service from pathological regular expressions.\n\n**Not designed for untrusted networks.** Do not expose the Firefox debug port to the network. All RDP traffic (page content, cookies, eval results) is transmitted in plaintext.\n\n## Architecture\n\n- **ff-rdp-core** — Protocol library: blocking TCP transport, length-prefixed JSON framing, typed errors\n- **ff-rdp-cli** — CLI binary: clap args, jq output pipeline, command dispatch, daemon proxy\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fractive%2Fff-rdp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fractive%2Fff-rdp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fractive%2Fff-rdp/lists"}