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.
@@ -28,7 +28,7 @@
28
28
  "<node_internals>/**"
29
29
  ],
30
30
  "program": "${file}",
31
- "args":["-c","-d"]
31
+ "args":["-c","-e=uptime","-e=ls -all"]
32
32
  }
33
33
  ]
34
34
  }
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
- stream.pipe(socket);
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
- stream.end();
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
- stream.end();
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
- _this.on_ssh_client_ready(opts.server_name, opts.proxy_ports, resolve);
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 '-d':
54
- case '--debug':
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 '-n':
98
- case '--ngrok':
99
- ngrokAPIKey = value;
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ssh_tunnel_proxy",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "obtain ngrok host port from api and establish a ssh connection",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {