* SSH is now functional for 'ssh', PuTTY, SyncTerm, EtherTerm, and hopefully most others

* Explicit detect of syncterm as ANSI
* Add serverType (TELNET, SSH) MCI: %ST
This commit is contained in:
Bryan Ashby 2015-10-21 22:51:35 -06:00
parent e7e9746a85
commit ad4eea6ba7
12 changed files with 101 additions and 43 deletions

View File

@ -175,7 +175,7 @@ function startListening() {
var port = parseInt(module.runtime.config.port); var port = parseInt(module.runtime.config.port);
if(isNaN(port)) { if(isNaN(port)) {
logger.log.error({ port : module.runtime.config.port, server : module.moduleInfo.name }, 'Cannot load server (Invalid port)'); logger.log.error( { port : module.runtime.config.port, server : module.moduleInfo.name }, 'Cannot load server (Invalid port)');
return; return;
} }
@ -188,11 +188,13 @@ function startListening() {
// //
// Start tracking the client. We'll assign it an ID which is // Start tracking the client. We'll assign it an ID which is
// just the index in our connections array. // just the index in our connections array.
// //
if(_.isUndefined(client.session)) { if(_.isUndefined(client.session)) {
client.session = {}; client.session = {};
} }
client.session.serverType = moduleInst.getServerType();
clientConns.addNewClient(client, clientSock); clientConns.addNewClient(client, clientSock);
client.on('ready', function onClientReady() { client.on('ready', function onClientReady() {

View File

@ -425,7 +425,15 @@ Client.prototype.end = function () {
clearInterval(this.idleCheck); clearInterval(this.idleCheck);
return this.output.end.apply(this.output, arguments); try {
//
// We can end up calling 'end' before TTY/etc. is established, e.g. with SSH
//
// :TODO: is this OK?
return this.output.end.apply(this.output, arguments);
} catch(e) {
// TypeError
}
}; };
Client.prototype.destroy = function () { Client.prototype.destroy = function () {

View File

@ -20,7 +20,10 @@ function addNewClient(client, clientSock) {
// Create a client specific logger // Create a client specific logger
client.log = logger.log.child( { clientId : id } ); client.log = logger.log.child( { clientId : id } );
var connInfo = { ip : clientSock.remoteAddress }; var connInfo = {
ip : clientSock.remoteAddress,
serverType : client.session.serverType,
};
if(client.log.debug()) { if(client.log.debug()) {
connInfo.port = clientSock.localPort; connInfo.port = clientSock.localPort;

View File

@ -74,6 +74,17 @@ function ClientTerminal(output) {
// SCREEN // SCREEN
// * ConnectBot // * ConnectBot
// //
// syncterm
// *
//
// Reports from various terminals
// SyncTERM
// * syncterm
//
// PuTTY
// * xterm
//
//
if(this.isANSI()) { if(this.isANSI()) {
this.outputEncoding = 'cp437'; this.outputEncoding = 'cp437';
} else { } else {
@ -125,7 +136,7 @@ function ClientTerminal(output) {
ClientTerminal.prototype.isANSI = function() { ClientTerminal.prototype.isANSI = function() {
// :TODO: Others?? // :TODO: Others??
return [ 'ansi', 'pc-ansi', 'qansi', 'scoansi' ].indexOf(this.termType) > -1; return [ 'ansi', 'pc-ansi', 'qansi', 'scoansi', 'syncterm' ].indexOf(this.termType) > -1;
}; };
// :TODO: probably need to update these to convert IAC (0xff) -> IACIAC (escape it) // :TODO: probably need to update these to convert IAC (0xff) -> IACIAC (escape it)

View File

@ -61,6 +61,8 @@ function getDefaultConfig() {
return { return {
general : { general : {
boardName : 'Another Fine ENiGMA½ BBS', boardName : 'Another Fine ENiGMA½ BBS',
loginAttempts : 3,
}, },
firstMenu : 'connected', firstMenu : 'connected',

View File

@ -54,6 +54,7 @@ function getPredefinedMCIValue(client, code) {
UC : function loginCount() { return client.user.properties.login_count.toString(); }, UC : function loginCount() { return client.user.properties.login_count.toString(); },
ND : function connectedNode() { return client.node.toString(); }, ND : function connectedNode() { return client.node.toString(); },
IP : function clientIpAddress() { return client.address().address; }, IP : function clientIpAddress() { return client.address().address; },
ST : function serverType() { return client.session.serverType; },
MS : function accountCreated() { return moment(client.user.properties.account_created).format(client.currentTheme.helpers.getDateFormat()); }, MS : function accountCreated() { return moment(client.user.properties.account_created).format(client.currentTheme.helpers.getDateFormat()); },
CS : function currentStatus() { return client.currentStatus; }, CS : function currentStatus() { return client.currentStatus; },

View File

@ -1,7 +1,7 @@
/* jslint node: true */ /* jslint node: true */
'use strict'; 'use strict';
var PluginModule = require('./plugin_module.js').PluginModule; var PluginModule = require('./plugin_module.js').PluginModule;
exports.ServerModule = ServerModule; exports.ServerModule = ServerModule;
@ -12,5 +12,7 @@ function ServerModule() {
require('util').inherits(ServerModule, PluginModule); require('util').inherits(ServerModule, PluginModule);
ServerModule.prototype.createServer = function() { ServerModule.prototype.createServer = function() {
return null; };
};
ServerModule.prototype.getServerType = function() {
};

View File

@ -40,54 +40,68 @@ function SSHClient(clientConn) {
var self = this; var self = this;
var loginAttempts = 0;
clientConn.on('authentication', function authAttempt(ctx) { clientConn.on('authentication', function authAttempt(ctx) {
self.log.trace( { method : ctx.method, username : ctx.username }, 'SSH authentication attempt'); self.log.trace( { method : ctx.method, username : ctx.username }, 'SSH authentication attempt');
var username = ctx.username || ''; var username = ctx.username || '';
var password = ctx.password || ''; var password = ctx.password || '';
if(0 === username.length > 0 && password.length > 0) { function termConnection() {
ctx.reject();
clientConn.end();
}
if(username.length > 0 && password.length > 0) {
loginAttempts += 1;
userLogin(self, ctx.username, ctx.password, function authResult(err) { userLogin(self, ctx.username, ctx.password, function authResult(err) {
if(err) { if(err) {
if(err.existingConn) { if(err.existingConn) {
// :TODO: Can we display somthing here? // :TODO: Can we display somthing here?
ctx.reject(); termConnection();
clientConn.end();
return; return;
} }
} else { } else {
ctx.accept(); ctx.accept();
} }
}); });
} } else {
if(-1 === SSHClient.ValidAuthMethods.indexOf(ctx.method)) {
return ctx.reject(SSHClient.ValidAuthMethods);
}
if('keyboard-interactive' !== ctx.method) { if(0 === username.length) {
return ctx.reject( ['keyboard-interactive'] ); // :TODO: can we display something here?
} return ctx.reject();
}
if(0 === username.length) { var interactivePrompt = { prompt: ctx.username + '\'s password: ', echo : false };
// :TODO: can we display something here?
return ctx.reject();
}
var interactivePrompt = { prompt: ctx.username + '\'s password: ', echo : false }; ctx.prompt(interactivePrompt, function retryPrompt(answers) {
loginAttempts += 1;
ctx.prompt(interactivePrompt, function retryPrompt(answers) { userLogin(self, username, (answers[0] || ''), function authResult(err) {
userLogin(self, username, (answers[0] || ''), function authResult(err) { if(err) {
if(err) { if(err.existingConn) {
if(err.existingConn) { // :TODO: can we display something here?
// :TODO: can we display something here? termConnection();
ctx.reject(); } else {
clientConn.end(); interactivePrompt.prompt = 'Access denied\n' + ctx.username + '\'s password: ';
if(loginAttempts >= conf.config.general.loginAttempts) {
termConnection();
} else {
return ctx.prompt(interactivePrompt, retryPrompt);
}
}
} else { } else {
interactivePrompt.prompt = 'Access denied\n' + interactivePrompt.prompt; ctx.accept();
return ctx.prompt(interactivePrompt, retryPrompt);
} }
} else { });
ctx.accept(); });
} }
});
});
}); });
this.updateTermInfo = function(info) { this.updateTermInfo = function(info) {
@ -125,14 +139,16 @@ function SSHClient(clientConn) {
clientConn.once('ready', function clientReady() { clientConn.once('ready', function clientReady() {
self.log.info('SSH authentication success'); self.log.info('SSH authentication success');
clientConn.once('session', function sess(accept, reject) { clientConn.on('session', function sess(accept, reject) {
var session = accept(); var session = accept();
session.once('pty', function pty(accept, reject, info) { session.on('pty', function pty(accept, reject, info) {
self.log.debug(info, 'SSH pty event'); self.log.debug(info, 'SSH pty event');
accept(); if(_.isFunction(accept)) {
accept();
}
if(self.input) { // do we have I/O? if(self.input) { // do we have I/O?
self.updateTermInfo(info); self.updateTermInfo(info);
@ -141,7 +157,7 @@ function SSHClient(clientConn) {
} }
}); });
session.once('shell', function shell(accept, reject) { session.on('shell', function shell(accept, reject) {
self.log.debug('SSH shell event'); self.log.debug('SSH shell event');
var channel = accept(); var channel = accept();
@ -164,6 +180,8 @@ function SSHClient(clientConn) {
session.on('window-change', function windowChange(accept, reject, info) { session.on('window-change', function windowChange(accept, reject, info) {
self.log.debug(info, 'SSH window-change event'); self.log.debug(info, 'SSH window-change event');
console.log('window-change: ' + accept)
self.updateTermInfo(info); self.updateTermInfo(info);
}); });
@ -175,13 +193,14 @@ function SSHClient(clientConn) {
}); });
clientConn.on('error', function connError(err) { clientConn.on('error', function connError(err) {
// :TODO: what to do here? self.log.warn( { error : err.toString(), code : err.code }, 'SSH connection error');
console.log(err)
}); });
} }
util.inherits(SSHClient, baseClient.Client); util.inherits(SSHClient, baseClient.Client);
SSHClient.ValidAuthMethods = [ 'password', 'keyboard-interactive' ];
function SSHServerModule() { function SSHServerModule() {
ServerModule.call(this); ServerModule.call(this);
} }
@ -212,4 +231,8 @@ SSHServerModule.prototype.createServer = function() {
}); });
return server; return server;
};
SSHServerModule.prototype.getServerType = function() {
return 'SSH';
}; };

View File

@ -784,4 +784,8 @@ TelnetServerModule.prototype.createServer = function() {
}); });
return server; return server;
}; };
TelnetServerModule.prototype.getServerType = function() {
return 'TELNET';
};

View File

@ -5,7 +5,7 @@ var MenuModule = require('../core/menu_module.js').MenuModule;
var userDb = require('../core/database.js').dbs.user; var userDb = require('../core/database.js').dbs.user;
var ViewController = require('../core/view_controller.js').ViewController; var ViewController = require('../core/view_controller.js').ViewController;
var TextView = require('../core/text_view.js').TextView; var TextView = require('../core/text_view.js').TextView;
var getUserLoginHistory = require('../core/stats.js').getUserLoginHistory; var getSystemLoginHistory = require('../core/stats.js').getSystemLoginHistory;
var util = require('util'); var util = require('util');
var moment = require('moment'); var moment = require('moment');
@ -92,7 +92,7 @@ LastCallersModule.prototype.mciReady = function(mciData, cb) {
}); });
}, },
function fetchHistory(callback) { function fetchHistory(callback) {
getUserLoginHistory(self.rows, function historyRetrieved(err, lh) { getSystemLoginHistory(self.rows, function historyRetrieved(err, lh) {
loginHistory = lh; loginHistory = lh;
callback(err); callback(err);
}); });

View File

@ -75,6 +75,7 @@
UG5: { width: 17 } UG5: { width: 17 }
UT6: { width: 17 } UT6: { width: 17 }
UC7: { width: 17 } UC7: { width: 17 }
ST8: { width: 17 }
} }
} }
@ -233,6 +234,7 @@
UG5: { width: 17 } UG5: { width: 17 }
UT6: { width: 17 } UT6: { width: 17 }
UC7: { width: 17 } UC7: { width: 17 }
ST8: { width: 17 }
} }
} }
} }