ssh_tunnel_proxy 1.2.3 → 1.2.5
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 +70 -8
- package/main.js +8 -0
- 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
|
|
|
@@ -104,7 +115,7 @@ class SSHTunnelProxy extends Client {
|
|
|
104
115
|
// create local socket server
|
|
105
116
|
const server = this.listener[server_name][proxy_port];
|
|
106
117
|
if (server && server.listening) {
|
|
107
|
-
this.debug_en && this.debug('SSH Server :: closing forward:', proxy_port)
|
|
118
|
+
this.debug_en && this.debug('SSH Server :: closing forward 2:', proxy_port)
|
|
108
119
|
server.close();
|
|
109
120
|
}
|
|
110
121
|
this.listener[server_name][proxy_port] = null;
|
|
@@ -122,6 +133,8 @@ class SSHTunnelProxy extends Client {
|
|
|
122
133
|
|
|
123
134
|
// start listening on port
|
|
124
135
|
try {
|
|
136
|
+
var status_msg = 'SSH Server :: before listen on ' + local_port;
|
|
137
|
+
_this.emit('debug', status_msg);
|
|
125
138
|
_this.listener[server_name][proxy_port].listen(local_port, () => {
|
|
126
139
|
|
|
127
140
|
// emit server listening on port message
|
|
@@ -130,7 +143,11 @@ class SSHTunnelProxy extends Client {
|
|
|
130
143
|
|
|
131
144
|
// if all listeners have been successfully established, resolve setup connection
|
|
132
145
|
if (listeners++ >= proxy_ports.length - 1) {
|
|
133
|
-
_this.emit('
|
|
146
|
+
_this.emit('ssh_tunnel_ready', {});
|
|
147
|
+
if (_this._tunnelReadyTimeout) {
|
|
148
|
+
clearTimeout(this._tunnelReadyTimeout);
|
|
149
|
+
_this._tunnelReadyTimeout = undefined
|
|
150
|
+
}
|
|
134
151
|
resolve();
|
|
135
152
|
}
|
|
136
153
|
});
|
|
@@ -140,6 +157,35 @@ class SSHTunnelProxy extends Client {
|
|
|
140
157
|
});
|
|
141
158
|
}
|
|
142
159
|
|
|
160
|
+
// handle remote shell stream processing
|
|
161
|
+
remote_shell(err, stream) {
|
|
162
|
+
const _this = this;
|
|
163
|
+
if (err) throw err;
|
|
164
|
+
|
|
165
|
+
// disable local echo of input chars, use remote output only
|
|
166
|
+
process.stdin.setRawMode(true);
|
|
167
|
+
|
|
168
|
+
// forward data from local terminal to remote host
|
|
169
|
+
const stdinListener = (data) => {
|
|
170
|
+
stream.stdin.write(data);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// shutdown this process when stream ends (user logs out)
|
|
174
|
+
stream.on('close', function () {
|
|
175
|
+
process.stdin.setRawMode(false);
|
|
176
|
+
process.stdin.removeListener("data", stdinListener);
|
|
177
|
+
process.exit();
|
|
178
|
+
}).stderr.on('data', function (data) {
|
|
179
|
+
_this.debug_en && _this.debug('shell' + data);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// skip next stops double printing of input
|
|
183
|
+
stream.stdout.on("data", (data) => {
|
|
184
|
+
process.stdout.write(data);
|
|
185
|
+
})
|
|
186
|
+
process.stdin.on("data", stdinListener)
|
|
187
|
+
}
|
|
188
|
+
|
|
143
189
|
// handle setting up ssh client and proxy forward ports
|
|
144
190
|
do_ssh_connect(opts) {
|
|
145
191
|
|
|
@@ -159,7 +205,18 @@ class SSHTunnelProxy extends Client {
|
|
|
159
205
|
}
|
|
160
206
|
|
|
161
207
|
_this.on('ready', () => {
|
|
208
|
+
|
|
209
|
+
// if shell requested, enable remote terminal
|
|
210
|
+
if (opts.shell) {
|
|
211
|
+
_this.shell(_this.remote_shell);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// setup local forwarding ports to remote host
|
|
162
215
|
_this.on_ssh_client_ready(opts.server_name, opts.proxy_ports, resolve);
|
|
216
|
+
if (_this._tunnelReadyTimeout) {
|
|
217
|
+
clearTimeout(this._tunnelReadyTimeout);
|
|
218
|
+
_this._tunnelReadyTimeout = undefined
|
|
219
|
+
}
|
|
163
220
|
});
|
|
164
221
|
|
|
165
222
|
_this.on('end', () => {
|
|
@@ -176,6 +233,10 @@ class SSHTunnelProxy extends Client {
|
|
|
176
233
|
_this.debug_en && _this.debug('SSH Client :: error :: ' + err);
|
|
177
234
|
_this.emit('debug', err);
|
|
178
235
|
if (_this.listener[opts.server_name]) _this.listener[opts.server_name].isConnected = false;
|
|
236
|
+
if (_this._tunnelReadyTimeout) {
|
|
237
|
+
clearTimeout(this._tunnelReadyTimeout);
|
|
238
|
+
_this._tunnelReadyTimeout = undefined
|
|
239
|
+
}
|
|
179
240
|
_this.ssh_retry_connect(opts);
|
|
180
241
|
resolve();
|
|
181
242
|
});
|
|
@@ -239,12 +300,13 @@ class SSHTunnelProxy extends Client {
|
|
|
239
300
|
}
|
|
240
301
|
|
|
241
302
|
// on network error, attempt to re-establish connection until 10 retries
|
|
303
|
+
//clearTimeout(this._readyTimeout);
|
|
242
304
|
ssh_retry_connect(opts) {
|
|
243
305
|
const _this = this;
|
|
244
306
|
const invoke = () => {
|
|
245
307
|
_this.connectSSH(opts);
|
|
246
308
|
}
|
|
247
|
-
if (this.retries++ < 10) setTimeout(invoke, 5000);
|
|
309
|
+
if (this.retries++ < 10) this._tunnelReadyTimeout = setTimeout(invoke, 5000);
|
|
248
310
|
}
|
|
249
311
|
|
|
250
312
|
// attempt to establish ssh tunnel to server with supplied parameters.
|
|
@@ -259,7 +321,7 @@ class SSHTunnelProxy extends Client {
|
|
|
259
321
|
const msg = 'SSH connection to ' + opts.server_name + ' established at ' + hostport;
|
|
260
322
|
_this.debug(msg);
|
|
261
323
|
}
|
|
262
|
-
_this.emit('status', '', 'ready', hostport);
|
|
324
|
+
//_this.emit('status', '', 'ready', hostport);
|
|
263
325
|
_this.retries = 0;
|
|
264
326
|
resolve();
|
|
265
327
|
});
|
package/main.js
CHANGED
|
@@ -17,6 +17,7 @@ var ngrokAPIKey = null;
|
|
|
17
17
|
var privateKey = null;
|
|
18
18
|
var service = null;
|
|
19
19
|
var account = null;
|
|
20
|
+
var shell = null;
|
|
20
21
|
|
|
21
22
|
function get_key_from_file(filename) {
|
|
22
23
|
try {
|
|
@@ -83,6 +84,10 @@ function main(args) {
|
|
|
83
84
|
case '--service':
|
|
84
85
|
service = value;
|
|
85
86
|
break;
|
|
87
|
+
case '-S':
|
|
88
|
+
case '--shell':
|
|
89
|
+
shell = true;
|
|
90
|
+
break;
|
|
86
91
|
case '--a':
|
|
87
92
|
account = value;
|
|
88
93
|
break;
|
|
@@ -139,6 +144,9 @@ function main(args) {
|
|
|
139
144
|
else if (config.private_key) {
|
|
140
145
|
config.private_key = get_key_from_file(config.private_key);
|
|
141
146
|
}
|
|
147
|
+
if (shell) {
|
|
148
|
+
config.shell=true;
|
|
149
|
+
}
|
|
142
150
|
|
|
143
151
|
// create new tunnel and start connection
|
|
144
152
|
var sshTunnelProxy = new SSHTunnelProxy();
|