diff --git a/core/servers/login/telnet.js b/core/servers/login/telnet.js index 111167fb..7bb938a4 100644 --- a/core/servers/login/telnet.js +++ b/core/servers/login/telnet.js @@ -176,9 +176,6 @@ class TelnetClient { this.socket.write('\b'); return this._logTrace(command, 'Are You There (AYT) - Replied'); }); - - // kick off negotiations - this._banner(); } disconnect() { @@ -189,6 +186,21 @@ class TelnetClient { } } + banner() { + this.socket.do.echo(); + this.socket.will.echo(); // we'll echo back + + this.socket.will.sga(); + this.socket.do.sga(); + + this.socket.do.transmit_binary(); + this.socket.will.transmit_binary(); + + this.socket.do.ttype(); + this.socket.do.naws(); + this.socket.do.new_environ(); + } + _logTrace(info, msg) { if (Config().loginServers.telnet.traceConnections) { const log = this.log || Log; @@ -209,21 +221,6 @@ class TelnetClient { this.clientReadyHandled = true; this.emit('ready', { firstMenu : Config().loginServers.telnet.firstMenu } ); } - - _banner() { - this.socket.do.echo(); - this.socket.will.echo(); // we'll echo back - - this.socket.will.sga(); - this.socket.do.sga(); - - this.socket.do.transmit_binary(); - this.socket.will.transmit_binary(); - - this.socket.do.ttype(); - this.socket.do.naws(); - this.socket.do.new_environ(); - } }; inherits(TelnetClient, Client); @@ -236,6 +233,7 @@ exports.getModule = class TelnetServerModule extends LoginServerModule { createServer(cb) { this.server = net.createServer( socket => { const client = new TelnetClient(socket); + client.banner(); // start negotiations this.handleNewClient(client, socket, ModuleInfo); }); diff --git a/core/servers/login/websocket.js b/core/servers/login/websocket.js index 1cff80e4..f0cdc0b1 100644 --- a/core/servers/login/websocket.js +++ b/core/servers/login/websocket.js @@ -24,100 +24,106 @@ const ModuleInfo = exports.moduleInfo = { packageName : 'codes.l33t.enigma.websocket.server', }; -function WebSocketClient(ws, req, serverType) { +class WebSocketClient extends TelnetClient { + constructor(ws, req, serverType) { + // + // This bridge makes accessible various calls that client sub classes + // want to access on I/O socket + // + const socketBridge = new class SocketBridge extends Writable { + constructor(ws) { + super(); + this.ws = ws; + } - Object.defineProperty(this, 'isSecure', { - get : () => ('secure' === serverType || true === this.proxied) ? true : false, - }); + setClient(client) { + this.client = client; + } - const self = this; + end() { + return ws.close(); + } - this.dataHandler = function(data) { - if(self.pipedDest) { - self.pipedDest.write(data); + write(data, cb) { + cb = cb || ( () => { /* eat it up */} ); // handle data writes after close + + return this.ws.send(data, { binary : true }, cb); + } + + pipe(dest) { + Log.trace('WebSocket SocketBridge pipe()'); + this.client.pipedDest = dest; + } + + unpipe() { + Log.trace('WebSocket SocketBridge unpipe()'); + this.client.pipedDest = null; + } + + resume() { + Log.trace('WebSocket SocketBridge resume()'); + } + + get remoteAddress() { + // Support X-Forwarded-For and X-Real-IP headers for proxied connections + return (this.client.proxied && (req.headers['x-forwarded-for'] || req.headers['x-real-ip'])) || req.connection.remoteAddress; + } + }(ws); + + // :TODO: this is quite the clusterfuck... + super(socketBridge); + this.socketBridge = socketBridge; + this.serverType = serverType; + + this.socketBridge.setClient(this); + + this.dataHandler = function(data) { + if(this.pipedDest) { + this.pipedDest.write(data); + } else { + this.socketBridge.emit('data', data); + } + }.bind(this); + + ws.on('message', this.dataHandler); + + ws.on('close', () => { + // we'll remove client connection which will in turn end() via our SocketBridge above + return this.emit('end'); + }); + + // + // Monitor connection status with ping/pong + // + ws.on('pong', () => { + Log.trace(`Pong from ${this.socketBridge.remoteAddress}`); + ws.isConnectionAlive = true; + }); + + Log.trace( { headers : req.headers }, 'WebSocket connection headers' ); + + // + // If the config allows it, look for 'x-forwarded-proto' as "https" + // to override |isSecure| + // + if(true === _.get(Config(), 'loginServers.webSocket.proxied') && + 'https' === req.headers['x-forwarded-proto']) + { + Log.debug(`Assuming secure connection due to X-Forwarded-Proto of "${req.headers['x-forwarded-proto']}"`); + this.proxied = true; } else { - self.socketBridge.emit('data', data); - } - }; - - // - // This bridge makes accessible various calls that client sub classes - // want to access on I/O socket - // - this.socketBridge = new class SocketBridge extends Writable { - constructor(ws) { - super(); - this.ws = ws; + this.proxied = false; } - end() { - return ws.close(); - } - - write(data, cb) { - cb = cb || ( () => { /* eat it up */} ); // handle data writes after close - - return this.ws.send(data, { binary : true }, cb); - } - - pipe(dest) { - Log.trace('WebSocket SocketBridge pipe()'); - self.pipedDest = dest; - } - - unpipe() { - Log.trace('WebSocket SocketBridge unpipe()'); - self.pipedDest = null; - } - - resume() { - Log.trace('WebSocket SocketBridge resume()'); - } - - get remoteAddress() { - // Support X-Forwarded-For and X-Real-IP headers for proxied connections - return (self.proxied && (req.headers['x-forwarded-for'] || req.headers['x-real-ip'])) || req.connection.remoteAddress; - } - }(ws); - - ws.on('message', this.dataHandler); - - ws.on('close', () => { - // we'll remove client connection which will in turn end() via our SocketBridge above - return this.emit('end'); - }); - - // - // Monitor connection status with ping/pong - // - ws.on('pong', () => { - Log.trace(`Pong from ${this.socketBridge.remoteAddress}`); - ws.isConnectionAlive = true; - }); - - TelnetClient.call(this, this.socketBridge); - - Log.trace( { headers : req.headers }, 'WebSocket connection headers' ); - - // - // If the config allows it, look for 'x-forwarded-proto' as "https" - // to override |isSecure| - // - if(true === _.get(Config(), 'loginServers.webSocket.proxied') && - 'https' === req.headers['x-forwarded-proto']) - { - Log.debug(`Assuming secure connection due to X-Forwarded-Proto of "${req.headers['x-forwarded-proto']}"`); - this.proxied = true; - } else { - this.proxied = false; + // start handshake process + this.banner(); } - // start handshake process - this.banner(); + get isSecure() { + return ('secure' === this.serverType || true === this.proxied) ? true : false; + } } -require('util').inherits(WebSocketClient, TelnetClient); - const WSS_SERVER_TYPES = [ 'insecure', 'secure' ]; exports.getModule = class WebSocketLoginServer extends LoginServerModule {