import json import pytest from browser_cli.auth.server_identity import load_or_create_server_identity, public_key_hex, sign_challenge, verify_challenge_signature from browser_cli.errors import BrowserNotConnected from browser_cli.remote import known_hosts def _challenge(tmp_path): key = load_or_create_server_identity(tmp_path / "server.pem") msg = { "type": "challenge", "nonce": "00" * 32, "server_version": "0.16.4", "min_client_version": "0.9.0", "server_pubkey": public_key_hex(key), } msg["server_sig"] = sign_challenge(msg, key) return msg def test_challenge_signature_verifies(tmp_path): challenge = _challenge(tmp_path) assert verify_challenge_signature(challenge) is True challenge["nonce"] = "11" * 32 assert verify_challenge_signature(challenge) is False def test_known_host_mismatch_is_rejected(monkeypatch, tmp_path): path = tmp_path / "known_hosts.json" challenge = _challenge(tmp_path) monkeypatch.setattr(known_hosts, "KNOWN_HOSTS_PATH", path) path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps({"browser-host.example": "00" * 32}), encoding="utf-8") with pytest.raises(BrowserNotConnected, match="REMOTE SERVER IDENTITY CHANGED"): known_hosts.verify_known_host("browser-host.example", challenge) def test_unknown_non_interactive_host_is_rejected(monkeypatch, tmp_path): path = tmp_path / "known_hosts.json" challenge = _challenge(tmp_path) monkeypatch.setattr(known_hosts, "KNOWN_HOSTS_PATH", path) monkeypatch.setattr("sys.stdin.isatty", lambda: False) with pytest.raises(BrowserNotConnected, match="Unknown remote server identity"): known_hosts.verify_known_host("browser-host.example", challenge) def test_loopback_unknown_host_is_allowed(monkeypatch, tmp_path): path = tmp_path / "known_hosts.json" challenge = _challenge(tmp_path) monkeypatch.setattr(known_hosts, "KNOWN_HOSTS_PATH", path) monkeypatch.setattr("sys.stdin.isatty", lambda: False) known_hosts.verify_known_host("127.0.0.1:8765", challenge) assert not path.exists() def test_save_and_remove_known_host(tmp_path): path = tmp_path / "known_hosts.json" known_hosts.save_known_host("browser-host.example:443", "11" * 32, path) assert json.loads(path.read_text(encoding="utf-8")) == {"browser-host.example": "11" * 32} assert known_hosts.remove_known_host("browser-host.example", path) is True assert known_hosts.load_known_hosts(path) == {}