@@ -63,7 +63,7 @@ Holesail Browser is composed of three parts: a browser extension, a native host
|
||||
| `https-proxy.js` | HTTPS reverse proxy on `127.0.0.1:8443`. Presents a wildcard `*.hole.sail` TLS cert. Reads the `Host` header, looks up the local tunnel port, and proxies HTTP. Returns a 502 HTML page for unknown hostnames. |
|
||||
| `connect-proxy.js` | HTTP CONNECT proxy on `127.0.0.1:8442`. Accepts `CONNECT hostname:443`, replies `200 Connection established`, then pipes the raw TCP stream to `127.0.0.1:8443`. |
|
||||
| `certificate-authority.js` | Generates a 2048-bit RSA root CA (10-year validity) using `node-forge`. Signs wildcard `*.hole.sail` domain certs (1-year). Installs the CA into the OS trust store. Fingerprint-verifies to detect stale entries. |
|
||||
| `ssh-manager.js` | Per SSH session: starts a Holesail client tunnel, spawns `ssh` with a real PTY via `tt-native` (`forkpty`), starts a `bare-ws` WebSocket server, and bridges PTY ↔ WebSocket. |
|
||||
| `ssh-manager.js` | Per SSH session: starts a Holesail client tunnel, spawns `ssh` with a real PTY via `tt-native` (`forkpty`), starts a `bare-ws` WebSocket server, and bridges PTY ↔ WebSocket. SSH is spawned only after the browser WebSocket client connects and sends a ready-signal. Password delivery uses `SSH_ASKPASS` + a named FIFO — public key auth is tried first; a password prompt appears in xterm.js only if key auth fails and no password is saved. |
|
||||
| `rdp-manager.js` | Per RDP/VNC session: starts a Holesail client tunnel, starts a WebSocket server. VNC: transparent byte pipe. RDP: `node-rdpjs-2` client, converts bitmap updates to JSON. |
|
||||
| `backup-manager.js` | Creates/restores `tar.gz` backups of `state.json` + all certificates. Supports create, list, restore, delete, and auto-prune by retention count. |
|
||||
|
||||
|
||||
+5
-2
@@ -184,12 +184,15 @@ Start an SSH session.
|
||||
"connectionId": "ssh-abc123",
|
||||
"hsUrl": "hs://abc123...",
|
||||
"username": "root",
|
||||
"port": 22,
|
||||
"password": "",
|
||||
"cols": 80,
|
||||
"rows": 24
|
||||
"rows": 24,
|
||||
"label": "My Server"
|
||||
}
|
||||
```
|
||||
|
||||
`password` is optional. If provided, it is delivered to SSH automatically via `SSH_ASKPASS` and a named FIFO — it is never written to disk or passed on the command line. If omitted, SSH tries public key auth first; if that fails, a password prompt appears in the xterm.js terminal.
|
||||
|
||||
**Response payload:**
|
||||
```json
|
||||
{ "ok": true, "sessionId": "ssh-session-1", "wsPort": 21000, "tunnelPort": 20000 }
|
||||
|
||||
+5
-4
@@ -101,11 +101,12 @@ The PAC script routes only `*.hole.sail` traffic through the proxy. All other tr
|
||||
|
||||
## SSH security
|
||||
|
||||
SSH sessions use the system `ssh` binary with its default security settings:
|
||||
SSH sessions use the system `ssh` binary. Authentication is tried in order: public key, then password.
|
||||
|
||||
- `StrictHostKeyChecking` is enabled by default — the first connection to a new host will prompt for host key verification
|
||||
- SSH keys and `~/.ssh/known_hosts` are used normally
|
||||
- The Holesail tunnel provides transport; `ssh`'s own encryption is layered on top
|
||||
- **Public key auth** — keys from `~/.ssh/` and `ssh-agent` are used automatically; no password prompt appears if a key is accepted
|
||||
- **Password auth** — passwords are never written to disk; a saved password is held in memory only and delivered to SSH via `SSH_ASKPASS` and a named FIFO pipe (not via the process environment or command line); interactive passwords are collected in xterm.js and delivered the same way
|
||||
- **`StrictHostKeyChecking=no` / `UserKnownHostsFile=/dev/null`** — host key verification is disabled for Holesail tunnels because the remote host's identity is already established by the `hs://` public key (Noise mutual authentication at the tunnel layer); adding known-hosts entries for `127.0.0.1` would be misleading since the port changes per session
|
||||
- The Holesail tunnel provides transport; `ssh`'s own encryption is layered on top, giving double encryption
|
||||
|
||||
---
|
||||
|
||||
|
||||
+63
-27
@@ -20,7 +20,37 @@ ssh binary (system ssh)
|
||||
Remote SSH daemon
|
||||
```
|
||||
|
||||
The `ssh` binary is the system's own SSH client — all its features (key auth, agent forwarding, known hosts, etc.) work as normal. The Holesail tunnel provides the transport; `ssh` sees it as a plain TCP connection to `127.0.0.1`.
|
||||
The `ssh` binary is the system's own SSH client — all its features (key auth, agent forwarding, etc.) work as normal. The Holesail tunnel provides the transport; `ssh` sees it as a plain TCP connection to `127.0.0.1`.
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
SSH authentication is handled entirely by the system `ssh` binary. The following methods are supported, tried in order:
|
||||
|
||||
### 1. Public key (automatic, no prompt)
|
||||
|
||||
If you have a key in `~/.ssh/` (e.g. `id_rsa`, `id_ed25519`) or loaded in `ssh-agent`, it is tried first. If the remote server accepts it, you are logged in with no prompt at all.
|
||||
|
||||
### 2. Password — saved on the connection
|
||||
|
||||
If you enter a password when saving the connection, it is stored in memory for the session (never written to disk). When connecting, the password is delivered to SSH automatically via a secure helper mechanism — no prompt appears.
|
||||
|
||||
### 3. Password — typed interactively
|
||||
|
||||
If no public key is available and no password is saved, the terminal displays a password prompt (`[email protected]'s password:`). Type your password and press Enter. The input is masked (no echo).
|
||||
|
||||
> **Note:** The native messaging host launched by Chrome has no controlling terminal (`/dev/tty`), so SSH cannot read passwords directly. Holesail Browser handles this transparently using `SSH_ASKPASS` and a named FIFO pipe — the password prompt appears in xterm.js and the typed password is securely forwarded to SSH without exposing it in the process environment or on disk.
|
||||
|
||||
### Authentication order summary
|
||||
|
||||
| Scenario | What happens |
|
||||
|----------|-------------|
|
||||
| Public key in `~/.ssh/` or `ssh-agent` | Logged in silently, no prompt |
|
||||
| Password saved on connection | Password delivered automatically, no prompt |
|
||||
| No key, no saved password | Password prompt appears in xterm.js |
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -29,17 +59,19 @@ The `ssh` binary is the system's own SSH client — all its features (key auth,
|
||||
1. Open the dashboard → **SSH**
|
||||
2. Click **Add Connection**
|
||||
3. Enter a label, the `hs://` key for the remote peer, and the username
|
||||
4. Click **Save** — the connection is stored in `state.json`
|
||||
4. Optionally enter a password (leave blank to type it each time, or to use a public key)
|
||||
5. Click **Save** — the connection definition is stored in `state.json`; the password is kept in memory only and is not persisted
|
||||
|
||||
### Connecting
|
||||
|
||||
1. Click **Connect** next to a saved connection
|
||||
2. An xterm.js terminal opens in the dashboard
|
||||
3. The native host starts a Holesail tunnel to the remote peer, then spawns `ssh`
|
||||
4. If authentication requires a password and none is saved, a prompt appears in the terminal
|
||||
|
||||
### Terminal resize
|
||||
|
||||
The terminal resizes automatically when you resize the dashboard window. Resize events are sent to the native host, which calls `ioctl(TIOCSWINSZ)` on the PTY and sends an SSH window-change request.
|
||||
The terminal resizes automatically when you resize the dashboard window. Resize events are sent to the native host, which calls `ioctl(TIOCSWINSZ)` on the PTY and sends an SSH window-change request to the remote sshd.
|
||||
|
||||
### Disconnecting
|
||||
|
||||
@@ -57,15 +89,17 @@ Start a new SSH session.
|
||||
```json
|
||||
{
|
||||
"connectionId": "ssh-abc123",
|
||||
"hostname": "myserver.hole.sail",
|
||||
"hsUrl": "hs://abc123...",
|
||||
"username": "root",
|
||||
"port": 22,
|
||||
"password": "",
|
||||
"cols": 80,
|
||||
"rows": 24
|
||||
"rows": 24,
|
||||
"label": "My Server"
|
||||
}
|
||||
```
|
||||
|
||||
The `password` field is optional. If omitted or empty, SSH will use public key auth or prompt interactively.
|
||||
|
||||
**Response payload:**
|
||||
```json
|
||||
{
|
||||
@@ -120,7 +154,7 @@ List active SSH sessions.
|
||||
|
||||
### `setSshConnections`
|
||||
|
||||
Save SSH connection definitions to `state.json`.
|
||||
Save SSH connection definitions to `state.json`. Passwords are stripped before saving — they are session-only.
|
||||
|
||||
**Request payload:**
|
||||
```json
|
||||
@@ -137,7 +171,10 @@ Save SSH connection definitions to `state.json`.
|
||||
|
||||
The dashboard connects to `ws://127.0.0.1:<wsPort>` after receiving the `startSshSession` response.
|
||||
|
||||
SSH is not spawned until the WebSocket client connects and sends a ready-signal (`\x00`). This ensures the terminal is live before SSH starts, so any prompts (password, host key) are visible immediately.
|
||||
|
||||
**Browser → native host:**
|
||||
- First byte `\x00`: ready-signal (triggers SSH spawn)
|
||||
- Binary frames: raw terminal input (keystrokes, paste)
|
||||
- Text frames: JSON control messages
|
||||
```json
|
||||
@@ -146,10 +183,6 @@ The dashboard connects to `ws://127.0.0.1:<wsPort>` after receiving the `startSs
|
||||
|
||||
**Native host → browser:**
|
||||
- Binary frames: raw PTY output (terminal data)
|
||||
- Text frames: JSON control messages
|
||||
```json
|
||||
{ "type": "exit", "code": 0 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -164,19 +197,9 @@ Ports are allocated sequentially and released when the session ends.
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- The `ssh` binary must be installed on the machine running the native host
|
||||
- macOS: included with the OS
|
||||
- Linux: install `openssh-client`
|
||||
- Windows: install OpenSSH via Windows Optional Features or Git for Windows
|
||||
- The remote host must be running an SSH daemon accessible via a Holesail `hs://` key
|
||||
|
||||
---
|
||||
|
||||
## Saved connections
|
||||
|
||||
SSH connections are stored in `state.json` under `sshConnections`:
|
||||
SSH connections are stored in `state.json` under `sshConnections`. Passwords are **never** written to disk — they are held in memory for the current session only and must be re-entered after a native host restart.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -191,7 +214,15 @@ SSH connections are stored in `state.json` under `sshConnections`:
|
||||
}
|
||||
```
|
||||
|
||||
Connections are restored on startup. Active sessions (the running PTY processes) are not persisted — they must be reconnected after a native host restart.
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- The `ssh` binary must be installed on the machine running the native host
|
||||
- macOS: included with the OS
|
||||
- Linux: install `openssh-client`
|
||||
- Windows: install OpenSSH via Windows Optional Features or Git for Windows
|
||||
- The remote host must be running an SSH daemon accessible via a Holesail `hs://` key
|
||||
|
||||
---
|
||||
|
||||
@@ -199,16 +230,21 @@ Connections are restored on startup. Active sessions (the running PTY processes)
|
||||
|
||||
**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
|
||||
The remote peer may be offline or the `hs://` key may be wrong. Check `~/.holesail-browser/holesail-browser.log` for tunnel errors.
|
||||
|
||||
**`ssh: command not found`**
|
||||
|
||||
The `ssh` binary is not in the PATH seen by the native host. Install OpenSSH or ensure `ssh` is in `/usr/bin/ssh` (macOS/Linux) or available in `PATH` (Windows).
|
||||
|
||||
**Host key verification fails**
|
||||
**Permission denied (publickey,password)**
|
||||
|
||||
SSH's `StrictHostKeyChecking` applies normally. If you see a host key warning, accept it in the terminal or add the host to `~/.ssh/known_hosts`.
|
||||
- If you have a public key but it is not accepted by the server, SSH falls back to password auth and shows a prompt in the terminal
|
||||
- If you enter the wrong password, SSH exits with "Permission denied" — reconnect and try again
|
||||
- If no authentication method works, check that the username is correct and that the server allows password auth
|
||||
|
||||
**Password prompt does not appear**
|
||||
|
||||
This should not happen with the current implementation. If it does, check `~/.holesail-browser/holesail-browser.log` for `WARNING: askpass setup failed` — this would indicate that `mkfifo` is not available on the system.
|
||||
|
||||
**Terminal display is garbled**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user