feat: ssh keyboard-interactive authentication support
This commit is contained in:
parent
1c4bfc2680
commit
0f3c7ab230
5 changed files with 285 additions and 175 deletions
58
README.md
58
README.md
|
@ -13,6 +13,7 @@ WebSSH2 is an HTML5 web-based terminal emulator and SSH client. It uses SSH2 as
|
||||||
- [Docker Setup](#docker-setup)
|
- [Docker Setup](#docker-setup)
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Configuration](#configuration)
|
- [Configuration](#configuration)
|
||||||
|
- [Features](#features)
|
||||||
- [Routes](#routes)
|
- [Routes](#routes)
|
||||||
- [Deprecation Notice](#deprecation-notice)
|
- [Deprecation Notice](#deprecation-notice)
|
||||||
- [Tips](#tips)
|
- [Tips](#tips)
|
||||||
|
@ -68,7 +69,7 @@ http://localhost:2222/ssh/host/127.0.0.1
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll be prompted for SSH credentials via HTTP Basic Authentication.
|
You'll be prompted for SSH credentials via HTTP Basic Authentication.
|
||||||
|
P
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### GET Parameters
|
### GET Parameters
|
||||||
|
@ -105,6 +106,61 @@ Edit `config.json` to customize the following options:
|
||||||
|
|
||||||
For detailed SSH algorithm configurations, refer to the full config file.
|
For detailed SSH algorithm configurations, refer to the full config file.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Keyboard Interactive Authentication
|
||||||
|
|
||||||
|
Keyboard Interactive authentication provides a flexible way to handle various authentication scenarios, including multi-factor authentication.
|
||||||
|
|
||||||
|
#### How it works
|
||||||
|
|
||||||
|
1. When the SSH server requests Keyboard Interactive authentication, WebSSH2 can handle it in two ways:
|
||||||
|
a) Automatically (default behavior)
|
||||||
|
b) By prompting the user through the web interface
|
||||||
|
|
||||||
|
2. In automatic mode:
|
||||||
|
- If all prompts contain the word "password" (case-insensitive), WebSSH2 will automatically respond using the password provided during the initial connection attempt.
|
||||||
|
- If any prompt doesn't contain "password", all prompts will be forwarded to the web client for user input.
|
||||||
|
|
||||||
|
3. When prompts are sent to the web client:
|
||||||
|
- A dialog box appears in the user's browser, displaying all prompts from the SSH server.
|
||||||
|
- The user can input responses for each prompt.
|
||||||
|
- Responses are sent back to the SSH server to complete the authentication process.
|
||||||
|
|
||||||
|
#### Configuration Options
|
||||||
|
|
||||||
|
You can customize the Keyboard Interactive authentication behavior using the following option in your `config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ssh": {
|
||||||
|
"alwaysSendKeyboardInteractivePrompts": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `alwaysSendKeyboardInteractivePrompts` (boolean, default: false):
|
||||||
|
- When set to `true`, all Keyboard Interactive prompts will always be sent to the web client, regardless of their content.
|
||||||
|
- When set to `false` (default), WebSSH2 will attempt to automatically handle password prompts and only send non-password prompts to the web client.
|
||||||
|
|
||||||
|
#### Use Cases
|
||||||
|
|
||||||
|
1. **Simple Password Authentication**:
|
||||||
|
With default settings, if the SSH server uses Keyboard Interactive for password authentication, WebSSH2 will automatically handle it without additional user interaction.
|
||||||
|
|
||||||
|
2. **Multi-Factor Authentication**:
|
||||||
|
For SSH servers requiring additional factors (e.g., OTP), WebSSH2 will present prompts to the user through the web interface.
|
||||||
|
|
||||||
|
3. **Always Prompt User**:
|
||||||
|
By setting `alwaysSendKeyboardInteractivePrompts` to `true`, you can ensure that users always see and respond to all authentication prompts, which can be useful for security-sensitive environments or for debugging purposes.
|
||||||
|
|
||||||
|
#### Security Considerations
|
||||||
|
|
||||||
|
- The automatic password handling feature is designed for convenience but may not be suitable for high-security environments. Consider setting `alwaysSendKeyboardInteractivePrompts` to `true` if you want users to explicitly enter their credentials for each session.
|
||||||
|
- Ensure that your WebSSH2 installation uses HTTPS to protect the communication between the web browser and the WebSSH2 server.
|
||||||
|
|
||||||
|
For more information on SSH keyboard-interactive authentication, refer to [RFC 4256](https://tools.ietf.org/html/rfc4256).
|
||||||
|
|
||||||
## Routes
|
## Routes
|
||||||
|
|
||||||
WebSSH2 provides two main routes:
|
WebSSH2 provides two main routes:
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// app/socket.js
|
// app/socket.js
|
||||||
|
|
||||||
const validator = require("validator")
|
const validator = require("validator")
|
||||||
|
const EventEmitter = require("events")
|
||||||
const SSHConnection = require("./ssh")
|
const SSHConnection = require("./ssh")
|
||||||
const { createNamespacedDebug } = require("./logger")
|
const { createNamespacedDebug } = require("./logger")
|
||||||
const { SSHConnectionError, handleError } = require("./errors")
|
const { SSHConnectionError, handleError } = require("./errors")
|
||||||
|
@ -14,8 +15,9 @@ const {
|
||||||
} = require("./utils")
|
} = require("./utils")
|
||||||
const { MESSAGES } = require("./constants")
|
const { MESSAGES } = require("./constants")
|
||||||
|
|
||||||
class WebSSH2Socket {
|
class WebSSH2Socket extends EventEmitter {
|
||||||
constructor(socket, config) {
|
constructor(socket, config) {
|
||||||
|
super()
|
||||||
this.socket = socket
|
this.socket = socket
|
||||||
this.config = config
|
this.config = config
|
||||||
this.ssh = new SSHConnection(config)
|
this.ssh = new SSHConnection(config)
|
||||||
|
@ -29,6 +31,7 @@ class WebSSH2Socket {
|
||||||
cols: null,
|
cols: null,
|
||||||
rows: null
|
rows: null
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initializeSocketEvents()
|
this.initializeSocketEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,24 +53,50 @@ class WebSSH2Socket {
|
||||||
this.socket.emit("authentication", { action: "request_auth" })
|
this.socket.emit("authentication", { action: "request_auth" })
|
||||||
}
|
}
|
||||||
|
|
||||||
this.socket.on(
|
this.ssh.on("keyboard-interactive", data => {
|
||||||
"authenticate",
|
this.handleKeyboardInteractive(data)
|
||||||
function(creds) {
|
})
|
||||||
this.handleAuthenticate(creds)
|
|
||||||
}.bind(this)
|
this.socket.on("authenticate", creds => {
|
||||||
)
|
this.handleAuthenticate(creds)
|
||||||
this.socket.on(
|
})
|
||||||
"terminal",
|
this.socket.on("terminal", data => {
|
||||||
function(data) {
|
this.handleTerminal(data)
|
||||||
this.handleTerminal(data)
|
})
|
||||||
}.bind(this)
|
this.socket.on("disconnect", reason => {
|
||||||
)
|
this.handleConnectionClose(reason)
|
||||||
this.socket.on(
|
})
|
||||||
"disconnect",
|
}
|
||||||
function(reason) {
|
|
||||||
this.handleConnectionClose(reason)
|
handleKeyboardInteractive(data) {
|
||||||
}.bind(this)
|
const self = this
|
||||||
|
debug(`handleKeyboardInteractive: ${this.socket.id}, %O`, data)
|
||||||
|
|
||||||
|
// Send the keyboard-interactive request to the client
|
||||||
|
this.socket.emit(
|
||||||
|
"authentication",
|
||||||
|
Object.assign(
|
||||||
|
{
|
||||||
|
action: "keyboard-interactive"
|
||||||
|
},
|
||||||
|
data
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Set up a one-time listener for the client's response
|
||||||
|
this.socket.once("authentication", clientResponse => {
|
||||||
|
const maskedclientResponse = maskSensitiveData(clientResponse, {
|
||||||
|
properties: ["responses"]
|
||||||
|
})
|
||||||
|
debug(
|
||||||
|
"handleKeyboardInteractive: Client response masked %O",
|
||||||
|
maskedclientResponse
|
||||||
|
)
|
||||||
|
if (clientResponse.action === "keyboard-interactive") {
|
||||||
|
// Forward the client's response to the SSH connection
|
||||||
|
self.ssh.emit("keyboard-interactive-response", clientResponse.responses)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAuthenticate(creds) {
|
handleAuthenticate(creds) {
|
||||||
|
@ -88,6 +117,7 @@ class WebSSH2Socket {
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeConnection(creds) {
|
initializeConnection(creds) {
|
||||||
|
const self = this
|
||||||
debug(
|
debug(
|
||||||
`initializeConnection: ${this.socket.id}, INITIALIZING SSH CONNECTION: Host: ${creds.host}, creds: %O`,
|
`initializeConnection: ${this.socket.id}, INITIALIZING SSH CONNECTION: Host: ${creds.host}, creds: %O`,
|
||||||
maskSensitiveData(creds)
|
maskSensitiveData(creds)
|
||||||
|
|
330
app/ssh.js
330
app/ssh.js
|
@ -2,6 +2,7 @@
|
||||||
// app/ssh.js
|
// app/ssh.js
|
||||||
|
|
||||||
const SSH = require("ssh2").Client
|
const SSH = require("ssh2").Client
|
||||||
|
const EventEmitter = require("events")
|
||||||
const { createNamespacedDebug } = require("./logger")
|
const { createNamespacedDebug } = require("./logger")
|
||||||
const { SSHConnectionError, handleError } = require("./errors")
|
const { SSHConnectionError, handleError } = require("./errors")
|
||||||
const { maskSensitiveData } = require("./utils")
|
const { maskSensitiveData } = require("./utils")
|
||||||
|
@ -10,163 +11,188 @@ const debug = createNamespacedDebug("ssh")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SSHConnection class handles SSH connections and operations.
|
* SSHConnection class handles SSH connections and operations.
|
||||||
* @class
|
* @extends EventEmitter
|
||||||
* @param {Object} config - Configuration object for the SSH connection.
|
|
||||||
*/
|
*/
|
||||||
function SSHConnection(config) {
|
class SSHConnection extends EventEmitter {
|
||||||
this.config = config
|
/**
|
||||||
this.conn = null
|
* Create an SSHConnection.
|
||||||
this.stream = null
|
* @param {Object} config - Configuration object for the SSH connection.
|
||||||
}
|
*/
|
||||||
|
constructor(config) {
|
||||||
|
super()
|
||||||
|
this.config = config
|
||||||
|
this.conn = null
|
||||||
|
this.stream = null
|
||||||
|
this.creds = null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects to the SSH server using the provided credentials.
|
* Connects to the SSH server using the provided credentials.
|
||||||
* @function
|
* @param {Object} creds - The credentials object containing host, port, username, and password.
|
||||||
* @memberof SSHConnection
|
* @returns {Promise<SSH>} - A promise that resolves with the SSH connection instance.
|
||||||
* @param {Object} creds - The credentials object containing host, port, username, and password.
|
*/
|
||||||
* @returns {Promise<SSH>} - A promise that resolves with the SSH connection instance.
|
connect(creds) {
|
||||||
*/
|
this.creds = creds
|
||||||
SSHConnection.prototype.connect = function(creds) {
|
debug("connect: %O", maskSensitiveData(creds))
|
||||||
debug("connect: %O", maskSensitiveData(creds))
|
return new Promise((resolve, reject) => {
|
||||||
return new Promise((resolve, reject) => {
|
if (this.conn) {
|
||||||
|
this.conn.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conn = new SSH()
|
||||||
|
|
||||||
|
const sshConfig = this.getSSHConfig(creds)
|
||||||
|
|
||||||
|
this.conn.on("ready", () => {
|
||||||
|
debug(`connect: ready: ${creds.host}`)
|
||||||
|
resolve(this.conn)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.conn.on("error", err => {
|
||||||
|
const error = new SSHConnectionError(
|
||||||
|
`SSH Connection error: ${err.message}`
|
||||||
|
)
|
||||||
|
handleError(error)
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.conn.on(
|
||||||
|
"keyboard-interactive",
|
||||||
|
(name, instructions, lang, prompts, finish) => {
|
||||||
|
this.handleKeyboardInteractive(
|
||||||
|
name,
|
||||||
|
instructions,
|
||||||
|
lang,
|
||||||
|
prompts,
|
||||||
|
finish
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
this.conn.connect(sshConfig)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<Object>} prompts - The list of prompts provided by the server.
|
||||||
|
* @param {Function} finish - The callback to complete the keyboard-interactive authentication.
|
||||||
|
*/
|
||||||
|
handleKeyboardInteractive(name, instructions, lang, prompts, finish) {
|
||||||
|
debug("handleKeyboardInteractive: Keyboard-interactive auth %O", prompts)
|
||||||
|
|
||||||
|
// Check if we should always send prompts to the client
|
||||||
|
if (this.config.ssh.alwaysSendKeyboardInteractivePrompts) {
|
||||||
|
this.sendPromptsToClient(name, instructions, prompts, finish)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const responses = []
|
||||||
|
let shouldSendToClient = false
|
||||||
|
|
||||||
|
for (let i = 0; i < prompts.length; i += 1) {
|
||||||
|
if (
|
||||||
|
prompts[i].prompt.toLowerCase().includes("password") &&
|
||||||
|
this.creds.password
|
||||||
|
) {
|
||||||
|
responses.push(this.creds.password)
|
||||||
|
} else {
|
||||||
|
shouldSendToClient = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSendToClient) {
|
||||||
|
this.sendPromptsToClient(name, instructions, prompts, finish)
|
||||||
|
} else {
|
||||||
|
finish(responses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends prompts to the client for keyboard-interactive authentication.
|
||||||
|
*
|
||||||
|
* @param {string} name - The name of the authentication method.
|
||||||
|
* @param {string} instructions - The instructions for the authentication.
|
||||||
|
* @param {Array<{ prompt: string, echo: boolean }>} prompts - The prompts to be sent to the client.
|
||||||
|
* @param {Function} finish - The callback function to be called when the client responds.
|
||||||
|
*/
|
||||||
|
sendPromptsToClient(name, instructions, prompts, finish) {
|
||||||
|
this.emit("keyboard-interactive", {
|
||||||
|
name: name,
|
||||||
|
instructions: instructions,
|
||||||
|
prompts: prompts.map(p => ({ prompt: p.prompt, echo: p.echo }))
|
||||||
|
})
|
||||||
|
|
||||||
|
this.once("keyboard-interactive-response", responses => {
|
||||||
|
finish(responses)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the SSH configuration object based on credentials.
|
||||||
|
* @param {Object} creds - The credentials object containing host, port, username, and password.
|
||||||
|
* @returns {Object} - The SSH configuration object.
|
||||||
|
*/
|
||||||
|
getSSHConfig(creds) {
|
||||||
|
return {
|
||||||
|
host: creds.host,
|
||||||
|
port: creds.port,
|
||||||
|
username: creds.username,
|
||||||
|
password: creds.password,
|
||||||
|
tryKeyboard: true,
|
||||||
|
algorithms: this.config.ssh.algorithms,
|
||||||
|
readyTimeout: this.config.ssh.readyTimeout,
|
||||||
|
keepaliveInterval: this.config.ssh.keepaliveInterval,
|
||||||
|
keepaliveCountMax: this.config.ssh.keepaliveCountMax,
|
||||||
|
debug: createNamespacedDebug("ssh2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an interactive shell session over the SSH connection.
|
||||||
|
* @param {Object} [options] - Optional parameters for the shell.
|
||||||
|
* @returns {Promise<Object>} - A promise that resolves with the SSH shell stream.
|
||||||
|
*/
|
||||||
|
shell(options) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.conn.shell(options, (err, stream) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
this.stream = stream
|
||||||
|
resolve(stream)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes the terminal window for the current SSH session.
|
||||||
|
* @param {number} rows - The number of rows for the terminal.
|
||||||
|
* @param {number} cols - The number of columns for the terminal.
|
||||||
|
*/
|
||||||
|
resizeTerminal(rows, cols) {
|
||||||
|
if (this.stream) {
|
||||||
|
this.stream.setWindow(rows, cols)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends the SSH connection and stream.
|
||||||
|
*/
|
||||||
|
end() {
|
||||||
|
if (this.stream) {
|
||||||
|
this.stream.end()
|
||||||
|
this.stream = null
|
||||||
|
}
|
||||||
if (this.conn) {
|
if (this.conn) {
|
||||||
this.conn.end()
|
this.conn.end()
|
||||||
|
this.conn = null
|
||||||
}
|
}
|
||||||
|
|
||||||
this.conn = new SSH()
|
|
||||||
|
|
||||||
const sshConfig = this.getSSHConfig(creds)
|
|
||||||
|
|
||||||
this.conn.on("ready", () => {
|
|
||||||
debug(`connect: ready: ${creds.host}`)
|
|
||||||
resolve(this.conn)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.conn.on("error", err => {
|
|
||||||
const error = new SSHConnectionError(
|
|
||||||
`SSH Connection error: ${err.message}`
|
|
||||||
)
|
|
||||||
handleError(error)
|
|
||||||
reject(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.conn.on(
|
|
||||||
"keyboard-interactive",
|
|
||||||
(name, instructions, lang, prompts, finish) => {
|
|
||||||
this.handleKeyboardInteractive(
|
|
||||||
creds,
|
|
||||||
name,
|
|
||||||
instructions,
|
|
||||||
lang,
|
|
||||||
prompts,
|
|
||||||
finish
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
this.conn.connect(sshConfig)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles keyboard-interactive authentication prompts.
|
|
||||||
* @function
|
|
||||||
* @memberof SSHConnection
|
|
||||||
* @param {Object} creds - The credentials object containing password.
|
|
||||||
* @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<Object>} prompts - The list of prompts provided by the server.
|
|
||||||
* @param {Function} finish - The callback to complete the keyboard-interactive authentication.
|
|
||||||
*/
|
|
||||||
SSHConnection.prototype.handleKeyboardInteractive = function(
|
|
||||||
creds,
|
|
||||||
name,
|
|
||||||
instructions,
|
|
||||||
lang,
|
|
||||||
prompts,
|
|
||||||
finish
|
|
||||||
) {
|
|
||||||
debug("handleKeyboardInteractive: Keyboard-interactive auth %O", prompts)
|
|
||||||
const responses = []
|
|
||||||
|
|
||||||
for (let i = 0; i < prompts.length; i += 1) {
|
|
||||||
if (prompts[i].prompt.toLowerCase().includes("password")) {
|
|
||||||
responses.push(creds.password)
|
|
||||||
} else {
|
|
||||||
// todo: For any non-password prompts, we meed to implement a way to
|
|
||||||
// get responses from the user through a modal. For now, we'll just
|
|
||||||
// send an empty string
|
|
||||||
responses.push("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finish(responses)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the SSH configuration object based on credentials.
|
|
||||||
* @function
|
|
||||||
* @memberof SSHConnection
|
|
||||||
* @param {Object} creds - The credentials object containing host, port, username, and password.
|
|
||||||
* @returns {Object} - The SSH configuration object.
|
|
||||||
*/
|
|
||||||
SSHConnection.prototype.getSSHConfig = function(creds) {
|
|
||||||
return {
|
|
||||||
host: creds.host,
|
|
||||||
port: creds.port,
|
|
||||||
username: creds.username,
|
|
||||||
password: creds.password,
|
|
||||||
tryKeyboard: true,
|
|
||||||
algorithms: this.config.ssh.algorithms,
|
|
||||||
readyTimeout: this.config.ssh.readyTimeout,
|
|
||||||
keepaliveInterval: this.config.ssh.keepaliveInterval,
|
|
||||||
keepaliveCountMax: this.config.ssh.keepaliveCountMax,
|
|
||||||
debug: createNamespacedDebug("ssh2")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens an interactive shell session over the SSH connection.
|
|
||||||
* @function
|
|
||||||
* @memberof SSHConnection
|
|
||||||
* @param {Object} [options] - Optional parameters for the shell.
|
|
||||||
* @returns {Promise<Object>} - A promise that resolves with the SSH shell stream.
|
|
||||||
*/
|
|
||||||
SSHConnection.prototype.shell = function(options) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.conn.shell(options, (err, stream) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err)
|
|
||||||
} else {
|
|
||||||
this.stream = stream
|
|
||||||
resolve(stream)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resizes the terminal window for the current SSH session.
|
|
||||||
* @function
|
|
||||||
* @memberof SSHConnection
|
|
||||||
* @param {number} rows - The number of rows for the terminal.
|
|
||||||
* @param {number} cols - The number of columns for the terminal.
|
|
||||||
*/
|
|
||||||
SSHConnection.prototype.resizeTerminal = function(rows, cols) {
|
|
||||||
if (this.stream) {
|
|
||||||
this.stream.setWindow(rows, cols)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SSHConnection.prototype.end = function() {
|
|
||||||
if (this.stream) {
|
|
||||||
this.stream.end()
|
|
||||||
this.stream = null
|
|
||||||
}
|
|
||||||
if (this.conn) {
|
|
||||||
this.conn.end()
|
|
||||||
this.conn = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -173,12 +173,10 @@ function modifyHtml(html, config) {
|
||||||
*/
|
*/
|
||||||
function maskSensitiveData(obj, options) {
|
function maskSensitiveData(obj, options) {
|
||||||
const defaultOptions = {}
|
const defaultOptions = {}
|
||||||
debug("maskSensitiveData: %O", obj)
|
debug("maskSensitiveData")
|
||||||
debug("maskSensitiveData: options: %O", options)
|
|
||||||
|
|
||||||
const maskingOptions = Object.assign({}, defaultOptions, options || {})
|
const maskingOptions = Object.assign({}, defaultOptions, options || {})
|
||||||
const maskedObject = maskObject(obj, maskingOptions)
|
const maskedObject = maskObject(obj, maskingOptions)
|
||||||
debug("maskSensitiveData: maskedObject: %O", maskedObject)
|
|
||||||
|
|
||||||
return maskedObject
|
return maskedObject
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
"socket.io": "~2.2.0",
|
"socket.io": "~2.2.0",
|
||||||
"ssh2": "~0.8.9",
|
"ssh2": "~0.8.9",
|
||||||
"validator": "^12.2.0",
|
"validator": "^12.2.0",
|
||||||
"webssh2_client": "^0.2.23"
|
"webssh2_client": "^0.2.25"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index.js",
|
"start": "node index.js",
|
||||||
|
|
Loading…
Reference in a new issue