mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
Register the native host with Firefox as well
Firefox reads its host manifests from ~/.mozilla/native-messaging-hosts (Mozilla/NativeMessagingHosts on macOS) and names the extension by its gecko id in allowed_extensions, not an origin. With the extension now asking for nativeMessaging, Firefox joins the router without a pairing code, as Chromium does. hanzo-tools-browser 0.5.14.
This commit is contained in:
@@ -29,6 +29,8 @@ from pathlib import Path
|
||||
|
||||
NAME = "ai.hanzo.zap"
|
||||
EXTENSIONS = ("biingenefmanpecedoafkfajbnlgdmbl",)
|
||||
# Firefox names an extension by its gecko id (manifest-firefox.json), not an origin.
|
||||
GECKO = ("[email protected]",)
|
||||
|
||||
# Where each Chromium-family browser looks for a user-level host manifest.
|
||||
_LINUX = (
|
||||
@@ -48,6 +50,9 @@ _DARWIN = (
|
||||
"~/Library/Application Support/Microsoft Edge",
|
||||
"~/Library/Application Support/Vivaldi",
|
||||
)
|
||||
# Where Firefox looks: the host directory itself, not a profile root.
|
||||
_FIREFOX_LINUX = ("~/.mozilla/native-messaging-hosts",)
|
||||
_FIREFOX_DARWIN = ("~/Library/Application Support/Mozilla/NativeMessagingHosts",)
|
||||
|
||||
|
||||
def _executable() -> str | None:
|
||||
@@ -73,16 +78,23 @@ def install() -> list[str]:
|
||||
"description": "Hanzo ZAP: the browser's seat on this machine's router",
|
||||
"path": exe,
|
||||
"type": "stdio",
|
||||
"allowed_origins": [f"chrome-extension://{e}/" for e in EXTENSIONS],
|
||||
}
|
||||
body = json.dumps(manifest, indent=2) + "\n"
|
||||
roots = _DARWIN if sys.platform == "darwin" else _LINUX
|
||||
chromium = json.dumps({**manifest, "allowed_origins": [f"chrome-extension://{e}/" for e in EXTENSIONS]}, indent=2) + "\n"
|
||||
firefox = json.dumps({**manifest, "allowed_extensions": list(GECKO)}, indent=2) + "\n"
|
||||
darwin = sys.platform == "darwin"
|
||||
targets = [
|
||||
(Path(r).expanduser(), Path(r).expanduser() / "NativeMessagingHosts", chromium)
|
||||
for r in (_DARWIN if darwin else _LINUX)
|
||||
] + [
|
||||
# Firefox's host directory: present once Firefox has a profile there.
|
||||
(Path(r).expanduser().parent, Path(r).expanduser(), firefox)
|
||||
for r in (_FIREFOX_DARWIN if darwin else _FIREFOX_LINUX)
|
||||
]
|
||||
written = []
|
||||
for root in roots:
|
||||
base = Path(root).expanduser()
|
||||
for base, hosts, body in targets:
|
||||
if not base.is_dir():
|
||||
continue
|
||||
target = base / "NativeMessagingHosts" / f"{NAME}.json"
|
||||
target = hosts / f"{NAME}.json"
|
||||
try:
|
||||
if target.exists() and target.read_text() == body:
|
||||
continue
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "hanzo-tools-browser"
|
||||
version = "0.5.13"
|
||||
version = "0.5.14"
|
||||
description = "Browser automation tools: drive the user's own browser through the Hanzo extension, over the ZAP router every ZAP process embeds."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import json
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from hanzo_tools.browser import native_host
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def home(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("HOME", str(tmp_path))
|
||||
monkeypatch.setattr(sys, "platform", "linux")
|
||||
exe = tmp_path / ".local" / "bin" / "hanzo-zap-host"
|
||||
exe.parent.mkdir(parents=True)
|
||||
exe.write_text("")
|
||||
monkeypatch.setattr(native_host, "_executable", lambda: str(exe))
|
||||
return tmp_path
|
||||
|
||||
|
||||
def test_every_installed_engine_gets_its_own_manifest(home):
|
||||
(home / ".config" / "chromium").mkdir(parents=True)
|
||||
(home / ".mozilla").mkdir()
|
||||
written = native_host.install()
|
||||
chromium = json.loads((home / ".config/chromium/NativeMessagingHosts/ai.hanzo.zap.json").read_text())
|
||||
firefox = json.loads((home / ".mozilla/native-messaging-hosts/ai.hanzo.zap.json").read_text())
|
||||
assert chromium["allowed_origins"] == ["chrome-extension://biingenefmanpecedoafkfajbnlgdmbl/"]
|
||||
assert "allowed_extensions" not in chromium
|
||||
assert firefox["allowed_extensions"] == ["[email protected]"]
|
||||
assert "allowed_origins" not in firefox
|
||||
assert len(written) == 2
|
||||
assert native_host.install() == [] # idempotent
|
||||
|
||||
|
||||
def test_an_engine_that_is_not_installed_is_left_alone(home):
|
||||
assert native_host.install() == []
|
||||
assert not (home / ".mozilla").exists()
|
||||
Reference in New Issue
Block a user