Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1fb9487
chore: add .worktrees/ to .gitignore
billchurch Feb 26, 2026
382852f
feat(telnet): add types, constants, and ProtocolService interface
billchurch Feb 26, 2026
b364064
feat(telnet): add default config and environment variable mapping
billchurch Feb 26, 2026
aeaac31
feat(telnet): add IAC negotiation layer for telnet protocol
billchurch Feb 26, 2026
06af9a2
feat(telnet): add expect-style authenticator for telnet login prompts
billchurch Feb 26, 2026
8077922
feat(telnet): add TelnetConnectionPool for managing telnet connections
billchurch Feb 26, 2026
d95672d
feat(telnet): add TelnetServiceImpl assembling negotiation, auth, and…
billchurch Feb 26, 2026
92b4a71
feat(telnet): add Express routes for /telnet/ mirroring SSH route pat…
billchurch Feb 26, 2026
e644107
feat(telnet): wire Socket.IO telnet namespace and protocol-aware adap…
billchurch Feb 26, 2026
ade0a19
fix: resolve lint errors in telnet test and config files
billchurch Feb 26, 2026
22519e3
docs: add telnet configuration to CONFIG-JSON.md and ENVIRONMENT-VARI…
billchurch Feb 26, 2026
f95012c
fix(telnet): address code review findings - security and robustness
billchurch Feb 26, 2026
6188b25
feat(telnet): add option state tracking and buildProactiveOffers()
billchurch Feb 26, 2026
813b369
feat(telnet): make handleDo() state-aware to prevent duplicate WILL
billchurch Feb 26, 2026
104edb8
feat(telnet): add IAC debug logging (webssh2:telnet:iac)
billchurch Feb 26, 2026
0e21ade
fix(telnet): replace unsolicited NAWS with proactive option offers
billchurch Feb 26, 2026
f556f5e
fix: resolve SonarQube issues across server codebase
billchurch Feb 27, 2026
4e72ebb
chore: update webssh2_client to 3.5.0-telnet.1, add rollup darwin-arm64
billchurch Feb 27, 2026
5f532c6
fix: remove platform-specific @rollup/rollup-darwin-arm64 from depend…
billchurch Feb 27, 2026
d460cdd
docs: add telnet routes and feature documentation [skip ci]
billchurch Mar 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ jobs:
type=raw,value=${{ steps.release_meta.outputs.semver_full }},enable=${{ steps.release_meta.outputs.has_release == 'true' }}
type=raw,value=${{ steps.release_meta.outputs.semver_minor }},enable=${{ steps.release_meta.outputs.has_release == 'true' }}
type=raw,value=${{ steps.release_meta.outputs.semver_major }},enable=${{ steps.release_meta.outputs.has_release == 'true' }}
type=ref,event=branch,enable=${{ github.event_name == 'push' && github.ref != 'refs/heads/main' }}
type=ref,event=branch,enable=${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref != 'refs/heads/main' }}
type=sha

- name: Build and push docker image
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ dist/
.migration/

.regression/
.worktrees/
config.json.backup

