ssh_tunnel_proxy 1.2.4 → 1.2.6
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/.vscode/launch.json +1 -1
- package/lib/index.js +100 -7
- package/main.js +33 -18
- package/package.json +1 -1
package/.vscode/launch.json
CHANGED
package/lib/index.js
CHANGED
|
@@ -17,6 +17,7 @@ License: MIT
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
const net = require('net');
|
|
20
|
+
const process = require('process');
|
|
20
21
|
const { Client } = require('electron-ssh2');
|
|
21
22
|
|
|
22
23
|
const KeypairStorage = require('./keypair_storage');
|
|
@@ -32,6 +33,7 @@ class SSHTunnelProxy extends Client {
|
|
|
32
33
|
this.retries = 0;
|
|
33
34
|
this.debug_en = false;
|
|
34
35
|
this.debug_ssh = false;
|
|
36
|
+
this._tunnelReadyTimeout = undefined;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
// function to close all active sockets for tunnel restart and exception handling
|
|
@@ -61,20 +63,29 @@ class SSHTunnelProxy extends Client {
|
|
|
61
63
|
return;
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
stream.on('end', () => {
|
|
67
|
+
socket.resume();
|
|
68
|
+
});
|
|
69
|
+
|
|
64
70
|
// pipe the data from the local socket to the remote port and visa versa
|
|
65
|
-
socket.pipe(stream);
|
|
66
|
-
|
|
71
|
+
stream.pipe(socket).pipe(stream);
|
|
72
|
+
|
|
73
|
+
const shutdown_forward = () => {
|
|
74
|
+
stream.unpipe(socket);
|
|
75
|
+
socket.unpipe(stream);
|
|
76
|
+
stream.end();
|
|
77
|
+
}
|
|
67
78
|
|
|
68
79
|
// if socket ends, close stream and pipes
|
|
69
80
|
socket.on('close', () => {
|
|
70
|
-
|
|
81
|
+
shutdown_forward();
|
|
71
82
|
});
|
|
72
83
|
|
|
73
84
|
// if socket error, emit error and close stream
|
|
74
85
|
socket.on('error', (err) => {
|
|
75
86
|
_this.emit('debug', err);
|
|
76
87
|
_this.debug_en && _this.debug('socket on error:', err);
|
|
77
|
-
|
|
88
|
+
shutdown_forward();
|
|
78
89
|
});
|
|
79
90
|
}
|
|
80
91
|
|
|
@@ -133,6 +144,10 @@ class SSHTunnelProxy extends Client {
|
|
|
133
144
|
// if all listeners have been successfully established, resolve setup connection
|
|
134
145
|
if (listeners++ >= proxy_ports.length - 1) {
|
|
135
146
|
_this.emit('ssh_tunnel_ready', {});
|
|
147
|
+
if (_this._tunnelReadyTimeout) {
|
|
148
|
+
clearTimeout(this._tunnelReadyTimeout);
|
|
149
|
+
_this._tunnelReadyTimeout = undefined
|
|
150
|
+
}
|
|
136
151
|
resolve();
|
|
137
152
|
}
|
|
138
153
|
});
|
|
@@ -142,6 +157,58 @@ class SSHTunnelProxy extends Client {
|
|
|
142
157
|
});
|
|
143
158
|
}
|
|
144
159
|
|
|
160
|
+
exec_next() {
|
|
161
|
+
const _this = this;
|
|
162
|
+
const remote_exec = (err, stream) => {
|
|
163
|
+
if (err) throw err;
|
|
164
|
+
stream.on('close', () => {
|
|
165
|
+
process.stdout.write('-- exec completed --\n\n');
|
|
166
|
+
if (!_this.exec_next()) process.exit();
|
|
167
|
+
}).on('data', (data) => {
|
|
168
|
+
process.stdout.write(data);
|
|
169
|
+
}).stderr.on('data', (data) => {
|
|
170
|
+
process.stderr.write(data);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (this.exec_cmds.length > 0) {
|
|
174
|
+
const cmd = this.exec_cmds[0];
|
|
175
|
+
this.exec_cmds.shift();
|
|
176
|
+
console.log('$: ' + cmd);
|
|
177
|
+
this.exec(cmd, remote_exec);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// handle remote shell stream processing
|
|
184
|
+
remote_shell(err, stream) {
|
|
185
|
+
const _this = this;
|
|
186
|
+
if (err) throw err;
|
|
187
|
+
|
|
188
|
+
// disable local echo of input chars, use remote output only
|
|
189
|
+
process.stdin.setRawMode(true);
|
|
190
|
+
|
|
191
|
+
// forward data from local terminal to remote host
|
|
192
|
+
const stdinListener = (data) => {
|
|
193
|
+
stream.stdin.write(data);
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
// shutdown this process when stream ends (user logs out)
|
|
197
|
+
stream.on('close', function () {
|
|
198
|
+
process.stdin.setRawMode(false);
|
|
199
|
+
process.stdin.removeListener("data", stdinListener);
|
|
200
|
+
process.exit();
|
|
201
|
+
}).stderr.on('data', function (data) {
|
|
202
|
+
_this.debug_en && _this.debug('shell' + data);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// skip next stops double printing of input
|
|
206
|
+
stream.stdout.on("data", (data) => {
|
|
207
|
+
process.stdout.write(data);
|
|
208
|
+
})
|
|
209
|
+
process.stdin.on("data", stdinListener)
|
|
210
|
+
}
|
|
211
|
+
|
|
145
212
|
// handle setting up ssh client and proxy forward ports
|
|
146
213
|
do_ssh_connect(opts) {
|
|
147
214
|
|
|
@@ -161,7 +228,29 @@ class SSHTunnelProxy extends Client {
|
|
|
161
228
|
}
|
|
162
229
|
|
|
163
230
|
_this.on('ready', () => {
|
|
164
|
-
|
|
231
|
+
|
|
232
|
+
// stop any pending retry timeouts
|
|
233
|
+
if (_this._tunnelReadyTimeout) {
|
|
234
|
+
clearTimeout(this._tunnelReadyTimeout);
|
|
235
|
+
_this._tunnelReadyTimeout = undefined;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// if shell requested, enable remote terminal
|
|
239
|
+
if (opts.shell) {
|
|
240
|
+
_this.shell(_this.remote_shell);
|
|
241
|
+
|
|
242
|
+
// if exec requested, exec series of cmds
|
|
243
|
+
} else {
|
|
244
|
+
if (opts.exec && opts.exec.length > 0) {
|
|
245
|
+
_this.exec_cmds = opts.exec;
|
|
246
|
+
_this.exec_next();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// if local forward requested, setup local forwarding ports to remote host
|
|
251
|
+
if (opts.proxy_ports) {
|
|
252
|
+
_this.on_ssh_client_ready(opts.server_name, opts.proxy_ports, resolve);
|
|
253
|
+
}
|
|
165
254
|
});
|
|
166
255
|
|
|
167
256
|
_this.on('end', () => {
|
|
@@ -178,6 +267,10 @@ class SSHTunnelProxy extends Client {
|
|
|
178
267
|
_this.debug_en && _this.debug('SSH Client :: error :: ' + err);
|
|
179
268
|
_this.emit('debug', err);
|
|
180
269
|
if (_this.listener[opts.server_name]) _this.listener[opts.server_name].isConnected = false;
|
|
270
|
+
if (_this._tunnelReadyTimeout) {
|
|
271
|
+
clearTimeout(this._tunnelReadyTimeout);
|
|
272
|
+
_this._tunnelReadyTimeout = undefined
|
|
273
|
+
}
|
|
181
274
|
_this.ssh_retry_connect(opts);
|
|
182
275
|
resolve();
|
|
183
276
|
});
|
|
@@ -247,7 +340,7 @@ class SSHTunnelProxy extends Client {
|
|
|
247
340
|
const invoke = () => {
|
|
248
341
|
_this.connectSSH(opts);
|
|
249
342
|
}
|
|
250
|
-
if (this.retries++ < 10) setTimeout(invoke, 5000);
|
|
343
|
+
if (this.retries++ < 10) this._tunnelReadyTimeout = setTimeout(invoke, 5000);
|
|
251
344
|
}
|
|
252
345
|
|
|
253
346
|
// attempt to establish ssh tunnel to server with supplied parameters.
|
|
@@ -262,7 +355,7 @@ class SSHTunnelProxy extends Client {
|
|
|
262
355
|
const msg = 'SSH connection to ' + opts.server_name + ' established at ' + hostport;
|
|
263
356
|
_this.debug(msg);
|
|
264
357
|
}
|
|
265
|
-
_this.emit('status', '', 'ready', hostport);
|
|
358
|
+
//_this.emit('status', '', 'ready', hostport);
|
|
266
359
|
_this.retries = 0;
|
|
267
360
|
resolve();
|
|
268
361
|
});
|
package/main.js
CHANGED
|
@@ -5,6 +5,7 @@ const { SSHTunnelProxy, KeypairStorage } = require('./lib/index.js');
|
|
|
5
5
|
const keypairStorage = new KeypairStorage();
|
|
6
6
|
const homedir = require('os').homedir();
|
|
7
7
|
var debug = false;
|
|
8
|
+
var exec = [];
|
|
8
9
|
var proxies = [];
|
|
9
10
|
var configs = null;
|
|
10
11
|
var host = null;
|
|
@@ -17,6 +18,7 @@ var ngrokAPIKey = null;
|
|
|
17
18
|
var privateKey = null;
|
|
18
19
|
var service = null;
|
|
19
20
|
var account = null;
|
|
21
|
+
var shell = null;
|
|
20
22
|
|
|
21
23
|
function get_key_from_file(filename) {
|
|
22
24
|
try {
|
|
@@ -50,15 +52,22 @@ function main(args) {
|
|
|
50
52
|
const cmd = arg[0];
|
|
51
53
|
const value = arg[1];
|
|
52
54
|
switch (cmd) {
|
|
53
|
-
case '
|
|
54
|
-
|
|
55
|
-
debug = true;
|
|
55
|
+
case '--a':
|
|
56
|
+
account = value;
|
|
56
57
|
break;
|
|
57
58
|
case '-c':
|
|
58
59
|
case '--config':
|
|
59
60
|
if (value) get_config(value);
|
|
60
61
|
else get_default_config();
|
|
61
62
|
break;
|
|
63
|
+
case '-d':
|
|
64
|
+
case '--debug':
|
|
65
|
+
debug = true;
|
|
66
|
+
break;
|
|
67
|
+
case '-e':
|
|
68
|
+
case '--exec':
|
|
69
|
+
exec.push(value);
|
|
70
|
+
break;
|
|
62
71
|
case '-h':
|
|
63
72
|
case '--host':
|
|
64
73
|
host = value;
|
|
@@ -67,10 +76,6 @@ function main(args) {
|
|
|
67
76
|
case '--port':
|
|
68
77
|
port = value;
|
|
69
78
|
break;
|
|
70
|
-
case '-u':
|
|
71
|
-
case '--username':
|
|
72
|
-
username = value;
|
|
73
|
-
break;
|
|
74
79
|
case '-P':
|
|
75
80
|
case '--password':
|
|
76
81
|
password = value;
|
|
@@ -79,24 +84,29 @@ function main(args) {
|
|
|
79
84
|
case '--key':
|
|
80
85
|
privateKey = value;
|
|
81
86
|
break;
|
|
82
|
-
case '-s':
|
|
83
|
-
case '--service':
|
|
84
|
-
service = value;
|
|
85
|
-
break;
|
|
86
|
-
case '--a':
|
|
87
|
-
account = value;
|
|
88
|
-
break;
|
|
89
87
|
case '-L':
|
|
90
88
|
case '--LocalForward':
|
|
91
89
|
forwardOut.push(value);
|
|
92
90
|
break;
|
|
91
|
+
case '-n':
|
|
92
|
+
case '--ngrok':
|
|
93
|
+
ngrokAPIKey = value;
|
|
94
|
+
break;
|
|
93
95
|
case '-R':
|
|
94
96
|
case '--RemoteForward':
|
|
95
97
|
forwardIn.push(value);
|
|
96
98
|
break;
|
|
97
|
-
case '-
|
|
98
|
-
case '--
|
|
99
|
-
|
|
99
|
+
case '-s':
|
|
100
|
+
case '--service':
|
|
101
|
+
service = value;
|
|
102
|
+
break;
|
|
103
|
+
case '-S':
|
|
104
|
+
case '--shell':
|
|
105
|
+
shell = true;
|
|
106
|
+
break;
|
|
107
|
+
case '-u':
|
|
108
|
+
case '--username':
|
|
109
|
+
username = value;
|
|
100
110
|
break;
|
|
101
111
|
default:
|
|
102
112
|
if (i > 1) console.log('Invalid argument:', arg);
|
|
@@ -139,7 +149,12 @@ function main(args) {
|
|
|
139
149
|
else if (config.private_key) {
|
|
140
150
|
config.private_key = get_key_from_file(config.private_key);
|
|
141
151
|
}
|
|
142
|
-
|
|
152
|
+
if (shell) {
|
|
153
|
+
config.shell = true;
|
|
154
|
+
}
|
|
155
|
+
if (exec.length > 0) {
|
|
156
|
+
config.exec = exec;
|
|
157
|
+
}
|
|
143
158
|
// create new tunnel and start connection
|
|
144
159
|
var sshTunnelProxy = new SSHTunnelProxy();
|
|
145
160
|
proxies.push(sshTunnelProxy);
|