From 642e22759f7848589cd7bd74b1652084de7ffe68 Mon Sep 17 00:00:00 2001 From: Daniel Dolezal Date: Sun, 14 Jun 2026 15:39:41 +0200 Subject: [PATCH] fix: allow Web Store extension native messaging - Add the Chrome Web Store extension ID alongside the keyed testing ID. - Register both extension origins in the native messaging host manifest. - Update install output so users can distinguish testing and Web Store IDs. - Add CLI coverage for the generated allowed_origins list. --- browser_cli/commands/install.py | 7 +++++-- browser_cli/constants.py | 2 ++ tests/test_cli.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/browser_cli/commands/install.py b/browser_cli/commands/install.py index 1a6b4b8..4b6f018 100644 --- a/browser_cli/commands/install.py +++ b/browser_cli/commands/install.py @@ -9,10 +9,12 @@ import click from rich.console import Console from browser_cli.constants import ( + ALLOWED_EXTENSION_IDS, EXTENSION_ID, NATIVE_HOST_DIRS, NATIVE_HOST_NAME, SUPPORTED_BROWSERS, + WEBSTORE_EXTENSION_ID, WINDOWS_NATIVE_HOST_REGISTRY_KEYS, ) from browser_cli.platform import install_base_dir, is_windows @@ -75,14 +77,15 @@ def cmd_install(browser): console.print(f" 1. Open [cyan]{ext_url}[/cyan]") console.print(" 2. Enable [bold]Developer mode[/bold] (top-right toggle)") console.print(f" 3. Click [bold]Load unpacked[/bold] → select: [cyan]{Path(__file__).parent.parent.parent / 'extension'}[/cyan]") - console.print(f" 4. Extension ID will be [cyan]{EXTENSION_ID}[/cyan] (fixed by built-in key)\n") + console.print(f" 4. Testing extension ID will be [cyan]{EXTENSION_ID}[/cyan] (fixed by built-in key)") + console.print(f" Chrome Web Store extension ID is [cyan]{WEBSTORE_EXTENSION_ID}[/cyan]\n") manifest = { "name": NATIVE_HOST_NAME, "description": "browser-cli native messaging host", "path": str(host_exe), "type": "stdio", - "allowed_origins": [f"chrome-extension://{EXTENSION_ID}/"], + "allowed_origins": [f"chrome-extension://{extension_id}/" for extension_id in ALLOWED_EXTENSION_IDS], } installed = _install_manifest(browser, host_exe, manifest) if not installed: diff --git a/browser_cli/constants.py b/browser_cli/constants.py index 231a82f..1e110d8 100644 --- a/browser_cli/constants.py +++ b/browser_cli/constants.py @@ -14,6 +14,8 @@ DEFAULT_ALIAS = "default" NATIVE_HOST_NAME = "com.browsercli.host" EXTENSION_ID = "bfpmkhngkjnfhabmfckgeohlilokodkg" +WEBSTORE_EXTENSION_ID = "hekaebjhbhhdbmakimmaklbblbmccahp" +ALLOWED_EXTENSION_IDS = [EXTENSION_ID, WEBSTORE_EXTENSION_ID] SUPPORTED_BROWSERS = ["chrome", "chromium", "brave", "edge", "vivaldi"] PROTOCOL_MIN_CLIENT = "0.9.0" diff --git a/tests/test_cli.py b/tests/test_cli.py index 76dc2eb..19ff608 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -89,6 +89,34 @@ def test_install_help_lists_supported_browsers(): assert result.exit_code == 0 assert "[chrome|chromium|brave|edge|vivaldi]" in result.output +def test_install_writes_testing_and_webstore_allowed_origins(tmp_path): + manifests = [] + + def fake_install_manifest(_browser, _host_exe, manifest): + manifests.append(manifest) + return [tmp_path / "com.browsercli.host.json"] + + with patch("browser_cli.commands.install.native_host_exe", return_value=tmp_path / "browser-cli-native-host"), patch( + "browser_cli.commands.install.write_native_host_exe" + ), patch("browser_cli.commands.install._install_manifest", side_effect=fake_install_manifest): + result = CliRunner().invoke(main, ["install", "brave"]) + + assert result.exit_code == 0 + assert manifests == [ + { + "name": "com.browsercli.host", + "description": "browser-cli native messaging host", + "path": str(tmp_path / "browser-cli-native-host"), + "type": "stdio", + "allowed_origins": [ + "chrome-extension://bfpmkhngkjnfhabmfckgeohlilokodkg/", + "chrome-extension://hekaebjhbhhdbmakimmaklbblbmccahp/", + ], + } + ] + assert "Testing extension ID" in result.output + assert "Chrome Web Store extension ID" in result.output + def test_install_windows_registers_native_host(tmp_path): writes = []