ssh2shell 1.9.8 → 1.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ssh2shell.js +55 -46
- package/package.json +1 -1
- package/src/ssh2shell.coffee +44 -38
- package/test/sudo no pass test.js +40 -0
package/lib/ssh2shell.js
CHANGED
|
@@ -133,66 +133,74 @@
|
|
|
133
133
|
response = this._sanitizeResponse().trim();
|
|
134
134
|
passwordPrompt = this.passwordPrompt.test(response);
|
|
135
135
|
standardPrompt = this.standardPrompt.test(response);
|
|
136
|
-
if (this.sshObj.verbose) {
|
|
137
|
-
this.emit('msg', this.sshObj.server.host + ": Password previously sent: " + this.sshObj.pwSent);
|
|
138
|
-
}
|
|
139
136
|
if (this.sshObj.debug) {
|
|
140
|
-
this.emit('msg', this.sshObj.server.host + ": Password prompt
|
|
137
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo Password prompt detected: " + passwordPrompt);
|
|
141
138
|
}
|
|
142
|
-
if (this.sshObj.
|
|
143
|
-
this.emit('msg', this.sshObj.server.host + ":
|
|
139
|
+
if (this.sshObj.debug) {
|
|
140
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo Password prompt: Password sent: " + this.sshObj.pwSent);
|
|
144
141
|
}
|
|
145
|
-
if (this.sshObj.
|
|
146
|
-
this.emit('msg', this.sshObj.server.host + ": Sudo Password
|
|
142
|
+
if (this.sshObj.debug) {
|
|
143
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo Password: " + this.sshObj.server.password);
|
|
147
144
|
}
|
|
148
145
|
if (this.sshObj.verbose) {
|
|
149
|
-
this.emit('msg', this.sshObj.server.host + ": Sudo
|
|
146
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo Response: " + response);
|
|
150
147
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (passwordPrompt) {
|
|
148
|
+
switch (true) {
|
|
149
|
+
case passwordPrompt && !this.sshObj.server.password:
|
|
150
|
+
if (this.sshObj.debug) {
|
|
151
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo password prompt no password");
|
|
152
|
+
}
|
|
153
|
+
return this._resetFromSudoError();
|
|
154
|
+
case passwordPrompt && !this.sshObj.pwSent:
|
|
159
155
|
if (this.sshObj.verbose) {
|
|
160
|
-
this.emit('msg', this.sshObj.server.host + ":
|
|
156
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo password prompt: Buffer: " + response);
|
|
161
157
|
}
|
|
162
158
|
if (this.sshObj.debug) {
|
|
163
|
-
this.emit('msg', this.sshObj.server.host + ":
|
|
159
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo password prompt: Send password ");
|
|
164
160
|
}
|
|
165
161
|
if (this.sshObj.verbose) {
|
|
166
|
-
this.emit('msg', this.sshObj.server.host + ":
|
|
162
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo sent password: " + this.sshObj.server.password);
|
|
167
163
|
}
|
|
168
164
|
this.sshObj.pwSent = true;
|
|
169
165
|
return this._runCommand("" + this.sshObj.server.password);
|
|
170
|
-
|
|
166
|
+
case passwordPrompt && this.sshObj.pwSent:
|
|
167
|
+
if (this.sshObj.verbose) {
|
|
168
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo password faied: response: " + response);
|
|
169
|
+
}
|
|
171
170
|
if (this.sshObj.debug) {
|
|
172
|
-
this.emit('
|
|
171
|
+
this.emit('error', this.sshObj.server.host + ": Sudo password was incorrect for " + this.sshObj.server.userName + ", Sudo authentication");
|
|
173
172
|
}
|
|
173
|
+
if (this.sshObj.debug) {
|
|
174
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo failed password prompt: Password: [" + this.sshObj.server.password + "]");
|
|
175
|
+
}
|
|
176
|
+
this.sshObj.pwSent = false;
|
|
177
|
+
return this._resetFromSudoError();
|
|
178
|
+
case standardPrompt:
|
|
179
|
+
if (this.sshObj.debug) {
|
|
180
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo prompt: Standard prompt detected");
|
|
181
|
+
}
|
|
182
|
+
this.sshObj.pwSent = false;
|
|
174
183
|
if (this.sshObj.verbose) {
|
|
175
|
-
this.emit('msg', this.sshObj.server.host + ":
|
|
184
|
+
this.emit('msg', this.sshObj.server.host + ": Sudo Standard Response: " + response);
|
|
176
185
|
}
|
|
177
|
-
return this.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this.emit('error', this.sshObj.server.host + ": Sudo password was incorrect for " + this.sshObj.server.userName, "Sudo authentication");
|
|
185
|
-
}
|
|
186
|
-
if (this.sshObj.debug) {
|
|
187
|
-
this.emit('msg', this.sshObj.server.host + ": Failed password prompt: Password: [" + this.sshObj.server.password + "]");
|
|
188
|
-
}
|
|
189
|
-
this.sshObj.sessionText += "" + this._buffer;
|
|
190
|
-
this._buffer = "";
|
|
191
|
-
this.command = "";
|
|
192
|
-
return this._stream.write('\x03');
|
|
186
|
+
return this._commandComplete();
|
|
187
|
+
default:
|
|
188
|
+
return this.idleTimer = setTimeout((function(_this) {
|
|
189
|
+
return function() {
|
|
190
|
+
return _this.emit('commandTimeout', _this.command, response, _this._stream, _this._connection);
|
|
191
|
+
};
|
|
192
|
+
})(this), this.idleTime);
|
|
193
193
|
}
|
|
194
194
|
};
|
|
195
195
|
|
|
196
|
+
SSH2Shell.prototype._resetFromSudoError = function() {
|
|
197
|
+
this.sshObj.pwSent = false;
|
|
198
|
+
this.sshObj.sessionText += "" + this._buffer;
|
|
199
|
+
this._buffer = "";
|
|
200
|
+
this.command = "";
|
|
201
|
+
return this._stream.write('\x03');
|
|
202
|
+
};
|
|
203
|
+
|
|
196
204
|
SSH2Shell.prototype._processSSHPrompt = function() {
|
|
197
205
|
var passphrasePrompt, passwordPrompt, response, standardPrompt, using;
|
|
198
206
|
response = this._sanitizeResponse().trim();
|
|
@@ -225,22 +233,22 @@
|
|
|
225
233
|
return this._runCommand("" + this.sshObj.server.passPhrase);
|
|
226
234
|
} else if (standardPrompt) {
|
|
227
235
|
if (this.sshObj.debug) {
|
|
228
|
-
this.emit('msg', this.sshObj.server.host + ": SSH
|
|
236
|
+
this.emit('msg', this.sshObj.server.host + ": SSH standard prompt: connection failed");
|
|
229
237
|
}
|
|
230
238
|
this.emit('msg', this.sshObj.server.host + ": SSH connection failed");
|
|
231
239
|
this.emit('msg', this.sshObj.server.host + ": SSH failed response: " + response);
|
|
232
240
|
this.sshObj.sessionText += this.sshObj.server.host + ": SSH failed: response: " + response;
|
|
233
241
|
return this._runExit();
|
|
234
242
|
} else {
|
|
235
|
-
this.emit('msg', this.sshObj.server.host + ": SSH
|
|
243
|
+
this.emit('msg', this.sshObj.server.host + ": SSH no prompt was not detected");
|
|
236
244
|
if (this.sshObj.verbose && !this.sshObj.server.hasOwnProperty("passPhrase")) {
|
|
237
|
-
this.emit('msg', this.sshObj.server.host + ":
|
|
245
|
+
this.emit('msg', this.sshObj.server.host + ": SSH password prompt " + this.sshObj.passwordPrompt);
|
|
238
246
|
}
|
|
239
247
|
if (this.sshObj.verbose && this.sshObj.server.hasOwnProperty("passPhrase")) {
|
|
240
|
-
this.emit('msg', this.sshObj.server.host + ":
|
|
248
|
+
this.emit('msg', this.sshObj.server.host + ": SSH passphrase prompt " + this.sshObj.passphrasePrompt);
|
|
241
249
|
}
|
|
242
250
|
if (this.sshObj.verbose) {
|
|
243
|
-
this.emit('msg', this.sshObj.server.host + ":
|
|
251
|
+
this.emit('msg', this.sshObj.server.host + ": SSH standard prompt " + this.sshObj.standardPrompt);
|
|
244
252
|
}
|
|
245
253
|
return this._runExit();
|
|
246
254
|
}
|
|
@@ -268,9 +276,9 @@
|
|
|
268
276
|
using = (function() {
|
|
269
277
|
switch (false) {
|
|
270
278
|
case !passwordPrompt:
|
|
271
|
-
return "password: " + this.sshObj.server.password;
|
|
279
|
+
return "SSH password: " + this.sshObj.server.password;
|
|
272
280
|
case !passphrasePrompt:
|
|
273
|
-
return "passphrase: " + this.sshObj.server.passPhrase;
|
|
281
|
+
return "SSH passphrase: " + this.sshObj.server.passPhrase;
|
|
274
282
|
}
|
|
275
283
|
}).call(this);
|
|
276
284
|
this.emit('error', this.sshObj.server.host + ": SSH authentication failed for " + this.sshObj.server.userName + "@" + this.sshObj.server.host, "Nested host authentication");
|
|
@@ -570,6 +578,7 @@
|
|
|
570
578
|
this._commandComplete = bind(this._commandComplete, this);
|
|
571
579
|
this._processNotifications = bind(this._processNotifications, this);
|
|
572
580
|
this._processSSHPrompt = bind(this._processSSHPrompt, this);
|
|
581
|
+
this._resetFromSudoError = bind(this._resetFromSudoError, this);
|
|
573
582
|
this._processPasswordPrompt = bind(this._processPasswordPrompt, this);
|
|
574
583
|
this._sanitizeResponse = bind(this._sanitizeResponse, this);
|
|
575
584
|
this._onData = bind(this._onData, this);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssh2shell",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.9",
|
|
4
4
|
"author": "cmp-202",
|
|
5
5
|
"description": "A wrapper class for ssh2 to run multiple sequential commands in an SSH shell session, handle command responses, and tunnel through to other hosts using nested host objects",
|
|
6
6
|
"main": "./lib/ssh2shell.js",
|
package/src/ssh2shell.coffee
CHANGED
|
@@ -88,45 +88,51 @@ class SSH2Shell extends Stream
|
|
|
88
88
|
return @_buffer.replace(@command.substr(0, @_buffer.length), "")
|
|
89
89
|
|
|
90
90
|
_processPasswordPrompt: =>
|
|
91
|
-
#First test for password prompt
|
|
91
|
+
#First test for password prompt
|
|
92
92
|
response = @_sanitizeResponse().trim()
|
|
93
93
|
passwordPrompt = @passwordPrompt.test(response)
|
|
94
94
|
standardPrompt = @standardPrompt.test(response)
|
|
95
|
-
@.emit 'msg', "#{@sshObj.server.host}: Password
|
|
96
|
-
@.emit 'msg', "#{@sshObj.server.host}: Password prompt: Password
|
|
97
|
-
@.emit 'msg', "#{@sshObj.server.host}:
|
|
98
|
-
@.emit 'msg', "#{@sshObj.server.host}: Sudo
|
|
99
|
-
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
@
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
@.emit 'msg', "#{@sshObj.server.host}:
|
|
109
|
-
@.emit 'msg', "#{@sshObj.server.host}:
|
|
110
|
-
@.emit 'msg', "#{@sshObj.server.host}: Sent password: #{@sshObj.server.password}" if @sshObj.verbose
|
|
95
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo Password prompt detected: #{passwordPrompt}" if @sshObj.debug
|
|
96
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo Password prompt: Password sent: #{@sshObj.pwSent}" if @sshObj.debug
|
|
97
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo Password: #{@sshObj.server.password}" if @sshObj.debug
|
|
98
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo Response: #{response}" if @sshObj.verbose
|
|
99
|
+
|
|
100
|
+
#Prompt detection
|
|
101
|
+
#no password
|
|
102
|
+
switch (true)
|
|
103
|
+
when passwordPrompt and not @sshObj.server.password
|
|
104
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo password prompt no password" if @sshObj.debug
|
|
105
|
+
@_resetFromSudoError()
|
|
106
|
+
when passwordPrompt and not @sshObj.pwSent
|
|
107
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo password prompt: Buffer: #{response}" if @sshObj.verbose
|
|
108
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo password prompt: Send password " if @sshObj.debug
|
|
109
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo sent password: #{@sshObj.server.password}" if @sshObj.verbose
|
|
111
110
|
#send password
|
|
112
111
|
@sshObj.pwSent = true
|
|
113
112
|
@_runCommand("#{@sshObj.server.password}")
|
|
114
|
-
|
|
115
|
-
@.emit 'msg', "#{@sshObj.server.host}: Password prompt: not detected" if @sshObj.debug
|
|
116
|
-
@.emit 'msg', "#{@sshObj.server.host}: Password prompt #{@sshObj.passwordPrompt}" if @sshObj.verbose
|
|
117
|
-
@_runExit()
|
|
118
|
-
#password sent so either check for failure or run next command
|
|
119
|
-
else if passwordPrompt
|
|
113
|
+
when passwordPrompt and @sshObj.pwSent
|
|
120
114
|
@.emit 'msg', "#{@sshObj.server.host}: Sudo password faied: response: #{response}" if @sshObj.verbose
|
|
121
|
-
@.emit 'error', "#{@sshObj.server.host}: Sudo password was incorrect for #{@sshObj.server.userName}
|
|
122
|
-
@.emit 'msg', "#{@sshObj.server.host}:
|
|
115
|
+
@.emit 'error', "#{@sshObj.server.host}: Sudo password was incorrect for #{@sshObj.server.userName}, Sudo authentication" if @sshObj.debug
|
|
116
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo failed password prompt: Password: [#{@sshObj.server.password}]" if @sshObj.debug
|
|
117
|
+
@sshObj.pwSent = false
|
|
123
118
|
#add buffer to sessionText so the sudo response can be seen
|
|
124
|
-
@
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
@
|
|
128
|
-
@
|
|
129
|
-
|
|
119
|
+
@_resetFromSudoError()
|
|
120
|
+
when standardPrompt
|
|
121
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo prompt: Standard prompt detected" if @sshObj.debug
|
|
122
|
+
@sshObj.pwSent = false
|
|
123
|
+
@.emit 'msg', "#{@sshObj.server.host}: Sudo Standard Response: #{response}" if @sshObj.verbose
|
|
124
|
+
@_commandComplete()
|
|
125
|
+
else
|
|
126
|
+
@idleTimer = setTimeout( =>
|
|
127
|
+
@.emit 'commandTimeout', @.command, response, @._stream, @._connection
|
|
128
|
+
, @idleTime)
|
|
129
|
+
|
|
130
|
+
_resetFromSudoError: =>
|
|
131
|
+
@sshObj.pwSent = false
|
|
132
|
+
@sshObj.sessionText += "#{@_buffer}"
|
|
133
|
+
@_buffer = ""
|
|
134
|
+
@command = ""
|
|
135
|
+
@_stream.write '\x03'
|
|
130
136
|
|
|
131
137
|
_processSSHPrompt: =>
|
|
132
138
|
#not authenticated yet so detect prompts
|
|
@@ -156,16 +162,16 @@ class SSH2Shell extends Stream
|
|
|
156
162
|
@_runCommand("#{@sshObj.server.passPhrase}")
|
|
157
163
|
#normal prompt so continue with next command
|
|
158
164
|
else if standardPrompt
|
|
159
|
-
@.emit 'msg', "#{@sshObj.server.host}: SSH
|
|
165
|
+
@.emit 'msg', "#{@sshObj.server.host}: SSH standard prompt: connection failed" if @sshObj.debug
|
|
160
166
|
@.emit 'msg', "#{@sshObj.server.host}: SSH connection failed"
|
|
161
167
|
@.emit 'msg', "#{@sshObj.server.host}: SSH failed response: #{response}"
|
|
162
168
|
@sshObj.sessionText += "#{@sshObj.server.host}: SSH failed: response: #{response}"
|
|
163
169
|
@_runExit()
|
|
164
170
|
else
|
|
165
|
-
@.emit 'msg', "#{@sshObj.server.host}: SSH
|
|
166
|
-
@.emit 'msg', "#{@sshObj.server.host}:
|
|
167
|
-
@.emit 'msg', "#{@sshObj.server.host}:
|
|
168
|
-
@.emit 'msg', "#{@sshObj.server.host}:
|
|
171
|
+
@.emit 'msg', "#{@sshObj.server.host}: SSH no prompt was not detected"
|
|
172
|
+
@.emit 'msg', "#{@sshObj.server.host}: SSH password prompt #{@sshObj.passwordPrompt}" if @sshObj.verbose and not @sshObj.server.hasOwnProperty("passPhrase")
|
|
173
|
+
@.emit 'msg', "#{@sshObj.server.host}: SSH passphrase prompt #{@sshObj.passphrasePrompt}" if @sshObj.verbose and @sshObj.server.hasOwnProperty("passPhrase")
|
|
174
|
+
@.emit 'msg', "#{@sshObj.server.host}: SSH standard prompt #{@sshObj.standardPrompt}" if @sshObj.verbose
|
|
169
175
|
@_runExit()
|
|
170
176
|
else
|
|
171
177
|
@.emit 'msg', "#{@sshObj.server.host}: SSH post authentication prompt detection" if @sshObj.debug
|
|
@@ -183,8 +189,8 @@ class SSH2Shell extends Stream
|
|
|
183
189
|
@.emit 'msg', "#{@sshObj.server.host}: SSH: failed response: #{response}" if @sshObj.verbose
|
|
184
190
|
@sshObj.sshAuth = false
|
|
185
191
|
using = switch
|
|
186
|
-
when passwordPrompt then "password: #{@sshObj.server.password}"
|
|
187
|
-
when passphrasePrompt then "passphrase: #{@sshObj.server.passPhrase}"
|
|
192
|
+
when passwordPrompt then "SSH password: #{@sshObj.server.password}"
|
|
193
|
+
when passphrasePrompt then "SSH passphrase: #{@sshObj.server.passPhrase}"
|
|
188
194
|
@.emit 'error', "#{@sshObj.server.host}: SSH authentication failed for #{@sshObj.server.userName}@#{@sshObj.server.host}", "Nested host authentication"
|
|
189
195
|
@.emit 'msg', "#{@sshObj.server.host}: SSH auth failed: Using " + using if @sshObj.debug
|
|
190
196
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
var dotenv = require('dotenv').config();
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Used `sudo visudo` to add `[username] ALL=(ALL) NOPASSWD: ALL` on the first test
|
|
5
|
+
* server to test no password required detecting normal prompt correctly to run the
|
|
6
|
+
* next command
|
|
7
|
+
*/
|
|
8
|
+
var sshObj = {
|
|
9
|
+
server: {
|
|
10
|
+
host: process.env.SERVER2_HOST,
|
|
11
|
+
port: process.env.PORT,
|
|
12
|
+
userName: process.env.SERVER2_USER_NAME,
|
|
13
|
+
password: process.env.SERVER2_PASSWORD
|
|
14
|
+
},
|
|
15
|
+
commands: ["sudo apt-get update","sudo apt-get upgrade", "sudo apt autoremove"],
|
|
16
|
+
userPromptSent: false,
|
|
17
|
+
debug: true,
|
|
18
|
+
verbose: false,
|
|
19
|
+
onCommandProcessing: function( command, response, sshObj, stream ) {
|
|
20
|
+
//Check the command and prompt exits and respond with a 'y' but only does it once
|
|
21
|
+
if (response.indexOf("[Y/n]") != -1 && !sshObj.userPromptSent) {
|
|
22
|
+
sshObj.userPromptSent = true
|
|
23
|
+
stream.write("y")
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
onCommandComplete: function( command, response, sshObj ) {
|
|
27
|
+
if(sshObj.userPromptSent){
|
|
28
|
+
sshObj.userPromptSent = false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//until npm published use the cloned dir path.
|
|
33
|
+
var SSH2Shell = require ('../lib/ssh2shell');
|
|
34
|
+
|
|
35
|
+
//run the commands in the shell session
|
|
36
|
+
var SSH = new SSH2Shell(sshObj);
|
|
37
|
+
var callback = function(sessionText, sshObj) {
|
|
38
|
+
console.log(`Session End: ` + sessionText);
|
|
39
|
+
}
|
|
40
|
+
SSH.connect(callback);
|