diff --git a/.gitignore b/.gitignore index 8b602dad..4dd7bc5a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ meshcentral.db meshcentral.db.json mesherrors.txt +bob.json ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. diff --git a/MeshCentralServer.njsproj b/MeshCentralServer.njsproj index 8fad80da..37d1ba17 100644 --- a/MeshCentralServer.njsproj +++ b/MeshCentralServer.njsproj @@ -94,6 +94,7 @@ + diff --git a/db.js b/db.js index 305778f6..81bdaf5d 100644 --- a/db.js +++ b/db.js @@ -99,7 +99,7 @@ module.exports.CreateDB = function (parent) { }); }; - obj.cleanup = function () { + obj.cleanup = function (func) { // TODO: Remove all mesh links to invalid users // TODO: Remove all meshes that dont have any links @@ -108,14 +108,43 @@ module.exports.CreateDB = function (parent) { var meshlist = []; if (err == null && docs.length > 0) { for (var i in docs) { meshlist.push(docs[i]._id); } } obj.file.remove({ meshid: { $exists: true, $nin: meshlist } }, { multi: true }); - }); - // Clear up all users - /* - obj.GetAllType('user', function (err, docs) { - for (var i in docs) { if (docs[i].subscriptions != null) { console.log('Clean user: ' + docs[i].name); obj.SetUser(docs[i]); } } // Remove "subscriptions" that should not be there. + // Fix all of the creating & login to ticks by seconds, not milliseconds. + obj.GetAllType('user', function (err, docs) { + if (err == null && docs.length > 0) { + for (var i in docs) { + var fixed = false; + + // Fix account creation + if (docs[i].creation) { + if (docs[i].creation > 1300000000000) { docs[i].creation = Math.floor(docs[i].creation / 1000); fixed = true; } + if ((docs[i].creation % 1) != 0) { docs[i].creation = Math.floor(docs[i].creation); fixed = true; } + } + + // Fix last account login + if (docs[i].login) { + if (docs[i].login > 1300000000000) { docs[i].login = Math.floor(docs[i].login / 1000); fixed = true; } + if ((docs[i].login % 1) != 0) { docs[i].login = Math.floor(docs[i].login); fixed = true; } + } + + // Fix last password change + if (docs[i].passchange) { + if (docs[i].passchange > 1300000000000) { docs[i].passchange = Math.floor(docs[i].passchange / 1000); fixed = true; } + if ((docs[i].passchange % 1) != 0) { docs[i].passchange = Math.floor(docs[i].passchange); fixed = true; } + } + + // Fix subscriptions + if (docs[i].subscriptions != null) { delete docs[i].subscriptions; fixed = true; } + + // Save the user if needed + if (fixed) { obj.Set(docs[i]); } + + // We are done + if (func) { func(); } + } + } + }); }); - */ }; obj.Set = function (data, func) { obj.file.update({ _id: data._id }, data, { upsert: true }, func); }; diff --git a/meshcentral.js b/meshcentral.js index 7cd87790..728e80f5 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -100,7 +100,8 @@ function CreateMeshCentralServer(config, args) { for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence. if ((obj.args.help == true) || (obj.args['?'] == true)) { - console.log('MeshCentral2 Beta 2, a web-based remote computer management web portal.\r\n'); + console.log('MeshCentral v' + obj.currentVer + ', a open source remote computer management web portal.'); + console.log('Details at: https://www.meshcommander.com/meshcentral2\r\n'); if (obj.platform == 'win32') { console.log('Run as a Windows Service'); console.log(' --install/uninstall Install Meshcentral as a background service.'); @@ -361,16 +362,16 @@ function CreateMeshCentralServer(config, args) { // Read or setup database configuration values obj.db.Get('dbconfig', function (err, dbconfig) { if (dbconfig.length == 1) { obj.dbconfig = dbconfig[0]; } else { obj.dbconfig = { _id: 'dbconfig', version: 1 }; } - if (obj.dbconfig.amtWsEventSecret == null) { require('crypto').randomBytes(32, function (err, buf) { obj.dbconfig.amtWsEventSecret = buf.toString('hex'); obj.db.Set(obj.dbconfig); }); } + if (obj.dbconfig.amtWsEventSecret == null) { obj.crypto.randomBytes(32, function (err, buf) { obj.dbconfig.amtWsEventSecret = buf.toString('hex'); obj.db.Set(obj.dbconfig); }); } // This is used by the user to create a username/password for a Intel AMT WSMAN event subscription if (obj.args.getwspass) { if (obj.args.getwspass.length == 64) { - require('crypto').randomBytes(6, function (err, buf) { + obj.crypto.randomBytes(6, function (err, buf) { while (obj.dbconfig.amtWsEventSecret == null) { process.nextTick(); } var username = buf.toString('hex'); var nodeid = obj.args.getwspass; - var pass = require('crypto').createHash('sha384').update(username.toLowerCase() + ":" + nodeid + ":" + obj.dbconfig.amtWsEventSecret).digest("base64").substring(0, 12).split("/").join("x").split("\\").join("x"); + var pass = obj.crypto.createHash('sha384').update(username.toLowerCase() + ":" + nodeid + ":" + obj.dbconfig.amtWsEventSecret).digest("base64").substring(0, 12).split("/").join("x").split("\\").join("x"); console.log('--- Intel(r) AMT WSMAN eventing credentials ---'); console.log('Username: ' + username); console.log('Password: ' + pass); @@ -489,7 +490,7 @@ function CreateMeshCentralServer(config, args) { obj.updateMeshAgentInstallScripts(); // Setup and start the web server - require('crypto').randomBytes(48, function (err, buf) { + obj.crypto.randomBytes(48, function (err, buf) { // Setup Mesh Multi-Server if needed obj.multiServer = require('./multiserver.js').CreateMultiServer(obj, obj.args); if (obj.multiServer != null) { diff --git a/meshuser.js b/meshuser.js index 0632e49d..67ae0680 100644 --- a/meshuser.js +++ b/meshuser.js @@ -587,7 +587,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var newusername = command.username, newuserid = 'user/' + domain.id + '/' + command.username.toLowerCase(); if (newusername == '~') break; // This is a reserved user name if (!obj.parent.users[newuserid]) { - var newuser = { type: 'user', _id: newuserid, name: newusername, creation: Date.now(), domain: domain.id }; + var newuser = { type: 'user', _id: newuserid, name: newusername, creation: Math.floor(Date.now() / 1000), domain: domain.id }; if (command.email != null) { newuser.email = command.email; } // Email obj.parent.users[newuserid] = newuser; // Create a user, generate a salt and hash the password diff --git a/package.json b/package.json index a996bc12..fdefaeb1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.2.6-w", + "version": "0.2.6-x", "keywords": [ "Remote Management", "Intel AMT", diff --git a/views/default.handlebars b/views/default.handlebars index d43a5c3a..b23c0852 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -1568,7 +1568,7 @@ } case 'login': { // Update the last login time - if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) { users['user/' + domain + '/' + message.event.username.toLowerCase()].login = message.event.time; } + if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) { users['user/' + domain + '/' + message.event.username.toLowerCase()].login = Math.floor(message.event.time / 1000); } break; } case 'scanamtdevice': { @@ -5247,7 +5247,8 @@ count++; // Mesh rights - var meshrights = meshes[i].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights; + var meshrights = 0; + if (meshes[i].links['user/' + domain + '/' + userinfo.name.toLowerCase()]) { meshrights = meshes[i].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights; } var rights = 'Partial Rights'; if (meshrights == 0xFFFFFFFF) rights = 'Full Administrator'; else if (meshrights == 0) rights = 'No Rights'; @@ -5882,7 +5883,7 @@ } if (sessions == 1) { msg += '1 active session'; } else { msg += sessions + ' active sessions'; } } else { - if (user.login) { msg += '' + new Date(user.login).toLocaleDateString() + ''; } + if (user.login) { msg += '' + new Date(user.login * 1000).toLocaleDateString() + ''; } } if (msg != '') msg += ', '; if (self) { msg += ""; } @@ -6058,8 +6059,8 @@ x += addDeviceAttribute('Email', everify + "" + email + ' '); x += addDeviceAttribute('Server Rights', "" + msg + ""); if (user.quota) x += addDeviceAttribute('Server Quota', EscapeHtml(parseInt(user.quota) / 1024) + ' k'); - x += addDeviceAttribute('Creation', new Date(user.creation).toLocaleString()); - if (user.login) x += addDeviceAttribute('Last Login', new Date(user.login).toLocaleString()); + x += addDeviceAttribute('Creation', new Date(user.creation * 1000).toLocaleString()); + if (user.login) x += addDeviceAttribute('Last Login', new Date(user.login * 1000).toLocaleString()); x += '
'; diff --git a/webserver.js b/webserver.js index 3a3522ec..36b22391 100644 --- a/webserver.js +++ b/webserver.js @@ -353,7 +353,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } // Save login time - user.login = Date.now(); + user.login = Math.floor(Date.now() / 1000); obj.db.SetUser(user); // Regenerate session when signing in to prevent fixation @@ -434,7 +434,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } else { var hint = req.body.apasswordhint; if (hint.length > 250) hint = hint.substring(0, 250); - var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Date.now(), login: Date.now(), domain: domain.id, passhint: hint }; + var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000), domain: domain.id, passhint: hint }; var usercount = 0; for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } } if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newaccounts === 2) { domain.newaccounts = 0; } } // If this is the first user, give the account site admin. @@ -563,7 +563,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { userinfo = obj.users[user._id]; userinfo.salt = salt; userinfo.hash = hash; - userinfo.passchange = Date.now(); + userinfo.passchange = Math.floor(Date.now() / 1000); userinfo.passhint = null; delete userinfo.otpsecret; // Currently a email password reset will turn off 2-step login. obj.db.SetUser(userinfo); @@ -658,7 +658,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { var user = obj.users[req.session.userid]; user.salt = salt; user.hash = hash; - user.passchange = Date.now(); + user.passchange = Math.floor(Date.now() / 1000); user.passhint = req.body.apasswordhint; obj.db.SetUser(user); req.session.viewmode = 2; @@ -743,7 +743,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { user = obj.users[req.session.userid]; if ((user == null) || (user.sid != req.session.usersid)) { // Create the domain user - var usercount = 0, user2 = { type: 'user', _id: req.session.userid, name: req.connection.user, domain: domain.id, sid: req.session.usersid, creation: Date.now() }; + var usercount = 0, user2 = { type: 'user', _id: req.session.userid, name: req.connection.user, domain: domain.id, sid: req.session.usersid, creation: Math.floor(Date.now() / 1000), login: Math.floor(Date.now() / 1000) }; for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } } if (usercount == 0) { user2.siteadmin = 0xFFFFFFFF; } // If this is the first user, give the account site admin. obj.users[req.session.userid] = user2;