feat: token-auth removal, security hardening, Stripe-style compat layer (v0.9.2)
- Remove token auth entirely; only Ed25519 pubkey auth or --no-auth - Add 32 MB message-size cap in serve and client (DoS protection) - Set Unix socket to 0o600 after bind in native_host (multi-user hardening) - Enforce browser-cli/VERSION user-agent on all TCP connections - Add PROTOCOL_MIN_CLIENT check (>= 0.9.0) server- and client-side - Include server_version + min_client_version in challenge frame - Add browser_cli/version_manager.py: parse_version, get_installed_version - Add browser_cli/compat.py: Stripe-style versioning layer with adapt_request / adapt_response hooks; baseline 0.9.2, no shims needed yet - Fix BrowserCLI key handling: no Path() wrap for agent specs - Fix _multi_browser_targets() to forward key to remote_browser_targets() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+8
-17
@@ -18,7 +18,6 @@ Usage:
|
||||
"""
|
||||
from collections.abc import Callable, Iterable
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from browser_cli.client import BrowserNotConnected, active_browser_targets, remote_browser_targets, send_command
|
||||
from browser_cli.models import Group, Tab
|
||||
@@ -34,7 +33,7 @@ class BrowserCounts:
|
||||
|
||||
|
||||
class BrowserCLI:
|
||||
def __init__(self, browser: str | None = None, remote: str | None = None, token: str | None = None, key: str | None = None):
|
||||
def __init__(self, browser: str | None = None, remote: str | None = None, key: str | None = None):
|
||||
"""
|
||||
Args:
|
||||
browser: Profile alias to target. Required when multiple browser
|
||||
@@ -43,24 +42,22 @@ class BrowserCLI:
|
||||
Format: ``"host:port"`` (e.g. ``"192.168.1.10:8765"``).
|
||||
Can be combined with ``browser`` to route to a specific
|
||||
remote profile.
|
||||
token: Auth token for the remote serve instance (legacy token auth).
|
||||
key: Path to Ed25519 private key PEM for pubkey auth. When set,
|
||||
overrides token auth. Defaults to ``~/.config/browser-cli/client.key.pem``
|
||||
if that file exists.
|
||||
key: Path to Ed25519 private key PEM for pubkey auth, or ``"agent"``
|
||||
to use a key from the SSH agent (YubiKey, gpg-agent, etc.).
|
||||
Defaults to ``~/.config/browser-cli/client.key.pem`` if that file exists.
|
||||
"""
|
||||
self._browser = browser
|
||||
self._remote = remote
|
||||
self._token = token
|
||||
self._key = Path(key) if key else None
|
||||
self._key = key if key else None
|
||||
|
||||
def _cmd(self, command: str, args: dict | None = None):
|
||||
return send_command(command, args, profile=self._browser, remote=self._remote, token=self._token, key=self._key)
|
||||
return send_command(command, args, profile=self._browser, remote=self._remote, key=self._key)
|
||||
|
||||
def _multi_browser_targets(self):
|
||||
if self._browser is not None:
|
||||
return []
|
||||
if self._remote:
|
||||
targets = remote_browser_targets(self._remote, self._token)
|
||||
targets = remote_browser_targets(self._remote, key=self._key)
|
||||
else:
|
||||
targets = active_browser_targets()
|
||||
if len(targets) <= 1 and not any(target.remote for target in targets):
|
||||
@@ -73,7 +70,7 @@ class BrowserCLI:
|
||||
for target in targets:
|
||||
try:
|
||||
if target.remote:
|
||||
data = send_command(command, args, profile=target.profile, remote=target.remote, token=target.token, key=self._key)
|
||||
data = send_command(command, args, profile=target.profile, remote=target.remote, key=self._key)
|
||||
else:
|
||||
data = send_command(command, args, profile=target.profile)
|
||||
except (BrowserNotConnected, RuntimeError):
|
||||
@@ -98,7 +95,6 @@ class BrowserCLI:
|
||||
browser_profile: str | None = None,
|
||||
browser_name: str | None = None,
|
||||
browser_remote: str | None = None,
|
||||
browser_token: str | None = None,
|
||||
) -> Tab:
|
||||
tab = Tab(
|
||||
id=data["id"],
|
||||
@@ -113,7 +109,6 @@ class BrowserCLI:
|
||||
tab._browser = self if browser_profile is None else BrowserCLI(
|
||||
browser=browser_profile,
|
||||
remote=browser_remote,
|
||||
token=browser_token,
|
||||
)
|
||||
return tab
|
||||
|
||||
@@ -124,7 +119,6 @@ class BrowserCLI:
|
||||
browser_profile: str | None = None,
|
||||
browser_name: str | None = None,
|
||||
browser_remote: str | None = None,
|
||||
browser_token: str | None = None,
|
||||
) -> Group:
|
||||
group = Group(
|
||||
id=data["id"],
|
||||
@@ -137,7 +131,6 @@ class BrowserCLI:
|
||||
group._browser = self if browser_profile is None else BrowserCLI(
|
||||
browser=browser_profile,
|
||||
remote=browser_remote,
|
||||
token=browser_token,
|
||||
)
|
||||
return group
|
||||
|
||||
@@ -237,7 +230,6 @@ class BrowserCLI:
|
||||
browser_profile=target.profile,
|
||||
browser_name=target.display_name,
|
||||
browser_remote=target.remote,
|
||||
browser_token=target.token,
|
||||
)
|
||||
for target, tabs in multi_results
|
||||
for tab in (tabs or [])
|
||||
@@ -392,7 +384,6 @@ class BrowserCLI:
|
||||
browser_profile=target.profile,
|
||||
browser_name=target.display_name,
|
||||
browser_remote=target.remote,
|
||||
browser_token=target.token,
|
||||
)
|
||||
for target, groups in multi_results
|
||||
for group in (groups or [])
|
||||
|
||||
Reference in New Issue
Block a user