Skip to content

Latest commit

 

History

History
179 lines (140 loc) · 5.48 KB

README.md

File metadata and controls

179 lines (140 loc) · 5.48 KB

Web-SSHD

WTFPL

WebSocket-based SSH server.

This server is meant to be used with WebSSHD Credential Storage and Cloush (you may also use it for your own project if you like).

Features

  • Multi-target support
  • Local shell (local pseudo terminal)
  • Remote shell (connect to remote legacy SSH server and convert to WebSocket-based SSH protocol)

Known Issues

Currently, I have encountered two major issues on Windows 10:

  • Enabling conty for local shell results in infinite blocking when forking PTY at a certain probability (seems to be fixed since conty is no longer marked as experimental in latest node-pty).
  • Windows 10 Pro 1909, which is my Windows version, forked pseudo terminals always crash (exit with code 1 and undefined signal) when resizing the window (to be exact, shrinking the window size). This is probably an issue of Windows itself, or caused by some breaking changes of pseudo terminal APIs provided by Windows 10.

And one general issue:

  • Forking PTY is a blocking operation (node-pty), which WILL block the processing of other connections/requests or any other operations sharing the same Node.js main thread. If you have anti-virus software installed, forking of PTY might be further interfered or even interrupted.

Usage

Install

npm install git+https://github.com/Luluno01/web-sshd.git --save

Clone

If you want a standalone WebSSHD, clone this repository.

git clone https://github.com/Luluno01/web-sshd.git --depth=1

use as a Middleware

import * as socketIO from 'socket.io'
import * as http from 'http'
import { WebSSHD } from 'web-sshd'

// ...

const server = http.createServer()
const io = socketIO(server)
io.use(new WebSSHD({ shell: 'bash' }))

Enable Authentication

import * as socketIO from 'socket.io'
import * as http from 'http'
import { EventEmitter } from 'event'
import { WebSSHD } from 'web-sshd'

// ...

const server = http.createServer()
const io = socketIO(server)
const authenticator = new EventEmitter
// Your own authentication middleware goes here
// Notify `WebSSHD` that whether a `socket` is authenticated or not by
// `authentication.emit(socket.id, authenticated)`, where `authenticated` is a
// boolean value, `true` for authenticated
io.use(new WebSSHD({ shell: 'bash', authenticator }))

For example, see SimpleAuth middleware (for example purpose only, deprecated) and server.

Run Development Server

For integrated development server, simply run

npm run serve

For integrated development server with auto-reload (by using nodemon), simply run

npm run dev

Config

{
  "port": 3000,  // Listening port for development server
  "auth": {
    "myAuth1": {  // An authentication configuration
      "type": "salty-auth",
      "timeout": 5000,  // Authentication timeout (to disable timeout, remove this or set to `undefined`)
      "username": "websshd",  // User name
      "password": "b8240ca4f47411d6cbbd2e5d364b92713656200cad8ba2f4fb6243b9ca08e1100932cef95d4596cb62aca51aa99b1aed19064910b6dae960207f4593cb9450db"  // Password
      "salt": "7S=Q`-~TM,iUD.>]"  // Salt for password
    },
    "myAuth2": {  // Another authentication configuration
      "type": "salty-auth",
      "timeout": 5000,  // Authentication timeout (to disable timeout, remove this or set to `undefined`)
      "username": "websshd",  // User name
      "password": "44fcb1f2049c2b80400890922d891c356f73e9bf01c43063e86c4a8f037273796b0f50fe9b16b1776fb24e5eddfd59d08a81cfae7b5e64b035d8823ffab8829e"  // Password
      "salt": "rt.-|(=6)W}64y,{"  // Salt for password
    }
  },
  "targets": [
    {
      "type": "local",  // Local target
      "nsp": "/local",  // Socket.IO namespace (or the "path" part of the URL)
      "auth": "myAuth1",  // Use "myAuth1"
      "shell": "cmd.exe",  // Shell
      "conty": false  // Use CONTY or not (for Windows only)
    },
    {
      "nsp": "/remote1",
      "type": "remote",  // Remote target
      "auth": "myAuth2",
      "host": "192.168.0.1",  // Remote SSH host
      "port": "22",  // Remote SSH port
      "username": "cloush",  // Remote SSH user
      "password": "ohMywebsshd"  // Password for remote SSH
    },
    {
      "nsp": "/remote2",
      "type": "remote",
      "auth": "myAuth2",
      "host": "192.168.0.1",
      "port": "22",
      "username": "cloush",
      "privateKey": "~/.ssh/id_rsa"  // Private key for remote SSH
    }
  ],
  "cors": [  // Allowed origins
    "*:*"
  ]
}

Example Usage

Server:

npm run serve

Client:

const socket = io('/')
socket.on('salts', ([ staticSalt, dynamicSalt ]) => socket.emit('password', sha512(dynamicSalt + sha512(staticSalt + 'ohMywebsshd'))))
socket.emit('username', 'websshd')
socket.on('message', console.log)
socket.on('exit', console.warn)
socket.on('authenticated', () => {
  socket.send('ls\r')
  socket.send('exit\r')
})
socket.on('timeout', () => console.error('Authentication timeout'))
socket.on('username-or-password-incorrect', () => console.error('Username or password incorrect'))

License

WTFPL