Files
sen 7f32f83815 feat: add browser extension bridge for CLI-to-browser communication (#89)
* [packages/actionbook-rs]feat: add browser extension

Implements the WebSocket bridge server and Chrome Extension skeleton
for controlling the user's own browser via extension mode.

New components:
- Chrome Extension (MV3): background service worker, popup UI,
  WebSocket client connecting to bridge on localhost:19222
- Bridge server: `actionbook extension serve` - routes commands
  between CLI and extension with request ID rewriting and timeouts
- CLI: --extension flag, `actionbook extension serve/status/ping`
- Extension mode routing for `eval` and `pages` browser commands

Architecture: CLI -> WebSocket -> Bridge -> Extension -> chrome.debugger

* [packages/actionbook-rs]fix: merge duplicate extension_send fns and fix is_bridge_running side effect

- Merge extension_send_cdp and extension_send into a single function
- Replace WebSocket-based is_bridge_running with plain TCP connect
  to avoid orphan connections and spurious bridge warnings

* [packages/actionbook-extension]feat: add offscreen keepalive, CDP event forwarding, createTab/activateTab

- Add offscreen document for Service Worker keepalive (ping every 20s)
- Forward CDP events from chrome.debugger.onEvent to CLI via WebSocket
- Add exponential backoff reconnect (1s base, 2x growth, 30s max)
- Auto-attach to active tab when no tab is attached
- Add Extension.createTab and Extension.activateTab command handlers
- Improve error handling for debugger detachment detection

* [packages/actionbook-rs]feat: add extension mode to all browser commands (Phase 2)

Add --extension flag support to all browser subcommands, routing CDP
operations through the WebSocket bridge instead of direct chromiumoxide.

Commands implemented: goto, back, forward, reload, open, switch, wait,
click, type, fill, select, hover, focus, press, screenshot, pdf, html,
text, snapshot, inspect, viewport, cookies, close, restart.

Includes js_resolve_selector helper for [ref=eN] snapshot references
and extension_eval helper with exception handling.

Also fixes escape order bug in js_resolve_selector (backslashes must
be escaped before single quotes).

* [packages/actionbook-rs]test: add extension bridge integration tests and mock extension

- Add [lib] crate to expose modules for integration tests
- Add 9 integration tests covering: CLI without extension error,
  full round-trip with id remapping, error forwarding, multiple
  concurrent CLIs, is_bridge_running detection, connection failure
- Add mock-extension.mjs for manual E2E testing with mock CDP responses

* [packages/actionbook-rs]test: add Chrome E2E test script and expand bridge unit tests

- Add extension-chrome-e2e.sh: real Chrome + arxiv.org E2E test covering
  navigation, content extraction, screenshots, cookies, tab management,
  interactions, and JSON output mode
- Expand bridge_tests module with additional assertions and helpers

* [packages/actionbook-rs]feat: add extension install/path/uninstall CLI commands

Embed all 9 Chrome extension files into the Rust binary via
include_str!/include_bytes! and provide CLI commands to extract them
to ~/.config/actionbook/extension/ for easy Chrome sideloading.

New commands:
- `actionbook extension install [--force]`
- `actionbook extension path`
- `actionbook extension uninstall`

Also updates `extension serve` to show the real installed path
with outdated/not-installed warnings. All commands support --json.

* [packages/actionbook-rs,actionbook-extension]feat: implement extension security Phase 0-2

Phase 0 - Connection Hardening:
- Lazy connect (idle start, user-triggered connection)
- Bounded reconnect with MAX_RETRIES=8 and exponential backoff
- Distinguish network errors from auth failures in pre-handshake close

Phase 1 - Session Token Auth:
- Token generation (abk_ + 32 hex), atomic file write (0600)
- Hello/hello_ack handshake protocol with token validation
- Constant-time token comparison (subtle crate) to prevent timing attacks
- TTL watchdog with 30min idle token rotation
- Token format validation (abk_ prefix + length) in both CLI and extension

Phase 2 - CDP Allowlist & Risk Levels:
- CDP method allowlist with L1/L2/L3 risk classification
- L3 human-in-the-loop confirmation via popup with nonce binding
- Sender validation (only popup.html can approve L3 or set tokens)
- Sensitive domain detection with L2→L3 risk elevation
- Origin validation (loopback + chrome-extension:// only)

Security hardening from dual review:
- Replace all console.log with debug utility behind DEBUG_ENABLED flag
- Remove token pre-population in popup input
- Reject concurrent L3 requests (no slot overwrite)

* [packages/actionbook-rs]chore: remove browser-extension-design.md from tracking

* [actionbook-extension]chore: replace placeholder icons with Actionbook logomark

Extract the logomark from docs/logo SVG and generate proper PNG icons
at 16x16, 48x48, and 128x128 to replace the blue placeholder squares.

* [packages/actionbook-rs,actionbook-extension]feat: switch cookie ops to chrome.cookies API with security gating

Replace CDP Network.* cookie methods (which required L3 popup confirmation
and always timed out in automated usage) with chrome.cookies.* API via
new Extension.getCookies/setCookie/removeCookie/clearCookies commands.

Security hardening from code review:
- All cookie ops require a valid http(s) URL scope — no cross-domain wildcard
- Cookie writes (set/remove/clear) gated by L3 confirmation on sensitive domains
- Input validation for url, name, value params in background.js
- Native messaging entry point validates exact extension ID (not prefix)
- setCookie checks for null return (browser rejection)
- clearCookies uses Promise.allSettled for parallel removal

Also adds native messaging auto-connect, bridge token rotation handling,
and fixes .gitignore typo (.doc -> .docs/).

* [packages/actionbook-rs]test: replace arxiv.org with automation-friendly test sites

Switch E2E test targets from arxiv.org (rate-limited) to
the-internet.herokuapp.com and example.com for reliable CI.

- Phase 2: use `browser open` to avoid chrome:// tab issues
- Phase 6: login form interactions on /login (public test creds)
- Phase 7: hover on /hovers `.figure`, focus link on homepage
- Phase 9: example.com for new-tab test
- login-result-page: check URL path instead of page title

* [actionbook-extension]docs: add extension usage guide

Cover installation, bridge setup, token pairing, all browser
subcommands (navigation, interaction, tabs, debug, cookies, connect),
Action Manual integration, and common troubleshooting.

* [packages/actionbook-rs,actionbook-extension]fix: address PR #89 review — bridge security, reliability, and correctness

- Add awaitPromise to Runtime.evaluate for async extension commands
- Fix origin validation prefix-matching bypass (exact host matching)
- Send token_expired notification before closing extension WebSocket
- Return immediate error when extension channel is closed
- Propagate custom bridge port to extension via native messaging
- Prioritize explicit --domain over current URL in cookie ops
- Retry native messaging with backoff instead of permanent disable
- Use serde_json for comprehensive JS string escaping
- Validate protocol version in bridge handshake with semver

* [packages/actionbook-rs,actionbook-extension]fix: tab auto-attach, profile validation, and cookie clear safety

1. (Critical) Extension.createTab and Extension.activateTab now auto-attach
   the Chrome debugger to the new/activated tab, so subsequent CDP commands
   target the correct tab instead of a stale attachedTabId.

2. (High) --profile flag combined with --extension now produces a hard error
   instead of being silently ignored.

3. (Medium) cookies clear gains --domain, --dry-run, and --yes flags.
   --yes is required to actually clear (both interactive and JSON modes).
   --dry-run previews which cookies would be cleared without deleting.
   --domain scopes the clear to a specific domain.
   CDP mode rejects --domain/--dry-run with a clear error message.

Tests: 6 new tests covering all three fixes (bridge-level + CLI parser).

* [skills/actionbook]docs: fix SKILL.md extension mode documentation

- Remove non-existent --path flag from extension install
- Add missing extension uninstall command and --extension-port flag
- Simplify Phase 2 alt to avoid redundant duplication of CDP example
- Move Extension Setup section after Browser Commands for logical flow
- Extract troubleshooting content to references/extension-troubleshooting.md
- Fix misleading "runs in background" description for serve (it's foreground)
- Replace opaque "L3 operations" term with concrete description
- Add browser close safety note for extension mode

* [packages/actionbook-rs,actionbook-extension]fix: use domain-based query for cookie clear to cover all paths

chrome.cookies.getAll({ url }) only returns cookies whose path matches
the URL path. When --domain builds https://domain/, cookies scoped to
/app, /account, etc. are silently missed. Pass an explicit domain param
so the extension uses getAll({ domain }) which covers all paths.
2026-02-09 14:06:44 +08:00

14 lines
506 B
JavaScript

// Actionbook Offscreen Document - Keeps the Service Worker alive
// Sends periodic pings to background.js to prevent the 30s idle timeout
const KEEPALIVE_INTERVAL_MS = 20000; // 20 seconds (under the 30s SW timeout)
setInterval(() => {
chrome.runtime.sendMessage({ type: "keepalive" }).catch(() => {
// SW might be briefly unavailable during restart, ignore
});
}, KEEPALIVE_INTERVAL_MS);
// Send initial keepalive immediately
chrome.runtime.sendMessage({ type: "keepalive" }).catch(() => {});