#!/usr/bin/env node var net = require('net'), fs = require('fs'), http = require('http'), websocket = require('websocket'), ssh2 = require('ssh2'), crypto = require('crypto'); config = require('../config'); libs = require('./libs'); world = require('./world'); try { var banner = fs.readFileSync(__dirname + "/../banner.txt", "utf-8"); config.welcomeBanner = banner; world.mud_load(); } catch (error) { libs.Output.toServerError("MUD cannot be loaded.", error); process.exit(1); } var telnetserver = net.createServer(function(socket) { var login = new libs.TelnetLogin(socket); login.attach(); socket.on('data', function(data) { try { login.receive(data); } catch (error) { libs.Output.toServerError("Error in telnet socket when receiving data", error); libs.Output.worldToMobiles("You sense a {error}tear{/error} in the fabric of reality."); } }); socket.on('end', function() { login.disconnect(); }); socket.on('error', function(error) { if(error.code == "EPIPE") { libs.Output.toServerError("Telnet socket "+socket.nickname+" was written to after being closed.", error); } else if (error.code == "ECONNRESET") { libs.Output.toServerError("Telnet socket connection reset.", error); } else { libs.Output.toServerError("Unknown telnet socket error", error); } }); socket.setTimeout(config.telnettimeout); socket.on('timeout', function() { socket.write('\nConnection timed out.\n'); socket.end(); }); }); telnetserver.on('error', function(error) { if(error.code == "EADDRINUSE") { libs.Output.toServerError("There is already a server running!", error); process.exit(1); } else { libs.Output.toServerError("Unknown telnet server error", error); } }); var webserver = http.createServer(function(request, response) { if(!config.enableWebserver) { return; } var configData = fs.readFileSync(__dirname + "/../config.json", "utf-8"); var webconfig = JSON.parse(configData); var controller = new libs.WebserverController(); controller.handleRequest(webconfig, request, response); }); webserver.on('error', function(error) { libs.Output.toServerError("Unknown webserver error", error); }); // create the server var websocketserver = new websocket.server({ httpServer: webserver }); // WebSocket server websocketserver.on('request', function(request) { var connection = request.accept(null, request.origin); var login = new libs.WebsocketLogin(connection); login.attach(); connection.on('message', function(message) { if (message.type === 'utf8') { try { login.receive(message.utf8Data); } catch (error) { libs.Output.toServerError("Error in websocket socket when receiving data", error); libs.Output.worldToMobiles("You sense a {error}tear{/error} in the fabric of reality."); } } else { libs.Output.toServer(message); } }); connection.on('close', function(connection) { login.disconnect(); }); }); var buffersEqual = function(buffer1, buffer2) { return 0 == Buffer.compare(buffer1, buffer2); } var sshserver = new ssh2.Server({ hostKeys: [fs.readFileSync(config.sshKeyPath)] }, function(client) { var userData = null; var login = new libs.SSHLogin(); client.on('authentication', function(ctx) { switch(ctx.method) { case "password": userData = world.mud_getUserData(ctx.username); if(userData == null) { ctx.reject(["password"]); return; } if(world.mud_isValidLogin(userData, ctx.password)) { ctx.accept(); } else { ctx.reject(); return; } break; case "publickey": var pubKeys = []; var validCheck = false; userData = world.mud_getUserData(ctx.username); if(userData == null) { ctx.reject(["publickey", "password"]); return; } for(var index in userData.pubKeys) { var pubKey = ssh2.utils.parseKey(userData.pubKeys[index]); if(ctx.key.algo === pubKey.type && buffersEqual(ctx.key.data, pubKey.getPublicSSH())) { if(ctx.signature) { if(pubKey.verify(ctx.blob, ctx.signature)) { ctx.accept() validCheck = true } } else { ctx.accept(); validCheck = true; } } } if(!validCheck) { ctx.reject(["password"]); } break; case "none": ctx.reject(["publickey","password"]); break; default: ctx.reject(); break; } }); client.on('ready', function() { client.on('session', function(accept, reject) { var session = accept(); session.on("pty", function(accept, reject, info) { //todo: some kinda screen resolution config console.log(info); }); session.on("shell", function(accept, reject) { var channel = accept(); login.attachChannel(channel); try { login.attach(userData); } catch (error) { libs.Output.toServerError("Error when attaching user in SSH", error); libs.Output.worldToMobiles("You sense a {error}ripple{/error} in the fabric of reality."); } channel.on("data", function(data){ try { login.receive(data); } catch (error) { libs.Output.toServerError("Error in ssh socket when receiving data", error); libs.Output.worldToMobiles("You sense a {error}tear{/error} in the fabric of reality."); } }); channel.on("close", function(data){ console.log("closing channel"); try { session.close(); } catch (error) { console.log("error closing session"); } }); }); session.on("close", function() { console.log("closing session"); try { client.end(); } catch (error) { console.log("error ending client"); } }); }); }); client.on('end', function() { console.log("client ending"); login.disconnect(); }); }); telnetserver.listen(config.telnetport, config.telnetlisten, function() { libs.Output.toServer("Telnet server listening on " + config.telnetlisten + ":" + config.telnetport); }); webserver.listen(config.websocketport, config.websocketlisten, function() { libs.Output.toServer("Websocket server listening on " + config.websocketlisten + ":" + config.websocketport); }); sshserver.listen(config.sshport, config.sshlisten, function() { libs.Output.toServer("SSH server listening on " + config.sshlisten + ":" + config.sshport); }); process.stdin.resume(); process.stdin.setEncoding('utf8'); process.stdin.on('data', function (data) { var input = data.trim().split(" "); switch(input.shift()) { case "say": libs.Output.worldToMobiles(input.join(" ")); break; case "exit": case "quit": case "stop": libs.Output.worldToMobiles("The server is shutting down!"); for(var playerIndex in session.players) { var player = session.players[playerIndex]; player.quit(); } process.exit(0); break; case "restart": for(var playerIndex in session.players) { var player = session.players[playerIndex]; player.quit(); } world.mud_load(); break; } });