diff --git a/core/art.js b/core/art.js index 24ce8bcc..22408cc9 100644 --- a/core/art.js +++ b/core/art.js @@ -47,10 +47,11 @@ function getFontNameFromSAUCE(sauce) { } function sliceAtEOF(data, eofMarker) { - var eof = data.length; - // :TODO: max scan back or other beter way of doing this?! - for(var i = data.length - 1; i > 0; i--) { - if(data[i] === eofMarker) { + let eof = data.length; + const stopPos = Math.max(data.length - (256), 0); // 256 = 2 * sizeof(SAUCE) + + for(let i = eof - 1; i > stopPos; i--) { + if(eofMarker === data[i]) { eof = i; break; } diff --git a/core/config.js b/core/config.js index d060f508..a6bbe25a 100644 --- a/core/config.js +++ b/core/config.js @@ -118,7 +118,7 @@ function getDefaultConfig() { users : { usernameMin : 2, usernameMax : 16, // Note that FidoNet wants 36 max - usernamePattern : '^[A-Za-z0-9~!@#$%^&*()\\-\\_+]+$', + usernamePattern : '^[A-Za-z0-9~!@#$%^&*()\\-\\_+ ]+$', passwordMin : 6, passwordMax : 128, diff --git a/core/stat_log.js b/core/stat_log.js index 9bf46a66..60e9e77f 100644 --- a/core/stat_log.js +++ b/core/stat_log.js @@ -50,6 +50,15 @@ class StatLog { }; } + get KeepType() { + return { + Forever : 'forever', + Days : 'days', + Max : 'max', + Count : 'max', + }; + } + get Order() { return { Timestamp : 'timestamp_asc', @@ -57,7 +66,7 @@ class StatLog { TimestampDesc : 'timestamp_desc', Random : 'random', }; - } + } setNonPeristentSystemStat(statName, statValue) { this.systemStats[statName] = statValue; @@ -129,33 +138,64 @@ class StatLog { // the time "now" in the ISO format we use and love :) get now() { return moment().format('YYYY-MM-DDTHH:mm:ss.SSSZ'); } - appendSystemLogEntry(logName, logValue, keepDays, cb) { + appendSystemLogEntry(logName, logValue, keep, keepType, cb) { sysDb.run( `INSERT INTO system_event_log (timestamp, log_name, log_value) VALUES (?, ?, ?);`, [ this.now, logName, logValue ], () => { // - // Handle keepDays + // Handle keep // - if(-1 === keepDays) { + if(-1 === keep) { if(cb) { return cb(null); } return; } - sysDb.run( - `DELETE FROM system_event_log - WHERE log_name = ? AND timestamp <= DATETIME("now", "-${keepDays} day");`, - [ logName ], - err => { - // cb optional - callers may fire & forget - if(cb) { - return cb(err); - } - } - ); + switch(keepType) { + // keep # of days + case 'days' : + sysDb.run( + `DELETE FROM system_event_log + WHERE log_name = ? AND timestamp <= DATETIME("now", "-${keep} day");`, + [ logName ], + err => { + // cb optional - callers may fire & forget + if(cb) { + return cb(err); + } + } + ); + break; + + case 'count': + case 'max' : + // keep max of N/count + sysDb.run( + `DELETE FROM system_event_log + WHERE id IN( + SELECT id + FROM system_event_log + WHERE log_name = ? + ORDER BY id DESC + LIMIT -1 OFFSET ${keep} + );`, + [ logName ], + err => { + if(cb) { + return cb(err); + } + } + ); + break; + + case 'forever' : + default : + // nop + break; + } } ); } diff --git a/core/system_view_validate.js b/core/system_view_validate.js index 354774f7..27975bf9 100644 --- a/core/system_view_validate.js +++ b/core/system_view_validate.js @@ -40,7 +40,7 @@ function validateUserNameAvail(data, cb) { } else { user.getUserIdAndName(data, function userIdAndName(err) { if(!err) { // err is null if we succeeded -- meaning this user exists already - return cb(new Error('Userame unavailable')); + return cb(new Error('Username unavailable')); } return cb(null); diff --git a/core/user_login.js b/core/user_login.js index 4c3cfcc6..038a0a4b 100644 --- a/core/user_login.js +++ b/core/user_login.js @@ -73,7 +73,8 @@ function userLogin(client, username, password, cb) { StatLog.incrementUserStat(user, 'login_count', 1, callback); }, function recordLoginHistory(callback) { - StatLog.appendSystemLogEntry('user_login_history', user.userId, 30, callback); + const LOGIN_HISTORY_MAX = 200; // history of up to last 200 callers + StatLog.appendSystemLogEntry('user_login_history', user.userId, LOGIN_HISTORY_MAX, StatLog.KeepType.Max, callback); } ], function complete(err) { diff --git a/misc/install.sh b/misc/install.sh index 7ef9455e..628cc51a 100755 --- a/misc/install.sh +++ b/misc/install.sh @@ -48,6 +48,9 @@ enigma_install_init() { log "Checking curl installation" enigma_install_needs curl + + log "Checking Python installation" + enigma_install_needs python } install_nvm() { @@ -90,6 +93,7 @@ install_node_packages() { log "npm package installation complete" else log_error "Failed to install ENiGMA½ npm packages. Please report this!" + exit 1 fi } diff --git a/mods/last_callers.js b/mods/last_callers.js index 5f9b49b0..ccb8f804 100644 --- a/mods/last_callers.js +++ b/mods/last_callers.js @@ -67,15 +67,29 @@ LastCallersModule.prototype.mciReady = function(mciData, cb) { function fetchHistory(callback) { callersView = vc.getView(MciCodeIds.CallerList); - StatLog.getSystemLogEntries('user_login_history', StatLog.Order.TimestampDesc, callersView.dimens.height, (err, lh) => { + // fetch up + StatLog.getSystemLogEntries('user_login_history', StatLog.Order.TimestampDesc, 200, (err, lh) => { loginHistory = lh; if(self.menuConfig.config.hideSysOpLogin) { - loginHistory = loginHistory.filter(lh => { + const noOpLoginHistory = loginHistory.filter(lh => { return false === isRootUserId(parseInt(lh.log_value)); // log_value=userId }); - } + // + // If we have enough items to display, or hideSysOpLogin is set to 'always', + // then set loginHistory to our filtered list. Else, we'll leave it be. + // + if(noOpLoginHistory.length >= callersView.dimens.height || 'always' === self.menuConfig.config.hideSysOpLogin) { + loginHistory = noOpLoginHistory; + } + } + + // + // Finally, we need to trim up the list to the needed size + // + loginHistory = loginHistory.slice(0, callersView.dimens.height); + return callback(err); }); }, diff --git a/mods/rumorz.js b/mods/rumorz.js index abc88886..45656ddf 100644 --- a/mods/rumorz.js +++ b/mods/rumorz.js @@ -52,7 +52,7 @@ exports.getModule = class RumorzModule extends MenuModule { if(_.isString(formData.value.rumor) && renderStringLength(formData.value.rumor) > 0) { const rumor = formData.value.rumor.trim(); // remove any trailing ws - StatLog.appendSystemLogEntry(STATLOG_KEY_RUMORZ, rumor, StatLog.KeepDays.Forever, () => { + StatLog.appendSystemLogEntry(STATLOG_KEY_RUMORZ, rumor, StatLog.KeepDays.Forever, StatLog.KeepType.Forever, () => { this.clearAddForm(); return this.displayViewScreen(true, cb); // true=cls });