# 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:`. 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": "" } ``` **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.