* Add FileBaseFilters

* Add HTTP(S) file web server with temp URLs
* Get temp web d/l from file list
* Add File area filter editor (all file area stuff will be rename to file "base" later)
* Concept of "listening servers" vs "login servers"
* Ability to get servers by their package name
* New MCI: %FN: File Base active filter name
* Some ES6 updates
* VC resetInitialFocus() to set focus to explicit/detected initial focus field
* Limit what is dumped out when logging form data
This commit is contained in:
Bryan Ashby 2016-10-24 21:49:45 -06:00
parent 712cf512f0
commit a7c0f2b7b0
22 changed files with 1233 additions and 286 deletions

123
core/servers/content/web.js Normal file
View file

@ -0,0 +1,123 @@
/* jslint node: true */
'use strict';
// ENiGMA½
const Log = require('../../logger.js').log;
const ServerModule = require('../../server_module.js').ServerModule;
const Config = require('../../config.js').config;
// deps
const http = require('http');
const https = require('https');
const _ = require('lodash');
const fs = require('fs');
const ModuleInfo = exports.moduleInfo = {
name : 'Web',
desc : 'Web Server',
author : 'NuSkooler',
packageName : 'codes.l33t.enigma.web.server',
};
class Route {
constructor(route) {
Object.assign(this, route);
if(this.method) {
this.method = this.method.toUpperCase();
}
try {
this.pathRegExp = new RegExp(this.path);
} catch(e) {
Log.debug( { route : route }, 'Invalid regular expression for route path' );
}
}
isValid() {
return (
this.pathRegExp instanceof RegExp &&
( -1 !== [ 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', ].indexOf(this.method) ) ||
!_.isFunction(this.handler)
);
}
matchesRequest(req) { return req.method === this.method && this.pathRegExp.test(req.url); }
getRouteKey() { return `${this.method}:${this.path}`; }
}
exports.getModule = class WebServerModule extends ServerModule {
constructor() {
super();
this.enableHttp = Config.contentServers.web.http.enabled || true;
this.enableHttps = Config.contentServers.web.https.enabled || false;
this.routes = {};
}
createServer() {
if(this.enableHttp) {
this.httpServer = http.createServer( (req, resp) => this.routeRequest(req, resp) );
}
if(this.enableHttps) {
const options = {
cert : fs.readFileSync(Config.contentServers.web.https.certPem),
key : fs.readFileSync(Config.contentServers.web.https.keyPem),
};
// additional options
Object.assign(options, Config.contentServers.web.https.options || {} );
this.httpsServer = https.createServer(options, this.routeRequest);
}
}
listen() {
let ok = true;
[ 'http', 'https' ].forEach(service => {
const name = `${service}Server`;
if(this[name]) {
const port = parseInt(Config.contentServers.web[service].port);
if(isNaN(port)) {
ok = false;
return Log.warn( { port : Config.contentServers.web[service].port, server : ModuleInfo.name }, `Invalid port (${service})` );
}
return this[name].listen(port);
}
});
return ok;
}
addRoute(route) {
route = new Route(route);
if(!route.isValid()) {
Log( { route : route }, 'Cannot add route: missing or invalid required members' );
return false;
}
const routeKey = route.getRouteKey();
if(routeKey in this.routes) {
Log( { route : route }, 'Cannot add route: duplicate method/path combination exists' );
return false;
}
this.routes[routeKey] = route;
return true;
}
routeRequest(req, resp) {
const route = _.find(this.routes, r => r.matchesRequest(req) );
return route ? route.handler(req, resp) : this.accessDenied(resp);
}
accessDenied(resp) {
resp.writeHead(401, { 'Content-Type' : 'text/html' } );
return resp.end('<html><body>Access denied</body></html>');
}
}

View file

@ -2,14 +2,14 @@
'use strict';
// ENiGMA½
const Config = require('../../config.js').config;
const baseClient = require('../../client.js');
const Log = require('../../logger.js').log;
const ServerModule = require('../../server_module.js').ServerModule;
const userLogin = require('../../user_login.js').userLogin;
const enigVersion = require('../../../package.json').version;
const theme = require('../../theme.js');
const stringFormat = require('../../string_format.js');
const Config = require('../../config.js').config;
const baseClient = require('../../client.js');
const Log = require('../../logger.js').log;
const LoginServerModule = require('../../login_server_module.js');
const userLogin = require('../../user_login.js').userLogin;
const enigVersion = require('../../../package.json').version;
const theme = require('../../theme.js');
const stringFormat = require('../../string_format.js');
// deps
const ssh2 = require('ssh2');
@ -18,15 +18,14 @@ const util = require('util');
const _ = require('lodash');
const assert = require('assert');
exports.moduleInfo = {
const ModuleInfo = exports.moduleInfo = {
name : 'SSH',
desc : 'SSH Server',
author : 'NuSkooler',
isSecure : true,
packageName : 'codes.l33t.enigma.ssh.server',
};
exports.getModule = SSHServerModule;
function SSHClient(clientConn) {
baseClient.Client.apply(this, arguments);
@ -226,40 +225,45 @@ util.inherits(SSHClient, baseClient.Client);
SSHClient.ValidAuthMethods = [ 'password', 'keyboard-interactive' ];
function SSHServerModule() {
ServerModule.call(this);
}
exports.getModule = class SSHServerModule extends LoginServerModule {
constructor() {
super();
}
util.inherits(SSHServerModule, ServerModule);
createServer() {
const serverConf = {
hostKeys : [
{
key : fs.readFileSync(Config.loginServers.ssh.privateKeyPem),
passphrase : Config.loginServers.ssh.privateKeyPass,
}
],
ident : 'enigma-bbs-' + enigVersion + '-srv',
// Note that sending 'banner' breaks at least EtherTerm!
debug : (sshDebugLine) => {
if(true === Config.loginServers.ssh.traceConnections) {
Log.trace(`SSH: ${sshDebugLine}`);
}
},
};
SSHServerModule.prototype.createServer = function() {
SSHServerModule.super_.prototype.createServer.call(this);
this.server = ssh2.Server(serverConf);
this.server.on('connection', (conn, info) => {
Log.info(info, 'New SSH connection');
this.handleNewClient(new SSHClient(conn), conn._sock, ModuleInfo);
});
}
const serverConf = {
hostKeys : [
{
key : fs.readFileSync(Config.loginServers.ssh.privateKeyPem),
passphrase : Config.loginServers.ssh.privateKeyPass,
}
],
ident : 'enigma-bbs-' + enigVersion + '-srv',
// Note that sending 'banner' breaks at least EtherTerm!
debug : (sshDebugLine) => {
if(true === Config.loginServers.ssh.traceConnections) {
Log.trace(`SSH: ${sshDebugLine}`);
}
},
};
listen() {
const port = parseInt(Config.loginServers.ssh.port);
if(isNaN(port)) {
Log.error( { server : ModuleInfo.name, port : Config.loginServers.ssh.port }, 'Cannot load server (invalid port)' );
return false;
}
const server = ssh2.Server(serverConf);
server.on('connection', function onConnection(conn, info) {
Log.info(info, 'New SSH connection');
const client = new SSHClient(conn);
this.emit('client', client, conn._sock);
});
return server;
this.server.listen(port);
Log.info( { server : ModuleInfo.name, port : port }, 'Listening for connections' );
return true;
}
};

View file

@ -2,10 +2,10 @@
'use strict';
// ENiGMA½
const baseClient = require('../../client.js');
const Log = require('../../logger.js').log;
const ServerModule = require('../../server_module.js').ServerModule;
const Config = require('../../config.js').config;
const baseClient = require('../../client.js');
const Log = require('../../logger.js').log;
const LoginServerModule = require('../../login_server_module.js');
const Config = require('../../config.js').config;
// deps
const net = require('net');
@ -16,16 +16,14 @@ const util = require('util');
//var debug = require('debug')('telnet');
exports.moduleInfo = {
const ModuleInfo = exports.moduleInfo = {
name : 'Telnet',
desc : 'Telnet Server',
author : 'NuSkooler',
isSecure : false,
packageName : 'codes.l33t.enigma.telnet.server',
};
exports.getModule = TelnetServerModule;
//
// Telnet Protocol Resources
// * http://pcmicro.com/netfoss/telnet.html
@ -767,22 +765,34 @@ Object.keys(OPTIONS).forEach(function(name) {
});
});
function TelnetServerModule() {
ServerModule.call(this);
}
exports.getModule = class TelnetServerModule extends LoginServerModule {
constructor() {
super();
}
util.inherits(TelnetServerModule, ServerModule);
createServer() {
this.server = net.createServer( sock => {
const client = new TelnetClient(sock, sock);
TelnetServerModule.prototype.createServer = function() {
TelnetServerModule.super_.prototype.createServer.call(this);
client.banner();
const server = net.createServer( (sock) => {
const client = new TelnetClient(sock, sock);
client.banner();
this.handleNewClient(client, sock, ModuleInfo);
});
server.emit('client', client, sock);
});
this.server.on('error', err => {
Log.info( { error : err.message }, 'Telnet server error');
});
}
return server;
listen() {
const port = parseInt(Config.loginServers.telnet.port);
if(isNaN(port)) {
Log.error( { server : ModuleInfo.name, port : Config.loginServers.telnet.port }, 'Cannot load server (invalid port)' );
return false;
}
this.server.listen(port);
Log.info( { server : ModuleInfo.name, port : port }, 'Listening for connections' );
return true;
}
};