From fd3192c75a56747fe7c215d9c09dbdde22919a0a Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sat, 28 May 2016 21:04:39 -0600 Subject: [PATCH] Add DoorParty support --- core/door_party.js | 126 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 core/door_party.js diff --git a/core/door_party.js b/core/door_party.js new file mode 100644 index 00000000..db00b841 --- /dev/null +++ b/core/door_party.js @@ -0,0 +1,126 @@ +/* jslint node: true */ +'use strict'; + +// enigma-bbs +const MenuModule = require('../core/menu_module.js').MenuModule; +const resetScreen = require('../core/ansi_term.js').resetScreen; + +// deps +const async = require('async'); +const _ = require('lodash'); +const SSHClient = require('ssh2').Client; + +exports.getModule = DoorPartyModule; + +exports.moduleInfo = { + name : 'DoorParty', + desc : 'DoorParty Access Module', + author : 'NuSkooler', +}; + + +function DoorPartyModule(options) { + MenuModule.call(this, options); + + const self = this; + + // establish defaults + this.config = options.menuConfig.config; + this.config.host = this.config.host || 'dp.throwbackbbs.com'; + this.config.sshPort = this.config.sshPort || 22; + this.config.rloginPort = this.config.rloginPort || 513; + + + this.initSequence = function() { + let clientTerminated; + + async.series( + [ + function validateConfig(callback) { + if(!_.isString(self.config.username)) { + return callback(new Error('Config requires "username"!')); + } + if(!_.isString(self.config.password)) { + return callback(new Error('Config requires "password"!')); + } + return callback(null); + }, + function establishSecureConnection(callback) { + self.client.term.write(resetScreen()); + self.client.term.write('Connecting to DoorParty, please wait...\n'); + + const sshClient = new SSHClient(); + + let pipeRestored = false; + let pipedStream; + const restorePipe = function() { + if(pipedStream && !pipeRestored && !clientTerminated) { + self.client.term.output.unpipe(pipedStream); + self.client.term.output.resume(); + } + }; + + sshClient.on('ready', () => { + // track client termination so we can clean up early + self.client.once('end', () => { + self.client.log.info('Connection ended. Terminating DoorParty connection'); + clientTerminated = true; + sshClient.end(); + }); + + // establish tunnel for rlogin + sshClient.forwardOut('127.0.0.1', self.config.sshPort, self.config.host, self.config.rloginPort, (err, stream) => { + if(err) { + return callback(new Error('Failed to establish tunnel')); + } + + // send rlogin + const rlogin = `\x00${self.config.username}\x00${self.config.username}\x00${self.client.term.termType}\x00`; + stream.write(rlogin); + + pipedStream = stream; // :TODO: this is hacky... + self.client.term.output.pipe(stream); + + stream.on('data', d => { + // :TODO: we should just pipe this... + self.client.term.rawWrite(d); + }); + + stream.on('close', () => { + restorePipe(); + sshClient.end(); + }); + }); + }); + + sshClient.on('close', () => { + restorePipe(); + callback(null); + }); + + sshClient.connect( { + host : self.config.host, + port : self.config.sshPort, + username : self.config.username, + password : self.config.password, + }); + + // note: no explicit callback() until we're finished! + } + ], + err => { + if(err) { + self.client.log.warn( { error : err.toString() }, 'DoorParty error'); + } + + // if the client is stil here, go to previous + if(!clientTerminated) { + self.prevMenu(); + } + } + ); + }; + +} + +require('util').inherits(DoorPartyModule, MenuModule); \ No newline at end of file