From e9836e18db7cb89dd9674f04d6dc0923241c1a05 Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Thu, 22 Oct 2015 12:22:03 -0600 Subject: [PATCH] * New user reserved names now direct to applicaiton process for SSH --- core/bbs.js | 9 ++-- core/config.js | 13 ++++-- core/servers/ssh.js | 28 ++++++++---- core/servers/telnet.js | 3 +- mods/menu.hjson | 101 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 130 insertions(+), 24 deletions(-) diff --git a/core/bbs.js b/core/bbs.js index d8fae297..3149b270 100644 --- a/core/bbs.js +++ b/core/bbs.js @@ -180,9 +180,6 @@ function startListening() { return; } - // servers require 'firstMenu' - assert(module.runtime.config.firstMenu, 'Server missing \'firstMenu\' member!'); - var moduleInst = new module.getModule(); var server = moduleInst.createServer(); @@ -202,13 +199,13 @@ function startListening() { clientConns.addNewClient(client, clientSock); - client.on('ready', function onClientReady() { + client.on('ready', function clientReady(readyOptions) { client.startIdleMonitor(); // Go to module -- use default error handler - prepareClient(client, function onPrepared() { - require('./connect.js').connectEntry(client, module.runtime.config.firstMenu); + prepareClient(client, function clientPrepared() { + require('./connect.js').connectEntry(client, readyOptions.firstMenu); }); }); diff --git a/core/config.js b/core/config.js index 40068bb8..b53f98df 100644 --- a/core/config.js +++ b/core/config.js @@ -62,6 +62,8 @@ function getDefaultConfig() { general : { boardName : 'Another Fine ENiGMA½ BBS', + closedSystem : false, // is the system closed to new users? + loginAttempts : 3, }, @@ -127,11 +129,12 @@ function getDefaultConfig() { firstMenu : 'telnetConnected', }, ssh : { - port : 8889, - enabled : true, - rsaPrivateKey : paths.join(__dirname, './../misc/default_key.rsa'), - dsaPrivateKey : paths.join(__dirname, './../misc/default_key.dsa'), - firstMenu : 'sshConnected', + port : 8889, + enabled : true, + rsaPrivateKey : paths.join(__dirname, './../misc/default_key.rsa'), + dsaPrivateKey : paths.join(__dirname, './../misc/default_key.dsa'), + firstMenu : 'sshConnected', + firstMenuNewUser : 'sshConnectedNewUser', } }, diff --git a/core/servers/ssh.js b/core/servers/ssh.js index c856d9d0..2553c9ae 100644 --- a/core/servers/ssh.js +++ b/core/servers/ssh.js @@ -2,7 +2,7 @@ 'use strict'; // ENiGMA½ -var conf = require('../config.js'); +var Config = require('../config.js').config; var baseClient = require('../client.js'); var Log = require('../logger.js').log; var ServerModule = require('../server_module.js').ServerModule; @@ -45,16 +45,25 @@ function SSHClient(clientConn) { var loginAttempts = 0; clientConn.on('authentication', function authAttempt(ctx) { - self.log.trace( { method : ctx.method, username : ctx.username }, 'SSH authentication attempt'); - var username = ctx.username || ''; var password = ctx.password || ''; + self.isNewUser = (Config.users.newUserNames || []).indexOf(username) > -1; + + self.log.trace( { method : ctx.method, username : username, newUser : self.isNewUser }, 'SSH authentication attempt'); function termConnection() { ctx.reject(); clientConn.end(); } + // + // If the system is open and |isNewUser| is true, the login + // sequence is hijacked in order to start the applicaiton process. + // + if(false === Config.general.closedSystem && self.isNewUser) { + return ctx.accept(); + } + if(username.length > 0 && password.length > 0) { loginAttempts += 1; @@ -76,8 +85,6 @@ function SSHClient(clientConn) { return ctx.reject(SSHClient.ValidAuthMethods); } - console.log(ctx.method) - if(0 === username.length) { // :TODO: can we display something here? return ctx.reject(); @@ -94,7 +101,7 @@ function SSHClient(clientConn) { // :TODO: can we display something here? termConnection(); } else { - if(loginAttempts >= conf.config.general.loginAttempts) { + if(loginAttempts >= Config.general.loginAttempts) { termConnection(); } else { var artOpts = { @@ -106,7 +113,7 @@ function SSHClient(clientConn) { if(err) { interactivePrompt.prompt = 'Access denied\n' + ctx.username + '\'s password: '; } else { - var newUserNameList = '"' + (conf.config.users.newUserNames || []).join(', ') + '"'; + var newUserNameList = '"' + (Config.users.newUserNames || []).join(', ') + '"'; interactivePrompt.prompt = 'Access denied\n' + artInfo.data.format( { newUserNames : newUserNameList } ) + @@ -194,7 +201,8 @@ function SSHClient(clientConn) { } // we're ready! - self.emit('ready'); + var firstMenu = self.isNewUser ? Config.servers.ssh.firstMenuNewUser : Config.servers.ssh.firstMenu; + self.emit('ready', { firstMenu : firstMenu } ); }); session.on('window-change', function windowChange(accept, reject, info) { @@ -231,11 +239,11 @@ SSHServerModule.prototype.createServer = function() { SSHServerModule.super_.prototype.createServer.call(this); var serverConf = { - privateKey : fs.readFileSync(conf.config.servers.ssh.rsaPrivateKey), + privateKey : fs.readFileSync(Config.servers.ssh.rsaPrivateKey), ident : 'enigma-bbs-' + enigVersion + '-srv', // Note that sending 'banner' breaks at least EtherTerm! debug : function debugSsh(dbgLine) { - if(true === conf.config.servers.ssh.debugConnections) { + if(true === Config.servers.ssh.debugConnections) { Log.trace('SSH: ' + dbgLine); } }, diff --git a/core/servers/telnet.js b/core/servers/telnet.js index 7e65cdd9..b889e5bc 100644 --- a/core/servers/telnet.js +++ b/core/servers/telnet.js @@ -5,6 +5,7 @@ var baseClient = require('../client.js'); var Log = require('../logger.js').log; var ServerModule = require('../server_module.js').ServerModule; +var Config = require('../config.js').config; var net = require('net'); var buffers = require('buffers'); @@ -583,7 +584,7 @@ TelnetClient.prototype.handleSbCommand = function(evt) { if(!self.didReady) { self.didReady = true; - self.emit('ready'); + self.emit('ready', { firstMenu : Config.servers.telnet.firstMenu } ); } } else if('new environment' === evt.option) { // diff --git a/mods/menu.hjson b/mods/menu.hjson index 63e35c1a..44012785 100644 --- a/mods/menu.hjson +++ b/mods/menu.hjson @@ -70,6 +70,17 @@ options: { nextTimeout: 1500 } } + // + // Another SSH specialization: If the user logs in with a new user + // name (e.g. "new", "apply", ...) they will be directed to the + // application process. + // + sshConnectedNewUser: { + art: CONNECT + next: newUserApplicationSsh + options: { nextTimeout: 1500 } + } + matrix: { art: matrix options: { @@ -248,7 +259,7 @@ } { value: { "submission" : 1 } - action: @menu:matrix + action: @systemMethod:fallbackMenu } ] } @@ -256,7 +267,93 @@ actionKeys: [ { keys: [ "escape" ] - action: @menu:matrix + action: @systemMethod:fallbackMenu + } + ] + } + } + } + + // SSH specialization of NUA + newUserApplicationSsh: { + art: NUA + fallback: logoff + next: newUserFeedbackToSysOpPreamble + form: { + 0: { + mci: { + ET1: { + focus: true + argName: username + maxLength: @config:users.usernameMax + } + ET2: { + argName: realName + maxLength: 32 + } + MET3: { + argName: birthdate + maskPattern: "####/##/##" + } + ME4: { + argName: sex + maskPattern: A + textStyle: upper + } + ET5: { + argName: location + maxLength: 32 + } + ET6: { + argName: affils + maxLength: 32 + } + ET7: { + argName: email + maxLength: 255 + } + ET8: { + argName: web + maxLength: 255 + } + ET9: { + argName: password + password: true + maxLength: @config:users.passwordMax + } + ET10: { + argName: passwordConfirm + password: true + maxLength: @config:users.passwordMax + } + TM12: { + argName: submission + items: [ "apply", "cancel" ] + submit: true + } + } + + submit: { + *: [ + { + value: { "submission" : 0 } + action: @method:apply/submitApplication + extraArgs: { + inactive: userNeedsActivated + error: newUserCreateError + } + } + { + value: { "submission" : 1 } + action: @systemMethod:fallbackMenu + } + ] + } + + actionKeys: [ + { + keys: [ "escape" ] + action: @systemMethod:fallbackMenu } ] }