479a0f1964
Testing / remote-protocol-compat (0.9.3) (push) Successful in 43s
Testing / test (push) Successful in 1m1s
Testing / remote-protocol-compat (0.9.5) (push) Successful in 39s
Build & Publish Package / publish (push) Successful in 58s
Package Extension / package-extension (push) Successful in 1m15s
- Allow remote host aliases passed via --browser to fan out for read-only multi-browser SDK paths while preserving strict routing for mutating commands. - Add remote host grouping and scoped profile labels to tabs tree output so global views avoid repeated host prefixes. - Carry browser family metadata through remote targets, tabs, and groups and style tree browser labels by family. - Split CLI rendering helpers into a typed rendering package with dedicated common, label, tabs-tree, and windows-tree modules. - Bump browser-cli and extension versions to 0.15.5. - Cover the new routing and rendering behavior with unit and CLI tests.
68 lines
2.7 KiB
Python
68 lines
2.7 KiB
Python
"""Built-in control commands handled directly by ``browser-cli serve``."""
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
from browser_cli.serve.logging import log_request
|
|
|
|
class ServeControlMixin:
|
|
addr: tuple
|
|
command: str
|
|
auth_keys_path: Path | None
|
|
|
|
async def send_error(self, msg: str, msg_id=None) -> None: ...
|
|
async def send_ok(self, payload, command: str | None = None) -> None: ...
|
|
|
|
async def handle_control_command(self, msg: dict) -> bool:
|
|
if self.command == "browser-cli.targets":
|
|
from browser_cli.client import active_browser_targets, send_command
|
|
targets = []
|
|
for target in active_browser_targets(include_remotes=False):
|
|
item = {"profile": target.profile, "displayName": target.display_name}
|
|
try:
|
|
clients = send_command("clients.list", profile=target.profile, suppress_pq_warning=True)
|
|
if clients:
|
|
browser_name = clients[0].get("name")
|
|
if browser_name:
|
|
item["browserName"] = browser_name
|
|
except Exception:
|
|
pass
|
|
targets.append(item)
|
|
await self.send_ok(targets, self.command)
|
|
log_request(self.addr, self.command, None, "OK")
|
|
return True
|
|
|
|
if self.command == "browser-cli.auth.keys":
|
|
if self.auth_keys_path is None:
|
|
await self.send_error("no authorized keys file configured on this server")
|
|
log_request(self.addr, self.command, None, "ERROR", "no authorized keys file")
|
|
return True
|
|
from browser_cli.auth import load_authorized_keys_with_names
|
|
entries = [{"pubkey": pk, "name": name} for pk, name in load_authorized_keys_with_names(self.auth_keys_path)]
|
|
await self.send_ok(entries, self.command)
|
|
log_request(self.addr, self.command, None, "OK")
|
|
return True
|
|
|
|
if self.command == "browser-cli.auth.trust":
|
|
return await self._handle_trust(msg)
|
|
return False
|
|
|
|
async def _handle_trust(self, msg: dict) -> bool:
|
|
if self.auth_keys_path is None:
|
|
await self.send_error("no authorized keys file configured on this server")
|
|
log_request(self.addr, self.command, None, "ERROR", "no authorized keys file")
|
|
return True
|
|
from browser_cli.auth import add_authorized_key
|
|
args = msg.get("args") or {}
|
|
pubkey = str(args.get("pubkey") or "")
|
|
name = str(args.get("name") or "")
|
|
if not re.fullmatch(r"[0-9a-f]{64}", pubkey):
|
|
await self.send_error("invalid pubkey: expected 64 lowercase hex characters")
|
|
log_request(self.addr, self.command, None, "ERROR", "invalid pubkey")
|
|
return True
|
|
added = add_authorized_key(self.auth_keys_path, pubkey, name)
|
|
await self.send_ok({"added": added}, self.command)
|
|
log_request(self.addr, self.command, None, "OK" if added else "ALREADY_TRUSTED")
|
|
return True
|