Files
holesail-browser/docs/REMOTE-DESKTOP.md
T
Raven Scott f5c349a4a3
CI / Build & Test (push) Successful in 2m56s
docs
2026-02-28 22:29:56 -05:00

288 lines
7.1 KiB
Markdown

# Remote Desktop
Holesail Browser supports VNC and RDP connections in the browser, tunneled over Holesail. VNC uses the noVNC RFB client; RDP uses `node-rdpjs-2`. Both are accessed from the dashboard's **Remote Desktop** tab.
## VNC vs RDP
| Feature | VNC | RDP |
|---------|-----|-----|
| Protocol | RFB (VNC) | RDP (Microsoft) |
| Browser client | noVNC (WebSocket → RFB) | node-rdpjs-2 (JSON bridge) |
| Performance | Good for most use cases | Moderate (JSON serialization overhead) |
| Compatibility | Any VNC server | Windows Remote Desktop, FreeRDP |
| Default port | 5900 | 3389 |
## Architecture
### VNC
```
Dashboard (noVNC / canvas)
│ WebSocket ws://127.0.0.1:23000+ (binary frames)
rdp-manager.js (transparent byte pipe)
│ TCP
127.0.0.1:22000+ (Holesail client tunnel)
│ P2P / Noise protocol
Remote VNC server (port 5900)
```
For VNC, the native host is a transparent pipe — it does not interpret the RFB protocol. noVNC handles all VNC protocol logic in the browser.
### RDP
```
Dashboard (canvas renderer)
│ WebSocket ws://127.0.0.1:23000+ (JSON frames)
rdp-manager.js (node-rdpjs-2 RDP client)
│ TCP
127.0.0.1:22000+ (Holesail client tunnel)
│ P2P / Noise protocol
Remote RDP server (port 3389)
```
For RDP, `node-rdpjs-2` handles the RDP protocol in the native host. Bitmap updates are serialized to JSON and sent to the browser, which renders them on a canvas. Mouse and keyboard input is sent as JSON from the browser to the native host.
## Usage
### Saving a connection
1. Open the dashboard → **Remote Desktop**
2. Click **Add Connection**
3. Enter:
- **Label** — a name for this connection
- **Type** — VNC or RDP
- **hs:// key** — the Holesail key for the remote peer
- **Port** — remote port (default: 5900 for VNC, 3389 for RDP)
- **Width / Height** — initial display resolution
- **Username** — (RDP only) login username
- **Password** — optional; saved as base64 in `state.json` and used automatically on reconnect
4. Click **Save**
### Connecting
1. Click **Connect** next to a saved connection
2. A viewer window opens in the dashboard
3. The native host starts a Holesail tunnel to the remote peer and begins the session
### Disconnecting
Click **Disconnect** or close the viewer. The tunnel and WebSocket server are cleaned up.
---
## Native host commands
### `startRdpSession`
Start a new VNC or RDP session.
**Request payload:**
```json
{
"connectionId": "rdp-abc123",
"hsUrl": "hs://abc123...",
"type": "vnc",
"port": 5900,
"width": 1280,
"height": 720,
"username": "",
"passwordB64": "cGFzc3dvcmQ="
}
```
`passwordB64` is optional. When present it is a base64-encoded UTF-8 password string used for RDP authentication.
**Response payload:**
```json
{
"ok": true,
"sessionId": "rdp-session-1",
"wsPort": 23000,
"tunnelPort": 22000
}
```
### `stopRdpSession`
Stop a running session.
**Request payload:**
```json
{ "sessionId": "rdp-session-1" }
```
**Response payload:**
```json
{ "ok": true }
```
### `getRdpSessions`
List active sessions.
**Response payload:**
```json
{
"ok": true,
"sessions": [
{ "sessionId": "rdp-session-1", "connectionId": "rdp-abc123", "type": "vnc", "wsPort": 23000 }
]
}
```
### `setRdpConnections`
Save RDP/VNC connection definitions to `state.json`.
**Request payload:**
```json
{
"connections": [
{
"id": "rdp-abc123",
"label": "Work PC",
"hsUrl": "hs://abc...",
"type": "vnc",
"port": 5900,
"width": 1280,
"height": 720,
"username": "",
"passwordB64": "cGFzc3dvcmQ="
}
]
}
```
`passwordB64` is optional. When present it is a base64-encoded UTF-8 password string (`btoa(unescape(encodeURIComponent(password)))`). It is persisted in `state.json` and used automatically when starting a session.
---
## WebSocket protocol
### VNC
The dashboard connects to `ws://127.0.0.1:<wsPort>`. All frames are binary — raw RFB bytes passed transparently between noVNC and the VNC server. The native host does not interpret the protocol.
### RDP
**Native host → browser (connection established):**
```json
{ "type": "connected", "width": 1280, "height": 720 }
```
**Native host → browser (bitmap updates):**
```json
{
"type": "bitmap",
"destLeft": 100,
"destTop": 50,
"destRight": 300,
"destBottom": 150,
"width": 200,
"height": 100,
"bitsPerPixel": 32,
"isCompress": false,
"data": "<base64-encoded bitmap>"
}
```
**Native host → browser (session events):**
```json
{ "type": "close" }
{ "type": "error", "message": "Authentication failed" }
```
**Browser → native host (mouse input):**
```json
{ "type": "mouseMove", "x": 150, "y": 75 }
{ "type": "mouseButton", "x": 150, "y": 75, "button": 1, "isDown": true }
{ "type": "mouseButton", "x": 150, "y": 75, "button": 1, "isDown": false }
```
**Browser → native host (keyboard input):**
```json
{ "type": "keyEvent", "code": 65, "isDown": true }
{ "type": "keyEvent", "code": 65, "isDown": false }
{ "type": "keyUnicode", "code": 65, "isDown": true }
```
> **Note:** `keyEvent` sends a scancode via `sendKeyEventScancode`; `keyUnicode` sends a Unicode code point via `sendKeyEventUnicode`. Use `keyEvent` for special keys (arrows, function keys, modifiers) and `keyUnicode` for printable characters.
---
## Port allocation
| Range | Usage |
|-------|-------|
| 22000+ | Holesail client tunnel (one per session) |
| 23000+ | WebSocket server (one per session) |
---
## Saved connections
RDP/VNC connections are stored in `state.json` under `rdpConnections`:
```json
{
"rdpConnections": [
{
"id": "rdp-abc123",
"label": "Work PC",
"hsUrl": "hs://abc123...",
"type": "vnc",
"port": 5900,
"width": 1280,
"height": 720,
"username": "",
"passwordB64": "cGFzc3dvcmQ="
}
]
}
```
`passwordB64` is omitted when no password was saved. Connections are restored on startup. Active sessions are not persisted — they must be reconnected after a native host restart.
---
## Requirements
### VNC
- A VNC server on the remote machine (e.g. TigerVNC, RealVNC, macOS Screen Sharing)
- The VNC server must be accessible via a Holesail `hs://` key
### RDP
- Windows Remote Desktop enabled on the remote machine, or a compatible RDP server (e.g. xrdp on Linux)
- The RDP server must be accessible via a Holesail `hs://` key
---
## Troubleshooting
**Connection times out**
- The remote peer may be offline or the `hs://` key may be wrong
- Check `~/.holesail-browser/holesail-browser.log` for tunnel errors
**VNC: black screen or no updates**
- Verify the VNC server is running and listening on the expected port
- Try disconnecting and reconnecting
**RDP: authentication fails**
- Verify the username and password on the remote machine
- Ensure the remote machine has Remote Desktop enabled and the user has permission to connect
**RDP: slow or choppy display**
RDP performance depends on the latency of the Holesail tunnel and the speed of JSON serialization. For better performance, use VNC if the remote machine supports it.