WebSockets work with new telnet server
This commit is contained in:
parent
6d307ec06b
commit
e85ba322ce
|
@ -176,9 +176,6 @@ class TelnetClient {
|
||||||
this.socket.write('\b');
|
this.socket.write('\b');
|
||||||
return this._logTrace(command, 'Are You There (AYT) - Replied');
|
return this._logTrace(command, 'Are You There (AYT) - Replied');
|
||||||
});
|
});
|
||||||
|
|
||||||
// kick off negotiations
|
|
||||||
this._banner();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect() {
|
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) {
|
_logTrace(info, msg) {
|
||||||
if (Config().loginServers.telnet.traceConnections) {
|
if (Config().loginServers.telnet.traceConnections) {
|
||||||
const log = this.log || Log;
|
const log = this.log || Log;
|
||||||
|
@ -209,21 +221,6 @@ class TelnetClient {
|
||||||
this.clientReadyHandled = true;
|
this.clientReadyHandled = true;
|
||||||
this.emit('ready', { firstMenu : Config().loginServers.telnet.firstMenu } );
|
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);
|
inherits(TelnetClient, Client);
|
||||||
|
@ -236,6 +233,7 @@ exports.getModule = class TelnetServerModule extends LoginServerModule {
|
||||||
createServer(cb) {
|
createServer(cb) {
|
||||||
this.server = net.createServer( socket => {
|
this.server = net.createServer( socket => {
|
||||||
const client = new TelnetClient(socket);
|
const client = new TelnetClient(socket);
|
||||||
|
client.banner(); // start negotiations
|
||||||
this.handleNewClient(client, socket, ModuleInfo);
|
this.handleNewClient(client, socket, ModuleInfo);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -24,100 +24,106 @@ const ModuleInfo = exports.moduleInfo = {
|
||||||
packageName : 'codes.l33t.enigma.websocket.server',
|
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', {
|
setClient(client) {
|
||||||
get : () => ('secure' === serverType || true === this.proxied) ? true : false,
|
this.client = client;
|
||||||
});
|
}
|
||||||
|
|
||||||
const self = this;
|
end() {
|
||||||
|
return ws.close();
|
||||||
|
}
|
||||||
|
|
||||||
this.dataHandler = function(data) {
|
write(data, cb) {
|
||||||
if(self.pipedDest) {
|
cb = cb || ( () => { /* eat it up */} ); // handle data writes after close
|
||||||
self.pipedDest.write(data);
|
|
||||||
|
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 {
|
} else {
|
||||||
self.socketBridge.emit('data', data);
|
this.proxied = false;
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end() {
|
// start handshake process
|
||||||
return ws.close();
|
this.banner();
|
||||||
}
|
|
||||||
|
|
||||||
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
|
get isSecure() {
|
||||||
this.banner();
|
return ('secure' === this.serverType || true === this.proxied) ? true : false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
require('util').inherits(WebSocketClient, TelnetClient);
|
|
||||||
|
|
||||||
const WSS_SERVER_TYPES = [ 'insecure', 'secure' ];
|
const WSS_SERVER_TYPES = [ 'insecure', 'secure' ];
|
||||||
|
|
||||||
exports.getModule = class WebSocketLoginServer extends LoginServerModule {
|
exports.getModule = class WebSocketLoginServer extends LoginServerModule {
|
||||||
|
|
Loading…
Reference in New Issue