* Fix file transfer bug for WebSockets and SSH. Set/restore temp data handler belongs in base client.

* Lint some files
This commit is contained in:
Bryan Ashby 2018-05-12 09:33:41 -06:00
parent b2ae81c59e
commit 388e581b90
4 changed files with 57 additions and 53 deletions

View File

@ -100,6 +100,16 @@ function Client(/*input, output*/) {
} }
}); });
this.setTemporaryDirectDataHandler = function(handler) {
this.input.removeAllListeners('data');
this.input.on('data', handler);
};
this.restoreDataHandler = function() {
this.input.removeAllListeners('data');
this.input.on('data', this.dataHandler);
};
// //
// Peek at incoming |data| and emit events for any special // Peek at incoming |data| and emit events for any special

View File

@ -129,6 +129,10 @@ function SSHClient(clientConn) {
} }
}); });
this.dataHandler = function(data) {
self.emit('data', data);
};
this.updateTermInfo = function(info) { this.updateTermInfo = function(info) {
// //
// From ssh2 docs: // From ssh2 docs:
@ -167,7 +171,7 @@ function SSHClient(clientConn) {
self.log.info('SSH authentication success'); self.log.info('SSH authentication success');
clientConn.on('session', accept => { clientConn.on('session', accept => {
const session = accept(); const session = accept();
session.on('pty', function pty(accept, reject, info) { session.on('pty', function pty(accept, reject, info) {
@ -191,9 +195,7 @@ function SSHClient(clientConn) {
self.setInputOutput(channel.stdin, channel.stdout); self.setInputOutput(channel.stdin, channel.stdout);
channel.stdin.on('data', data => { channel.stdin.on('data', self.dataHandler);
self.emit('data', data);
});
if(self.cachedPtyInfo) { if(self.cachedPtyInfo) {
self.updateTermInfo(self.cachedPtyInfo); self.updateTermInfo(self.cachedPtyInfo);
@ -207,7 +209,7 @@ function SSHClient(clientConn) {
session.on('window-change', (accept, reject, info) => { session.on('window-change', (accept, reject, info) => {
self.log.debug(info, 'SSH window-change event'); self.log.debug(info, 'SSH window-change event');
self.updateTermInfo(info); self.updateTermInfo(info);
}); });
@ -237,13 +239,13 @@ exports.getModule = class SSHServerModule extends LoginServerModule {
hostKeys : [ hostKeys : [
{ {
key : fs.readFileSync(Config.loginServers.ssh.privateKeyPem), key : fs.readFileSync(Config.loginServers.ssh.privateKeyPem),
passphrase : Config.loginServers.ssh.privateKeyPass, passphrase : Config.loginServers.ssh.privateKeyPass,
} }
], ],
ident : 'enigma-bbs-' + enigVersion + '-srv', ident : 'enigma-bbs-' + enigVersion + '-srv',
// Note that sending 'banner' breaks at least EtherTerm! // Note that sending 'banner' breaks at least EtherTerm!
debug : (sshDebugLine) => { debug : (sshDebugLine) => {
if(true === Config.loginServers.ssh.traceConnections) { if(true === Config.loginServers.ssh.traceConnections) {
Log.trace(`SSH: ${sshDebugLine}`); Log.trace(`SSH: ${sshDebugLine}`);
} }

View File

@ -39,8 +39,8 @@ exports.TelnetClient = TelnetClient;
* Document OPTIONS -- add any missing * Document OPTIONS -- add any missing
* Internally handle OPTIONS: * Internally handle OPTIONS:
* Some should be emitted generically * Some should be emitted generically
* Some shoudl be handled internally -- denied, handled, etc. * Some shoudl be handled internally -- denied, handled, etc.
* *
* Allow term (ttype) to be set by environ sub negotiation * Allow term (ttype) to be set by environ sub negotiation
@ -67,7 +67,7 @@ const COMMANDS = {
EL : 248, // Erase Line EL : 248, // Erase Line
GA : 249, // Go Ahead GA : 249, // Go Ahead
SB : 250, // Start Sub-Negotiation Parameters SB : 250, // Start Sub-Negotiation Parameters
WILL : 251, // WILL : 251, //
WONT : 252, WONT : 252,
DO : 253, DO : 253,
DONT : 254, DONT : 254,
@ -101,7 +101,7 @@ const OPTIONS = {
TIMING_MARK : 6, // http://tools.ietf.org/html/rfc860 TIMING_MARK : 6, // http://tools.ietf.org/html/rfc860
//RC_TRANS_AND_ECHO : 7, // aka 'RCTE' @ http://www.rfc-base.org/txt/rfc-726.txt //RC_TRANS_AND_ECHO : 7, // aka 'RCTE' @ http://www.rfc-base.org/txt/rfc-726.txt
//OUPUT_LINE_WIDTH : 8, //OUPUT_LINE_WIDTH : 8,
//OUTPUT_PAGE_SIZE : 9, // //OUTPUT_PAGE_SIZE : 9, //
//OUTPUT_CARRIAGE_RETURN_DISP : 10, // RFC 652 //OUTPUT_CARRIAGE_RETURN_DISP : 10, // RFC 652
//OUTPUT_HORIZ_TABSTOPS : 11, // RFC 653 //OUTPUT_HORIZ_TABSTOPS : 11, // RFC 653
//OUTPUT_HORIZ_TAB_DISP : 12, // RFC 654 //OUTPUT_HORIZ_TAB_DISP : 12, // RFC 654
@ -195,15 +195,15 @@ function unknownOption(bufs, i, event) {
const OPTION_IMPLS = {}; const OPTION_IMPLS = {};
// :TODO: fill in the rest... // :TODO: fill in the rest...
OPTION_IMPLS.NO_ARGS = OPTION_IMPLS.NO_ARGS =
OPTION_IMPLS[OPTIONS.ECHO] = OPTION_IMPLS[OPTIONS.ECHO] =
OPTION_IMPLS[OPTIONS.STATUS] = OPTION_IMPLS[OPTIONS.STATUS] =
OPTION_IMPLS[OPTIONS.LINEMODE] = OPTION_IMPLS[OPTIONS.LINEMODE] =
OPTION_IMPLS[OPTIONS.TRANSMIT_BINARY] = OPTION_IMPLS[OPTIONS.TRANSMIT_BINARY] =
OPTION_IMPLS[OPTIONS.AUTHENTICATION] = OPTION_IMPLS[OPTIONS.AUTHENTICATION] =
OPTION_IMPLS[OPTIONS.TERMINAL_SPEED] = OPTION_IMPLS[OPTIONS.TERMINAL_SPEED] =
OPTION_IMPLS[OPTIONS.REMOTE_FLOW_CONTROL] = OPTION_IMPLS[OPTIONS.REMOTE_FLOW_CONTROL] =
OPTION_IMPLS[OPTIONS.X_DISPLAY_LOCATION] = OPTION_IMPLS[OPTIONS.X_DISPLAY_LOCATION] =
OPTION_IMPLS[OPTIONS.SEND_LOCATION] = OPTION_IMPLS[OPTIONS.SEND_LOCATION] =
OPTION_IMPLS[OPTIONS.ARE_YOU_THERE] = OPTION_IMPLS[OPTIONS.ARE_YOU_THERE] =
OPTION_IMPLS[OPTIONS.SUPPRESS_GO_AHEAD] = function(bufs, i, event) { OPTION_IMPLS[OPTIONS.SUPPRESS_GO_AHEAD] = function(bufs, i, event) {
event.buf = bufs.splice(0, i).toBuffer(); event.buf = bufs.splice(0, i).toBuffer();
@ -453,7 +453,7 @@ function parseCommand(bufs, i, event) {
} }
event.buf = bufs.splice(0, 2).toBuffer(); event.buf = bufs.splice(0, 2).toBuffer();
return event; return event;
} }
} }
@ -486,16 +486,6 @@ function TelnetClient(input, output) {
newEnvironRequested : false, newEnvironRequested : false,
}; };
this.setTemporaryDirectDataHandler = function(handler) {
this.input.removeAllListeners('data');
this.input.on('data', handler);
};
this.restoreDataHandler = function() {
this.input.removeAllListeners('data');
this.input.on('data', this.dataHandler);
};
this.dataHandler = function(b) { this.dataHandler = function(b) {
if(!Buffer.isBuffer(b)) { if(!Buffer.isBuffer(b)) {
EnigAssert(false, `Cannot push non-buffer ${typeof b}`); EnigAssert(false, `Cannot push non-buffer ${typeof b}`);
@ -516,15 +506,15 @@ function TelnetClient(input, output) {
} }
EnigAssert(bufs.length > (i + 1)); EnigAssert(bufs.length > (i + 1));
if(i > 0) { if(i > 0) {
self.emit('data', bufs.splice(0, i).toBuffer()); self.emit('data', bufs.splice(0, i).toBuffer());
} }
i = parseBufs(bufs); i = parseBufs(bufs);
if(MORE_DATA_REQUIRED === i) { if(MORE_DATA_REQUIRED === i) {
break; break;
} else if(i) { } else if(i) {
if(i.option) { if(i.option) {
self.emit(i.option, i); // "transmit binary", "echo", ... self.emit(i.option, i); // "transmit binary", "echo", ...
@ -589,7 +579,7 @@ util.inherits(TelnetClient, baseClient.Client);
// Telnet Command/Option handling // Telnet Command/Option handling
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
TelnetClient.prototype.handleTelnetEvent = function(evt) { TelnetClient.prototype.handleTelnetEvent = function(evt) {
if(!evt.command) { if(!evt.command) {
return this.connectionWarn( { evt : evt }, 'No command for event'); return this.connectionWarn( { evt : evt }, 'No command for event');
} }
@ -611,7 +601,7 @@ TelnetClient.prototype.handleWillCommand = function(evt) {
// //
// See RFC 1091 @ http://www.faqs.org/rfcs/rfc1091.html // See RFC 1091 @ http://www.faqs.org/rfcs/rfc1091.html
// //
this.requestTerminalType(); this.requestTerminalType();
} else if('new environment' === evt.option) { } else if('new environment' === evt.option) {
// //
// See RFC 1572 @ http://www.faqs.org/rfcs/rfc1572.html // See RFC 1572 @ http://www.faqs.org/rfcs/rfc1572.html
@ -630,7 +620,7 @@ TelnetClient.prototype.handleWontCommand = function(evt) {
this.sentDont[evt.option] = true; this.sentDont[evt.option] = true;
if('new environment' === evt.option) { if('new environment' === evt.option) {
this.dont.new_environment(); this.dont.new_environment();
} else { } else {
this.connectionTrace(evt, 'WONT'); this.connectionTrace(evt, 'WONT');
@ -693,16 +683,16 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
self.term.termHeight = parseInt(evt.envVars[name]); self.term.termHeight = parseInt(evt.envVars[name]);
self.clearMciCache(); // term size changes = invalidate cache self.clearMciCache(); // term size changes = invalidate cache
self.connectionDebug({ termHeight : self.term.termHeight, source : 'NEW-ENVIRON'}, 'Window height updated'); self.connectionDebug({ termHeight : self.term.termHeight, source : 'NEW-ENVIRON'}, 'Window height updated');
} else { } else {
if(name in self.term.env) { if(name in self.term.env) {
EnigAssert( EnigAssert(
SB_COMMANDS.INFO === evt.type || SB_COMMANDS.IS === evt.type, SB_COMMANDS.INFO === evt.type || SB_COMMANDS.IS === evt.type,
'Unexpected type: ' + evt.type 'Unexpected type: ' + evt.type
); );
self.connectionWarn( self.connectionWarn(
{ varName : name, value : evt.envVars[name], existingValue : self.term.env[name] }, { varName : name, value : evt.envVars[name], existingValue : self.term.env[name] },
'Environment variable already exists' 'Environment variable already exists'
); );
} else { } else {
@ -719,7 +709,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) {
// //
self.term.termWidth = evt.width; self.term.termWidth = evt.width;
self.term.termHeight = evt.height; self.term.termHeight = evt.height;
if(evt.width > 0) { if(evt.width > 0) {
self.term.env.COLUMNS = evt.height; self.term.env.COLUMNS = evt.height;
} }
@ -752,11 +742,11 @@ TelnetClient.prototype.handleMiscCommand = function(evt) {
if('ip' === evt.command) { if('ip' === evt.command) {
// Interrupt Process (IP) // Interrupt Process (IP)
this.log.debug('Interrupt Process (IP) - Ending'); this.log.debug('Interrupt Process (IP) - Ending');
this.input.end(); this.input.end();
} else if('ayt' === evt.command) { } else if('ayt' === evt.command) {
this.output.write('\b'); this.output.write('\b');
this.log.debug('Are You There (AYT) - Replied "\\b"'); this.log.debug('Are You There (AYT) - Replied "\\b"');
} else if(IGNORED_COMMANDS.indexOf(evt.commandCode)) { } else if(IGNORED_COMMANDS.indexOf(evt.commandCode)) {
this.log.debug({ evt : evt }, 'Ignoring command'); this.log.debug({ evt : evt }, 'Ignoring command');
@ -767,11 +757,11 @@ TelnetClient.prototype.handleMiscCommand = function(evt) {
TelnetClient.prototype.requestTerminalType = function() { TelnetClient.prototype.requestTerminalType = function() {
const buf = Buffer.from( [ const buf = Buffer.from( [
COMMANDS.IAC, COMMANDS.IAC,
COMMANDS.SB, COMMANDS.SB,
OPTIONS.TERMINAL_TYPE, OPTIONS.TERMINAL_TYPE,
SB_COMMANDS.SEND, SB_COMMANDS.SEND,
COMMANDS.IAC, COMMANDS.IAC,
COMMANDS.SE ]); COMMANDS.SE ]);
this.output.write(buf); this.output.write(buf);
}; };
@ -790,15 +780,15 @@ TelnetClient.prototype.requestNewEnvironment = function() {
return; return;
} }
const self = this; const self = this;
const bufs = buffers(); const bufs = buffers();
bufs.push(Buffer.from( [ bufs.push(Buffer.from( [
COMMANDS.IAC, COMMANDS.IAC,
COMMANDS.SB, COMMANDS.SB,
OPTIONS.NEW_ENVIRONMENT, OPTIONS.NEW_ENVIRONMENT,
SB_COMMANDS.SEND ] SB_COMMANDS.SEND ]
)); ));
for(let i = 0; i < WANTED_ENVIRONMENT_VAR_BUFS.length; ++i) { for(let i = 0; i < WANTED_ENVIRONMENT_VAR_BUFS.length; ++i) {
bufs.push(Buffer.from( [ NEW_ENVIRONMENT_COMMANDS.VAR ] ), WANTED_ENVIRONMENT_VAR_BUFS[i] ); bufs.push(Buffer.from( [ NEW_ENVIRONMENT_COMMANDS.VAR ] ), WANTED_ENVIRONMENT_VAR_BUFS[i] );
@ -828,7 +818,7 @@ TelnetClient.prototype.banner = function() {
function Command(command, client) { function Command(command, client) {
this.command = COMMANDS[command.toUpperCase()]; this.command = COMMANDS[command.toUpperCase()];
this.client = client; this.client = client;
} }
// Create Command objects with echo, transmit_binary, ... // Create Command objects with echo, transmit_binary, ...

View File

@ -30,6 +30,10 @@ function WebSocketClient(ws, req, serverType) {
const self = this; const self = this;
this.dataHandler = function(data) {
self.socketBridge.emit('data', data);
};
// //
// This bridge makes accessible various calls that client sub classes // This bridge makes accessible various calls that client sub classes
// want to access on I/O socket // want to access on I/O socket
@ -65,9 +69,7 @@ function WebSocketClient(ws, req, serverType) {
} }
}(ws); }(ws);
ws.on('message', data => { ws.on('message', this.dataHandler);
this.socketBridge.emit('data', data);
});
ws.on('close', () => { ws.on('close', () => {
// we'll remove client connection which will in turn end() via our SocketBridge above // we'll remove client connection which will in turn end() via our SocketBridge above