<commit_before>/* jslint node: true */
'use strict';

//	ENiGMA½
const Config			= require('../../config.js').config;
const TelnetClient		= require('./telnet.js').TelnetClient;
const Log				= require('../../logger.js').log;
const LoginServerModule	= require('../../login_server_module.js');

//	deps
const _					= require('lodash');
const WebSocketServer	= require('ws').Server;
const http				= require('http');
const https				= require('https');
const fs				= require('graceful-fs');
const EventEmitter		= require('events');

const ModuleInfo = exports.moduleInfo = {
	name		: 'WebSocket',
	desc		: 'WebSocket Server',
	author		: 'NuSkooler',
	packageName	: 'codes.l33t.enigma.websocket.server',
};

function WebSocketClient(ws, req, serverType) {

	Object.defineProperty(this, 'isSecure', {
		get : () => ('secure' === serverType || true === this.proxied) ? true : false,
	});

	//
	//	This bridge makes accessible various calls that client sub classes
	//	want to access on I/O socket
	//
	this.socketBridge = new class SocketBridge extends EventEmitter {
		constructor(ws) {
			super();
			this.ws = ws;
		}

		end() {
			return ws.terminate();
		}

		write(data, cb) {
			return this.ws.send(data, { binary : true }, cb);
		}

		get remoteAddress() {
			//	Support X-Forwarded-For and X-Real-IP headers for proxied connections
			return (this.proxied && (req.headers['x-forwarded-for'] || req.headers['x-real-ip'])) || req.connection.remoteAddress;
		}
	}(ws);

	ws.on('message', data => {
		this.socketBridge.emit('data', data);
	});

	ws.on('close', () => {
		this.end();
	});

	//
	//	Montior connection status with ping/pong
	//
	ws.on('pong', () => { 
		Log.trace(`Pong from ${this.socketBridge.remoteAddress}`);
		ws.isConnectionAlive = true;
	});

	TelnetClient.call(this, this.socketBridge, 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;
	}

	//	start handshake process
	this.banner();
}

require('util').inherits(WebSocketClient, TelnetClient);

const WSS_SERVER_TYPES = [ 'insecure', 'secure' ];

exports.getModule = class WebSocketLoginServer extends LoginServerModule {
	constructor() {
		super();
	}

	createServer() {<commit_msg>Fix proxied check for remoteAddress<commit_after>/* jslint node: true */
'use strict';

//	ENiGMA½
const Config			= require('../../config.js').config;
const TelnetClient		= require('./telnet.js').TelnetClient;
const Log				= require('../../logger.js').log;
const LoginServerModule	= require('../../login_server_module.js');

//	deps
const _					= require('lodash');
const WebSocketServer	= require('ws').Server;
const http				= require('http');
const https				= require('https');
const fs				= require('graceful-fs');
const EventEmitter		= require('events');

const ModuleInfo = exports.moduleInfo = {
	name		: 'WebSocket',
	desc		: 'WebSocket Server',
	author		: 'NuSkooler',
	packageName	: 'codes.l33t.enigma.websocket.server',
};

function WebSocketClient(ws, req, serverType) {

	Object.defineProperty(this, 'isSecure', {
		get : () => ('secure' === serverType || true === this.proxied) ? true : false,
	});

	const self = this;

	//
	//	This bridge makes accessible various calls that client sub classes
	//	want to access on I/O socket
	//
	this.socketBridge = new class SocketBridge extends EventEmitter {
		constructor(ws) {
			super();
			this.ws = ws;
		}

		end() {
			return ws.terminate();
		}

		write(data, cb) {
			return this.ws.send(data, { binary : true }, cb);
		}

		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', data => {
		this.socketBridge.emit('data', data);
	});

	ws.on('close', () => {
		this.end();
	});

	//
	//	Montior connection status with ping/pong
	//
	ws.on('pong', () => { 
		Log.trace(`Pong from ${this.socketBridge.remoteAddress}`);
		ws.isConnectionAlive = true;
	});

	TelnetClient.call(this, this.socketBridge, 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();
}

require('util').inherits(WebSocketClient, TelnetClient);

const WSS_SERVER_TYPES = [ 'insecure', 'secure' ];

exports.getModule = class WebSocketLoginServer extends LoginServerModule {
	constructor() {
		super();
	}

	createServer() {
{'fraction_non_alphanumeric': 0.1750822209324821, 'fraction_numerical': 0.0007738440704198104, 'mean_word_length': 3.7737765466297324, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3079645', 'n_tokens_mistral': 1904, 'n_tokens_neox': 1764, 'n_words': 382}