mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-19 16:12:30 +00:00
fix(webui): allow LAN access when host is 0.0.0.0
The webui bootstrap endpoint (/webui/bootstrap) rejected all non-localhost connections with HTTP 403, preventing the embedded webui from working when accessed from another device on the LAN — even when host was set to 0.0.0.0. Skip the localhost check when the server is explicitly bound to 0.0.0.0 or ::, since that signals intent to accept external connections.
This commit is contained in:
parent
790a03ec28
commit
bad584cb0e
@ -607,7 +607,9 @@ class WebSocketChannel(BaseChannel):
|
||||
self._api_tokens.pop(token_key, None)
|
||||
|
||||
def _handle_webui_bootstrap(self, connection: Any) -> Response:
|
||||
if not _is_localhost(connection):
|
||||
if self.config.host not in ("0.0.0.0", "::") and not _is_localhost(
|
||||
connection,
|
||||
):
|
||||
return _http_error(403, "webui bootstrap is localhost-only")
|
||||
# Cap outstanding tokens to avoid runaway growth from a misbehaving client.
|
||||
self._purge_expired_issued_tokens()
|
||||
|
||||
@ -379,3 +379,41 @@ async def test_api_token_pool_purges_expired(bus: MagicMock, tmp_path: Path) ->
|
||||
headers = {"Authorization": "Bearer live"}
|
||||
|
||||
assert channel._check_api_token(_LiveReq()) is True
|
||||
|
||||
|
||||
class _FakeConn:
|
||||
"""Minimal connection stub with a configurable remote_address."""
|
||||
|
||||
def __init__(self, remote_address: tuple[str, int]):
|
||||
self.remote_address = remote_address
|
||||
|
||||
def respond(self, status: int, body: str) -> Any:
|
||||
from websockets.http11 import Response
|
||||
|
||||
return Response(status=status, body=body.encode())
|
||||
|
||||
|
||||
def test_bootstrap_rejects_non_localhost_by_default(bus: MagicMock) -> None:
|
||||
channel = _ch(bus, host="127.0.0.1")
|
||||
conn = _FakeConn(("192.168.1.5", 12345))
|
||||
resp = channel._handle_webui_bootstrap(conn)
|
||||
assert resp.status_code == 403
|
||||
|
||||
|
||||
def test_bootstrap_allows_non_localhost_when_host_is_wildcard(bus: MagicMock) -> None:
|
||||
channel = _ch(bus, host="0.0.0.0")
|
||||
conn = _FakeConn(("192.168.1.5", 12345))
|
||||
resp = channel._handle_webui_bootstrap(conn)
|
||||
assert resp.status_code == 200
|
||||
body = json.loads(resp.body)
|
||||
assert body["token"].startswith("nbwt_")
|
||||
assert body["ws_path"] == "/"
|
||||
|
||||
|
||||
def test_bootstrap_allows_non_localhost_when_host_is_ipv6_wildcard(
|
||||
bus: MagicMock,
|
||||
) -> None:
|
||||
channel = _ch(bus, host="::")
|
||||
conn = _FakeConn(("192.168.1.5", 12345))
|
||||
resp = channel._handle_webui_bootstrap(conn)
|
||||
assert resp.status_code == 200
|
||||
|
||||
@ -72,6 +72,26 @@ If your gateway listens on a non-default port, point the dev server at it:
|
||||
NANOBOT_API_URL=http://127.0.0.1:9000 bun run dev
|
||||
```
|
||||
|
||||
### Access from another device (LAN)
|
||||
|
||||
To use the webui from another device on the same network, set `host` to `"0.0.0.0"` in `~/.nanobot/config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"channels": {
|
||||
"websocket": {
|
||||
"enabled": true,
|
||||
"host": "0.0.0.0",
|
||||
"port": 8765
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then open `http://<your-ip>:8765` on the other device. When `host` is `"0.0.0.0"`, the bootstrap endpoint accepts requests from any source instead of restricting to localhost.
|
||||
|
||||
> **Note:** This exposes the gateway to all interfaces. Only use on trusted networks.
|
||||
|
||||
## Build for packaged runtime
|
||||
|
||||
```bash
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user