From 9172fdda9dff422325d3fb18dbbb246623446e9d Mon Sep 17 00:00:00 2001 From: Bryan Ashby Date: Sun, 12 Jun 2022 14:12:03 -0600 Subject: [PATCH] Re-apply some Prettier formatting after merge --- core/abracadabra.js | 38 ++-- core/bbs.js | 125 ++++++----- core/client.js | 8 +- core/client_connections.js | 72 +++--- core/door.js | 7 +- core/event_scheduler.js | 5 +- core/file_area_list.js | 18 +- core/file_area_web.js | 31 ++- core/file_base_download_manager.js | 5 +- core/file_base_web_download_manager.js | 2 +- core/file_transfer.js | 5 +- core/menu_module.js | 51 +++-- core/menu_view.js | 4 +- core/message_area.js | 84 +++---- core/misc_scheduled_events.js | 4 +- core/msg_area_post_fse.js | 6 +- core/node_msg.js | 54 +++-- core/nua.js | 12 +- core/predefined_mci.js | 219 ++++++++++++------ core/stat_log.js | 108 +++++---- core/string_util.js | 6 +- core/sys_event_user_log.js | 6 +- core/system_log.js | 4 +- core/system_property.js | 40 ++-- core/telnet_bridge.js | 11 +- core/theme.js | 31 ++- core/user.js | 54 +++-- core/user_config.js | 28 ++- core/user_interrupt_queue.js | 6 +- core/user_login.js | 53 +++-- core/user_property.js | 4 +- core/vertical_menu_view.js | 37 +-- core/view.js | 4 +- core/view_controller.js | 91 ++++---- core/wfc.js | 299 ++++++++++++++----------- core/whos_online.js | 18 +- package.json | 140 ++++++------ 37 files changed, 978 insertions(+), 712 deletions(-) diff --git a/core/abracadabra.js b/core/abracadabra.js index 200c28aa..2a9dd035 100644 --- a/core/abracadabra.js +++ b/core/abracadabra.js @@ -108,14 +108,22 @@ exports.getModule = class AbracadabraModule extends MenuModule { name: self.config.name, activeCount: activeDoorNodeInstances[self.config.name], }, - `Too many active instances of door "${self.config.name}"`); + `Too many active instances of door "${self.config.name}"` + ); - if(_.isString(self.config.tooManyArt)) { - theme.displayThemeArt( { client : self.client, name : self.config.tooManyArt }, function displayed() { - self.pausePrompt( () => { - return callback(Errors.AccessDenied('Too many active instances')); - }); - }); + if (_.isString(self.config.tooManyArt)) { + theme.displayThemeArt( + { client: self.client, name: self.config.tooManyArt }, + function displayed() { + self.pausePrompt(() => { + return callback( + Errors.AccessDenied( + 'Too many active instances' + ) + ); + }); + } + ); } else { self.client.term.write( '\nToo many active instances. Try again later.\n' @@ -171,14 +179,14 @@ exports.getModule = class AbracadabraModule extends MenuModule { this.client.term.write(ansi.resetScreen()); const exeInfo = { - name : this.config.name, - cmd : this.config.cmd, - cwd : this.config.cwd || paths.dirname(this.config.cmd), - args : this.config.args, - io : this.config.io || 'stdio', - encoding : this.config.encoding || 'cp437', - node : this.client.node, - env : this.config.env, + name: this.config.name, + cmd: this.config.cmd, + cwd: this.config.cwd || paths.dirname(this.config.cmd), + args: this.config.args, + io: this.config.io || 'stdio', + encoding: this.config.encoding || 'cp437', + node: this.client.node, + env: this.config.env, }; if (this.dropFile) { diff --git a/core/bbs.js b/core/bbs.js index 2d8e895b..ddc6bfb5 100644 --- a/core/bbs.js +++ b/core/bbs.js @@ -6,14 +6,14 @@ //SegfaultHandler.registerHandler('enigma-bbs-segfault.log'); // ENiGMA½ -const conf = require('./config.js'); -const logger = require('./logger.js'); -const database = require('./database.js'); -const resolvePath = require('./misc_util.js').resolvePath; -const UserProps = require('./user_property.js'); -const SysProps = require('./system_property.js'); -const SysLogKeys = require('./system_log.js'); -const UserLogNames = require('./user_log_name'); +const conf = require('./config.js'); +const logger = require('./logger.js'); +const database = require('./database.js'); +const resolvePath = require('./misc_util.js').resolvePath; +const UserProps = require('./user_property.js'); +const SysProps = require('./system_property.js'); +const SysLogKeys = require('./system_log.js'); +const UserLogNames = require('./user_log_name'); // deps const async = require('async'); @@ -152,7 +152,9 @@ function shutdownSystem() { [ function closeConnections(callback) { const ClientConns = require('./client_connections.js'); - const activeConnections = ClientConns.getActiveConnections(ClientConns.AllConnections); + const activeConnections = ClientConns.getActiveConnections( + ClientConns.AllConnections + ); let i = activeConnections.length; while (i--) { const activeTerm = activeConnections[i].term; @@ -327,68 +329,77 @@ function initialize(cb) { const StatLog = require('./stat_log'); const entries = [ - [ UserLogNames.UlFiles, [ SysProps.FileUlTodayCount, 'count' ] ], - [ UserLogNames.UlFileBytes, [ SysProps.FileUlTodayBytes, 'obj' ] ], - [ UserLogNames.DlFiles, [ SysProps.FileDlTodayCount, 'count' ] ], - [ UserLogNames.DlFileBytes, [ SysProps.FileDlTodayBytes, 'obj' ] ], - [ UserLogNames.NewUser, [ SysProps.NewUsersTodayCount, 'count' ] ], + [UserLogNames.UlFiles, [SysProps.FileUlTodayCount, 'count']], + [UserLogNames.UlFileBytes, [SysProps.FileUlTodayBytes, 'obj']], + [UserLogNames.DlFiles, [SysProps.FileDlTodayCount, 'count']], + [UserLogNames.DlFileBytes, [SysProps.FileDlTodayBytes, 'obj']], + [UserLogNames.NewUser, [SysProps.NewUsersTodayCount, 'count']], ]; - async.each(entries, (entry, nextEntry) => { - const [ logName, [sysPropName, resultType] ] = entry; + async.each( + entries, + (entry, nextEntry) => { + const [logName, [sysPropName, resultType]] = entry; - const filter = { - logName, - resultType, - date : moment(), - }; + const filter = { + logName, + resultType, + date: moment(), + }; - StatLog.findUserLogEntries(filter, (err, stat) => { - if (!err) { - if (resultType === 'obj') { - stat = stat.reduce( (bytes, entry) => bytes + parseInt(entry.log_value) || 0, 0); + StatLog.findUserLogEntries(filter, (err, stat) => { + if (!err) { + if (resultType === 'obj') { + stat = stat.reduce( + (bytes, entry) => + bytes + parseInt(entry.log_value) || 0, + 0 + ); + } + + StatLog.setNonPersistentSystemStat(sysPropName, stat); } - - StatLog.setNonPersistentSystemStat(sysPropName, stat); - } - return nextEntry(null); - }); - }, - () => { - return callback(null); - }); + return nextEntry(null); + }); + }, + () => { + return callback(null); + } + ); }, function initLastLogin(callback) { const StatLog = require('./stat_log'); - StatLog.getSystemLogEntries(SysLogKeys.UserLoginHistory, 'timestamp_desc', 1, (err, lastLogin) => { - if (err) { - return callback(null); - } + StatLog.getSystemLogEntries( + SysLogKeys.UserLoginHistory, + 'timestamp_desc', + 1, + (err, lastLogin) => { + if (err) { + return callback(null); + } - let loginObj; - try - { - loginObj = JSON.parse(lastLogin[0].log_value); - loginObj.timestamp = moment(lastLogin[0].timestamp); - } - catch (e) - { - return callback(null); - } + let loginObj; + try { + loginObj = JSON.parse(lastLogin[0].log_value); + loginObj.timestamp = moment(lastLogin[0].timestamp); + } catch (e) { + return callback(null); + } - // For live stats we want to resolve user ID -> name, etc. - const User = require('./user'); - User.getUserInfo(loginObj.userId, (err, props) => { - const stat = Object.assign({}, props, loginObj); - StatLog.setNonPersistentSystemStat(SysProps.LastLogin, stat); - return callback(null); - }); - }); + // For live stats we want to resolve user ID -> name, etc. + const User = require('./user'); + User.getUserInfo(loginObj.userId, (err, props) => { + const stat = Object.assign({}, props, loginObj); + StatLog.setNonPersistentSystemStat(SysProps.LastLogin, stat); + return callback(null); + }); + } + ); }, function initUserCount(callback) { const User = require('./user.js'); User.getUserCount((err, count) => { - if(err) { + if (err) { return callback(err); } diff --git a/core/client.js b/core/client.js index b187e17e..30a0f7cd 100644 --- a/core/client.js +++ b/core/client.js @@ -592,12 +592,10 @@ Client.prototype.isLocal = function () { return ['127.0.0.1', '::ffff:127.0.0.1'].includes(this.remoteAddress); }; -Client.prototype.friendlyRemoteAddress = function() { +Client.prototype.friendlyRemoteAddress = function () { // convert any :ffff: IPv4's to 32bit version - return this.remoteAddress - .replace(/^::ffff:/, '') - .replace(/^::1$/, 'localhost'); -} + return this.remoteAddress.replace(/^::ffff:/, '').replace(/^::1$/, 'localhost'); +}; /////////////////////////////////////////////////////////////////////////////// // Default error handlers diff --git a/core/client_connections.js b/core/client_connections.js index f34fe8a8..fea32a3e 100644 --- a/core/client_connections.js +++ b/core/client_connections.js @@ -24,13 +24,23 @@ exports.clientConnections = clientConnections; const AllConnections = { authUsersOnly: false, visibleOnly: false, availOnly: false }; exports.AllConnections = AllConnections; -const UserVisibleConnections = { authUsersOnly: false, visibleOnly: true, availOnly: false }; +const UserVisibleConnections = { + authUsersOnly: false, + visibleOnly: true, + availOnly: false, +}; exports.UserVisibleConnections = UserVisibleConnections; -const UserMessageableConnections = { authUsersOnly: true, visibleOnly: true, availOnly: true }; +const UserMessageableConnections = { + authUsersOnly: true, + visibleOnly: true, + availOnly: true, +}; exports.UserMessageableConnections = UserMessageableConnections; -function getActiveConnections(options = { authUsersOnly: true, visibleOnly: true, availOnly: false }) { +function getActiveConnections( + options = { authUsersOnly: true, visibleOnly: true, availOnly: false } +) { return clientConnections.filter(conn => { if (options.authUsersOnly && !conn.user.isAuthenticated()) { return false; @@ -46,7 +56,9 @@ function getActiveConnections(options = { authUsersOnly: true, visibleOnly: true }); } -function getActiveConnectionList(options = { authUsersOnly: true, visibleOnly: true, availOnly: false }) { +function getActiveConnectionList( + options = { authUsersOnly: true, visibleOnly: true, availOnly: false } +) { const now = moment(); return _.map(getActiveConnections(options), ac => { @@ -54,33 +66,36 @@ function getActiveConnectionList(options = { authUsersOnly: true, visibleOnly: t try { // attempting to fetch a bad menu stack item can blow up/assert action = _.get(ac, 'currentMenuModule.menuConfig.desc', 'Unknown'); - } catch(e) { + } catch (e) { action = 'Unknown'; } const entry = { - node : ac.node, - authenticated : ac.user.isAuthenticated(), - userId : ac.user.userId, - action : action, - serverName : ac.session.serverName, - isSecure : ac.session.isSecure, - isVisible : ac.user.isVisible(), - isAvailable : ac.user.isAvailable(), + node: ac.node, + authenticated: ac.user.isAuthenticated(), + userId: ac.user.userId, + action: action, + serverName: ac.session.serverName, + isSecure: ac.session.isSecure, + isVisible: ac.user.isVisible(), + isAvailable: ac.user.isAvailable(), }; // // There may be a connection, but not a logged in user as of yet // - if(ac.user.isAuthenticated()) { - entry.text = ac.user.username; - entry.userName = ac.user.username; - entry.realName = ac.user.properties[UserProps.RealName]; - entry.location = ac.user.properties[UserProps.Location]; - entry.affils = entry.affiliation = ac.user.properties[UserProps.Affiliations]; + if (ac.user.isAuthenticated()) { + entry.text = ac.user.username; + entry.userName = ac.user.username; + entry.realName = ac.user.properties[UserProps.RealName]; + entry.location = ac.user.properties[UserProps.Location]; + entry.affils = entry.affiliation = ac.user.properties[UserProps.Affiliations]; - const diff = now.diff(moment(ac.user.properties[UserProps.LastLoginTs]), 'minutes'); - entry.timeOn = moment.duration(diff, 'minutes'); + const diff = now.diff( + moment(ac.user.properties[UserProps.LastLoginTs]), + 'minutes' + ); + entry.timeOn = moment.duration(diff, 'minutes'); } return entry; @@ -115,10 +130,10 @@ function addNewClient(client, clientSock) { client.log = logger.log.child({ nodeId, sessionId: client.session.uniqueId }); const connInfo = { - remoteAddress : remoteAddress, + remoteAddress: remoteAddress, freiendlyRemoteAddress: client.friendlyRemoteAddress(), - serverName : client.session.serverName, - isSecure : client.session.isSecure, + serverName: client.session.serverName, + isSecure: client.session.isSecure, }; if (client.log.debug()) { @@ -126,7 +141,10 @@ function addNewClient(client, clientSock) { connInfo.family = clientSock.localFamily; } - client.log.info(connInfo, `Client connected (${connInfo.serverName}/${connInfo.port})`); + client.log.info( + connInfo, + `Client connected (${connInfo.serverName}/${connInfo.port})` + ); Events.emit(Events.getSystemEvents().ClientConnected, { client: client, @@ -170,9 +188,9 @@ function removeClient(client) { } function getConnectionByUserId(userId) { - return getActiveConnections(AllConnections).find( ac => userId === ac.user.userId ); + return getActiveConnections(AllConnections).find(ac => userId === ac.user.userId); } function getConnectionByNodeId(nodeId) { - return getActiveConnections(AllConnections).find( ac => nodeId == ac.node ); + return getActiveConnections(AllConnections).find(ac => nodeId == ac.node); } diff --git a/core/door.js b/core/door.js index 42fc17f8..305ae162 100644 --- a/core/door.js +++ b/core/door.js @@ -32,7 +32,10 @@ module.exports = class Door { }); conn.once('error', err => { - this.client.log.warn( { error : err.message }, 'Door socket server connection'); + this.client.log.warn( + { error: err.message }, + 'Door socket server connection' + ); return this.restoreIo(conn); }); @@ -73,7 +76,7 @@ module.exports = class Door { const args = exeInfo.args.map(arg => stringFormat(arg, formatObj)); this.client.log.info( - { cmd : exeInfo.cmd, args, io : this.io }, + { cmd: exeInfo.cmd, args, io: this.io }, `Executing external door (${exeInfo.name})` ); diff --git a/core/event_scheduler.js b/core/event_scheduler.js index c31a1deb..076e116f 100644 --- a/core/event_scheduler.js +++ b/core/event_scheduler.js @@ -112,7 +112,10 @@ class ScheduledEvent { } executeAction(reason, cb) { - Log.info( { eventName : this.name, action : this.action, reason : reason }, `Executing scheduled event "${this.name}"...`); + Log.info( + { eventName: this.name, action: this.action, reason: reason }, + `Executing scheduled event "${this.name}"...` + ); if ('method' === this.action.type) { const modulePath = path.join(__dirname, '../', this.action.location); // enigma-bbs base + supplied location (path/file.js') diff --git a/core/file_area_list.js b/core/file_area_list.js index f7501ae4..77b079ff 100644 --- a/core/file_area_list.js +++ b/core/file_area_list.js @@ -351,7 +351,7 @@ exports.getModule = class FileAreaList extends MenuModule { top: artData.mciMap.XY2.position, bottom: artData.mciMap.XY3.position, }; - } catch(e) { + } catch (e) { throw Errors.DoesNotExist('Missing XY2 and XY3 position indicators!'); } } @@ -380,7 +380,10 @@ exports.getModule = class FileAreaList extends MenuModule { return self.displayArtAndPrepViewController( 'browse', FormIds.browse, - { clearScreen : clearScreen, artDataPrep: self.displayArtDataPrepCallback.bind(self) }, + { + clearScreen: clearScreen, + artDataPrep: self.displayArtDataPrepCallback.bind(self), + }, callback ); }, @@ -473,7 +476,10 @@ exports.getModule = class FileAreaList extends MenuModule { return self.displayArtAndPrepViewController( 'details', FormIds.details, - { clearScreen : true, artDataPrep: self.displayArtDataPrepCallback.bind(self) }, + { + clearScreen: true, + artDataPrep: self.displayArtDataPrepCallback.bind(self), + }, callback ); }, @@ -725,9 +731,9 @@ exports.getModule = class FileAreaList extends MenuModule { name, FormIds[name], { - clearScreen : false, - noInput : true, - artDataPrep: self.displayArtDataPrepCallback.bind(self) + clearScreen: false, + noInput: true, + artDataPrep: self.displayArtDataPrepCallback.bind(self), }, callback ); diff --git a/core/file_area_web.js b/core/file_area_web.js index 525d094b..4ffe2491 100644 --- a/core/file_area_web.js +++ b/core/file_area_web.js @@ -534,23 +534,22 @@ class FileAreaWebAccess { StatLog.incrementSystemStat(SysProps.FileDlTotalCount, 1); StatLog.incrementSystemStat(SysProps.FileDlTotalBytes, dlBytes); - StatLog.incrementNonPersistentSystemStat(SysProps.FileDlTodayCount, 1); - StatLog.incrementNonPersistentSystemStat(SysProps.FileDlTodayBytes, dlBytes); + StatLog.incrementNonPersistentSystemStat(SysProps.FileDlTodayCount, 1); + StatLog.incrementNonPersistentSystemStat( + SysProps.FileDlTodayBytes, + dlBytes + ); - return callback(null, user); - }, - function sendEvent(user, callback) { - Events.emit( - Events.getSystemEvents().UserDownload, - { - user : user, - files : fileEntries, - } - ); - return callback(null); - } - ] - ); + return callback(null, user); + }, + function sendEvent(user, callback) { + Events.emit(Events.getSystemEvents().UserDownload, { + user: user, + files: fileEntries, + }); + return callback(null); + }, + ]); } } diff --git a/core/file_base_download_manager.js b/core/file_base_download_manager.js index 92490783..b8564b73 100644 --- a/core/file_base_download_manager.js +++ b/core/file_base_download_manager.js @@ -193,8 +193,9 @@ exports.getModule = class FileBaseDownloadQueueManager extends MenuModule { [ function prepArtAndViewController(callback) { return self.displayArtAndPrepViewController( - 'queueManager', FormIds.queueManager, - { clearScreen : clearScreen }, + 'queueManager', + FormIds.queueManager, + { clearScreen: clearScreen }, callback ); }, diff --git a/core/file_base_web_download_manager.js b/core/file_base_web_download_manager.js index 6d30c996..233a247e 100644 --- a/core/file_base_web_download_manager.js +++ b/core/file_base_web_download_manager.js @@ -188,7 +188,7 @@ exports.getModule = class FileBaseWebDownloadQueueManager extends MenuModule { return self.displayArtAndPrepViewController( 'queueManager', FormIds.queueManager, - { clearScreen : clearScreen }, + { clearScreen: clearScreen }, callback ); }, diff --git a/core/file_transfer.js b/core/file_transfer.js index c99f25a0..af166d24 100644 --- a/core/file_transfer.js +++ b/core/file_transfer.js @@ -148,7 +148,10 @@ exports.getModule = class TransferFileModule extends MenuModule { sentFiles.push(f.path); }); - this.client.log.info( { sentFiles : sentFiles }, `User "${self.client.user.username}" uploaded ${sentFiles.length} file(s)` ); + this.client.log.info( + { sentFiles: sentFiles }, + `User "${self.client.user.username}" uploaded ${sentFiles.length} file(s)` + ); } return cb(err); }); diff --git a/core/menu_module.js b/core/menu_module.js index 613c7949..f233b1f7 100644 --- a/core/menu_module.js +++ b/core/menu_module.js @@ -613,45 +613,48 @@ exports.MenuModule = class MenuModule extends PluginModule { async.waterfall( [ - (callback) => { - if(options.clearScreen) { + callback => { + if (options.clearScreen) { this.client.term.rawWrite(ansi.resetScreen()); } theme.displayThemedAsset( config.art[name], this.client, - { font : this.menuConfig.font, trailingLF : false }, + { font: this.menuConfig.font, trailingLF: false }, (err, artData) => { return callback(err, artData); } ); }, (artData, callback) => { - if(_.isUndefined(this.viewControllers[name])) { + if (_.isUndefined(this.viewControllers[name])) { const vcOpts = { - client : this.client, - formId : formId, + client: this.client, + formId: formId, }; - if(!_.isUndefined(options.noInput)) { + if (!_.isUndefined(options.noInput)) { vcOpts.noInput = options.noInput; } - const vc = this.addViewController(name, new ViewController(vcOpts)); + const vc = this.addViewController( + name, + new ViewController(vcOpts) + ); if (_.isFunction(options.artDataPrep)) { try { options.artDataPrep(name, artData, vc); - } catch(e) { + } catch (e) { return callback(e); } } const loadOpts = { - callingMenu : this, - mciMap : artData.mciMap, - formId : formId, + callingMenu: this, + mciMap: artData.mciMap, + formId: formId, }; return vc.loadFromMenuConfig(loadOpts, callback); @@ -815,18 +818,24 @@ exports.MenuModule = class MenuModule extends PluginModule { } // Various common helpers - getDateFormat(defaultStyle='short') { - return this.config.dateFormat || - this.client.currentTheme.helpers.getDateFormat(defaultStyle); + getDateFormat(defaultStyle = 'short') { + return ( + this.config.dateFormat || + this.client.currentTheme.helpers.getDateFormat(defaultStyle) + ); } - getTimeFormat(defaultStyle='short') { - return this.config.timeFormat || - this.client.currentTheme.helpers.getTimeFormat(defaultStyle); + getTimeFormat(defaultStyle = 'short') { + return ( + this.config.timeFormat || + this.client.currentTheme.helpers.getTimeFormat(defaultStyle) + ); } - getDateTimeFormat(defaultStyle='short') { - return this.config.dateTimeFormat || - this.client.currentTheme.helpers.getDateTimeFormat(defaultStyle); + getDateTimeFormat(defaultStyle = 'short') { + return ( + this.config.dateTimeFormat || + this.client.currentTheme.helpers.getDateTimeFormat(defaultStyle) + ); } }; diff --git a/core/menu_view.js b/core/menu_view.js index 952546fc..3b145bfa 100644 --- a/core/menu_view.js +++ b/core/menu_view.js @@ -233,11 +233,11 @@ MenuView.prototype.setFocusItemIndex = function (index) { this.focusedItemIndex = index; }; -MenuView.prototype.getFocusItemIndex = function() { +MenuView.prototype.getFocusItemIndex = function () { return this.focusedItemIndex; }; -MenuView.prototype.onKeyPress = function(ch, key) { +MenuView.prototype.onKeyPress = function (ch, key) { const itemIndex = this.getHotKeyItemIndex(ch); if (itemIndex >= 0) { this.setFocusItemIndex(itemIndex); diff --git a/core/message_area.js b/core/message_area.js index ef903154..32825c71 100644 --- a/core/message_area.js +++ b/core/message_area.js @@ -24,29 +24,29 @@ exports.getAvailableMessageConferences = getAvailableMessageConferences; exports.getSortedAvailMessageConferences = getSortedAvailMessageConferences; exports.getAvailableMessageAreasByConfTag = getAvailableMessageAreasByConfTag; exports.getSortedAvailMessageAreasByConfTag = getSortedAvailMessageAreasByConfTag; -exports.getAllAvailableMessageAreaTags = getAllAvailableMessageAreaTags; -exports.getDefaultMessageConferenceTag = getDefaultMessageConferenceTag; -exports.getDefaultMessageAreaTagByConfTag = getDefaultMessageAreaTagByConfTag; -exports.getSuitableMessageConfAndAreaTags = getSuitableMessageConfAndAreaTags; -exports.getMessageConferenceByTag = getMessageConferenceByTag; -exports.getMessageAreaByTag = getMessageAreaByTag; -exports.getMessageConfTagByAreaTag = getMessageConfTagByAreaTag; -exports.changeMessageConference = changeMessageConference; -exports.changeMessageArea = changeMessageArea; -exports.hasMessageConfAndAreaRead = hasMessageConfAndAreaRead; -exports.hasMessageConfAndAreaWrite = hasMessageConfAndAreaWrite; -exports.filterMessageAreaTagsByReadACS = filterMessageAreaTagsByReadACS; -exports.filterMessageListByReadACS = filterMessageListByReadACS; -exports.tempChangeMessageConfAndArea = tempChangeMessageConfAndArea; -exports.getMessageListForArea = getMessageListForArea; -exports.getNewMessageCountInAreaForUser = getNewMessageCountInAreaForUser; -exports.getNewMessageCountAddressedToUser = getNewMessageCountAddressedToUser; -exports.getNewMessagesInAreaForUser = getNewMessagesInAreaForUser; -exports.getMessageIdNewerThanTimestampByArea = getMessageIdNewerThanTimestampByArea; -exports.getMessageAreaLastReadId = getMessageAreaLastReadId; -exports.updateMessageAreaLastReadId = updateMessageAreaLastReadId; -exports.persistMessage = persistMessage; -exports.trimMessageAreasScheduledEvent = trimMessageAreasScheduledEvent; +exports.getAllAvailableMessageAreaTags = getAllAvailableMessageAreaTags; +exports.getDefaultMessageConferenceTag = getDefaultMessageConferenceTag; +exports.getDefaultMessageAreaTagByConfTag = getDefaultMessageAreaTagByConfTag; +exports.getSuitableMessageConfAndAreaTags = getSuitableMessageConfAndAreaTags; +exports.getMessageConferenceByTag = getMessageConferenceByTag; +exports.getMessageAreaByTag = getMessageAreaByTag; +exports.getMessageConfTagByAreaTag = getMessageConfTagByAreaTag; +exports.changeMessageConference = changeMessageConference; +exports.changeMessageArea = changeMessageArea; +exports.hasMessageConfAndAreaRead = hasMessageConfAndAreaRead; +exports.hasMessageConfAndAreaWrite = hasMessageConfAndAreaWrite; +exports.filterMessageAreaTagsByReadACS = filterMessageAreaTagsByReadACS; +exports.filterMessageListByReadACS = filterMessageListByReadACS; +exports.tempChangeMessageConfAndArea = tempChangeMessageConfAndArea; +exports.getMessageListForArea = getMessageListForArea; +exports.getNewMessageCountInAreaForUser = getNewMessageCountInAreaForUser; +exports.getNewMessageCountAddressedToUser = getNewMessageCountAddressedToUser; +exports.getNewMessagesInAreaForUser = getNewMessagesInAreaForUser; +exports.getMessageIdNewerThanTimestampByArea = getMessageIdNewerThanTimestampByArea; +exports.getMessageAreaLastReadId = getMessageAreaLastReadId; +exports.updateMessageAreaLastReadId = updateMessageAreaLastReadId; +exports.persistMessage = persistMessage; +exports.trimMessageAreasScheduledEvent = trimMessageAreasScheduledEvent; function startup(cb) { // by default, private messages are NOT included @@ -536,20 +536,30 @@ function getNewMessageCountInAreaForUser(userId, areaTag, cb) { // that are addressed to that user (ie: matching username) // Does NOT Include private messages. function getNewMessageCountAddressedToUser(client, cb) { - const areaTags = getAllAvailableMessageAreaTags(client).filter(areaTag => areaTag !== Message.WellKnownAreaTags.Private); + const areaTags = getAllAvailableMessageAreaTags(client).filter( + areaTag => areaTag !== Message.WellKnownAreaTags.Private + ); let newMessageCount = 0; - async.forEach(areaTags, (areaTag, nextAreaTag) => { - getMessageAreaLastReadId(client.user.userId, areaTag, (_, lastMessageId) => { - lastMessageId = lastMessageId || 0; - getNewMessageCountInAreaForUser(client.user.userId, areaTag, (err, count) => { - newMessageCount += count; - return nextAreaTag(err); + async.forEach( + areaTags, + (areaTag, nextAreaTag) => { + getMessageAreaLastReadId(client.user.userId, areaTag, (_, lastMessageId) => { + lastMessageId = lastMessageId || 0; + getNewMessageCountInAreaForUser( + client.user.userId, + areaTag, + (err, count) => { + newMessageCount += count; + return nextAreaTag(err); + } + ); }); - }); - }, () => { - return cb(null, newMessageCount); - }); + }, + () => { + return cb(null, newMessageCount); + } + ); } function getNewMessagesInAreaForUser(userId, areaTag, cb) { @@ -572,10 +582,8 @@ function getNewMessagesInAreaForUser(userId, areaTag, cb) { }); } - -function getMessageListForArea(client, areaTag, filter, cb) -{ - if(!cb && _.isFunction(filter)) { +function getMessageListForArea(client, areaTag, filter, cb) { + if (!cb && _.isFunction(filter)) { cb = filter; filter = { areaTag, diff --git a/core/misc_scheduled_events.js b/core/misc_scheduled_events.js index 444cd3c7..ba794eb8 100644 --- a/core/misc_scheduled_events.js +++ b/core/misc_scheduled_events.js @@ -12,7 +12,9 @@ function dailyMaintenanceScheduledEvent(args, cb) { // // :TODO: files/etc. here const resetProps = [ - SysProps.LoginsToday, SysProps.MessagesToday, SysProps.NewUsersTodayCount, + SysProps.LoginsToday, + SysProps.MessagesToday, + SysProps.NewUsersTodayCount, ]; resetProps.forEach(prop => { diff --git a/core/msg_area_post_fse.js b/core/msg_area_post_fse.js index 645a8793..9eacd1f5 100644 --- a/core/msg_area_post_fse.js +++ b/core/msg_area_post_fse.js @@ -46,7 +46,11 @@ exports.getModule = class AreaPostFSEModule extends FullScreenEditorModule { } else { // note: not logging 'from' here as it's part of client.log.xxxx() self.client.log.info( - { to : msg.toUserName, subject : msg.subject, uuid : msg.messageUuid }, + { + to: msg.toUserName, + subject: msg.subject, + uuid: msg.messageUuid, + }, `User "${self.client.user.username}" posted message to "${msg.toUserName}" (${msg.areaTag})` ); } diff --git a/core/node_msg.js b/core/node_msg.js index b0b11fa2..71530f9c 100644 --- a/core/node_msg.js +++ b/core/node_msg.js @@ -7,13 +7,13 @@ const { getActiveConnectionList, getConnectionByNodeId, UserMessageableConnections, -} = require('./client_connections.js'); -const UserInterruptQueue = require('./user_interrupt_queue.js'); -const { getThemeArt } = require('./theme.js'); -const { pipeToAnsi } = require('./color_codes.js'); -const stringFormat = require('./string_format.js'); -const { renderStringLength } = require('./string_util.js'); -const Events = require('./events.js'); +} = require('./client_connections.js'); +const UserInterruptQueue = require('./user_interrupt_queue.js'); +const { getThemeArt } = require('./theme.js'); +const { pipeToAnsi } = require('./color_codes.js'); +const stringFormat = require('./string_format.js'); +const { renderStringLength } = require('./string_util.js'); +const Events = require('./events.js'); // deps const series = require('async/series'); @@ -221,22 +221,30 @@ exports.getModule = class NodeMessageModule extends MenuModule { prepareNodeList() { // standard node list with {text} field added for compliance - this.nodeList = [{ - text : '-ALL-', - // dummy fields: - node : -1, - authenticated : false, - userId : 0, - action : 'N/A', - userName : 'Everyone', - realName : 'All Users', - location : 'N/A', - affils : 'N/A', - timeOn : 'N/A', - }].concat(getActiveConnectionList(UserMessageableConnections) - .map(node => Object.assign(node, { text : -1 == node.node ? '-ALL-' : node.node.toString() } )) - ).filter(node => node.node !== this.client.node); // remove our client's node - this.nodeList.sort( (a, b) => a.node - b.node ); // sort by node + this.nodeList = [ + { + text: '-ALL-', + // dummy fields: + node: -1, + authenticated: false, + userId: 0, + action: 'N/A', + userName: 'Everyone', + realName: 'All Users', + location: 'N/A', + affils: 'N/A', + timeOn: 'N/A', + }, + ] + .concat( + getActiveConnectionList(UserMessageableConnections).map(node => + Object.assign(node, { + text: -1 == node.node ? '-ALL-' : node.node.toString(), + }) + ) + ) + .filter(node => node.node !== this.client.node); // remove our client's node + this.nodeList.sort((a, b) => a.node - b.node); // sort by node } nodeListSelectionIndexUpdate(idx) { diff --git a/core/nua.js b/core/nua.js index 1aaf67c1..4f6f355d 100644 --- a/core/nua.js +++ b/core/nua.js @@ -129,8 +129,11 @@ exports.getModule = class NewUserAppModule extends MenuModule { sessionId: self.client.session.uniqueId, // used for events/etc. }; newUser.create(createUserInfo, err => { - if(err) { - self.client.log.warn( { error : err, username : formData.value.username }, 'New user creation failed'); + if (err) { + self.client.log.warn( + { error: err, username: formData.value.username }, + 'New user creation failed' + ); self.gotoMenu(extraArgs.error, err => { if (err) { @@ -139,7 +142,10 @@ exports.getModule = class NewUserAppModule extends MenuModule { return cb(null); }); } else { - self.client.log.info( { username : formData.value.username, userId : newUser.userId }, `New user "${formData.value.username}" created`); + self.client.log.info( + { username: formData.value.username, userId: newUser.userId }, + `New user "${formData.value.username}" created` + ); // Cache SysOp information now // :TODO: Similar to bbs.js. DRY diff --git a/core/predefined_mci.js b/core/predefined_mci.js index 105f8a74..8461d283 100644 --- a/core/predefined_mci.js +++ b/core/predefined_mci.js @@ -15,11 +15,11 @@ const SysProps = require('./system_property.js'); const SysLogKeys = require('./system_log.js'); // deps -const packageJson = require('../package.json'); -const os = require('os'); -const _ = require('lodash'); -const moment = require('moment'); -const async = require('async'); +const packageJson = require('../package.json'); +const os = require('os'); +const _ = require('lodash'); +const moment = require('moment'); +const async = require('async'); exports.getPredefinedMCIValue = getPredefinedMCIValue; exports.init = init; @@ -27,14 +27,14 @@ exports.init = init; function init(cb) { async.series( [ - (callback) => { + callback => { return setNextRandomRumor(callback); }, - (callback) => { + callback => { // by fetching a memory or load we'll force a refresh now StatLog.getSystemStat(SysProps.SystemMemoryStats); return callback(null); - } + }, ], err => { return cb(err); @@ -98,38 +98,87 @@ const PREDEFINED_MCI_GENERATORS = { }, // +op info - SN : function opUserName() { return StatLog.getSystemStat(SysProps.SysOpUsername); }, - SR : function opRealName() { return StatLog.getSystemStat(SysProps.SysOpRealName); }, - SL : function opLocation() { return StatLog.getSystemStat(SysProps.SysOpLocation); }, - SA : function opAffils() { return StatLog.getSystemStat(SysProps.SysOpAffiliations); }, - SS : function opSex() { return StatLog.getSystemStat(SysProps.SysOpSex); }, - SE : function opEmail() { return StatLog.getSystemStat(SysProps.SysOpEmailAddress); }, + SN: function opUserName() { + return StatLog.getSystemStat(SysProps.SysOpUsername); + }, + SR: function opRealName() { + return StatLog.getSystemStat(SysProps.SysOpRealName); + }, + SL: function opLocation() { + return StatLog.getSystemStat(SysProps.SysOpLocation); + }, + SA: function opAffils() { + return StatLog.getSystemStat(SysProps.SysOpAffiliations); + }, + SS: function opSex() { + return StatLog.getSystemStat(SysProps.SysOpSex); + }, + SE: function opEmail() { + return StatLog.getSystemStat(SysProps.SysOpEmailAddress); + }, // // Current user / session // - UN : function userName(client) { return client.user.username; }, - UI : function userId(client) { return client.user.userId.toString(); }, - UG : function groups(client) { return _.values(client.user.groups).join(', '); }, - UR : function realName(client) { return userStatAsString(client, UserProps.RealName, ''); }, - LO : function location(client) { return userStatAsString(client, UserProps.Location, ''); }, - UA : function age(client) { return client.user.getAge().toString(); }, - BD : function birthdate(client) { // iNiQUiTY - return moment(client.user.properties[UserProps.Birthdate]).format(client.currentTheme.helpers.getDateFormat()); + UN: function userName(client) { + return client.user.username; }, - US : function sex(client) { return userStatAsString(client, UserProps.Sex, ''); }, - UE : function emailAddress(client) { return userStatAsString(client, UserProps.EmailAddress, ''); }, - UW : function webAddress(client) { return userStatAsString(client, UserProps.WebAddress, ''); }, - UF : function affils(client) { return userStatAsString(client, UserProps.Affiliations, ''); }, - UT : function themeName(client) { - return _.get(client, 'currentTheme.info.name', userStatAsString(client, UserProps.ThemeId, '')); + UI: function userId(client) { + return client.user.userId.toString(); }, - UD : function themeId(client) { return userStatAsString(client, UserProps.ThemeId, ''); }, - UC : function loginCount(client) { return userStatAsCountString(client, UserProps.LoginCount, 0); }, - ND : function connectedNode(client) { return client.node.toString(); }, - IP : function clientIpAddress(client) { return client.friendlyRemoteAddress() }, - ST : function serverName(client) { return client.session.serverName; }, - FN : function activeFileBaseFilterName(client) { + UG: function groups(client) { + return _.values(client.user.groups).join(', '); + }, + UR: function realName(client) { + return userStatAsString(client, UserProps.RealName, ''); + }, + LO: function location(client) { + return userStatAsString(client, UserProps.Location, ''); + }, + UA: function age(client) { + return client.user.getAge().toString(); + }, + BD: function birthdate(client) { + // iNiQUiTY + return moment(client.user.properties[UserProps.Birthdate]).format( + client.currentTheme.helpers.getDateFormat() + ); + }, + US: function sex(client) { + return userStatAsString(client, UserProps.Sex, ''); + }, + UE: function emailAddress(client) { + return userStatAsString(client, UserProps.EmailAddress, ''); + }, + UW: function webAddress(client) { + return userStatAsString(client, UserProps.WebAddress, ''); + }, + UF: function affils(client) { + return userStatAsString(client, UserProps.Affiliations, ''); + }, + UT: function themeName(client) { + return _.get( + client, + 'currentTheme.info.name', + userStatAsString(client, UserProps.ThemeId, '') + ); + }, + UD: function themeId(client) { + return userStatAsString(client, UserProps.ThemeId, ''); + }, + UC: function loginCount(client) { + return userStatAsCountString(client, UserProps.LoginCount, 0); + }, + ND: function connectedNode(client) { + return client.node.toString(); + }, + IP: function clientIpAddress(client) { + return client.friendlyRemoteAddress(); + }, + ST: function serverName(client) { + return client.session.serverName; + }, + FN: function activeFileBaseFilterName(client) { const activeFilter = FileBaseFilters.getActiveFilter(client); return activeFilter ? activeFilter.name : '(Unknown)'; }, @@ -234,19 +283,22 @@ const PREDEFINED_MCI_GENERATORS = { const minutes = client.user.properties[UserProps.MinutesOnlineTotalCount] || 0; return moment.duration(minutes, 'minutes').humanize(); }, - NM : function userNewMessagesAddressedToCount(client) { - return StatLog.getUserStatNumByClient(client, UserProps.NewAddressedToMessageCount); + NM: function userNewMessagesAddressedToCount(client) { + return StatLog.getUserStatNumByClient( + client, + UserProps.NewAddressedToMessageCount + ); }, - NP : function userNewPrivateMailCount(client) { + NP: function userNewPrivateMailCount(client) { return StatLog.getUserStatNumByClient(client, UserProps.NewPrivateMailCount); }, - IA : function userStatusAvailableIndicator(client) { + IA: function userStatusAvailableIndicator(client) { const indicators = client.currentTheme.helpers.getStatusAvailIndicators(); - return client.user.isAvailable() ? (indicators[0] || 'Y') : (indicators[1] || 'N'); + return client.user.isAvailable() ? indicators[0] || 'Y' : indicators[1] || 'N'; }, - IV : function userStatusVisibleIndicator(client) { + IV: function userStatusVisibleIndicator(client) { const indicators = client.currentTheme.helpers.getStatusVisibleIndicators(); - return client.user.isVisible() ? (indicators[0] || 'Y') : (indicators[1] || 'N'); + return client.user.isVisible() ? indicators[0] || 'Y' : indicators[1] || 'N'; }, // @@ -294,27 +346,37 @@ const PREDEFINED_MCI_GENERATORS = { .trim(); }, - MB : function totalMemoryBytes() { - const stats = StatLog.getSystemStat(SysProps.SystemMemoryStats) || { totalBytes : 0 }; + MB: function totalMemoryBytes() { + const stats = StatLog.getSystemStat(SysProps.SystemMemoryStats) || { + totalBytes: 0, + }; return formatByteSize(stats.totalBytes, true); // true=withAbbr }, - MF : function totalMemoryFreeBytes() { - const stats = StatLog.getSystemStat(SysProps.SystemMemoryStats) || { freeBytes : 0 }; - return formatByteSize(stats.freeBytes, true); // true=withAbbr + MF: function totalMemoryFreeBytes() { + const stats = StatLog.getSystemStat(SysProps.SystemMemoryStats) || { + freeBytes: 0, + }; + return formatByteSize(stats.freeBytes, true); // true=withAbbr }, - LA : function systemLoadAverage() { - const stats = StatLog.getSystemStat(SysProps.SystemLoadStats) || { average : 0.0 }; + LA: function systemLoadAverage() { + const stats = StatLog.getSystemStat(SysProps.SystemLoadStats) || { average: 0.0 }; return stats.average.toLocaleString(); }, - CL : function systemCurrentLoad() { - const stats = StatLog.getSystemStat(SysProps.SystemLoadStats) || { current : 0 }; + CL: function systemCurrentLoad() { + const stats = StatLog.getSystemStat(SysProps.SystemLoadStats) || { current: 0 }; return `${stats.current}%`; }, - UU : function systemUptime() { + UU: function systemUptime() { return moment.duration(process.uptime(), 'seconds').humanize(); }, - NV : function nodeVersion() { return process.version; }, - AN : function activeNodes() { return clientConnections.getActiveConnections(clientConnections.UserVisibleConnections).length.toString(); }, + NV: function nodeVersion() { + return process.version; + }, + AN: function activeNodes() { + return clientConnections + .getActiveConnections(clientConnections.UserVisibleConnections) + .length.toString(); + }, TC: function totalCalls() { return StatLog.getSystemStat(SysProps.LoginCount).toLocaleString(); @@ -333,13 +395,17 @@ const PREDEFINED_MCI_GENERATORS = { // // System File Base, Up/Download Info // - SD : function systemNumDownloads() { return StatLog.getFriendlySystemStat(SysProps.FileDlTotalCount, 0); }, - SO : function systemByteDownload() { + SD: function systemNumDownloads() { + return StatLog.getFriendlySystemStat(SysProps.FileDlTotalCount, 0); + }, + SO: function systemByteDownload() { const byteSize = StatLog.getSystemStatNum(SysProps.FileDlTotalBytes); return formatByteSize(byteSize, true); // true=withAbbr }, - SU : function systemNumUploads() { return StatLog.getFriendlySystemStat(SysProps.FileUlTotalCount, 0); }, - SP : function systemByteUpload() { + SU: function systemNumUploads() { + return StatLog.getFriendlySystemStat(SysProps.FileUlTotalCount, 0); + }, + SP: function systemByteUpload() { const byteSize = StatLog.getSystemStatNum(SysProps.FileUlTotalBytes); return formatByteSize(byteSize, true); // true=withAbbr }, @@ -352,49 +418,55 @@ const PREDEFINED_MCI_GENERATORS = { const totalBytes = parseInt(_.get(areaStats, 'totalBytes', 0)); return formatByteSize(totalBytes, true); // true=withAbbr }, - PT : function messagesPostedToday() { // Obv/2 + PT: function messagesPostedToday() { + // Obv/2 return StatLog.getFriendlySystemStat(SysProps.MessagesToday, 0); }, - TP : function totalMessagesOnSystem() { // Obv/2 + TP: function totalMessagesOnSystem() { + // Obv/2 return StatLog.getFriendlySystemStat(SysProps.MessageTotalCount, 0); }, - FT : function totalUploadsToday() { // Obv/2 + FT: function totalUploadsToday() { + // Obv/2 return StatLog.getFriendlySystemStat(SysProps.FileUlTodayCount, 0); }, - FB : function totalUploadBytesToday() { + FB: function totalUploadBytesToday() { const byteSize = StatLog.getSystemStatNum(SysProps.FileUlTodayBytes); - return formatByteSize(byteSize, true); // true=withAbbr + return formatByteSize(byteSize, true); // true=withAbbr }, - DD : function totalDownloadsToday() { // iNiQUiTY + DD: function totalDownloadsToday() { + // iNiQUiTY return StatLog.getFriendlySystemStat(SysProps.FileDlTodayCount, 0); }, - DB : function totalDownloadBytesToday() { + DB: function totalDownloadBytesToday() { const byteSize = StatLog.getSystemStatNum(SysProps.FileDlTodayBytes); - return formatByteSize(byteSize, true); // true=withAbbr + return formatByteSize(byteSize, true); // true=withAbbr }, - NT : function totalNewUsersToday() { // Obv/2 + NT: function totalNewUsersToday() { + // Obv/2 return StatLog.getSystemStatNum(SysProps.NewUsersTodayCount); }, // :TODO: TZ - Average *system* post/call ratio (iNiQUiTY) // :TODO: ?? - Total users on system - TU : function totalSystemUsers() { + TU: function totalSystemUsers() { return StatLog.getSystemStatNum(SysProps.TotalUserCount) || 1; }, - LC : function lastCallerUserName() { // Obv/2 + LC: function lastCallerUserName() { + // Obv/2 const lastLogin = StatLog.getSystemStat(SysProps.LastLogin) || {}; return lastLogin.userName || 'N/A'; }, - LD : function lastCallerDate(client) { + LD: function lastCallerDate(client) { const lastLogin = StatLog.getSystemStat(SysProps.LastLogin) || {}; if (!lastLogin.timestamp) { return 'N/A'; } return lastLogin.timestamp.format(client.currentTheme.helpers.getDateFormat()); }, - LT : function lastCallerTime(client) { + LT: function lastCallerTime(client) { const lastLogin = StatLog.getSystemStat(SysProps.LastLogin) || {}; if (!lastLogin.timestamp) { return 'N/A'; @@ -437,8 +509,11 @@ function getPredefinedMCIValue(client, code, extra) { let value; try { value = generator(client, extra); - } catch(e) { - Log.error( { code : code, exception : e.message }, `Failed generating predefined MCI value (${code})` ); + } catch (e) { + Log.error( + { code: code, exception: e.message }, + `Failed generating predefined MCI value (${code})` + ); } return value; diff --git a/core/stat_log.js b/core/stat_log.js index fe3c2614..8c80fc6c 100644 --- a/core/stat_log.js +++ b/core/stat_log.js @@ -1,19 +1,17 @@ /* jslint node: true */ 'use strict'; -const sysDb = require('./database.js').dbs.system; -const { - getISOTimestampString -} = require('./database.js'); -const Errors = require('./enig_error.js'); -const SysProps = require('./system_property.js'); +const sysDb = require('./database.js').dbs.system; +const { getISOTimestampString } = require('./database.js'); +const Errors = require('./enig_error.js'); +const SysProps = require('./system_property.js'); const UserProps = require('./user_property'); const Message = require('./message'); // deps -const _ = require('lodash'); -const moment = require('moment'); -const SysInfo = require('systeminformation'); +const _ = require('lodash'); +const moment = require('moment'); +const SysInfo = require('systeminformation'); /* System Event Log & Stats @@ -171,7 +169,7 @@ class StatLog { return parseInt(this.getUserStat(user, statName)) || 0; } - getUserStatNumByClient(client, statName, ttlSeconds=10) { + getUserStatNumByClient(client, statName, ttlSeconds = 10) { const stat = this.getUserStatNum(client.user, statName); this._refreshUserStat(client, statName, ttlSeconds); return stat; @@ -359,8 +357,8 @@ class StatLog { _refreshSystemStat(statName) { switch (statName) { - case SysProps.SystemLoadStats : - case SysProps.SystemMemoryStats : + case SysProps.SystemLoadStats: + case SysProps.SystemMemoryStats: return this._refreshSysInfoStats(); } } @@ -374,23 +372,27 @@ class StatLog { this.lastSysInfoStatsRefresh = now; const basicSysInfo = { - mem : 'total, free', - currentLoad : 'avgLoad, currentLoad', + mem: 'total, free', + currentLoad: 'avgLoad, currentLoad', }; SysInfo.get(basicSysInfo) .then(sysInfo => { const memStats = { - totalBytes : sysInfo.mem.total, - freeBytes : sysInfo.mem.free, + totalBytes: sysInfo.mem.total, + freeBytes: sysInfo.mem.free, }; this.setNonPersistentSystemStat(SysProps.SystemMemoryStats, memStats); const loadStats = { // Not avail on BSD, yet. - average : parseFloat(_.get(sysInfo, 'currentLoad.avgLoad', 0).toFixed(2)), - current : parseFloat(_.get(sysInfo, 'currentLoad.currentLoad', 0).toFixed(2)), + average: parseFloat( + _.get(sysInfo, 'currentLoad.avgLoad', 0).toFixed(2) + ), + current: parseFloat( + _.get(sysInfo, 'currentLoad.currentLoad', 0).toFixed(2) + ), }; this.setNonPersistentSystemStat(SysProps.SystemLoadStats, loadStats); @@ -401,13 +403,23 @@ class StatLog { } _refreshUserStat(client, statName, ttlSeconds) { - switch(statName) { + switch (statName) { case UserProps.NewPrivateMailCount: - this._wrapUserRefreshWithCachedTTL(client, statName, this._refreshUserPrivateMailCount, ttlSeconds); + this._wrapUserRefreshWithCachedTTL( + client, + statName, + this._refreshUserPrivateMailCount, + ttlSeconds + ); break; case UserProps.NewAddressedToMessageCount: - this._wrapUserRefreshWithCachedTTL(client, statName, this._refreshUserNewAddressedToMessageCount, ttlSeconds); + this._wrapUserRefreshWithCachedTTL( + client, + statName, + this._refreshUserNewAddressedToMessageCount, + ttlSeconds + ); break; } } @@ -427,17 +439,21 @@ class StatLog { _refreshUserPrivateMailCount(client) { const MsgArea = require('./message_area'); - MsgArea.getNewMessageCountInAreaForUser(client.user.userId, Message.WellKnownAreaTags.Private, (err, count) => { - if (!err) { - client.user.setProperty(UserProps.NewPrivateMailCount, count); + MsgArea.getNewMessageCountInAreaForUser( + client.user.userId, + Message.WellKnownAreaTags.Private, + (err, count) => { + if (!err) { + client.user.setProperty(UserProps.NewPrivateMailCount, count); + } } - }); + ); } _refreshUserNewAddressedToMessageCount(client) { const MsgArea = require('./message_area'); MsgArea.getNewMessageCountAddressedToUser(client, (err, count) => { - if(!err) { + if (!err) { client.user.setProperty(UserProps.NewAddressedToMessageCount, count); } }); @@ -445,21 +461,19 @@ class StatLog { _findLogEntries(logTable, filter, cb) { filter = filter || {}; - if(!_.isString(filter.logName)) { + if (!_.isString(filter.logName)) { return cb(Errors.MissingParam('filter.logName is required')); } - filter.resultType = filter.resultType || 'obj'; - filter.order = filter.order || 'timestamp'; + filter.resultType = filter.resultType || 'obj'; + filter.order = filter.order || 'timestamp'; let sql; - if('count' === filter.resultType) { - sql = - `SELECT COUNT() AS count + if ('count' === filter.resultType) { + sql = `SELECT COUNT() AS count FROM ${logTable}`; } else { - sql = - `SELECT timestamp, log_value + sql = `SELECT timestamp, log_value FROM ${logTable}`; } @@ -473,40 +487,42 @@ class StatLog { sql += ` AND session_id = ${filter.sessionId}`; } - if(filter.date) { + if (filter.date) { filter.date = moment(filter.date); - sql += ` AND DATE(timestamp, "localtime") = DATE("${filter.date.format('YYYY-MM-DD')}")`; + sql += ` AND DATE(timestamp, "localtime") = DATE("${filter.date.format( + 'YYYY-MM-DD' + )}")`; } - if('count' !== filter.resultType) { - switch(filter.order) { - case 'timestamp' : - case 'timestamp_asc' : + if ('count' !== filter.resultType) { + switch (filter.order) { + case 'timestamp': + case 'timestamp_asc': sql += ' ORDER BY timestamp ASC'; break; - case 'timestamp_desc' : + case 'timestamp_desc': sql += ' ORDER BY timestamp DESC'; break; - case 'random' : + case 'random': sql += ' ORDER BY RANDOM()'; break; } } - if(_.isNumber(filter.limit) && 0 !== filter.limit) { + if (_.isNumber(filter.limit) && 0 !== filter.limit) { sql += ` LIMIT ${filter.limit}`; } sql += ';'; - if('count' === filter.resultType) { - sysDb.get(sql, [ filter.logName ], (err, row) => { + if ('count' === filter.resultType) { + sysDb.get(sql, [filter.logName], (err, row) => { return cb(err, row ? row.count : 0); }); } else { - sysDb.all(sql, [ filter.logName ], (err, rows) => { + sysDb.all(sql, [filter.logName], (err, rows) => { return cb(err, rows); }); } diff --git a/core/string_util.js b/core/string_util.js index 57815194..3f78b37d 100644 --- a/core/string_util.js +++ b/core/string_util.js @@ -379,9 +379,9 @@ function formatByteSizeAbbr(byteSize) { } function formatByteSize(byteSize, withAbbr = false, decimals = 2) { - const i = 0 === byteSize ? byteSize : Math.floor(Math.log(byteSize) / Math.log(1024)); - let result = parseFloat((byteSize / Math.pow(1024, i)).toFixed(decimals)).toString(); - if(withAbbr) { + const i = 0 === byteSize ? byteSize : Math.floor(Math.log(byteSize) / Math.log(1024)); + let result = parseFloat((byteSize / Math.pow(1024, i)).toFixed(decimals)).toString(); + if (withAbbr) { result += ` ${BYTE_SIZE_ABBRS[i]}`; } return result; diff --git a/core/sys_event_user_log.js b/core/sys_event_user_log.js index 8061b11f..1f42ff29 100644 --- a/core/sys_event_user_log.js +++ b/core/sys_event_user_log.js @@ -1,9 +1,9 @@ /* jslint node: true */ 'use strict'; -const Events = require('./events.js'); -const LogNames = require('./user_log_name.js'); -const SysProps = require('./system_property.js'); +const Events = require('./events.js'); +const LogNames = require('./user_log_name.js'); +const SysProps = require('./system_property.js'); const DefaultKeepForDays = 365; diff --git a/core/system_log.js b/core/system_log.js index 47e10fa4..1a833f01 100644 --- a/core/system_log.js +++ b/core/system_log.js @@ -5,6 +5,6 @@ // Common SYSTEM/global log keys // module.exports = { - UserAddedRumorz : 'system_rumorz', - UserLoginHistory : 'user_login_history', // JSON object + UserAddedRumorz: 'system_rumorz', + UserLoginHistory: 'user_login_history', // JSON object }; diff --git a/core/system_property.js b/core/system_property.js index c9e17b8e..b8d8b5c8 100644 --- a/core/system_property.js +++ b/core/system_property.js @@ -8,9 +8,9 @@ // their own! // module.exports = { - LoginCount : 'login_count', - LoginsToday : 'logins_today', // non-persistent - LastLogin : 'last_login', // object { userId, sessionId, userName, userRealName, timestamp }; non-persistent + LoginCount: 'login_count', + LoginsToday: 'logins_today', // non-persistent + LastLogin: 'last_login', // object { userId, sessionId, userName, userRealName, timestamp }; non-persistent FileBaseAreaStats: 'file_base_area_stats', // object - see file_base_area.js::getAreaStats FileUlTotalCount: 'ul_total_count', @@ -18,26 +18,26 @@ module.exports = { FileDlTotalCount: 'dl_total_count', FileDlTotalBytes: 'dl_total_bytes', - FileUlTodayCount : 'ul_today_count', // non-persistent - FileUlTodayBytes : 'ul_today_bytes', // non-persistent - FileDlTodayCount : 'dl_today_count', // non-persistent - FileDlTodayBytes : 'dl_today_bytes', // non-persistent + FileUlTodayCount: 'ul_today_count', // non-persistent + FileUlTodayBytes: 'ul_today_bytes', // non-persistent + FileDlTodayCount: 'dl_today_count', // non-persistent + FileDlTodayBytes: 'dl_today_bytes', // non-persistent - MessageTotalCount : 'message_post_total_count', // total non-private messages on the system; non-persistent - MessagesToday : 'message_post_today', // non-private messages posted/imported today; non-persistent + MessageTotalCount: 'message_post_total_count', // total non-private messages on the system; non-persistent + MessagesToday: 'message_post_today', // non-private messages posted/imported today; non-persistent - SysOpUsername : 'sysop_username', // non-persistent - SysOpRealName : 'sysop_real_name', // non-persistent - SysOpLocation : 'sysop_location', // non-persistent - SysOpAffiliations : 'sysop_affiliation', // non-persistent - SysOpSex : 'sysop_sex', // non-persistent - SysOpEmailAddress : 'sysop_email_address', // non-persistent + SysOpUsername: 'sysop_username', // non-persistent + SysOpRealName: 'sysop_real_name', // non-persistent + SysOpLocation: 'sysop_location', // non-persistent + SysOpAffiliations: 'sysop_affiliation', // non-persistent + SysOpSex: 'sysop_sex', // non-persistent + SysOpEmailAddress: 'sysop_email_address', // non-persistent - NextRandomRumor : 'random_rumor', + NextRandomRumor: 'random_rumor', - SystemMemoryStats : 'system_memory_stats', // object { totalBytes, freeBytes }; non-persistent - SystemLoadStats : 'system_load_stats', // object { average, current }; non-persistent + SystemMemoryStats: 'system_memory_stats', // object { totalBytes, freeBytes }; non-persistent + SystemLoadStats: 'system_load_stats', // object { average, current }; non-persistent - TotalUserCount : 'user_total_count', // non-persistent - NewUsersTodayCount : 'user_new_today_count', // non-persistent + TotalUserCount: 'user_total_count', // non-persistent + NewUsersTodayCount: 'user_new_today_count', // non-persistent }; diff --git a/core/telnet_bridge.js b/core/telnet_bridge.js index 993fc60e..b4a836cf 100644 --- a/core/telnet_bridge.js +++ b/core/telnet_bridge.js @@ -217,10 +217,15 @@ exports.getModule = class TelnetBridgeModule extends MenuModule { }); telnetConnection.on('end', err => { - self.client.removeListener('key press', connectionKeyPressHandler); + self.client.removeListener( + 'key press', + connectionKeyPressHandler + ); - if(err) { - self.client.log.warn(`Telnet bridge connection error: ${err.message}`); + if (err) { + self.client.log.warn( + `Telnet bridge connection error: ${err.message}` + ); } callback( diff --git a/core/theme.js b/core/theme.js index 3fef5886..e97a11da 100644 --- a/core/theme.js +++ b/core/theme.js @@ -364,17 +364,30 @@ exports.ThemeManager = class ThemeManager { const format = Config().theme.timeFormat[style] || 'h:mm a'; return _.get(theme, `customization.defaults.timeFormat.${style}`, format); }, - getDateTimeFormat : function(style = 'short') { - const format = Config().theme.dateTimeFormat[style] || 'MM/DD/YYYY h:mm a'; - return _.get(theme, `customization.defaults.dateTimeFormat.${style}`, format); + getDateTimeFormat: function (style = 'short') { + const format = + Config().theme.dateTimeFormat[style] || 'MM/DD/YYYY h:mm a'; + return _.get( + theme, + `customization.defaults.dateTimeFormat.${style}`, + format + ); }, - getStatusAvailIndicators : function() { - const format = Config().theme.statusAvailableIndicators || [ 'Y', 'N' ]; - return _.get(theme, 'customization.defaults.statusAvailableIndicators', format); + getStatusAvailIndicators: function () { + const format = Config().theme.statusAvailableIndicators || ['Y', 'N']; + return _.get( + theme, + 'customization.defaults.statusAvailableIndicators', + format + ); }, - getStatusVisibleIndicators : function() { - const format = Config().theme.statusVisibleIndicators || [ 'Y', 'N' ]; - return _.get(theme, 'customization.defaults.statusVisibleIndicators', format); + getStatusVisibleIndicators: function () { + const format = Config().theme.statusVisibleIndicators || ['Y', 'N']; + return _.get( + theme, + 'customization.defaults.statusVisibleIndicators', + format + ); }, }; } diff --git a/core/user.js b/core/user.js index e4ce1e23..58cf69d9 100644 --- a/core/user.js +++ b/core/user.js @@ -12,22 +12,22 @@ const Log = require('./logger.js').log; const StatLog = require('./stat_log.js'); // deps -const crypto = require('crypto'); -const assert = require('assert'); -const async = require('async'); -const _ = require('lodash'); -const moment = require('moment'); -const sanatizeFilename = require('sanitize-filename'); -const ssh2 = require('ssh2'); +const crypto = require('crypto'); +const assert = require('assert'); +const async = require('async'); +const _ = require('lodash'); +const moment = require('moment'); +const sanatizeFilename = require('sanitize-filename'); +const ssh2 = require('ssh2'); module.exports = class User { constructor() { - this.userId = 0; - this.username = ''; - this.properties = {}; // name:value - this.groups = []; // group membership(s) - this.authFactor = User.AuthFactors.None; - this.statusFlags = User.StatusFlags.None; + this.userId = 0; + this.username = ''; + this.properties = {}; // name:value + this.groups = []; // group membership(s) + this.authFactor = User.AuthFactors.None; + this.statusFlags = User.StatusFlags.None; } // static property accessors @@ -72,10 +72,10 @@ module.exports = class User { static get StatusFlags() { return { - None : 0x00000000, - NotAvailable : 0x00000001, // Not currently available for chat, message, page, etc. - NotVisible : 0x00000002, // Invisible -- does not show online, last callers, etc. - } + None: 0x00000000, + NotAvailable: 0x00000001, // Not currently available for chat, message, page, etc. + NotVisible: 0x00000002, // Invisible -- does not show online, last callers, etc. + }; } isAuthenticated() { @@ -736,21 +736,27 @@ module.exports = class User { if (!cb && _.isFunction(propsList)) { cb = propsList; propsList = [ - UserProps.RealName, UserProps.Sex, UserProps.EmailAddress, - UserProps.Location, UserProps.Affiliations, + UserProps.RealName, + UserProps.Sex, + UserProps.EmailAddress, + UserProps.Location, + UserProps.Affiliations, ]; } async.waterfall( [ - (callback) => { + callback => { return User.getUserName(userId, callback); }, (userName, callback) => { - User.loadProperties(userId, { names : propsList }, (err, props) => { - return callback(err, Object.assign({}, props, { user_name : userName })); + User.loadProperties(userId, { names: propsList }, (err, props) => { + return callback( + err, + Object.assign({}, props, { user_name: userName }) + ); }); - } + }, ], (err, userProps) => { if (err) { @@ -904,7 +910,7 @@ module.exports = class User { `SELECT count() AS user_count FROM user;`, (err, row) => { - if(err) { + if (err) { return cb(err); } return cb(null, row.user_count); diff --git a/core/user_config.js b/core/user_config.js index 3f7d1bcc..859c63e8 100644 --- a/core/user_config.js +++ b/core/user_config.js @@ -140,20 +140,30 @@ exports.getModule = class UserConfigModule extends MenuModule { return self.prevMenu(cb); } - self.client.log.info(`User "${self.client.user.username}" updated configuration`); + self.client.log.info( + `User "${self.client.user.username}" updated configuration` + ); // // New password if it's not empty // - if(formData.value.password.length > 0) { - self.client.user.setNewAuthCredentials(formData.value.password, err => { - if(err) { - self.client.log.error( { err : err }, 'Failed storing new authentication credentials'); - } else { - self.client.log.info(`User "${self.client.user.username}" updated authentication credentials`); + if (formData.value.password.length > 0) { + self.client.user.setNewAuthCredentials( + formData.value.password, + err => { + if (err) { + self.client.log.error( + { err: err }, + 'Failed storing new authentication credentials' + ); + } else { + self.client.log.info( + `User "${self.client.user.username}" updated authentication credentials` + ); + } + return self.prevMenu(cb); } - return self.prevMenu(cb); - }); + ); } else { return self.prevMenu(cb); } diff --git a/core/user_interrupt_queue.js b/core/user_interrupt_queue.js index 5d785703..c495d5a4 100644 --- a/core/user_interrupt_queue.js +++ b/core/user_interrupt_queue.js @@ -25,13 +25,15 @@ module.exports = class UserInterruptQueue { } else if (opts.omit) { omitNodes = [opts.omit]; } - omitNodes = omitNodes.map(n => _.isNumber(n) ? n : n.node); + omitNodes = omitNodes.map(n => (_.isNumber(n) ? n : n.node)); const connOpts = { authUsersOnly: true, visibleOnly: true, availOnly: true, }; - opts.clients = getActiveConnections(connOpts).filter(ac => !omitNodes.includes(ac.node)); + opts.clients = getActiveConnections(connOpts).filter( + ac => !omitNodes.includes(ac.node) + ); } if (!Array.isArray(opts.clients)) { opts.clients = [opts.clients]; diff --git a/core/user_login.js b/core/user_login.js index 9f151343..e7242132 100644 --- a/core/user_login.js +++ b/core/user_login.js @@ -21,10 +21,10 @@ const { const { getFileAreaByTag, getDefaultFileAreaTag } = require('./file_base_area.js'); // deps -const async = require('async'); -const _ = require('lodash'); -const assert = require('assert'); -const moment = require('moment'); +const async = require('async'); +const _ = require('lodash'); +const assert = require('assert'); +const moment = require('moment'); exports.userLogin = userLogin; exports.recordLogin = recordLogin; @@ -38,8 +38,11 @@ function userLogin(client, username, password, options, cb) { const config = Config(); - if(config.users.badUserNames.includes(username.toLowerCase())) { - client.log.info( { username, ip : client.remoteAddress }, `Attempt to login with banned username "${username}"`); + if (config.users.badUserNames.includes(username.toLowerCase())) { + client.log.info( + { username, ip: client.remoteAddress }, + `Attempt to login with banned username "${username}"` + ); // slow down a bit to thwart brute force attacks return setTimeout(() => { @@ -75,7 +78,7 @@ function userLogin(client, username, password, options, cb) { ); // ...but same user }); - if(existingClientConnection) { + if (existingClientConnection) { client.log.warn( { existingNodeId: existingClientConnection.node, @@ -193,8 +196,13 @@ function recordLogin(client, cb) { StatLog.incrementNonPersistentSystemStat(SysProps.LoginsToday, 1); return StatLog.incrementSystemStat(SysProps.LoginCount, 1, callback); }, - (callback) => { - return StatLog.setUserStat(user, UserProps.LastLoginTs, loginTimestamp, callback); + callback => { + return StatLog.setUserStat( + user, + UserProps.LastLoginTs, + loginTimestamp, + callback + ); }, callback => { return StatLog.incrementUserStat(user, UserProps.LoginCount, 1, callback); @@ -214,24 +222,24 @@ function recordLogin(client, cb) { callback ); }, - (callback) => { + callback => { // Update live last login information which includes additional // (pre-resolved) information such as user name/etc. const lastLogin = { - userId : user.userId, - sessionId : user.sessionId, - userName : user.username, - realName : user.getProperty(UserProps.RealName), - affiliation : user.getProperty(UserProps.Affiliations), - emailAddress : user.getProperty(UserProps.EmailAddress), - sex : user.getProperty(UserProps.Sex), - location : user.getProperty(UserProps.Location), - timestamp : moment(loginTimestamp), + userId: user.userId, + sessionId: user.sessionId, + userName: user.username, + realName: user.getProperty(UserProps.RealName), + affiliation: user.getProperty(UserProps.Affiliations), + emailAddress: user.getProperty(UserProps.EmailAddress), + sex: user.getProperty(UserProps.Sex), + location: user.getProperty(UserProps.Location), + timestamp: moment(loginTimestamp), }; StatLog.setNonPersistentSystemStat(SysProps.LastLogin, lastLogin); return callback(null); - } + }, ], err => { return cb(err); @@ -247,6 +255,9 @@ function transformLoginError(err, client, username) { err = Errors.BadLogin('To many failed login attempts', ErrorReasons.TooMany); } - client.log.warn( { username, ip : client.remoteAddress, reason : err.message }, `Failed login attempt for user "${username}", ${client.friendlyRemoteAddress()}`); + client.log.warn( + { username, ip: client.remoteAddress, reason: err.message }, + `Failed login attempt for user "${username}", ${client.friendlyRemoteAddress()}` + ); return err; } diff --git a/core/user_property.js b/core/user_property.js index f0af68be..c3f979b3 100644 --- a/core/user_property.js +++ b/core/user_property.js @@ -59,8 +59,8 @@ module.exports = { MinutesOnlineTotalCount: 'minutes_online_total_count', - NewPrivateMailCount : 'new_private_mail_count', // non-persistent - NewAddressedToMessageCount : 'new_addr_to_msg_count', // non-persistent + NewPrivateMailCount: 'new_private_mail_count', // non-persistent + NewAddressedToMessageCount: 'new_addr_to_msg_count', // non-persistent SSHPubKey: 'ssh_public_key', // OpenSSH format (ssh-keygen, etc.) AuthFactor1Types: 'auth_factor1_types', // List of User.AuthFactor1Types value(s) AuthFactor2OTP: 'auth_factor2_otp', // If present, OTP type for 2FA. See OTPTypes diff --git a/core/vertical_menu_view.js b/core/vertical_menu_view.js index b6f01af3..59455a91 100644 --- a/core/vertical_menu_view.js +++ b/core/vertical_menu_view.js @@ -9,16 +9,16 @@ const formatString = require('./string_format'); const pipeToAnsi = require('./color_codes.js').pipeToAnsi; // deps -const util = require('util'); -const _ = require('lodash'); +const util = require('util'); +const _ = require('lodash'); const { throws } = require('assert'); exports.VerticalMenuView = VerticalMenuView; function VerticalMenuView(options) { - options.cursor = options.cursor || 'hide'; - options.justify = options.justify || 'left'; - this.focusItemAtTop = true; + options.cursor = options.cursor || 'hide'; + options.justify = options.justify || 'left'; + this.focusItemAtTop = true; MenuView.call(this, options); @@ -53,8 +53,8 @@ function VerticalMenuView(options) { const topIndex = (this.focusItemAtTop ? throws.focusedItemIndex : 0) || 0; self.viewWindow = { - top : topIndex, - bottom : Math.min(topIndex + self.maxVisibleItems, self.items.length) - 1, + top: topIndex, + bottom: Math.min(topIndex + self.maxVisibleItems, self.items.length) - 1, }; }; @@ -109,14 +109,17 @@ function VerticalMenuView(options) { this.setRenderCacheItem(index, text, item.focused); }; - this.drawRemovedItem = function(index) { + this.drawRemovedItem = function (index) { if (index <= this.items.length - 1) { return; } const row = this.position.row + index; - this.client.term.rawWrite(`${ansi.goto(row, this.position.col)}${ansi.normal()}${this.fillChar.repeat(this.dimens.width)}`) + this.client.term.rawWrite( + `${ansi.goto(row, this.position.col)}${ansi.normal()}${this.fillChar.repeat( + this.dimens.width + )}` + ); }; - } util.inherits(VerticalMenuView, MenuView); @@ -188,15 +191,15 @@ VerticalMenuView.prototype.setFocus = function (focused) { VerticalMenuView.prototype.setFocusItemIndex = function (index) { VerticalMenuView.super_.prototype.setFocusItemIndex.call(this, index); // sets this.focusedItemIndex - const remainAfterFocus = this.focusItemAtTop ? - this.items.length - index : - this.items.length; - if(remainAfterFocus >= this.maxVisibleItems) { + const remainAfterFocus = this.focusItemAtTop + ? this.items.length - index + : this.items.length; + if (remainAfterFocus >= this.maxVisibleItems) { const topIndex = (this.focusItemAtTop ? throws.focusedItemIndex : 0) || 0; this.viewWindow = { - top : topIndex, - bottom : Math.min(topIndex + this.maxVisibleItems, this.items.length) - 1 + top: topIndex, + bottom: Math.min(topIndex + this.maxVisibleItems, this.items.length) - 1, }; this.positionCacheExpired = false; // skip standard behavior @@ -407,7 +410,7 @@ VerticalMenuView.prototype.setItemSpacing = function (itemSpacing) { this.positionCacheExpired = true; }; -VerticalMenuView.prototype.setPropertyValue = function(propName, value) { +VerticalMenuView.prototype.setPropertyValue = function (propName, value) { if (propName === 'focusItemAtTop' && _.isBoolean(value)) { this.focusItemAtTop = value; } diff --git a/core/view.js b/core/view.js index 341517f7..5063322a 100644 --- a/core/view.js +++ b/core/view.js @@ -130,7 +130,7 @@ View.prototype.setPosition = function (pos) { // // Allow the following forms: [row, col], { row : r, col : c }, or (row, col) // - if(Array.isArray(pos)) { + if (Array.isArray(pos)) { this.position.row = pos[0]; this.position.col = pos[1]; } else if (_.isNumber(pos.row) && _.isNumber(pos.col)) { @@ -285,7 +285,7 @@ View.prototype.setFocusProperty = function (focused) { this.hasFocus = focused; }; -View.prototype.setFocus = function(focused) { +View.prototype.setFocus = function (focused) { // Call separate method to differentiate between a value set as a // property vs focus programmatically called. this.setFocusProperty(focused); diff --git a/core/view_controller.js b/core/view_controller.js index 696e18b7..daa37b51 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -257,56 +257,59 @@ function ViewController(options) { } }; - this.applyViewConfig = function(config, cb) { + this.applyViewConfig = function (config, cb) { let highestId = 1; let submitId; let initialFocusId = 1; - async.each(Object.keys(config.mci || {}), function entry(mci, nextItem) { - const mciMatch = mci.match(MCI_REGEXP); // :TODO: How to handle auto-generated IDs???? - if(null === mciMatch) { - self.client.log.warn( { mci : mci }, 'Unable to parse MCI code'); - return; - } - - const viewId = parseInt(mciMatch[2]); - assert(!isNaN(viewId), 'Cannot parse view ID: ' + mciMatch[2]); // shouldn't be possible with RegExp used - - if(viewId > highestId) { - highestId = viewId; - } - - const view = self.getView(viewId); - - if(!view) { - return nextItem(null); - } - - const mciConf = config.mci[mci]; - - self.setViewPropertiesFromMCIConf(view, mciConf); - - if(mciConf.focus) { - initialFocusId = viewId; - } - - if(true === view.submit) { - submitId = viewId; - } - - nextItem(null); - }, - err => { - // default to highest ID if no 'submit' entry present - if(!submitId) { - const highestIdView = self.getView(highestId); - if(highestIdView) { - highestIdView.submit = true; + async.each( + Object.keys(config.mci || {}), + function entry(mci, nextItem) { + const mciMatch = mci.match(MCI_REGEXP); // :TODO: How to handle auto-generated IDs???? + if (null === mciMatch) { + self.client.log.warn({ mci: mci }, 'Unable to parse MCI code'); + return; } - } - return cb(err, { initialFocusId : initialFocusId } ); - }); + const viewId = parseInt(mciMatch[2]); + assert(!isNaN(viewId), 'Cannot parse view ID: ' + mciMatch[2]); // shouldn't be possible with RegExp used + + if (viewId > highestId) { + highestId = viewId; + } + + const view = self.getView(viewId); + + if (!view) { + return nextItem(null); + } + + const mciConf = config.mci[mci]; + + self.setViewPropertiesFromMCIConf(view, mciConf); + + if (mciConf.focus) { + initialFocusId = viewId; + } + + if (true === view.submit) { + submitId = viewId; + } + + nextItem(null); + }, + err => { + // default to highest ID if no 'submit' entry present + if (!submitId) { + const highestIdView = self.getView(highestId); + if (highestIdView) { + highestIdView.submit = true; + } + } + + return cb(err, { initialFocusId: initialFocusId }); + } + ); }; // method for comparing submitted form data to configuration entries diff --git a/core/wfc.js b/core/wfc.js index 40eedfe1..b36070f8 100644 --- a/core/wfc.js +++ b/core/wfc.js @@ -2,10 +2,7 @@ const { MenuModule } = require('./menu_module'); const stringFormat = require('./string_format'); -const { - getActiveConnectionList, - AllConnections -} = require('./client_connections'); +const { getActiveConnectionList, AllConnections } = require('./client_connections'); const StatLog = require('./stat_log'); const SysProps = require('./system_property'); const UserProps = require('./user_property'); @@ -19,9 +16,9 @@ const moment = require('moment'); const bunyan = require('bunyan'); exports.moduleInfo = { - name : 'WFC', - desc : 'Semi-Traditional Waiting For Caller', - author : 'NuSkooler', + name: 'WFC', + desc: 'Semi-Traditional Waiting For Caller', + author: 'NuSkooler', }; const FormIds = { @@ -31,13 +28,13 @@ const FormIds = { }; const MciViewIds = { - main : { - nodeStatus : 1, - quickLogView : 2, - nodeStatusSelection : 3, + main: { + nodeStatus: 1, + quickLogView: 2, + nodeStatusSelection: 3, - customRangeStart : 10, - } + customRangeStart: 10, + }, }; // Secure + 2FA + root user + 'wfc' group. @@ -49,30 +46,32 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { constructor(options) { super(options); - this.config = Object.assign({}, _.get(options, 'menuConfig.config'), { extraArgs : options.extraArgs }); + this.config = Object.assign({}, _.get(options, 'menuConfig.config'), { + extraArgs: options.extraArgs, + }); this.config.acs = this.config.acs || DefaultACS; if (!this.config.acs.includes('SC')) { - this.config.acs = 'SC' + this.config.acs; // secure connection at the very least + this.config.acs = 'SC' + this.config.acs; // secure connection at the very least } this.selectedNodeStatusIndex = -1; // no selection this.menuMethods = { - toggleAvailable : (formData, extraArgs, cb) => { + toggleAvailable: (formData, extraArgs, cb) => { const avail = this.client.user.isAvailable(); this.client.user.setAvailability(!avail); return this._refreshAll(cb); }, - toggleVisible : (formData, extraArgs, cb) => { + toggleVisible: (formData, extraArgs, cb) => { const visible = this.client.user.isVisible(); this.client.user.setVisibility(!visible); return this._refreshAll(cb); }, - displayHelp : (formData, extraArgs, cb) => { + displayHelp: (formData, extraArgs, cb) => { return this._displayHelpPage(cb); }, - setNodeStatusSelection : (formData, extraArgs, cb) => { + setNodeStatusSelection: (formData, extraArgs, cb) => { const nodeStatusView = this.getView('main', MciViewIds.main.nodeStatus); if (!nodeStatusView) { return cb(null); @@ -89,19 +88,19 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { this._selectNodeByIndex(nodeStatusView, this.selectedNodeStatusIndex); } return cb(null); - } - } + }, + }; } initSequence() { async.series( [ - (callback) => { + callback => { return this.beforeArt(callback); }, - (callback) => { + callback => { return this._displayMainPage(false, callback); - } + }, ], () => { this.finishedLoading(); @@ -112,7 +111,7 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { _displayMainPage(clearScreen, cb) { async.series( [ - (callback) => { + callback => { return this.displayArtAndPrepViewController( 'main', FormIds.main, @@ -120,34 +119,49 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { callback ); }, - (callback) => { - const quickLogView = this.getView('main', MciViewIds.main.quickLogView); + callback => { + const quickLogView = this.getView( + 'main', + MciViewIds.main.quickLogView + ); if (!quickLogView) { return callback(null); } if (!this.logRingBuffer) { - const logLevel = this.config.quickLogLevel || // WFC specific - _.get(Config(), 'logging.rotatingFile.level') || // ...or system setting - 'info'; // ...or default to info + const logLevel = + this.config.quickLogLevel || // WFC specific + _.get(Config(), 'logging.rotatingFile.level') || // ...or system setting + 'info'; // ...or default to info - this.logRingBuffer = new bunyan.RingBuffer({ limit : quickLogView.dimens.height || 24 }); + this.logRingBuffer = new bunyan.RingBuffer({ + limit: quickLogView.dimens.height || 24, + }); Log.log.addStream({ - name : 'wfc-ringbuffer', - type : 'raw', - level : logLevel, - stream : this.logRingBuffer + name: 'wfc-ringbuffer', + type: 'raw', + level: logLevel, + stream: this.logRingBuffer, }); } - const nodeStatusView = this.getView('main', MciViewIds.main.nodeStatus); - const nodeStatusSelectionView = this.getView('main', MciViewIds.main.nodeStatusSelection); - const nodeStatusSelectionFormat = this.config.nodeStatusSelectionFormat || '{text}'; + const nodeStatusView = this.getView( + 'main', + MciViewIds.main.nodeStatus + ); + const nodeStatusSelectionView = this.getView( + 'main', + MciViewIds.main.nodeStatusSelection + ); + const nodeStatusSelectionFormat = + this.config.nodeStatusSelectionFormat || '{text}'; if (nodeStatusView && nodeStatusSelectionView) { nodeStatusView.on('index update', index => { const item = nodeStatusView.getItems()[index]; if (item) { - nodeStatusSelectionView.setText(stringFormat(nodeStatusSelectionFormat, item)); + nodeStatusSelectionView.setText( + stringFormat(nodeStatusSelectionFormat, item) + ); // :TODO: Update view // :TODO: this is not triggered by key-presses (1, 2, ...) -- we need to handle that as well } @@ -156,9 +170,9 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { return callback(null); }, - (callback) => { + callback => { return this._refreshAll(callback); - } + }, ], err => { if (!err) { @@ -172,15 +186,11 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { _displayHelpPage(cb) { this._stopRefreshing(); - this.displayAsset( - this.menuConfig.config.art.help, - { clearScreen : true }, - () => { - this.client.waitForKeyPress( () => { - return this._displayMainPage(true, cb); - }); - } - ); + this.displayAsset(this.menuConfig.config.art.help, { clearScreen: true }, () => { + this.client.waitForKeyPress(() => { + return this._displayMainPage(true, cb); + }); + }); } enter() { @@ -207,11 +217,15 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { const vis = this.config.opVisibility || 'current'; switch (vis) { - case 'hidden' : this.client.user.setVisibility(false); break; - case 'visible' : this.client.user.setVisibility(true); break; - default : break; + case 'hidden': + this.client.user.setVisibility(false); + break; + case 'visible': + this.client.user.setVisibility(true); + break; + default: + break; } - } _restoreOpVisibility() { @@ -223,7 +237,7 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { this._stopRefreshing(); } - this.mainRefreshTimer = setInterval( () => { + this.mainRefreshTimer = setInterval(() => { this._refreshAll(); }, MainStatRefreshTimeMs); } @@ -238,23 +252,23 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { _refreshAll(cb) { async.series( [ - (callback) => { + callback => { return this._refreshStats(callback); }, - (callback) => { + callback => { return this._refreshNodeStatus(callback); }, - (callback) => { + callback => { return this._refreshQuickLog(callback); }, - (callback) => { + callback => { this.updateCustomViewTextsWithFilter( 'main', MciViewIds.main.customRangeStart, this.stats ); return callback(null); - } + }, ], err => { if (cb) { @@ -265,46 +279,47 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { } _getStatusStrings(isAvailable, isVisible) { - const availIndicators = Array.isArray(this.config.statusAvailableIndicators) ? - this.config.statusAvailableIndicators : - this.client.currentTheme.helpers.getStatusAvailableIndicators(); - const visIndicators = Array.isArray(this.config.statusVisibleIndicators) ? - this.config.statusVisibleIndicators : - this.client.currentTheme.helpers.getStatusVisibleIndicators(); + const availIndicators = Array.isArray(this.config.statusAvailableIndicators) + ? this.config.statusAvailableIndicators + : this.client.currentTheme.helpers.getStatusAvailableIndicators(); + const visIndicators = Array.isArray(this.config.statusVisibleIndicators) + ? this.config.statusVisibleIndicators + : this.client.currentTheme.helpers.getStatusVisibleIndicators(); return [ - isAvailable ? (availIndicators[1] || 'Y') : (availIndicators[0] || 'N'), - isVisible ? (visIndicators[1] || 'Y') : (visIndicators[0] || 'N'), + isAvailable ? availIndicators[1] || 'Y' : availIndicators[0] || 'N', + isVisible ? visIndicators[1] || 'Y' : visIndicators[0] || 'N', ]; } _refreshStats(cb) { - const fileAreaStats = StatLog.getSystemStat(SysProps.FileBaseAreaStats) || {}; - const sysMemStats = StatLog.getSystemStat(SysProps.SystemMemoryStats) || {}; - const sysLoadStats = StatLog.getSystemStat(SysProps.SystemLoadStats) || {}; - const lastLoginStats = StatLog.getSystemStat(SysProps.LastLogin); + const fileAreaStats = StatLog.getSystemStat(SysProps.FileBaseAreaStats) || {}; + const sysMemStats = StatLog.getSystemStat(SysProps.SystemMemoryStats) || {}; + const sysLoadStats = StatLog.getSystemStat(SysProps.SystemLoadStats) || {}; + const lastLoginStats = StatLog.getSystemStat(SysProps.LastLogin); const now = moment(); const [availIndicator, visIndicator] = this._getStatusStrings( - this.client.user.isAvailable(), this.client.user.isVisible() + this.client.user.isAvailable(), + this.client.user.isVisible() ); this.stats = { // Date/Time - nowDate : now.format(this.getDateFormat()), - nowTime : now.format(this.getTimeFormat()), - now : now.format(this._dateTimeFormat('now')), + nowDate: now.format(this.getDateFormat()), + nowTime: now.format(this.getTimeFormat()), + now: now.format(this._dateTimeFormat('now')), // Current process (our Node.js service) - processUptimeSeconds : process.uptime(), + processUptimeSeconds: process.uptime(), // Totals - totalCalls : StatLog.getSystemStatNum(SysProps.LoginCount), - totalPosts : StatLog.getSystemStatNum(SysProps.MessageTotalCount), - totalUsers : StatLog.getSystemStatNum(SysProps.TotalUserCount), - totalFiles : fileAreaStats.totalFiles || 0, - totalFileBytes : fileAreaStats.totalFileBytes || 0, + totalCalls: StatLog.getSystemStatNum(SysProps.LoginCount), + totalPosts: StatLog.getSystemStatNum(SysProps.MessageTotalCount), + totalUsers: StatLog.getSystemStatNum(SysProps.TotalUserCount), + totalFiles: fileAreaStats.totalFiles || 0, + totalFileBytes: fileAreaStats.totalFileBytes || 0, // totalUploads : // totalUploadBytes : @@ -312,30 +327,42 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { // totalDownloadBytes : // Today's Stats - callsToday : StatLog.getSystemStatNum(SysProps.LoginsToday), - postsToday : StatLog.getSystemStatNum(SysProps.MessagesToday), - uploadsToday : StatLog.getSystemStatNum(SysProps.FileUlTodayCount), - uploadBytesToday : StatLog.getSystemStatNum(SysProps.FileUlTodayBytes), - downloadsToday : StatLog.getSystemStatNum(SysProps.FileDlTodayCount), - downloadBytesToday : StatLog.getSystemStatNum(SysProps.FileDlTodayBytes), - newUsersToday : StatLog.getSystemStatNum(SysProps.NewUsersTodayCount), + callsToday: StatLog.getSystemStatNum(SysProps.LoginsToday), + postsToday: StatLog.getSystemStatNum(SysProps.MessagesToday), + uploadsToday: StatLog.getSystemStatNum(SysProps.FileUlTodayCount), + uploadBytesToday: StatLog.getSystemStatNum(SysProps.FileUlTodayBytes), + downloadsToday: StatLog.getSystemStatNum(SysProps.FileDlTodayCount), + downloadBytesToday: StatLog.getSystemStatNum(SysProps.FileDlTodayBytes), + newUsersToday: StatLog.getSystemStatNum(SysProps.NewUsersTodayCount), // Current - currentUserName : this.client.user.username, - currentUserRealName : this.client.user.getProperty(UserProps.RealName) || this.client.user.username, - availIndicator : availIndicator, - visIndicator : visIndicator, - lastLoginUserName : lastLoginStats.userName, - lastLoginRealName : lastLoginStats.realName, - lastLoginDate : moment(lastLoginStats.timestamp).format(this.getDateFormat()), - lastLoginTime : moment(lastLoginStats.timestamp).format(this.getTimeFormat()), - lastLogin : moment(lastLoginStats.timestamp).format(this._dateTimeFormat('lastLogin')), - totalMemoryBytes : sysMemStats.totalBytes || 0, - freeMemoryBytes : sysMemStats.freeBytes || 0, - systemAvgLoad : sysLoadStats.average || 0, - systemCurrentLoad : sysLoadStats.current || 0, - newPrivateMail : StatLog.getUserStatNumByClient(this.client, UserProps.NewPrivateMailCount, MailCountTTLSeconds), - newMessagesAddrTo : StatLog.getUserStatNumByClient(this.client, UserProps.NewAddressedToMessageCount, MailCountTTLSeconds), + currentUserName: this.client.user.username, + currentUserRealName: + this.client.user.getProperty(UserProps.RealName) || + this.client.user.username, + availIndicator: availIndicator, + visIndicator: visIndicator, + lastLoginUserName: lastLoginStats.userName, + lastLoginRealName: lastLoginStats.realName, + lastLoginDate: moment(lastLoginStats.timestamp).format(this.getDateFormat()), + lastLoginTime: moment(lastLoginStats.timestamp).format(this.getTimeFormat()), + lastLogin: moment(lastLoginStats.timestamp).format( + this._dateTimeFormat('lastLogin') + ), + totalMemoryBytes: sysMemStats.totalBytes || 0, + freeMemoryBytes: sysMemStats.freeBytes || 0, + systemAvgLoad: sysLoadStats.average || 0, + systemCurrentLoad: sysLoadStats.current || 0, + newPrivateMail: StatLog.getUserStatNumByClient( + this.client, + UserProps.NewPrivateMailCount, + MailCountTTLSeconds + ), + newMessagesAddrTo: StatLog.getUserStatNumByClient( + this.client, + UserProps.NewAddressedToMessageCount, + MailCountTTLSeconds + ), }; return cb(null); @@ -364,32 +391,37 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { .map(ac => { // Handle pre-authenticated if (!ac.authenticated) { - ac.text = ac.userName = '*Pre Auth*'; - ac.action = 'Logging In'; + ac.text = ac.userName = '*Pre Auth*'; + ac.action = 'Logging In'; } - const [availIndicator, visIndicator] = this._getStatusStrings(ac.isAvailable, ac.isVisible); + const [availIndicator, visIndicator] = this._getStatusStrings( + ac.isAvailable, + ac.isVisible + ); const timeOn = ac.timeOn || moment.duration(0); return Object.assign(ac, { availIndicator, visIndicator, - timeOnMinutes : timeOn.asMinutes(), - timeOn : _.upperFirst(timeOn.humanize()), // make friendly - affils : ac.affils || 'N/A', - realName : ac.realName || 'N/A', + timeOnMinutes: timeOn.asMinutes(), + timeOn: _.upperFirst(timeOn.humanize()), // make friendly + affils: ac.affils || 'N/A', + realName: ac.realName || 'N/A', }); - }); + }); // :TODO: Currently this always redraws due to setItems(). We really need painters alg.; The alternative now is to compare items... yuk. nodeStatusView.setItems(nodeStatusItems); - this._selectNodeByIndex(nodeStatusView, this.selectedNodeStatusIndex); // redraws + this._selectNodeByIndex(nodeStatusView, this.selectedNodeStatusIndex); // redraws return cb(null); } _refreshQuickLog(cb) { - const quickLogView = this.viewControllers.main.getView(MciViewIds.main.quickLogView); + const quickLogView = this.viewControllers.main.getView( + MciViewIds.main.quickLogView + ); if (!quickLogView) { return cb(null); } @@ -407,25 +439,23 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { } const quickLogTimestampFormat = - this.config.quickLogTimestampFormat || - this.getDateTimeFormat('short'); + this.config.quickLogTimestampFormat || this.getDateTimeFormat('short'); - const levelIndicators = this.config.quickLogLevelIndicators || - { - trace : 'T', - debug : 'D', - info : 'I', - warn : 'W', - error : 'E', - fatal : 'F', - }; + const levelIndicators = this.config.quickLogLevelIndicators || { + trace: 'T', + debug: 'D', + info: 'I', + warn: 'W', + error: 'E', + fatal: 'F', + }; - - const makeLevelIndicator = (level) => { + const makeLevelIndicator = level => { return levelIndicators[level] || '?'; }; - const quickLogLevelMessagePrefixes = this.config.quickLogLevelMessagePrefixes || {}; + const quickLogLevelMessagePrefixes = + this.config.quickLogLevelMessagePrefixes || {}; const prefixMssage = (message, level) => { const prefix = quickLogLevelMessagePrefixes[level] || ''; return `${prefix}${message}`; @@ -434,12 +464,12 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { const logItems = records.map(rec => { const level = bunyan.nameFromLevel[rec.level]; return { - timestamp : moment(rec.time).format(quickLogTimestampFormat), - level : rec.level, - levelIndicator : makeLevelIndicator(level), - nodeId : rec.nodeId || '*', - sessionId : rec.sessionId || '', - message : prefixMssage(rec.msg, level), + timestamp: moment(rec.time).format(quickLogTimestampFormat), + level: rec.level, + levelIndicator: makeLevelIndicator(level), + nodeId: rec.nodeId || '*', + sessionId: rec.sessionId || '', + message: prefixMssage(rec.msg, level), }; }); @@ -454,4 +484,3 @@ exports.getModule = class WaitingForCallerModule extends MenuModule { return format || this.getDateFormat(); } }; - diff --git a/core/whos_online.js b/core/whos_online.js index 5fb1bbb3..fb59429e 100644 --- a/core/whos_online.js +++ b/core/whos_online.js @@ -2,11 +2,12 @@ 'use strict'; // ENiGMA½ -const { MenuModule } = require('./menu_module.js'); +const { MenuModule } = require('./menu_module.js'); const { getActiveConnectionList, - UserVisibleConnections } = require('./client_connections.js'); -const { Errors } = require('./enig_error.js'); + UserVisibleConnections, +} = require('./client_connections.js'); +const { Errors } = require('./enig_error.js'); // deps const async = require('async'); @@ -51,9 +52,14 @@ exports.getModule = class WhosOnlineModule extends MenuModule { ); } - const onlineList = getActiveConnectionList(UserVisibleConnections).slice(0, onlineListView.height).map( - oe => Object.assign(oe, { text : oe.userName, timeOn : _.upperFirst(oe.timeOn.humanize()) }) - ); + const onlineList = getActiveConnectionList(UserVisibleConnections) + .slice(0, onlineListView.height) + .map(oe => + Object.assign(oe, { + text: oe.userName, + timeOn: _.upperFirst(oe.timeOn.humanize()), + }) + ); onlineListView.setItems(onlineList); onlineListView.redraw(); diff --git a/package.json b/package.json index ef914f2c..1e795709 100644 --- a/package.json +++ b/package.json @@ -1,72 +1,72 @@ { - "name": "enigma-bbs", - "version": "0.0.13-beta", - "description": "ENiGMA½ Bulletin Board System", - "author": "Bryan Ashby ", - "license": "BSD-2-Clause", - "scripts": { - "start": "node main.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/NuSkooler/enigma-bbs.git" - }, - "homepage": "https://github.com/NuSkooler/enigma-bbs", - "bugs": { - "url": "https://github.com/NuSkooler/enigma-bbs/issues" - }, - "keywords": [ - "bbs", - "telnet", - "ssh", - "retro" - ], - "dependencies": { - "@breejs/later": "4.1.0", - "async": "^3.2.3", - "binary-parser": "2.0.2", - "buffers": "github:NuSkooler/node-buffers", - "bunyan": "1.8.15", - "deepdash": "^5.3.9", - "exiftool": "^0.0.3", - "fs-extra": "^10.0.1", - "glob": "^7.2.0", - "graceful-fs": "^4.2.10", - "hashids": "^2.2.10", - "hjson": "3.2.2", - "iconv-lite": "0.6.3", - "ini-config-parser": "^1.0.4", - "inquirer": "^8.2.2", - "lodash": "4.17.21", - "lru-cache": "^7.8.0", - "mime-types": "^2.1.35", - "minimist": "^1.2.6", - "moment": "^2.29.2", - "nntp-server": "^1.0.3", - "node-pty": "0.10.1", - "nodemailer": "^6.7.3", - "otplib": "11.0.1", - "qrcode-generator": "^1.4.4", - "rlogin": "^1.0.0", - "sane": "5.0.1", - "sanitize-filename": "^1.6.3", - "sqlite3": "^4.2.0", - "sqlite3-trans": "^1.2.2", - "ssh2": "^1.9.0", - "telnet-socket": "^0.2.3", - "temptmp": "^1.1.0", - "uuid": "8.3.2", - "uuid-parse": "1.1.0", - "ws": "7.4.3", - "yazl": "^2.5.1", - "systeminformation" : "^5.11.14" - }, - "devDependencies": { - "eslint": "^8.13.0", - "eslint-config-prettier": "^8.5.0", - "prettier": "2.6.2" - }, - "engines": { - "node": ">=14" - } + "name": "enigma-bbs", + "version": "0.0.13-beta", + "description": "ENiGMA½ Bulletin Board System", + "author": "Bryan Ashby ", + "license": "BSD-2-Clause", + "scripts": { + "start": "node main.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/NuSkooler/enigma-bbs.git" + }, + "homepage": "https://github.com/NuSkooler/enigma-bbs", + "bugs": { + "url": "https://github.com/NuSkooler/enigma-bbs/issues" + }, + "keywords": [ + "bbs", + "telnet", + "ssh", + "retro" + ], + "dependencies": { + "@breejs/later": "4.1.0", + "async": "^3.2.3", + "binary-parser": "2.0.2", + "buffers": "github:NuSkooler/node-buffers", + "bunyan": "1.8.15", + "deepdash": "^5.3.9", + "exiftool": "^0.0.3", + "fs-extra": "^10.0.1", + "glob": "^7.2.0", + "graceful-fs": "^4.2.10", + "hashids": "^2.2.10", + "hjson": "3.2.2", + "iconv-lite": "0.6.3", + "ini-config-parser": "^1.0.4", + "inquirer": "^8.2.2", + "lodash": "4.17.21", + "lru-cache": "^7.8.0", + "mime-types": "^2.1.35", + "minimist": "^1.2.6", + "moment": "^2.29.2", + "nntp-server": "^1.0.3", + "node-pty": "0.10.1", + "nodemailer": "^6.7.3", + "otplib": "11.0.1", + "qrcode-generator": "^1.4.4", + "rlogin": "^1.0.0", + "sane": "5.0.1", + "sanitize-filename": "^1.6.3", + "sqlite3": "^4.2.0", + "sqlite3-trans": "^1.2.2", + "ssh2": "^1.9.0", + "telnet-socket": "^0.2.3", + "temptmp": "^1.1.0", + "uuid": "8.3.2", + "uuid-parse": "1.1.0", + "ws": "7.4.3", + "yazl": "^2.5.1", + "systeminformation": "^5.11.14" + }, + "devDependencies": { + "eslint": "^8.13.0", + "eslint-config-prettier": "^8.5.0", + "prettier": "2.6.2" + }, + "engines": { + "node": ">=14" + } }