* 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:
parent
e7e9746a85
commit
ad4eea6ba7
|
@ -193,6 +193,8 @@ function startListening() {
|
||||||
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() {
|
||||||
|
|
|
@ -425,7 +425,15 @@ Client.prototype.end = function () {
|
||||||
|
|
||||||
clearInterval(this.idleCheck);
|
clearInterval(this.idleCheck);
|
||||||
|
|
||||||
|
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);
|
return this.output.end.apply(this.output, arguments);
|
||||||
|
} catch(e) {
|
||||||
|
// TypeError
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Client.prototype.destroy = function () {
|
Client.prototype.destroy = function () {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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; },
|
||||||
|
|
|
@ -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() {
|
||||||
};
|
};
|
|
@ -40,29 +40,36 @@ 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)) {
|
||||||
if('keyboard-interactive' !== ctx.method) {
|
return ctx.reject(SSHClient.ValidAuthMethods);
|
||||||
return ctx.reject( ['keyboard-interactive'] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 === username.length) {
|
if(0 === username.length) {
|
||||||
|
@ -73,21 +80,28 @@ function SSHClient(clientConn) {
|
||||||
var interactivePrompt = { prompt: ctx.username + '\'s password: ', echo : false };
|
var interactivePrompt = { prompt: ctx.username + '\'s password: ', echo : false };
|
||||||
|
|
||||||
ctx.prompt(interactivePrompt, function retryPrompt(answers) {
|
ctx.prompt(interactivePrompt, function retryPrompt(answers) {
|
||||||
|
loginAttempts += 1;
|
||||||
|
|
||||||
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?
|
||||||
ctx.reject();
|
termConnection();
|
||||||
clientConn.end();
|
} else {
|
||||||
|
interactivePrompt.prompt = 'Access denied\n' + ctx.username + '\'s password: ';
|
||||||
|
|
||||||
|
if(loginAttempts >= conf.config.general.loginAttempts) {
|
||||||
|
termConnection();
|
||||||
} else {
|
} else {
|
||||||
interactivePrompt.prompt = 'Access denied\n' + interactivePrompt.prompt;
|
|
||||||
return ctx.prompt(interactivePrompt, retryPrompt);
|
return ctx.prompt(interactivePrompt, retryPrompt);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.accept();
|
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');
|
||||||
|
|
||||||
|
if(_.isFunction(accept)) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -213,3 +232,7 @@ SSHServerModule.prototype.createServer = function() {
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SSHServerModule.prototype.getServerType = function() {
|
||||||
|
return 'SSH';
|
||||||
|
};
|
|
@ -785,3 +785,7 @@ TelnetServerModule.prototype.createServer = function() {
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TelnetServerModule.prototype.getServerType = function() {
|
||||||
|
return 'TELNET';
|
||||||
|
};
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
Binary file not shown.
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue