Gathering detailed insights and metrics for ssh2shell-extra-ciphers
Gathering detailed insights and metrics for ssh2shell-extra-ciphers
Gathering detailed insights and metrics for ssh2shell-extra-ciphers
Gathering detailed insights and metrics for ssh2shell-extra-ciphers
npm install ssh2shell-extra-ciphers
Typescript
Module System
Min. Node Version
Node Version
NPM Version
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
2
Wrapper class for ssh2 shell command.
ssh2shell supports the following functionality:
sudo
, sudo su
and su user
commands.The Class is written in coffee script which can be found here: ./src/ssh2shell.coffee
.
It has comments not found in the build output javascript file ./lib/ssh2shell.js
.
npm install ssh2shell
1var host = { 2 server: { 3 host: "127.0.0.1", 4 userName: "test", 5 password: "1234", 6 }, 7 commands: [ 8 "msg:Connected", 9 "echo $(pwd)", 10 "ls -l" 11 ] 12}; 13 14 15var SSH2Shell = require ('ssh2shell'), 16//Create a new instance passing in the host object 17SSH = new SSH2Shell(host); 18 19//Start the process 20SSH.connect();
SSH2Shell expects an object with the following structure to be passed to its constructor:
1//Host object 2host = { 3 //ssh2.connection.connect properties 4 server: { 5 host: "IP Address", 6 port: "external port number", 7 userName: "user name", 8 password: "user password", 9 passPhrase: "privateKeyPassphrase", //optional string 10 privateKey: require('fs').readFileSync('/path/to/private/key/id_rsa'), //optional string 11 //other ssh2.connect parameters. See https://github.com/mscdex/ssh2#client-methods 12 //These other ssh2.connect parameters are only valid for the first host connection which uses 13 //ssh2.connect. 14 }, 15 //Array of host object for multiple host connections optional 16 hosts: [Array, of, nested, host, configs, objects], 17 //Prompt detection values optional 18 standardPrompt: ">$%#",//string 19 passwordPrompt: ":",//string 20 passphrasePrompt: ":",//string 21 //Enter key character to send as end of line. 22 enter: "\n", //windows = "\r\n" | "\x0d\x0a", Linux = "\n" | "\x0a\, Mac = "\r" | "x0d" 23 //Text output filters to clean server response optional 24 asciiFilter: "[^\r\n\x20-\x7e]", //regular exression string 25 diableColorFilter: false, //optional bollean 26 textColorFilter: "(\[{1}[0-9;]+m{1})", /regular exression string 27 //array of commands 28 commands: ["Array", "of", "command", "strings"], //array() of command strings 29 //msg functional is optional. Used by this.emit("msg", "my message") 30 msg: { 31 send: function( message ) { 32 console.log(message); 33 } 34 }, 35 //debug options optional 36 verbose: false, //boolean 37 debug: false, //boolean 38 //onCommandTimeout setting optional 39 idleTimeOut: 5000, //integer 40 //connection messages optional 41 connectedMessage: "Connected", //string 42 readyMessage: "Ready", //string 43 closedMessage: "Closed", //string 44 45 //Host event handlers replace the default class event handlers. 46 //These event handlers only apply to that current host object being used. 47 //All host event handler definitions are optional 48 49 //Keyboard interactive authentication event handler 50 //Required if the first host.server.tryKeyboard is set to true. 51 onKeyboardInteractive: function(name, instructions, instructionsLang, prompts, finish){ 52 //See https://github.com/mscdex/ssh2#client-events 53 //name, instructions, instructionsLang don't seem to be of interest for authenticating 54 //prompts is an object of expected prompts and if they are to be showen to the user 55 //finish is the function to be called with an array of responses in the same order as 56 //the prompts parameter defined them. 57 //See [Client events](https://github.com/mscdex/ssh2#client-events) for more information 58 //if a non standard prompt results from a successfull connection then handle its detection and response in 59 //onCommandProcessing or commandTimeout. 60 //see text/keyboard-interactivetest.js 61 }, 62 63 //onCommandProcessing is triggered on every data received event (one character) until a 64 //prompt is detected. Optional 65 onCommandProcessing: function( command, response, sshObj, stream ) { 66 //command is the last command run. This is "" just after connection before the first prompt 67 //response is the buffer that is being loaded with each data event 68 //sshObj is the current host object and gives access to the current set of commands and other settings 69 //stream object allows stream.write() access if a responce is required outside the normal command flow. 70 }, 71 72 //onCommandComplete is triggered after a command is run and a standard prompt is detected. optional 73 onCommandComplete: function( command, response, sshObj ) { 74 //response is the full response from the host 75 //sshObj is this object and gives access to the current set of commands and other settings 76 }, 77 78 //onCommandTimeout is triggered when no standard prompt after host.idleTimeout. Optional 79 //This allows responding to an imput requiest that hasn't been handles or 80 //disconnect to stop the connection hanging. 81 onCommandTimeout: function( command, response, stream, connection ) { 82 //command is the last command run or "" if no prompt after connection 83 //response is the text response from the command up to the time out 84 //stream object is used to send text to the host without having to close the connection. 85 //connection gives access to close the connection if all else fails 86 //The connection will hang if you send text to the host but get no response and you don't close the 87 //connection. 88 //The timer can be reset from within this event in case a stream write gets no response 89 //Set this to empty if you want the instance event handler to be the default action. 90 //See test/timeouttest.js for and example of multiple commandTimeout triggers. 91 }, 92 93 //onEnd is run when the stream.on ("finish") event is triggered. 94 onEnd: function( sessionText, sshObj ) { 95 //SessionText is the full text for this hosts session 96 //sshObj is the host object and gives access to the current settings 97 }, 98 99 100 //onError is run when an error event is raised. Optional 101 onError: function( err, type, close = false, callback ) { 102 //err is either an Error object or a string containing the error message 103 //type is a string containing the error type 104 //close is a boolean value indicating if the connection should be closed or not 105 //callback is the function to run with handling the error in the form of function(err,type) 106 //To close the connection us connection.close() 107 } 108};
this
keyword is available within host event handlers to give access to ssh2shell object api like
this.emit() and other functions.this.sshObj
or sshObj variable passed into a function provides access to all the host config and some instance
variables.SSH2Shell extends events.EventEmitter
Methods
.constructor(sshObj) requires a host object as defined above. SSH = new SSH2Shell(host);
.connect() Is the main function to establish the connection and handle data events from the server which triggers the rest of the process.
.emit("eventName", function, parms,... ). raises the event based on the name in the first string and takes input parameters based on the handler function definition.
Variables
.sshObj is the host object as defined above along with some instance variables.
.command is the current command being run until a new prompt is detected and the next command replaces it or a commandTimeout event is raised which may cause a disconnection.
.idleTime is used by the command timeout timer
.asciiFilter is the regular expression used to filter out non-standard ascii values from response text
.textColorFilter is the regular expression used to filter out text colour codes
.passwordPromt is the characters used to identify a valid password prompt
.passphrasePromt is the characters used to identify a valid passphrase prompt
.standardPromt is the characters used to identify a valid standard prompt
1//single host test 2cp .env-example .env 3 4//multiple nested hosts 5//requires the additional details added to .env file for each server 6//my tests were done using three VM hosts 7node test/tunneltest.js 8 9//test the command idle time out timer and provide an example of a more complicated timeout handler 10node test/timeouttest.js 11 12//Test multiple sudo and su combinations for changing user 13//Issue #10 14//Also test promt detection with no password requested 15//Issue #14 16node test/sudosutest.js 17 18//Test using notification commands as the last command 19//Issue #11 20node test/notificationstest.js 21 22//Test keyboard-interactivs authentication on the host that has it enabled 23node test/keyboard-interactivetest.js
How to:
(will require a package json with ssh2shell, dotenv and email defined as dependencies)
.env
HOST=192.168.0.1
PORT=22
USER_NAME=myuser
PASSWORD=mypassword
PRIV_KEY_PATH=~/.ssh/id_rsa
PASS_PHRASE=myPassPhrase
app.js
1var dotenv = require('dotenv'); 2dotenv.load(); 3var Email = require('email'); 4 5var host = { 6 server: { 7 host: process.env.HOST, 8 port: process.env.PORT, 9 userName: process.env.USER_NAME, 10 password: process.env.PASSWORD, 11 passPhrase: process.env.PASS_PHRASE, 12 privateKey: require('fs').readFileSync(process.env.PRIV_KEY_PATH) 13 }, 14 commands: [ 15 "`This is a message that will be added to the full sessionText`", 16 "msg:This is a message that will be handled by the msg.send code", 17 "echo $(pwd)", 18 "sudo su", 19 "msg:changing directory", 20 "cd ~/", 21 "ls -l", 22 "msg:Confirming the current path", 23 "echo $(pwd)", 24 "msg:Getting the directory listing to confirm the extra command was added", 25 "ls -l", 26 "`All done!`" 27 ], 28 onCommandComplete: function( command, response, sshObj ) { 29 //confirm it is the root home dir and change to root's .ssh folder 30 if(sshObj.debug){ 31 this.emit("msg", this.sshObj.server.host + ": host.onCommandComplete event, command: " + command); 32 } 33 if (command === "echo $(pwd)" && response.indexOf("/root") != -1 ) { 34 //unshift will add the command as the next command, use push to add command as the last command 35 sshObj.commands.unshift("msg:The command and response check worked. Added another cd command."); 36 sshObj.commands.unshift("cd .ssh"); 37 } 38 //we are listing the dir so output it to the msg handler 39 else if (command === "ls -l"){ 40 this.emit("msg", response); 41 } 42 }, 43 onEnd: function( sessionText, sshObj ) { 44 //email the session text instead of outputting it to the console 45 if(sshObj.debug){this.emit("msg", this.sshObj.server.host + ": host.onEnd event");} 46 var sessionEmail = new Email({ 47 from: "me@example.com", 48 to: "me@example.com", 49 subject: "Automated SSH Session Response", 50 body: "\nThis is the full session responses for " + sshObj.server.host + ":\n\n" + sessionText 51 }); 52 this.emit("msg", "Sending session response email"); 53 54 // if callback is provided, errors will be passed into it 55 // else errors will be thrown 56 sessionEmail.send(function(err){ sshObj.msg.send('error', err, 'Email'); }); 57 } 58}; 59 60//Create a new instance 61var SSH2Shell = require ('ssh2shell'), 62 SSH = new SSH2Shell(host); 63 64//Start the process 65SSH.connect();
SSH tunnelling has been incorporated into core of the class process enabling nested host objects.
The new hosts: [ host1, host2]
setting can make multiple sequential host connections possible and each host object
can also contain nested hosts. Each host config object has its own server settings, commands, command handlers and
event handlers. The msg handler can be shared between all objects. This a very robust and simple multi host
configuration method.
Tunnelling Example: This example shows two hosts (server2, server3) that are connected to via server1. The two host configs are add to server1.hosts array.
server1.hosts = [server2, server3]
server2.hosts = []
server3.hosts = []
The following would also be valid:
server1.hosts = [server2]
server2.hosts = [server3]
server3.hosts = []
The nested process:
Note:
How to:
1var dotenv = require('dotenv'); 2dotenv.load(); 3 4//Host connection and authentication parameters 5var conParamsHost1 = { 6 host: process.env.SERVER1_HOST, 7 port: process.env.SERVER1_PORT, 8 userName: process.env.SERVER1_USER_NAME, 9 password: process.env.SERVER1_PASSWORD, 10 passPhrase: process.env.SERVER1_PASS_PHRASE, 11 privateKey: require('fs').readFileSync(process.env.SERVER1_PRIV_KEY_PATH) 12 }, 13 conParamsHost2 = { 14 host: process.env.SERVER2_HOST, 15 port: process.env.SERVER2_PORT, 16 userName: process.env.SERVER2_USER_NAME, 17 password: process.env.SERVER2_PASSWORD 18 }, 19 conParamsHost3 = { 20 host: process.env.SERVER3_HOST, 21 port: process.env.SERVER3_PORT, 22 userName: process.env.SERVER3_USER_NAME, 23 password: process.env.SERVER3_PASSWORD 24 } 25 26//functions used by all hosts 27var msg = { 28 send: function( message ) { 29 console.log(message); 30 } 31 } 32 33//Host objects: 34var host1 = { 35 server: conParamsHost1, 36 commands: [ 37 "msg:connected to host: passed. Listing dir.", 38 "ls -l" 39 ], 40 msg: msg, 41 onCommandComplete: function( command, response, sshObj ) { 42 //we are listing the dir so output it to the msg handler 43 if(sshObj.debug){ 44 this.emit("msg", this.sshObj.server.host + ": host.onCommandComplete host1, command: " + command); 45 } 46 if (command == "ls -l"){ 47 this.emit("msg", response); 48 } 49 } 50}, 51 52host2 = { 53 server: conParamsHost2, 54 commands: [ 55 "msg:connected to host: passed", 56 "sudo su", 57 "msg:Changing to root dir", 58 "cd ~/", 59 "msg:Listing dir", 60 "ls -l" 61 ], 62 msg: msg, 63 connectedMessage: "Connected to host2", 64 onCommandComplete: function( command, response, sshObj ) { 65 //we are listing the dir so output it to the msg handler 66 if(sshObj.debug){ 67 this.emit("msg", this.sshObj.server.host + ": host.onCommandComplete host2, command: " + command); 68 } 69 if (command == "sudo su"){ 70 this.emit("msg", "Just ran a sudo su command"); 71 } 72 } 73}, 74 75host3 = { 76 server: conParamsHost3, 77 commands: [ 78 "msg:connected to host: passed", 79 "sudo su", 80 "cd ~/", 81 "msg:Listing root dir", 82 "ls -l" 83 ], 84 msg: msg, 85 connectedMessage: "Connected to host3", 86 onCommandComplete: function( command, response, sshObj) { 87 //we are listing the dir so output it to the msg handler 88 if(sshObj.debug){ 89 this.emit("msg", this.sshObj.server.host + ": host.onCommandComplete host3, command: " + command); 90 } 91 if (command.indexOf("cd") != -1){ 92 this.emit("msg", "Just ran a cd command:"); 93 this.emit("msg", response); 94 } 95 } 96} 97 98//Set the two hosts you are tunnelling to through host1 99host1.hosts = [ host2, host3 ]; 100 101//or the alternative nested tunnelling method outlined above: 102//host2.hosts = [ host3 ]; 103//host1.hosts = [ host2 ]; 104 105//Create the new instance 106var SSH2Shell = require ('ssh2shell'), 107 SSH = new SSH2Shell(host1); 108 109//Add an on end event handler used by all hosts 110SSH.on ('end', function( sessionText, sshObj ) { 111 //show the full session output. This could be emailed or saved to a log file. 112 if(sshObj.debug){this.emit("msg", this.sshObj.server.host + ": instanse.onEnd all hosts");} 113 this.emit ("msg", "\nSession text for " + sshObj.server.host + ":\n" + sessionText); 114 }); 115 116//Start the process 117SSH.connect(); 118
"msg:Doing something"
to your commands array at key points will help you track the sequence of
what has been done as the process runs. (see examples)Error: Unable to parse private key while generating public key (expected sequence)
is caused by the passphrase
being incorrect. This confused me because it doesn't indicate the passphrase was the problem but it does indicate
that it could not decrypt the private key.host.debug = true
Note: Do not add these to the commandProccessing event which is called every time a character is received from the host
Add your own verbose messages as follows:
if(this.sshObj.verbose){this.emit("msg", this.sshObj.server.host + ": response: " + response);}
//response might need
to be changed to this._buffer
Add your own debug messages as follows:
if(this.sshObj.debug){this.emit("msg", this.sshObj.server.host + ": eventName");}
//where eventName is the text
identifying what happened
When the program doesn't detect a standard prompt and doesn't recieve any more data the onCommandTimeout event triggers after the host.idleTimeOut value (in ms). This is usually because an unexpected prompt on the server is requiring a response that isn't handled or the host is not responding at all. In either case detection of the standard prompt will never happen causeing the program to hang, perpetuley waiting for a response it wont get. The commandTimeout stops this. The commandTimeout event can enable you to handle such prompts without having to disconnect by providing the response the host requires. The host then replies with more text triggering a data recieved event resetting the timer and enabling the process to continue. It is recommended to close the connection as a default action if all else fails so you are not left with a hanging script again. The default action is to add the last response text to the session text and disconnect. Enabling host.debug would also provide the process path leading upto disconnection which in conjunction with the session text would clarify what command and output triggered the event.
**Note: If you receive garble back before the clear response you may need to save the previous response text to the
sessionText and clear the buffer before using stream.write() in commandTimeout.
this.sshObj.sessionText = response
and this._buffer = ""
1host.onCommandTimeout = function( command, response, stream, connection ) { 2 if(sshObj.debug){this.emit("msg", this.sshObj.server.host + ": host.onCommandTimeout");} 3 if (command === "atp-get install node" 4 && response.indexOf("[Y/n]?") != -1 5 && this.sshObj.nodePrompt != true) { 6 //Setting this.sshObj.nodePrompt stops a response loop 7 this.sshObj.nodePrompt = true 8 stream.write('y\n') 9 }else{ 10 //emit an error that passes true for the close parameter and callback that loads the last response 11 //into sessionText 12 this.emit ("error", this.sshObj.server.host 13 + ": Command timed out after #{this._idleTime/1000} seconds. command: " 14 + command, "Timeout", true, function(err, type){ 15 this.sshObj.sessionText += response 16 }) 17 } 18} 19 20or 21 22host.onCommandTimeout = function( command, response, stream, connection ) { 23 if(sshObj.debug){this.emit("msg", this.sshObj.server.host + ": host.onCommandTimeout");} 24 if (command === "" && response === "Connected to port 22" && this.sshObj.noFirstPrompt != true) { 25 //Setting this.sshObj.noFirstPrompt stops a response loop 26 this.sshObj.noFirstPrompt = true 27 stream.write('\n') 28 return true 29 } 30 //emit an error that passes true for the close parameter and callback the loads the last of session text 31 this.emit ("error", this.sshObj.server.host 32 + ": Command timed out after #{this._idleTime/1000} seconds. command: " 33 + command, "Timeout", true, function(err, type){ 34 this.sshObj.sessionText += response 35 }) 36} 37 38or 39 40//reset the default handler to do nothing so it doesn't close the connection 41host.onCommandTimeout = function( command, response, stream, connection ) {}; 42 43//Create the new instance 44var SSH2Shell = require ('ssh2shell'), 45 SSH = new SSH2Shell(host) 46 47//And do it all in the instance event handler 48SSH.on ('commandTimeout',function( command, response, stream, connection ){ 49 if(sshObj.debug){this.emit("msg", this.sshObj.server.host + ": instance.onCommandTimeout");} 50 //first test should only pass once to stop a response loop 51 if (command === "atp-get install node" 52 && response.indexOf("[Y/n]?") != -1 53 && this.sshObj.nodePrompt != true) { 54 this.sshObj.nodePrompt = true; 55 stream.write('y\n'); 56 return true; 57 } 58 this.sshObj.sessionText += response; 59 this.emit("error", this.sshObj.server.host + ": Command `" + command + "` timed out after " 60 + (this._idleTime / 1000) + " seconds. command: " + command, "Command Timeout", true); 61}); 62 63SSH.on ('end', function( sessionText, sshObj ) { 64 //show the full session output. This could be emailed or saved to a log file. 65 if(sshObj.debug){this.emit("msg", this.sshObj.server.host + ": instance.onEnd");} 66 this.emit("msg","\nSession text for " + sshObj.server.host + ":\n" + sessionText); 67 }); 68 69SSH.connect();
At connection time the hash of the servers public key can be compared with the hash the client had previously recorded for that server. This stops "man in the middle" attacks where you are redirected to a different server as you connect to the server you expected to. This hash only changes with a reinstall of SSH, a key change on the server or a load balancer is now in place.
Note: Fingerprint check doesn't work the same way for tunnelling. The first host will vailidate using this method but the subsequent connections would have to be handled by your commands. Only the first host uses the SSH2 connection method that does the validation.
To use figngerprint validation you first need the server hash string which can be obtained using ssh2shell as follows:
Fingerprint validation example:
1//Define the hostValidation function in the host.server config. 2//hashKey needs to be defined at the top level if you want to access the server hash at run time 3var serverHash, host; 4//don't set expectedHash if you want to know the server hash 5var expectedHash 6expectedHash = "85:19:8a:fb:60:4b:94:13:5c:ea:fe:3b:99:c7:a5:4e"; 7 8host = { 9 server: { 10 //other normal connection params, 11 hashMethod: "md5", //"md5" or "sha1" 12 //hostVerifier function must be defined and return true for match of false for failure. 13 hostVerifier: function(hashedKey) { 14 var recievedHash; 15 16 expectedHash = expectedHash + "".replace(/[:]/g, "").toLowerCase(); 17 recievedHash = hashedKey + "".replace(/[:]/g, "").toLowerCase(); 18 if (expectedHash === "") { 19 //No expected hash so save save what was recived from the host (hashedKey) 20 //serverHash needs to be defined before host object 21 serverHash = hashedKey; 22 console.log("Server hash: " + serverHash); 23 return true; 24 } else if (recievedHash === expectedHash) { 25 console.log("Hash values matched"); 26 return true; 27 } 28 //Output the failed comparison to the console if you want to see what went wrong 29 console.log("Hash values: Server = " + recievedHash + " <> Client = " + expectedHash); 30 return false; 31 }, 32 }, 33 //Other settings 34}; 35 36var SSH2Shell = require ('ssh2shell'), 37 SSH = new SSH2Shell(host); 38SSH.connect();
Note: host.server.hashMethod only supports md5 or sha1 according to the current SSH2 documentaion anything else may produce undesired results.
Keyboard-interactive authentication is available when both host.server.tryKeyboard is set to true and the event handler keyboard-interactive is defined as below. The keyboard-interactive event handler can only be used on the first connection.
Also see test/keyboard-interactivetest.js for the full example
keyboard-interactive event handler definition
1//this is required 2host.server.tryKeyboard = true; 3 4var SSH2Shell = require ('../lib/ssh2shell'); 5var SSH = new SSH2Shell(host); 6 7//Add the keyboard-interactive handler 8//The event function must call finish() with an array of responses in the same order as prompts recieved 9// in the prompts array 10SSH.on ('keyboard-interactive', function(name, instructions, instructionsLang, prompts, finish){ 11 if (this.sshObj.debug) {this.emit('msg', this.sshObj.server.host + ": Keyboard-interactive");} 12 if (this.sshObj.verbose){ 13 this.emit('msg', "name: " + name); 14 this.emit('msg', "instructions: " + instructions); 15 var str = JSON.stringify(prompts, null, 4); 16 this.emit('msg', "Prompts object: " + str); 17 } 18 //The example presumes only the password is required 19 finish([this.sshObj.server.password] ); 20 }); 21 22SSH.connect();
Or
1host = { 2 ..., 3 keyboard-interactive: function(name, instructions, instructionsLang, prompts, finish){ 4 if (this.sshObj.debug) {this.emit('msg', this.sshObj.server.host + ": Keyboard-interactive");} 5 if (this.sshObj.verbose){ 6 this.emit('msg', "name: " + name); 7 this.emit('msg', "instructions: " + instructions); 8 var str = JSON.stringify(prompts, null, 4); 9 this.emit('msg', "Prompts object: " + str); 10 } 11 //The example presumes only the password is required 12 finish([this.sshObj.server.password] ); 13 }, 14 ... 15} 16 17 18Sudo and su Commands: 19-------------- 20It is possible to use `sudo [command]`, `sudo su`, `su [username]` and `sudo -u [username] -i`. Sudo commands uses the 21password for the user that is accessing the server and is handled by SSH2shell. Su on the other hand uses the password 22of root or the other user (`su seconduser`) and requires you detect the password prompt in onCommandProcessing. 23 24See: [su VS sudo su VS sudo -u -i](http://johnkpaul.tumblr.com/post/19841381351/su-vs-sudo-su-vs-sudo-u-i) for 25 clarification about the difference between the commands. 26 27See: test/sudosutest.js for a working code example. 28 29 30Notification commands: 31---------------------- 32There are two notification commands that are added to the host.commands array but are not run as a command on the host. 33 341. `"msg:This is a message intended for monitoring the process as it runs"`. The `msg:` command raises a onMsg(message) 35 event. 36 * The text after `msg:` is passed to the message property of the onMsg event. 372. "\`SessionText notification\`" will take the text between "\` \`" and add it to the sessionText. 38 * The reason for not using echo or printf commands as a normal command is that you see both the command and the message 39 in the sessionTest which is pointless when all you want is the message. 40 41 42Prompt detection override: 43------------------------- 44The following properties have been added to the host object making it possable to override prompt string values used 45with regular expressions to for prompt detection. Being able to change these values enables you to easily manage all 46sorts of prompt options subject to you server prompts. 47 48These are optional settings.
host.standardPrompt = ">$%#"; host.passwordPrompt = ":"; host.passphrasePrompt = ":";
Text regular expression filters:
-------------------------------
There are two regular expression filters that remove unwanted text from responce data.
The first removes non-statndard ascii and the second removes ANSI text formating codes. Both of these can be modified in
your host object to overide defaults. It is also possible to output the ANSI codes by setting disableColorFilter to true.
These are optional settings
```javascript
host.asciiFilter = "[^\r\n\x20-\x7e]"
host.disableColorFilter = false //or true
host.textColorFilter = "(\[{1}[0-9;]+m{1})"
When running commands there are cases that you might need to respond to specific prompt that results from the command being run. The command response check method is the same as in the example for the host.onCommandComplete event handler but in this case we use it in the host.onCommandProcessing event handler. The stream object is available in onCommandProcessing to the prompt directly using strea.write("y\n"), note "\n" might be required to comlete the response.
Host definition that replaces the default handler and runs only for the current host connection
1host.onCommandProcessing = function( command, response, sshObj, stream ) { 2 //Check the command and prompt exits and respond with a 'y' but only does it once 3 if (command == "apt-get install nano" && response.indexOf("[y/N]?") != -1 && sshObj.firstRun != true) { 4 //This debug message will only run when conditions are met not on every data event so is ok here 5 if (sshObj.debug) {this.emit('msg', this.sshObj.server.host + ": Responding to nano install");} 6 sshObj.firstRun = true 7 stream.write('y\n'); 8 } 9 }; 10\\sshObj.firstRun can be reset to false in onCommandComplete to allow for another non-standed prompt
Instance definition that runs in parrallel with every other commandProcessing for every host connection
1//To handle all hosts the same add an event handler to the class instance 2//Don't define an event handler in the host object with the same code, it will do it twice! 3var SSH2Shell = require ('../lib/ssh2shell'); 4var SSH = new SSH2Shell(host); 5 6SSH.on ('commandProcessing', function onCommandProcessing( command, response, sshObj, stream ) { 7 8 //Check the command and prompt exits and respond with a 'y' 9 if (command == "apt-get install nano" && response.indexOf("[y/N]?") != -1 && sshObj.firstRun != true ) { 10 //This debug message will only run when conditions are met not on every data event so is ok here 11 if (sshObj.debug) {this.emit('msg', this.sshObj.server.host + ": Responding to nano install");} 12 sshObj.firstRun = true 13 stream.write('y\n'); 14 } 15};
Note: If there is no response from the server the commandTimeout will be triggered after the idleTimeOut period.
If the commands you need to run would be better suited to a bash script as part of the process it is possible to generate or get the script on the fly. You can echo/printf the script content into a file as a command, ensure it is executable, run it and then delete it. The other option is to curl or wget the script from a remote location and do the same but this has some risks associated with it. I like to know what is in the script I am running.
Note # and > in the following commands with conflict with the host.standardPrompt definition ">$%#" change it to "$%"
host.commands = [ "some commands here",
"if [ ! -f myscript.sh ]; then printf '#!/bin/bash\n" +
" #\n" +
" current=$(pwd);\n" +
"cd ..;\n" +
"if [ -f myfile ]; then" +
"sed \"/^[ \\t]*$/d\" ${current}/myfile | while read line; do\n" +
"printf \"Doing some stuff\";\n" +
"printf $line;\n" +
"done\n" +
"fi\n' > myscript.sh;" +
"fi",
"sudo chmod 700 myscript.sh",
"./myscript.sh",
"rm myscript.sh"
],
There are a number of event handlers that enable you to add your own code to be run when those events are triggered. Most of these you have already encountered in the host object. You do not have to add event handlers unless you want to add your own functionality as the class already has default handlers defined.
There are two ways to add event handlers:
this
is always referencing the ssh2shell instance at run time.this
including the Emitter functions like
this.emit("myEvent", properties).An event can be raised using this.emit('eventName', parameters)
.
Further reading: node.js event emitter
Class Instance Event Definitions:
1ssh2shell.on ("connect", function onConnect() { 2 //default: outputs primaryHost.connectedMessage 3}); 4 5ssh2shell.on ("ready", function onReady() { 6 //default: outputs primaryHost.readyMessage 7}); 8 9ssh2shell.on ("msg", function onMsg( message ) { 10 //default: outputs the message to the host.msg.send function. If undefined output is to console.log 11 //message is the text to ouput. 12}); 13 14ssh2shell.on ("commandProcessing", function onCommandProcessing( command, response, sshObj, stream ) { 15 //Allows for the handling of a commands response as each character is loaded into the buffer 16 //default: no action 17 //default is replaced by host.onCommandProcessing function if defined 18 //command is the command that is being processed 19 //response is the text buffer that is being loaded with each data event from stream.ready 20 //sshObj is the host object 21 //stream is the connection stream 22}); 23 24ssh2shell.on ("commandComplete", function onCommandComplete( command, response, sshObj ) { 25 //Allows for the handling of a commands response before the next command is run 26 //default: returns a debug message if host.debug = true 27 //default is replaced by host.onCommandComplete function if defined 28 //command is the compleated command 29 //response is the full buffer response from the command 30 //sshObj is the host object 31}); 32 33ssh2shell.on ("commandTimeout", function onCommandTimeout( command, response, stream ,connection ) { 34 //Allows for handling a command timeout that would normally cause the script to hang in a wait state 35 //default: an error is raised adding response to this.sshObj.sessionText and the connection is closed 36 //default is replaced by host.onCommandTimeout function if defined 37 //command is the command that timed out 38 //response is the text buffer up to the time out period 39 //stream is the session stream 40 //connection is the main connection object 41}); 42 43ssh2shell.on ("end", function onEnd( sessionText, sshObj ) { 44 //Allows access to sessionText when stream.finish triggers 45 //default: returns a debug message if host.debug = true 46 //default is replaced by host.onEnd function if defined 47 //sessionText is the full text response from the session 48 //sshObj is the host object 49}); 50 51ssh2shell.on ("close", function onClose(had_error = void(0)) { 52 //default: outputs primaryHost.closeMessage or error if one was received 53 //default: returns a debug message if host.debug = true 54 //had_error indicates an error was recieved on close 55}); 56 57ssh2shell.on ("error", function onError(err, type, close = false, callback(err, type) = undefined) { 58 //default: rasies a msg with the error message, runs the callback if defined and closes the connection 59 //default is replaced by host.onEnd function if defined 60 //err is the error received it maybe an Error object or a string containing the error message. 61 //type is a string identifying the source of the error 62 //close is a boolean value indicating if the event should close the connection. 63 //callback a fuction that will be run by the handler 64}); 65 66ssh2shell.on ("keyboard-interactive", 67 function onKeyboardInteractive(name, instructions, instructionsLang, prompts, finish){ 68 //See https://github.com/mscdex/ssh2#client-events 69 //name, instructions, instructionsLang don't seem to be of interest for authenticating 70 //prompts is an object of expected prompts and if they are to be showen to the user 71 //finish is the function to be called with an array of responses in the same order as 72 //the prompts parameter defined them. 73 //See [Client events](https://github.com/mscdex/ssh2#client-events) for more information 74 //if a non standard prompt results from a successfull connection then handle its detection and response in 75 //onCommandProcessing or commandTimeout. 76 //see text/keyboard-interactivetest.js 77});
No vulnerabilities found.
No security vulnerabilities found.