diff --git a/CONFIG.md b/CONFIG.md
index 299c45a..68eea3e 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -84,7 +84,7 @@ Renamed and expanded options:
## Detailed Changes
### 1. Authentication Options
-- Added support for SSH private key authentication via `user.privateKey`
+- Added support for SSH private key authentication via `user.privateKey` and passphrase encrypted private keys via `user.passphrase`
- Removed `user.overridebasic` option
- Added keyboard-interactive authentication controls
@@ -128,7 +128,8 @@ These settings are now managed client-side.
"user": {
"name": null,
"password": null,
- "privateKey": null
+ "privateKey": null,
+ "passphrase": null
},
"ssh": {
"host": null,
@@ -138,7 +139,39 @@ These settings are now managed client-side.
"keepaliveInterval": 120000,
"keepaliveCountMax": 10,
"algorithms": {
- // ... algorithm configurations ...
+ "cipher": [
+ "aes128-ctr",
+ "aes192-ctr",
+ "aes256-ctr",
+ "aes128-gcm",
+ "aes128-gcm@openssh.com",
+ "aes256-gcm",
+ "aes256-gcm@openssh.com",
+ "aes256-cbc"
+ ],
+ "compress": [
+ "none",
+ "zlib@openssh.com",
+ "zlib"
+ ],
+ "hmac": [
+ "hmac-sha2-256",
+ "hmac-sha2-512",
+ "hmac-sha1"
+ ],
+ "kex": [
+ "ecdh-sha2-nistp256",
+ "ecdh-sha2-nistp384",
+ "ecdh-sha2-nistp521",
+ "diffie-hellman-group-exchange-sha256",
+ "diffie-hellman-group14-sha1"
+ ],
+ "serverHostKey": [
+ "ecdsa-sha2-nistp256",
+ "ecdsa-sha2-nistp384",
+ "ecdsa-sha2-nistp521",
+ "ssh-rsa"
+ ]
}
},
"options": {
diff --git a/ChangeLog.md b/ChangeLog.md
index cae9fda..c957620 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,6 +2,46 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+## [0.2.24](https://github.com/billchurch/WebSSH2/compare/v0.2.23...v0.2.24) (2024-12-04)
+
+
+### Bug Fixes
+
+* config.json.sample had `disableInteractiveAuth` set to `true`, changed to `false` ([0c5de9f](https://github.com/billchurch/WebSSH2/commit/0c5de9f))
+
+
+
+
+## [0.2.23](https://github.com/billchurch/WebSSH2/compare/v0.2.20...v0.2.23) (2024-12-04)
+
+
+### Bug Fixes
+
+* fixes document: config file moved from /usr/src to /usr/src/app [#372](https://github.com/billchurch/WebSSH2/issues/372) ([bc2d018](https://github.com/billchurch/WebSSH2/commit/bc2d018))
+* bug: support /ssh/host without a hostname [#373](https://github.com/billchurch/WebSSH2/issues/373) ([8c55c83](https://github.com/billchurch/WebSSH2/commit/8c55c83))
+* config change `privatekey` to `privateKey` for consistency with ssh2 module ([a176167](https://github.com/billchurch/WebSSH2/commit/a176167))
+* config move algorithims to ssh property ([52a989b](https://github.com/billchurch/WebSSH2/commit/52a989b))
+* pass full ssh error to browser ([27d9bfb](https://github.com/billchurch/WebSSH2/commit/27d9bfb))
+* username/password in config file no longer honored [#374](https://github.com/billchurch/WebSSH2/issues/374) ([4185df7](https://github.com/billchurch/WebSSH2/commit/4185df7))
+
+
+### Features
+
+* accept private key from client [#381](https://github.com/billchurch/WebSSH2/issues/381) ([829b5cd](https://github.com/billchurch/WebSSH2/commit/829b5cd))
+* add `ssh.disableInteractiveAuth` feature in support of [#379](https://github.com/billchurch/WebSSH2/issues/379) ([c7dfad0](https://github.com/billchurch/WebSSH2/commit/c7dfad0))
+* allow passphrase encrypted ssh keys from client [#381](https://github.com/billchurch/WebSSH2/issues/381) ([056e87b](https://github.com/billchurch/WebSSH2/commit/056e87b))
+* Allow setting environment variables from the URL [#371](https://github.com/billchurch/WebSSH2/issues/371) ([6ec0490](https://github.com/billchurch/WebSSH2/commit/6ec0490))
+* implement ssh private key auth [#379](https://github.com/billchurch/WebSSH2/issues/379) ([402b678](https://github.com/billchurch/WebSSH2/commit/402b678))
+* passphrase encrypted private key authentication [#382](https://github.com/billchurch/WebSSH2/issues/382) ([7961451](https://github.com/billchurch/WebSSH2/commit/7961451))
+* support uploading of ssh-rsa private key from client for authentication [#381](https://github.com/billchurch/WebSSH2/issues/381) ([2f4083f](https://github.com/billchurch/WebSSH2/commit/2f4083f))
+* update jsmasker to v1.4.0 ([3315df1](https://github.com/billchurch/WebSSH2/commit/3315df1))
+* update webssh_client to 0.2.26 ([a1b2e56](https://github.com/billchurch/WebSSH2/commit/a1b2e56))
+* update webssh2_client to 0.2.27 ([b511ce5](https://github.com/billchurch/WebSSH2/commit/b511ce5))
+* webssh2_client to 0.2.28 ([b4b7429](https://github.com/billchurch/WebSSH2/commit/b4b7429))
+
+
+
## [0.2.22](https://github.com/billchurch/WebSSH2/compare/v0.2.21...v0.2.22) (2024-11-30)
@@ -539,4 +579,4 @@ Mostly client (browser) related changes in this release
### Added
-- Initial proof of concept and release. For historical purposes only.
+- Initial proof of concept and release. For historical purposes only.
\ No newline at end of file
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index d224308..dbfc5ab 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -149,7 +149,7 @@ If you encounter issues:
4. Verify the ports (3000 and 2222) are available
5. Clear browser cache if changes aren't reflecting
-## Building for Production
+## Building for Production (client)
When ready to build for production:
diff --git a/README.md b/README.md
index 633c84e..b0f7862 100644
--- a/README.md
+++ b/README.md
@@ -196,7 +196,7 @@ For more information on SSH keyboard-interactive authentication, refer to [RFC 4
### SSH Private Key Authentication
-WebSSH2 supports SSH private key authentication when using the `/ssh/host/` endpoint with a private key configured in the server settings.
+WebSSH2 supports SSH private key authentication when using the `/ssh/host/` endpoint with a private key configured in the server settings or via the interactive method with the `/ssh/` endpoint.
#### Configuration
@@ -215,13 +215,17 @@ Private key authentication can only be configured through the `config.json` file
#### Key Requirements
- Only `ssh-rsa` type keys are supported
+- Passphrase encryption is supported, and if used the `passphrase` must be provided
- The private key must be in PEM format
- The key in `config.json` must be on a single line with `\n` as line separators
- Must include the appropriate header and footer:
```
-----BEGIN RSA PRIVATE KEY-----\n[... key content ...]\n-----END RSA PRIVATE KEY-----
```
-
+ or for encrypted keys:
+ ```
+ -----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-128-CBC,5930F19760F7FBBC865400940A89D954\n\n[... key content ...]\n-----END RSA PRIVATE KEY-----
+ ```
#### Generating a Private Key
To generate a new SSH private key, you can use the following command:
@@ -231,10 +235,10 @@ ssh-keygen -m PEM -t rsa -b 4096 -f ~/.ssh/id_rsa
#### Converting Your Private Key
-To convert your existing SSH private key into the correct format for `config.json`, you can use this bash command:
+Keys uploaded or pasted using the interactive mode through the `/ssh` endpoint can work as-is, however if using a key with `config.json` you must convert your existing SSH private key into the correct format (single line). A bash one-liner you can to accomplish this is:
```bash
-echo '"'$(cat ~/.ssh/id_rsa | tr '\n' '~' | sed 's/~/\\n/g')'"'
+echo ' "privateKey": "'$(cat ~/.ssh/id_rsa | tr '\n' '~' | sed 's/~/\\n/g')'"'
```
This command:
diff --git a/app/app.js b/app/app.js
index 6b9dfe7..8e9e9c0 100644
--- a/app/app.js
+++ b/app/app.js
@@ -3,6 +3,7 @@
import express from 'express'
import config from './config.js'
+import SSHConnection from './ssh.js'
import socketHandler from './socket.js'
import { createRoutes } from './routes.js'
import { applyMiddleware } from './middleware.js'
@@ -52,7 +53,7 @@ function initializeServer() {
const io = configureSocketIO(server, sessionMiddleware, config)
// Set up Socket.IO listeners
- socketHandler(io, config)
+ socketHandler(io, config, SSHConnection)
// Start the server
startServer(server, config)
diff --git a/app/config.js b/app/config.js
index ae0fd29..86776d0 100644
--- a/app/config.js
+++ b/app/config.js
@@ -23,6 +23,8 @@ const defaultConfig = {
user: {
name: null,
password: null,
+ privateKey: null,
+ passphrase: null,
},
ssh: {
host: null,
diff --git a/app/configSchema.js b/app/configSchema.js
index c4692e6..60dc100 100644
--- a/app/configSchema.js
+++ b/app/configSchema.js
@@ -28,6 +28,7 @@ const configSchema = {
name: { type: ['string', 'null'] },
password: { type: ['string', 'null'] },
privateKey: { type: ['string', 'null'] },
+ passphrase: { type: ['string', 'null'] },
},
required: ['name', 'password'],
},
diff --git a/app/socket.js b/app/socket.js
index a897ef4..1b1cfd8 100644
--- a/app/socket.js
+++ b/app/socket.js
@@ -3,20 +3,27 @@
import validator from 'validator'
import { EventEmitter } from 'events'
-import SSHConnection from './ssh.js'
import { createNamespacedDebug } from './logger.js'
import { SSHConnectionError, handleError } from './errors.js'
-const debug = createNamespacedDebug('socket')
import { isValidCredentials, maskSensitiveData, validateSshTerm } from './utils.js'
import { MESSAGES } from './constants.js'
+const debug = createNamespacedDebug('socket')
+
class WebSSH2Socket extends EventEmitter {
- constructor(socket, config) {
+ /**
+ * Creates a new WebSSH2Socket instance
+ * @param {Object} socket - The Socket.IO socket instance
+ * @param {Object} config - The application configuration
+ * @param {Function} SSHConnectionClass - The SSH connection class constructor
+ */
+ constructor(socket, config, SSHConnectionClass) {
super()
this.socket = socket
this.config = config
- this.ssh = new SSHConnection(config)
+ this.SSHConnectionClass = SSHConnectionClass
+ this.ssh = null
this.sessionState = {
authenticated: false,
username: null,
@@ -58,10 +65,6 @@ class WebSSH2Socket extends EventEmitter {
this.socket.emit('authentication', { action: 'request_auth' })
}
- this.ssh.on('keyboard-interactive', (data) => {
- this.handleKeyboardInteractive(data)
- })
-
this.socket.on('authenticate', (creds) => {
this.handleAuthenticate(creds)
})
@@ -129,6 +132,14 @@ class WebSSH2Socket extends EventEmitter {
creds.privateKey = this.config.user.privateKey
}
+ // Create new SSH connection instance
+ this.ssh = new this.SSHConnectionClass(this.config)
+
+ // Set up SSH event handlers
+ this.ssh.on("keyboard-interactive", data => {
+ this.handleKeyboardInteractive(data)
+ })
+
this.ssh
.connect(creds)
.then(() => {
@@ -342,6 +353,6 @@ class WebSSH2Socket extends EventEmitter {
}
}
-export default function (io, config) {
- io.on('connection', (socket) => new WebSSH2Socket(socket, config))
+export default function (io, config, SSHConnectionClass) {
+ io.on('connection', (socket) => new WebSSH2Socket(socket, config, SSHConnectionClass))
}
diff --git a/app/ssh.js b/app/ssh.js
index 02d24c8..5898db4 100644
--- a/app/ssh.js
+++ b/app/ssh.js
@@ -25,14 +25,30 @@ class SSHConnection extends EventEmitter {
}
/**
- * Validates the format of an RSA private key
+ * Validates the format of an RSA private key, supporting both standard and encrypted keys
* @param {string} key - The private key string to validate
* @returns {boolean} - Whether the key appears to be valid
*/
validatePrivateKey(key) {
- const keyPattern =
+ // Pattern for standard RSA private key
+ const standardKeyPattern =
/^-----BEGIN (?:RSA )?PRIVATE KEY-----\r?\n([A-Za-z0-9+/=\r\n]+)\r?\n-----END (?:RSA )?PRIVATE KEY-----\r?\n?$/
- return keyPattern.test(key)
+
+ // Pattern for encrypted RSA private key
+ const encryptedKeyPattern =
+ /^-----BEGIN RSA PRIVATE KEY-----\r?\n(?:Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: ([^\r\n]+)\r?\n\r?\n)([A-Za-z0-9+/=\r\n]+)\r?\n-----END RSA PRIVATE KEY-----\r?\n?$/
+
+ // Test for either standard or encrypted key format
+ return standardKeyPattern.test(key) || encryptedKeyPattern.test(key)
+ }
+
+ /**
+ * Checks if a private key is encrypted
+ * @param {string} key - The private key to check
+ * @returns {boolean} - Whether the key is encrypted
+ */
+ isEncryptedKey(key) {
+ return key.includes('Proc-Type: 4,ENCRYPTED')
}
/**
@@ -126,12 +142,68 @@ class SSHConnection extends EventEmitter {
this.handleKeyboardInteractive(name, instructions, lang, prompts, finish)
})
}
+ /**
+ * Handles keyboard-interactive authentication prompts.
+ * @param {string} name - The name of the authentication request.
+ * @param {string} instructions - The instructions for the keyboard-interactive prompt.
+ * @param {string} lang - The language of the prompt.
+ * @param {Array