release-artifacts/
Expand Down
89 changes: 89 additions & 0 deletions DOCS/api/ROUTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,95 @@ fetch('/ssh', {
4. **Use SSO integration** when possible for enterprise deployments
5. **Configure CORS properly** via `http.origins` configuration

## Telnet Routes

> **Telnet support is disabled by default.** Set `WEBSSH2_TELNET_ENABLED=true` or `telnet.enabled: true` in `config.json` to enable these routes. See [Configuration](../configuration/CONFIG-JSON.md) for all telnet options.

> **Security Warning:** Telnet transmits all data, including credentials, in plain text. Only use on trusted, isolated networks. Prefer SSH whenever possible.

### 1. `/telnet` - Interactive Login

- **URL:** `http(s)://your-webssh2-server/telnet`
- **Method:** GET
- **Features:**
- Interactive login form (telnet-specific UI)
- Security warning banner displayed to users
- Expect-style authentication with configurable prompt patterns
- SFTP and host key features hidden (SSH-only)

### 2. `/telnet/host/:host` - Host-Locked Mode

- **URL:** `http(s)://your-webssh2-server/telnet/host/:host`
- **Method:** GET
- **Features:**
- Direct connection to a specific telnet host
- Optional `port` parameter (e.g., `?port=2323`, default: 23)
- Host is locked and cannot be changed by the user

### 3. `/telnet` - HTTP POST Auth

- **URL:** `http(s)://your-webssh2-server/telnet`
- **Method:** POST
- **Content-Type:** `application/json`
- **Features:**
- SSO form submission for telnet connections
- Same integration patterns as SSH POST auth

#### Request Body

```json
{
"username": "string",
"password": "string",
"host": "string",
"port": 23
}
```

### 4. `/telnet/host/:host` - POST with Host Locked

- **URL:** `http(s)://your-webssh2-server/telnet/host/:host`
- **Method:** POST
- **Features:**
- SSO form submission with host pre-set
- Host parameter locked from URL path

### 5. `/telnet/config` - Telnet Configuration Endpoint

- **URL:** `http(s)://your-webssh2-server/telnet/config`
- **Method:** GET
- **Purpose:** Exposes telnet server configuration to clients
- **Response:** JSON with `protocol`, `defaultPort`, and `term`

```json
{
"protocol": "telnet",
"defaultPort": 23,
"term": "vt100"
}
```

### Telnet Query Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `port` | integer | 23 | Telnet port to connect to |
| `header` | string | - | Header text override |
| `headerBackground` | string | green | Header background color |

### Telnet Examples

```text
http://localhost:2222/telnet/host/192.168.1.1?port=2323
```

```bash
# Docker with telnet enabled
docker run --rm -p 2222:2222 \
-e WEBSSH2_TELNET_ENABLED=true \
ghcr.io/billchurch/webssh2:latest
```

## Related Documentation

- [Authentication Overview](../features/AUTHENTICATION.md)
Expand Down
123 changes: 123 additions & 0 deletions DOCS/configuration/CONFIG-JSON.md
Original file line number Diff line number Diff line change
Expand Up @@ -588,3 +588,126 @@ See [ENVIRONMENT-VARIABLES.md](./ENVIRONMENT-VARIABLES.md) for details.
- `WEBSSH2_SSH_SFTP_TIMEOUT`

See [ENVIRONMENT-VARIABLES.md](./ENVIRONMENT-VARIABLES.md) for details on environment variable format and examples.

### Telnet Configuration

> **Security Warning:** Telnet transmits all data, including credentials, in **plain text**. It should only be used on trusted networks or for connecting to legacy devices that do not support SSH. Never expose telnet endpoints to the public internet without additional network-level protections (e.g., VPN, firewall rules).

WebSSH2 includes optional telnet support for connecting to legacy devices and systems that do not support SSH. Telnet is **disabled by default** and must be explicitly enabled.

#### Configuration Options

- `telnet.enabled` (boolean, default: `false`): Enable telnet support. When `false`, all `/telnet` routes return 404.

- `telnet.defaultPort` (number, default: `23`): Default telnet port used when no port is specified in the connection request.

- `telnet.timeout` (number, default: `30000`): Connection timeout in milliseconds. If the connection cannot be established within this time, it is aborted.

- `telnet.term` (string, default: `"vt100"`): Terminal type sent during TERMINAL-TYPE negotiation. Common values include `vt100`, `vt220`, `xterm`, and `ansi`.

- `telnet.auth.loginPrompt` (string, regex, default: `"login:\\s*$"`): Regular expression pattern used to detect the login prompt. The authenticator watches incoming data for this pattern to know when to send the username.

- `telnet.auth.passwordPrompt` (string, regex, default: `"[Pp]assword:\\s*$"`): Regular expression pattern used to detect the password prompt. The authenticator watches incoming data for this pattern to know when to send the password.

- `telnet.auth.failurePattern` (string, regex, default: `"Login incorrect|Access denied|Login failed"`): Regular expression pattern used to detect authentication failure. When matched, the connection reports an authentication error.

- `telnet.auth.expectTimeout` (number, default: `10000`): Maximum time in milliseconds to wait for prompt pattern matches during authentication. If no prompt is detected within this time, the authenticator falls back to pass-through mode, forwarding raw data to the terminal.

- `telnet.allowedSubnets` (string[], default: `[]`): Restrict which hosts can be connected to via telnet. Uses the same CIDR notation format as `ssh.allowedSubnets`. When empty, all hosts are allowed.

#### Default Telnet Configuration

```json
{
"telnet": {
"enabled": false,
"defaultPort": 23,
"timeout": 30000,
"term": "vt100",
"auth": {
"loginPrompt": "login:\\s*$",
"passwordPrompt": "[Pp]assword:\\s*$",
"failurePattern": "Login incorrect|Access denied|Login failed",
"expectTimeout": 10000
},
"allowedSubnets": []
}
}
```

> **Note:** Telnet is disabled by default. Set `enabled` to `true` to activate telnet support.

#### Use Cases

**Enable telnet for legacy network devices:**

```json
{
"telnet": {
"enabled": true,
"defaultPort": 23,
"term": "vt100"
}
}
```

This enables telnet with default authentication patterns, suitable for most Linux/Unix systems and network equipment.

**Custom prompts for non-standard devices:**

```json
{
"telnet": {
"enabled": true,
"auth": {
"loginPrompt": "Username:\\s*$",
"passwordPrompt": "Password:\\s*$",
"failurePattern": "Authentication failed|Bad password|Access denied",
"expectTimeout": 15000
}
}
}
```

Some devices use non-standard prompt text. Adjust the regex patterns to match your equipment.

**Restrict telnet to specific subnets:**

```json
{
"telnet": {
"enabled": true,
"allowedSubnets": ["10.0.0.0/8", "192.168.1.0/24"],
"timeout": 15000
}
}
```

Only allow telnet connections to hosts within the specified private network ranges.

**Disable telnet (default):**

```json
{
"telnet": {
"enabled": false
}
}
```

Telnet is disabled by default. This configuration is only needed if you want to explicitly disable it after previously enabling it.

#### Environment Variables

These options can also be configured via environment variables:

- `WEBSSH2_TELNET_ENABLED`
- `WEBSSH2_TELNET_DEFAULT_PORT`
- `WEBSSH2_TELNET_TIMEOUT`
- `WEBSSH2_TELNET_TERM`
- `WEBSSH2_TELNET_AUTH_LOGIN_PROMPT`
- `WEBSSH2_TELNET_AUTH_PASSWORD_PROMPT`
- `WEBSSH2_TELNET_AUTH_FAILURE_PATTERN`
- `WEBSSH2_TELNET_AUTH_EXPECT_TIMEOUT`

See [ENVIRONMENT-VARIABLES.md](./ENVIRONMENT-VARIABLES.md) for details.
60 changes: 60 additions & 0 deletions DOCS/configuration/ENVIRONMENT-VARIABLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,66 @@ WEBSSH2_SSH_SFTP_TRANSFER_RATE_LIMIT_BYTES_PER_SEC=0
WEBSSH2_SSH_SFTP_ENABLED=false
```

### Telnet Configuration

> **Security Warning:** Telnet transmits all data, including credentials, in **plain text**. Only use telnet on trusted networks or for legacy devices that do not support SSH.

| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `WEBSSH2_TELNET_ENABLED` | boolean | `false` | Enable or disable telnet support. When disabled, `/telnet` routes return 404 |
| `WEBSSH2_TELNET_DEFAULT_PORT` | number | `23` | Default telnet port |
| `WEBSSH2_TELNET_TIMEOUT` | number | `30000` | Connection timeout in milliseconds |
| `WEBSSH2_TELNET_TERM` | string | `vt100` | Terminal type for TERMINAL-TYPE negotiation |
| `WEBSSH2_TELNET_AUTH_LOGIN_PROMPT` | string | `login:\s*$` | Regex pattern to detect login prompt |
| `WEBSSH2_TELNET_AUTH_PASSWORD_PROMPT` | string | `[Pp]assword:\s*$` | Regex pattern to detect password prompt |
| `WEBSSH2_TELNET_AUTH_FAILURE_PATTERN` | string | `Login incorrect\|Access denied\|Login failed` | Regex pattern to detect authentication failure |
| `WEBSSH2_TELNET_AUTH_EXPECT_TIMEOUT` | number | `10000` | Max time (ms) to wait for prompt matches before falling back to pass-through mode |
| `WEBSSH2_TELNET_ALLOWED_SUBNETS` | array | `[]` | Comma-separated CIDR ranges restricting which hosts can be connected to via telnet (e.g., `10.0.0.0/8,192.168.0.0/16`) |

#### Telnet Configuration Examples

**Enable telnet with defaults:**

```bash
# Enable telnet support (disabled by default)
WEBSSH2_TELNET_ENABLED=true
```

**Custom prompts for non-standard devices:**

```bash
# Enable telnet
WEBSSH2_TELNET_ENABLED=true

# Custom prompt patterns for network equipment
WEBSSH2_TELNET_AUTH_LOGIN_PROMPT="Username:\\s*$"
WEBSSH2_TELNET_AUTH_PASSWORD_PROMPT="Password:\\s*$"
WEBSSH2_TELNET_AUTH_FAILURE_PATTERN="Authentication failed|Bad password|Access denied"

# Longer timeout for slow devices
WEBSSH2_TELNET_AUTH_EXPECT_TIMEOUT=15000
```

**Docker with telnet enabled:**

```bash
docker run -d \
-p 2222:2222 \
-e WEBSSH2_TELNET_ENABLED=true \
-e WEBSSH2_TELNET_DEFAULT_PORT=23 \
-e WEBSSH2_TELNET_TERM=vt100 \
webssh2:latest
```

**Disable telnet (default):**

```bash
# Telnet is disabled by default, but you can explicitly disable it
WEBSSH2_TELNET_ENABLED=false
```

See [CONFIG-JSON.md](./CONFIG-JSON.md) for `config.json` examples and additional details.

#### Authentication Allow List

`WEBSSH2_AUTH_ALLOWED` lets administrators enforce which SSH authentication methods can be used. Supported tokens are:
Expand Down
42 changes: 40 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

![Orthrus Mascot](DOCS/images/orthrus2.png)

WebSSH2 is an HTML5 web-based terminal emulator and SSH client. It uses SSH2 as a client on a host to proxy a Websocket / Socket.io connection to an SSH2 server.
WebSSH2 is an HTML5 web-based terminal emulator and SSH client with optional telnet support. It uses SSH2 as a client on a host to proxy a Websocket / Socket.io connection to an SSH2 server.

![WebSSH2 Screenshot](DOCS/images/Screenshot_sm.png)

Expand All @@ -30,7 +30,7 @@ npm install --production
npm start
```

Access WebSSH2 at: `http://localhost:2222/ssh`
Access WebSSH2 at: `http://localhost:2222/ssh` (or `http://localhost:2222/telnet` if telnet is enabled)

### Official Containers

Expand Down Expand Up @@ -129,6 +129,7 @@ Need the Docker Hub mirror instead? Use `docker.io/billchurch/webssh2:latest`.
- [Exec Channel](./DOCS/features/EXEC-CHANNEL.md) - Non-interactive command execution
- [Environment Forwarding](./DOCS/features/ENVIRONMENT-FORWARDING.md) - Pass environment variables
- [Host Key Verification](#host-key-verification) - MITM protection and key management
- [Telnet Support](#telnet-support) - Optional telnet for legacy devices

### Development

Expand Down Expand Up @@ -158,6 +159,7 @@ Need the Docker Hub mirror instead? Use `docker.io/billchurch/webssh2:latest`.
- 🌍 **Environment Variables** - Pass custom environment to SSH sessions
- 🛡️ **Subnet Restrictions** - IPv4/IPv6 CIDR subnet validation for access control
- 📁 **SFTP Support** - File transfer capabilities (v2.6.0+)
- 📡 **Telnet Support** - Optional telnet protocol for legacy devices (disabled by default)

## Host Key Verification

Expand Down Expand Up @@ -338,6 +340,42 @@ If you receive frequent mismatches for hosts you did not change, investigate for
**Client verification times out:**
When using `prompt` mode, the client has 30 seconds to respond to a `hostkey:verify` event. If the client does not respond in time, the connection is refused. Ensure the client application handles the `hostkey:verify` Socket.IO event.

## Telnet Support

WebSSH2 includes optional telnet protocol support for connecting to legacy devices such as network switches, routers, and older systems that don't support SSH. Telnet is **disabled by default** and must be explicitly enabled.

> **Security Warning:** Telnet transmits all data in plain text, including credentials. Only use on trusted, isolated networks.

### Enabling Telnet

```bash
# Via environment variable
docker run --rm -p 2222:2222 \
-e WEBSSH2_TELNET_ENABLED=true \
ghcr.io/billchurch/webssh2:latest
```

Or in `config.json`:

```json
{
"telnet": {
"enabled": true
}
}
```

Once enabled, access telnet at `http://localhost:2222/telnet` or connect to a specific host at `http://localhost:2222/telnet/host/192.168.1.1`.

### Telnet Features

- **Expect-style authentication** - Configurable regex patterns for login/password prompt detection
- **IAC negotiation** - Full RFC 854/857/858/1073/1091 support (ECHO, SGA, NAWS, TERMINAL_TYPE)
- **Subnet restrictions** - Limit which hosts can be reached via telnet
- **Security warnings** - Visual banner in the client UI reminding users of telnet's insecurity

For full configuration options, see [Environment Variables](./DOCS/configuration/ENVIRONMENT-VARIABLES.md) and [Config JSON](./DOCS/configuration/CONFIG-JSON.md).

## Release Workflow Overview

- **Development**: Run `npm install` (or `npm ci`) and continue using scripts such as `npm run dev` and `npm run build`. The TypeScript sources remain the source of truth.
Expand Down
Loading