ssh_tunnel_proxy 1.2.6 → 1.2.8

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","-e=uptime","-e=ls -all"]
31
+ "args":["-c","-r=nqs"]
32
32
  }
33
33
  ]
34
34
  }
package/README.md CHANGED
@@ -3,9 +3,13 @@ Initiate a ssh reverse tunnel proxy with forwarding ports
3
3
 
4
4
  ssh_tunnel_proxy can function as a stand-alone api, nodejs command line script or as part of an electron_js app. To setup a ssh tunnel, parameters are suppled for host, port, authentication and a list of proxy ports. If a ngrok api key is provided the host and port of the ngrok tunnel are obtained. A list of port forwards is provided and is validated to restrict connections to system ports on the remote host to a list of pre-defined ports such as http or https. After establishing a ssh connection on the remote server, local proxy port forwards are opened. If the connection is interrupted or connection errors occur, attempts are made re-establish the tunnel.
5
5
 
6
- Example command line usage:
6
+ Example command line to establish a list of local forwards:
7
7
 
8
- config file, located at:
8
+ ```
9
+ node main.js -c
10
+ ```
11
+
12
+ default config file, located at:
9
13
  ~/.config/ssh_tunnel_proxy/config.json
10
14
  ```json
11
15
  [{
@@ -28,21 +32,44 @@ config file, located at:
28
32
  "server_name": "test",
29
33
  "ngrok_api": "<ngrok api key>"
30
34
  }]
35
+ ```
31
36
 
37
+ Command line to execute a series of commands on remote host:
38
+ ```
39
+ node main.js -c -e='uptime' -e='ls -all'
32
40
  ```
33
- start tunnel with default config, located at ~/.config/ssh_tunnel_proxy/config.json
34
41
 
42
+ Or execute commands defined in default config:
35
43
  ```
36
- node main.js -c -d
44
+ node main.js -c
37
45
  ```
46
+ ```json
47
+ [{
48
+ "enabled": true,
49
+ "username": "<username>",
50
+ "service_name": "ssh_proxy_client",
51
+ "server_name": "test",
52
+ "exec" : [
53
+ "uptime",
54
+ "ls -all"
55
+ ],
56
+ "ngrok_api": "<ngrok api key>"
57
+ }]
58
+ ```
59
+
60
+ Start a terminal session on the remote host:
61
+ ```
62
+ node main.js -c -S
63
+ ```
64
+
65
+ The following code is an example of use of the api with electronjs.
38
66
 
39
- The following code is an example of use of the api with electronjs and is to be installed in main.js, preload.js and the render process.
40
67
  main.js:
