"""Remote client auth/key preparation for browser command messages.""" from __future__ import annotations import asyncio import os from pathlib import Path from browser_cli.remote import registry as remote_registry from browser_cli.constants import DEFAULT_KEY_PATH, NO_ROUTE_COMMANDS from browser_cli.version_manager import USER_AGENT def load_private_key(key_path: Path | str | None = None): """Load an Ed25519 signing key from file or SSH agent spec.""" raw = str(key_path) if key_path is not None else os.environ.get("BROWSER_CLI_KEY", str(DEFAULT_KEY_PATH)) if raw == "agent" or raw.startswith("agent:"): selector = raw[6:] or None from browser_cli.auth import agent_find_key return agent_find_key(selector) path = Path(raw) if not path.exists(): return None try: from browser_cli.auth import load_private_key as load_pem_key return load_pem_key(path) except Exception: return None def add_remote_auth_fields(msg: dict, command: str, requested_profile: str | None, remote_endpoint: str, key, auto_router) -> object: """Mutate *msg* with remote auth/routing fields and return the signing key.""" from browser_cli import transport msg["user_agent"] = USER_AGENT msg["accept_encoding"] = transport.client_accept_encoding() key_spec = key if key is not None else remote_registry.key_for_remote(remote_endpoint) private_key = load_private_key(key_spec) if key is not None: remote_registry.save_remote_key(remote_endpoint, str(key)) route_profile = requested_profile if not route_profile and command not in NO_ROUTE_COMMANDS: route_profile = auto_router(remote_endpoint, key=key_spec) if route_profile: msg["_route"] = route_profile return private_key async def add_remote_auth_fields_async(msg: dict, command: str, requested_profile: str | None, remote_endpoint: str, key, auto_router) -> object: from browser_cli import transport msg["user_agent"] = USER_AGENT msg["accept_encoding"] = transport.client_accept_encoding() key_spec = key if key is not None else await asyncio.to_thread(remote_registry.key_for_remote, remote_endpoint) private_key = await asyncio.to_thread(load_private_key, key_spec) if key is not None: await asyncio.to_thread(remote_registry.save_remote_key, remote_endpoint, str(key)) route_profile = requested_profile if not route_profile and command not in NO_ROUTE_COMMANDS: route_profile = await auto_router(remote_endpoint, key=key_spec) if route_profile: msg["_route"] = route_profile return private_key