diff --git a/db.js b/db.js index a738fb95..61428627 100644 --- a/db.js +++ b/db.js @@ -124,12 +124,13 @@ module.exports.CreateDB = function (parent) { // Check if we need to reset indexes var indexesByName = {}, indexCount = 0; for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; } - if ((indexCount != 2) || (indexesByName['ExpireTime1'] == null)) { + if ((indexCount != 3) || (indexesByName['ExpireTime1'] == null)) { // Reset all indexes console.log('Resetting server stats indexes...'); obj.serverstatsfile.dropIndexes(function (err) { // Create all indexes obj.serverstatsfile.createIndex({ "time": 1 }, { expireAfterSeconds: expireServerStatsSeconds, name: 'ExpireTime1' }); + obj.serverstatsfile.createIndex({ "expire": 1 }, { expireAfterSeconds: 0, name: 'ExpireTime2' }); // Auto-expire events }); } else if (indexesByName['ExpireTime1'].expireAfterSeconds != expireServerStatsSeconds) { // Reset the timeout index @@ -197,6 +198,7 @@ module.exports.CreateDB = function (parent) { obj.serverstatsfile = new Datastore({ filename: obj.parent.getConfigFilePath('meshcentral-stats.db'), autoload: true }); obj.serverstatsfile.persistence.setAutocompactionInterval(36000); obj.serverstatsfile.ensureIndex({ fieldName: 'time', expireAfterSeconds: 60 * 60 * 24 * 30 }); // Limit the server stats log to 30 days (Seconds * Minutes * Hours * Days) + obj.serverstatsfile.ensureIndex({ fieldName: 'expire', expireAfterSeconds: 0 }); // Auto-expire events } obj.SetupDatabase = function (func) { diff --git a/meshcentral.js b/meshcentral.js index e9766eae..030111e3 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -60,6 +60,7 @@ function CreateMeshCentralServer(config, args) { obj.serverKey = Buffer.from(obj.crypto.randomBytes(48), 'binary'); obj.loginCookieEncryptionKey = null; obj.serverSelfWriteAllowed = true; + obj.serverStatsCounter = Math.floor(Math.random() * 1000); obj.taskLimiter = obj.common.createTaskLimiterQueue(50, 20, 60); // (maxTasks, maxTaskTime, cleaningInterval) This is a task limiter queue to smooth out server work. try { obj.currentVer = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { } // Fetch server version @@ -802,8 +803,19 @@ function CreateMeshCentralServer(config, args) { // Start collecting server stats every 5 minutes setInterval(function () { + obj.serverStatsCounter++; + var hours = 720; // Start with all events lasting 30 days. + if (((obj.serverStatsCounter) % 2) == 1) { hours = 3; } // Half of the event get removed after 3 hours. + else if ((math.floor(obj.serverStatsCounter / 2) % 2) == 1) { hours = 8; } // Another half of the event get removed after 8 hours. + else if ((math.floor(obj.serverStatsCounter / 4) % 2) == 1) { hours = 24; } // Another half of the event get removed after 24 hours. + else if ((math.floor(obj.serverStatsCounter / 8) % 2) == 1) { hours = 48; } // Another half of the event get removed after 48 hours. + else if ((math.floor(obj.serverStatsCounter / 16) % 2) == 1) { hours = 72; } // Another half of the event get removed after 72 hours. + var expire = new Date(); + t.setTime(t.getTime() + (60 * 60 * 1000 * hours)); + var data = { time: new Date(), + expire: expire, mem: process.memoryUsage(), //cpu: process.cpuUsage(), conn: { @@ -1616,7 +1628,13 @@ function getConfig(createSampleConfig) { function InstallModules(modules, func) { var missingModules = []; if (modules.length > 0) { - for (var i in modules) { try { var xxmodule = require(modules[i]); } catch (e) { missingModules.push(modules[i]); } } + for (var i in modules) { + try { + var xxmodule = require(modules[i]); + } catch (e) { + if (previouslyInstalledModules[modules[i]] !== true) { previouslyInstalledModules[modules[i]] = true; missingModules.push(modules[i]); } + } + } if (missingModules.length > 0) { InstallModule(missingModules.shift(), InstallModules, modules, func); } else { func(); } } } @@ -1641,6 +1659,7 @@ process.on('SIGINT', function () { if (meshserver != null) { meshserver.Stop(); // Load the really basic modules var meshserver = null; +var previouslyInstalledModules = { }; function mainStart(args) { // Check the NodeJS is version 6 or better. if (Number(process.version.match(/^v(\d+\.\d+)/)[1]) < 6) { console.log("MeshCentral requires Node v6.x or above, current version is " + process.version + "."); return; } @@ -1664,7 +1683,6 @@ function mainStart(args) { if (config.letsencrypt != null) { modules.push('greenlock'); modules.push('le-store-certbot'); modules.push('le-challenge-fs'); modules.push('le-acme-core'); } // Add Greenlock Modules if (config.settings.mongodb != null) { modules.push('mongojs'); } // Add MongoDB if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support - if (yubikey == true) { modules.push('yubikeyotp'); } // Add YubiKey OTP support // Get the current node version var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]); @@ -1672,8 +1690,13 @@ function mainStart(args) { // If running NodeJS < 8, install "util.promisify" if (nodeVersion < 8) { modules.push('util.promisify'); } - // if not all SSPI, WebAuthn/FIDO2 or U2F support depending on the NodeJS version. FIDO2 does not work below NodeJS 8.x - if (allsspi == false) { modules.push('otplib'); if (nodeVersion >= 8) { modules.push('@davedoesdev/fido2-lib'); } else { modules.push('authdog'); } } + // Setup 2nd factor authentication + if (config.settings.no2factorauth !== true) { + // Setup YubiKey OTP if configured + if (yubikey == true) { modules.push('yubikeyotp'); } // Add YubiKey OTP support + // if not all SSPI, WebAuthn/FIDO2 or U2F support depending on the NodeJS version. FIDO2 does not work below NodeJS 8.x + if (allsspi == false) { modules.push('otplib'); if (nodeVersion >= 8) { modules.push('@davedoesdev/fido2-lib'); } else { modules.push('authdog'); } } + } // Install any missing modules and launch the server InstallModules(modules, function () { meshserver = CreateMeshCentralServer(config, args); meshserver.Start(); }); diff --git a/meshuser.js b/meshuser.js index 4fbc3649..01d72352 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1896,6 +1896,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'otp-hkey-yubikey-add': { + if (parent.parent.config.settings.no2factorauth === true) return; + // Yubico API id and signature key can be requested from https://upgrade.yubico.com/getapikey/ var yubikeyotp = null; try { yubikeyotp = require('yubikeyotp'); } catch (ex) { } @@ -1945,6 +1947,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'otp-hkey-setup-request': { + if (parent.parent.config.settings.no2factorauth === true) return; + var authdoglib = null; try { authdoglib = require('authdog'); } catch (ex) { } @@ -1971,6 +1975,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'otp-hkey-setup-response': { + if (parent.parent.config.settings.no2factorauth === true) return; + var authdoglib = null; try { authdoglib = require('authdog'); } catch (ex) { } @@ -1997,6 +2003,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'webauthn-startregister': { + if (parent.parent.config.settings.no2factorauth === true) return; + // Check is 2-step login is supported const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true)); if ((twoStepLoginSupported == false) || (command.name == null) || (parent.f2l == null)) break; @@ -2019,6 +2027,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'webauthn-endregister': { + if (parent.parent.config.settings.no2factorauth === true) return; if ((obj.webAuthnReqistrationRequest == null) || (parent.f2l == null)) return; // Figure out the origin diff --git a/package-lock.json b/package-lock.json index 671ebfa9..2a9d7b13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.3.1-a", + "version": "0.3.1-h", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -16,7 +16,7 @@ "jwk-to-pem": "2.0.1", "node-jose": "1.1.3", "pkijs": "2.1.58", - "psl": "1.1.29" + "psl": "1.1.31" } }, "@peculiar/asn1-schema": { @@ -50,9 +50,9 @@ } }, "@types/node": { - "version": "10.14.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.3.tgz", - "integrity": "sha512-2lhc7S28vo8FwR3Jv3Ifyd77AxEsx+Nl9ajWiac6/eWuvZ84zPK4RE05pfqcn3acIzlZDpQj5F1rIKQZX3ptLQ==" + "version": "10.14.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.4.tgz", + "integrity": "sha512-DT25xX/YgyPKiHFOpNuANIQIVvYEwCWXgK2jYYwqgaMrYE6+tq+DtmMwlD3drl6DJbUwtlIDnn0d7tIn/EbXBg==" }, "accepts": { "version": "1.3.5", @@ -1638,9 +1638,9 @@ } }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha1-YPWA02AXC7cip5fMcEQR5tqFDGc=" + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" }, "punycode": { "version": "2.1.1", @@ -1652,7 +1652,7 @@ "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.0.4.tgz", "integrity": "sha512-lBDyLfPIWZjxHr6Nnl83/iaZgVLczDcpEqWdqRnghzBKXifRU/7D5T6JPYWUAm0sJdFeF9+sNTKto6dj/3P/Kg==", "requires": { - "@types/node": "10.14.3", + "@types/node": "10.14.4", "tslib": "1.9.3" } }, @@ -1920,7 +1920,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "psl": "1.1.29", + "psl": "1.1.31", "punycode": "1.4.1" }, "dependencies": { diff --git a/package.json b/package.json index b52ece0b..72de9a3a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.3.1-h", + "version": "0.3.1-i", "keywords": [ "Remote Management", "Intel AMT", diff --git a/sample-config.json b/sample-config.json index 8c8eb1ca..2affe5a5 100644 --- a/sample-config.json +++ b/sample-config.json @@ -30,6 +30,7 @@ }, "_TlsOffload": true, "_MpsTlsOffload": true, + "_No2FactorAuth": true, "_WebRtConfig": { "iceServers": [ { "urls": "stun:stun.services.mozilla.com" }, diff --git a/views/default-min.handlebars b/views/default-min.handlebars index 32dedec6..56b56fed 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1 +1 @@ -
{{{logoutControl}}}
My Devices | My Account | My Events | My Files |
{{{logoutControl}}}
My Devices | My Account | My Events | My Files |