41
68
  ```js
42
69
 
43
70
  async function init_sshTunnelProxy(win) {
44
71
 
45
- const SSHTunnelProxy = require('ssh_tunnel_proxy');
72
+ const { SSHTunnelProxy } = require('ssh_tunnel_proxy');
46
73
  const sshTunnelProxy = new SSHTunnelProxy();
47
74
 
48
75
  ipcMain.on('connect_ssh_sync', async function(event,opts) {
package/lib/index.js CHANGED
@@ -18,6 +18,7 @@ License: MIT
18
18
 
19
19
  const net = require('net');
20
20
  const process = require('process');
21
+ const { Buffer } = require('node:buffer');
21
22
  const { Client } = require('electron-ssh2');
22
23
 
23
24
  const KeypairStorage = require('./keypair_storage');
@@ -157,27 +158,42 @@ class SSHTunnelProxy extends Client {
157
158
  });
158
159
  }
159
160
 
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);
161
+ exec_cmd(cmd, dataStream, errStream) {
162
+
163
+ return new Promise((resolve, reject) => {
164
+ var bufs = [];
165
+ var errs = [];
166
+
167
+ const remote_exec = (err, stream) => {
168
+ if (err) {
169
+ reject(err);
170
+ return;
171
+ }
172
+ stream.on('close', () => {
173
+ var buf = Buffer.concat(bufs);
174
+ var err = Buffer.concat(errs);
175
+ resolve(buf, err);
176
+ })
177
+
178
+ if (dataStream) {
179
+ stream.pipe(dataStream);
180
+ } else {
181
+ stream.on('data', (data) => {
182
+ bufs.push(data);
183
+ })
184
+ }
185
+
186
+ if (errStream) {
187
+ stream.stderr.pipe(errStream);
188
+ } else {
189
+ stream.stderr.on('data', (data) => {
190
+ errs.push(data);
191
+ });
192
+ }
193
+
194
+ }
177
195
  this.exec(cmd, remote_exec);
178
- return true;
179
- }
180
- return false;
196
+ })
181
197
  }
182
198
 
183
199
  // handle remote shell stream processing
@@ -227,7 +243,7 @@ class SSHTunnelProxy extends Client {
227
243
  _this.listener[opts.server_name] = {};
228
244
  }
229
245
 
230
- _this.on('ready', () => {
246
+ _this.on('ready', async () => {
231
247
 
232
248
  // stop any pending retry timeouts
233
249
  if (_this._tunnelReadyTimeout) {
@@ -242,14 +258,21 @@ class SSHTunnelProxy extends Client {
242
258
  // if exec requested, exec series of cmds
243
259
  } else {
244
260
  if (opts.exec && opts.exec.length > 0) {
245
- _this.exec_cmds = opts.exec;
246
- _this.exec_next();
261
+ for (var i = 0; i < opts.exec.length; i++) {
262
+ var cmd = opts.exec[i];
263
+ console.log(opts.username + '@' + opts.hostname + ':' + cmd);
264
+ var result = await _this.exec_cmd(cmd);
265
+ console.log(result.toString());
266
+ }
267
+ process.exit();
247
268
  }
248
269
  }
249
270
 
250
271
  // if local forward requested, setup local forwarding ports to remote host
251
272
  if (opts.proxy_ports) {
252
273
  _this.on_ssh_client_ready(opts.server_name, opts.proxy_ports, resolve);
274
+ } else {
275
+ resolve();
253
276
  }
254
277
  });
255
278
 
@@ -310,6 +333,9 @@ class SSHTunnelProxy extends Client {
310
333
 
311
334
  // validate local forwards for correct format and valid ports
312
335
  validate_local_forward(proxy_ports, whitelist) {
336
+
337
+ if (!proxy_ports) return;
338
+
313
339
  const local_ports = [];
314
340
  const remote_ports = [];
315
341
  proxy_ports.forEach(proxy_port => {
package/main.js CHANGED
@@ -6,6 +6,7 @@ const keypairStorage = new KeypairStorage();
6
6
  const homedir = require('os').homedir();
7
7
  var debug = false;
8
8
  var exec = [];
9
+ var remote_host = null;
9
10
  var proxies = [];
10
11
  var configs = null;
11
12
  var host = null;
@@ -92,6 +93,10 @@ function main(args) {
92
93
  case '--ngrok':
93
94
  ngrokAPIKey = value;
94
95
  break;
96
+ case '-r':
97
+ case '--remote':
98
+ remote_host = value;
99
+ break;
95
100
  case '-R':
96
101
  case '--RemoteForward':
97
102
  forwardIn.push(value);
@@ -140,6 +145,9 @@ function main(args) {
140
145
  // skip tunnel if not enabled
141
146
  if (!config.enabled) return;
142
147
 
148
+ // if remote host specified, only select tunnel for remote host
149
+ if (remote_host && remote_host !== config.alias) return;
150
+
143
151
  // if system key storage name specified get key from system keychain
144
152
  if (config.server_name) {
145
153
  const service_name = config.service_name || 'ssh_tunnel_proxy';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ssh_tunnel_proxy",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "description": "obtain ngrok host port from api and establish a ssh connection",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {