feat: harden remote serve and reuse connections
Testing / remote-protocol-compat (0.9.5) (push) Successful in 56s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 59s
Testing / test (push) Successful in 1m1s
Build & Publish Package / publish (push) Successful in 33s
Package Extension / package-extension (push) Successful in 36s
Testing / remote-protocol-compat (0.9.5) (push) Successful in 56s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 59s
Testing / test (push) Successful in 1m1s
Build & Publish Package / publish (push) Successful in 33s
Package Extension / package-extension (push) Successful in 36s
- Gate TCP serve commands with safe-by-default policies, per-key allow tokens, per-key rate limiting, and audit labels. - Reuse authenticated encrypted remote sessions and parallelize/caches multi-browser fanout to reduce repeated handshake roundtrips. - Increase paged native-host batch size with extension-side byte budgeting to speed large tab listings safely. - Point install output at public Chrome Web Store / Firefox AMO listings by default, with --dev preserving unpacked workflows. - Share search-engine metadata between CLI and SDK and bump the package/extension version to 0.16.0. - Cover the new security, pooling, paging, install, and fanout behavior with expanded Python and extension tests.
This commit is contained in:
@@ -10,6 +10,7 @@ from rich.console import Console
|
||||
|
||||
from browser_cli import BrowserCLI
|
||||
from browser_cli.command_security import CommandPolicy, assert_command_allowed
|
||||
from browser_cli.commands import command_policy_from_options, command_policy_options
|
||||
|
||||
console = Console()
|
||||
|
||||
@@ -24,9 +25,11 @@ class _Handler(BaseHTTPRequestHandler):
|
||||
def _authorized(self) -> bool:
|
||||
if self.token is None:
|
||||
return True
|
||||
if self.headers.get("Authorization", "") == f"Bearer {self.token}":
|
||||
bearer = self.headers.get("Authorization", "")
|
||||
if bearer.startswith("Bearer ") and secrets.compare_digest(bearer[len("Bearer "):], self.token):
|
||||
return True
|
||||
return self.headers.get("X-Browser-CLI-Token") == self.token
|
||||
header = self.headers.get("X-Browser-CLI-Token")
|
||||
return header is not None and secrets.compare_digest(header, self.token)
|
||||
|
||||
def _require_auth(self) -> bool:
|
||||
if self._authorized():
|
||||
@@ -87,10 +90,8 @@ class _Handler(BaseHTTPRequestHandler):
|
||||
@click.option("--key", default=None, help="Remote auth key spec")
|
||||
@click.option("--token", default=None, help="Bearer token required for HTTP access (generated by default)")
|
||||
@click.option("--no-auth", is_flag=True, help="Disable HTTP auth (only allowed on loopback hosts)")
|
||||
@click.option("--allow-read-page", is_flag=True, help="Allow /command to run page-content read commands")
|
||||
@click.option("--allow-control", is_flag=True, help="Allow /command to run browser-control commands")
|
||||
@click.option("--allow-dangerous", is_flag=True, help="Allow /command to run high-risk commands")
|
||||
def cmd_serve_http(host, port, browser, remote, key, token, no_auth, allow_read_page, allow_control, allow_dangerous):
|
||||
@command_policy_options
|
||||
def cmd_serve_http(host, port, browser, remote, key, token, no_auth, allow_read_page, allow_control, allow_dangerous, allow_keys, allow_all):
|
||||
"""Expose a tiny local HTTP JSON gateway (/tabs, /clients, /command).
|
||||
|
||||
Auth is enabled by default. Pass the printed token as either
|
||||
@@ -99,7 +100,7 @@ def cmd_serve_http(host, port, browser, remote, key, token, no_auth, allow_read_
|
||||
if no_auth and not _is_loopback(host):
|
||||
raise click.ClickException("--no-auth is only allowed on loopback hosts")
|
||||
auth_token = None if no_auth else (token or secrets.token_urlsafe(32))
|
||||
policy = CommandPolicy(allow_read_page=allow_read_page, allow_control=allow_control, allow_dangerous=allow_dangerous)
|
||||
policy = command_policy_from_options(allow_read_page=allow_read_page, allow_control=allow_control, allow_dangerous=allow_dangerous, allow_keys=allow_keys, allow_all=allow_all)
|
||||
handler = type(
|
||||
"BrowserCLIHTTPHandler",
|
||||
(_Handler,),
|
||||
|
||||
Reference in New Issue
Block a user