diff --git a/backend/app/channels/buzz.py b/backend/app/channels/buzz.py index 212e12fbb1..d1f7489875 100644 --- a/backend/app/channels/buzz.py +++ b/backend/app/channels/buzz.py @@ -254,14 +254,15 @@ class BuzzChannel(Channel): def __init__(self, bus: MessageBus, config: dict[str, Any]) -> None: super().__init__(name="buzz", bus=bus, config=config) self._relay_url = str(config.get("relay_url", "")).strip() - if not self._relay_url.startswith(("ws://", "wss://")): - raise ValueError("channels.buzz.relay_url must be a ws:// or wss:// URL") + parsed_relay_url = urlparse(self._relay_url) + if parsed_relay_url.scheme not in ("ws", "wss") or not parsed_relay_url.hostname: + raise ValueError("channels.buzz.relay_url must be a ws:// or wss:// URL with a host") # One community per relay URL (see the design's multi-community note), so the # relay host is this channel's workspace: it scopes inbound dedupe, the # persisted connection row written by `/connect`, and the lookup that resolves # that row back on the inbound path. Computed once here so those three uses # can never drift apart. - self._workspace_id = urlparse(self._relay_url).netloc + self._workspace_id = parsed_relay_url.netloc self._private_key_raw = str(config.get("private_key", "")) self._keys: buzz_nostr.NostrKeys | None = None # parsed in start() so coincurve stays lazy self._allowed_users = {buzz_nostr.parse_pubkey(v) for v in config.get("allowed_users", []) or []} diff --git a/backend/tests/test_buzz_channel.py b/backend/tests/test_buzz_channel.py index d00f01c588..239e9404fc 100644 --- a/backend/tests/test_buzz_channel.py +++ b/backend/tests/test_buzz_channel.py @@ -63,9 +63,18 @@ def test_config_parsing_normalizes_allowlist_and_defaults(): assert ch._relay_url == "wss://buzz.example.com" -def test_config_rejects_non_websocket_relay_url(): +@pytest.mark.parametrize( + "relay_url", + [ + "https://buzz.example.com", + "ws://", + "wss://", + "ws:///missing-host", + ], +) +def test_config_rejects_invalid_websocket_relay_url(relay_url): with pytest.raises(ValueError): - _channel(relay_url="https://buzz.example.com") + _channel(relay_url=relay_url) def test_start_and_stop_manage_outbound_subscription():