diff --git a/agents/meshinstall-linux.sh b/agents/meshinstall-linux.sh index e4e71074..c6b5de85 100644 --- a/agents/meshinstall-linux.sh +++ b/agents/meshinstall-linux.sh @@ -157,7 +157,7 @@ DownloadAgent() { then # upstart echo -e "start on runlevel [2345]\nstop on runlevel [016]\n\nrespawn\n\nchdir /usr/local/mesh\nexec /usr/local/mesh/meshagent\n\n" > /etc/init/meshagent.conf - initctl start meshagent + initctl start meshagent echo 'meshagent installed as upstart/init.d service.' echo 'To start service: sudo initctl start meshagent' echo 'To stop service: sudo initctl stop meshagent' @@ -191,23 +191,23 @@ UninstallAgent() { systemctl stop meshagent rm -f /sbin/meshcmd /lib/systemd/system/meshagent.service systemctl stop meshagentDiagnostic &> /dev/null - rm -f /lib/systemd/system/meshagentDiagnostic.service &> /dev/null + rm -f /lib/systemd/system/meshagentDiagnostic.service &> /dev/null else if [ $starttype -eq 3 ]; then # initd service meshagent stop update-rc.d -f meshagent remove rm -f /sbin/meshcmd /etc/init.d/meshagent - service meshagentDiagnostic stop &> /dev/null - rm -f /etc/init.d/meshagentDiagnostic &> /dev/null + service meshagentDiagnostic stop &> /dev/null + rm -f /etc/init.d/meshagentDiagnostic &> /dev/null elif [ $starttype -eq 2 ]; then # upstart initctl stop meshagent rm -f /sbin/meshcmd rm -f /etc/init/meshagent.conf rm -f /etc/rc2.d/S20mesh /etc/rc3.d/S20mesh /etc/rc5.d/S20mesh - initctl stop meshagentDiagnostic &> /dev/null - rm -f /etc/init/meshagentDiagnostic.conf &> /dev/null + initctl stop meshagentDiagnostic &> /dev/null + rm -f /etc/init/meshagentDiagnostic.conf &> /dev/null fi fi @@ -240,6 +240,7 @@ then UninstallAgent fi else + UninstallAgent CheckInstallAgent $1 $2 $3 fi fi diff --git a/db.js b/db.js index e70f8465..62e1954d 100644 --- a/db.js +++ b/db.js @@ -66,15 +66,29 @@ module.exports.CreateDB = function (parent, func) { // TODO: Remove all meshes that dont have any links // Remove all events, power events and SMBIOS data from the main collection. They are all in seperate collections now. - obj.file.remove({ type: 'event' }, { multi: true }); - obj.file.remove({ type: 'power' }, { multi: true }); - obj.file.remove({ type: 'smbios' }, { multi: true }); + if (obj.databaseType == 3) { + // MongoDB + obj.file.deleteMany({ type: 'event' }, { multi: true }); + obj.file.deleteMany({ type: 'power' }, { multi: true }); + obj.file.deleteMany({ type: 'smbios' }, { multi: true }); + } else { + // NeDB or MongoJS + obj.file.remove({ type: 'event' }, { multi: true }); + obj.file.remove({ type: 'power' }, { multi: true }); + obj.file.remove({ type: 'smbios' }, { multi: true }); + } // Remove all objects that have a "meshid" that no longer points to a valid mesh. obj.GetAllType('mesh', function (err, docs) { 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 }); + if (obj.databaseType == 3) { + // MongoDB + obj.file.deleteMany({ meshid: { $exists: true, $nin: meshlist } }, { multi: true }); + } else { + // NeDB or MongoJS + obj.file.remove({ meshid: { $exists: true, $nin: meshlist } }, { multi: true }); + } // Fix all of the creating & login to ticks by seconds, not milliseconds. obj.GetAllType('user', function (err, docs) { @@ -114,206 +128,6 @@ module.exports.CreateDB = function (parent, func) { }); }; - if (obj.databaseType == 3) { - // Database actions on the main collection (MongoDB) - function xfind(collection, query, projection, func) { - if (projection) { - collection.find(query, projection, function (err, cursor) { if (err) { func(err); } else { var r = []; cursor.each(function (err, item) { if (err) { func(err); } else { if (item) { r.push(item); } else { func(null, r); } } }); } }); - } else { - collection.find(query, function (err, cursor) { if (err) { func(err); } else { var r = []; cursor.each(function (err, item) { if (err) { func(err); } else { if (item) { r.push(item); } else { func(null, r); } } }); } }); - } - }; - - obj.Set = function (data, func) { obj.file.update({ _id: data._id }, data, { upsert: true }, func); }; - obj.Get = function (id, func) { - if (arguments.length > 2) { - var parms = [func]; - for (var parmx = 2; parmx < arguments.length; ++parmx) { parms.push(arguments[parmx]); } - var func2 = function _func2(arg1, arg2) { - var userCallback = _func2.userArgs.shift(); - _func2.userArgs.unshift(arg2); - _func2.userArgs.unshift(arg1); - userCallback.apply(obj, _func2.userArgs); - }; - func2.userArgs = parms; - xfind(obj.file, { _id: id }, null, func2); - } else { - xfind(obj.file, { _id: id }, null, func); - } - }; - obj.GetAll = function (func) { xfind(obj.file, {}, null, func); }; - obj.GetAllTypeNoTypeField = function (type, domain, func) { xfind(obj.file, { type: type, domain: domain }, { type: 0 }, func); }; - obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { var x = { type: type, domain: domain, meshid: { $in: meshes } }; if (id) { x._id = id; } xfind(obj.file, x, { type: 0 }, func); }; - obj.GetAllType = function (type, func) { xfind(obj.file, { type: type }, null, func); }; - obj.GetAllIdsOfType = function (ids, domain, type, func) { xfind(obj.file, { type: type, domain: domain, _id: { $in: ids } }, func); }; - obj.GetUserWithEmail = function (domain, email, func) { xfind(obj.file, { type: 'user', domain: domain, email: email }, { type: 0 }, func); }; - obj.GetUserWithVerifiedEmail = function (domain, email, func) { xfind(obj.file, { type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }, func); }; - obj.Remove = function (id) { obj.file.remove({ _id: id }); }; - obj.RemoveAll = function (func) { obj.file.remove({}, { multi: true }, func); }; - obj.RemoveAllOfType = function (type, func) { obj.file.remove({ type: type }, { multi: true }, func); }; - obj.InsertMany = function (data, func) { obj.file.insert(data, func); }; - obj.RemoveMeshDocuments = function (id) { obj.file.remove({ meshid: id }, { multi: true }); obj.file.remove({ _id: 'nt' + id }); }; - obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; - obj.DeleteDomain = function (domain, func) { obj.file.remove({ domain: domain }, { multi: true }, func); }; - obj.SetUser = function (user) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); }; - obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; - obj.getLocalAmtNodes = function (func) { xfind(obj.file, { type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); }; - obj.getAmtUuidNode = function (meshid, uuid, func) { xfind(obj.file, { type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); }; - obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } } - - // Database actions on the events collection - obj.GetAllEvents = function (func) { xfind(obj.eventsfile, {}, func); }; - obj.StoreEvent = function (event) { obj.eventsfile.insert(event); }; - obj.GetEvents = function (ids, domain, func) { if (obj.databaseType == 1) { xfind(obj.eventsfile, { domain: domain, ids: { $in: ids } }, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); } else { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); } }; - obj.GetEventsWithLimit = function (ids, domain, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } }; - obj.GetUserEvents = function (ids, domain, username, func) { xfind(obj.eventsfile, { domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); }; - obj.GetUserEventsWithLimit = function (ids, domain, username, limit, func) { xfind(obj.eventsfile, { domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); }; - obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { xfind(obj.eventsfile, { domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); }; - obj.RemoveAllEvents = function (domain) { obj.eventsfile.remove({ domain: domain }, { multi: true }); }; - obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.remove({ domain: domain, nodeid: nodeid }, { multi: true }); }; - - // Database actions on the power collection - obj.getAllPower = function (func) { xfind(obj.powerfile, {}, func); }; - obj.storePowerEvent = function (event, multiServer, func) { if (multiServer != null) { event.server = multiServer.serverid; } obj.powerfile.insert(event, func); }; - obj.getPowerTimeline = function (nodeid, func) { xfind(obj.powerfile, { nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }).exec(func); }; - obj.removeAllPowerEvents = function () { obj.powerfile.remove({}, { multi: true }); }; - obj.removeAllPowerEventsForNode = function (nodeid) { obj.powerfile.remove({ nodeid: nodeid }, { multi: true }); }; - - // Database actions on the SMBIOS collection - obj.SetSMBIOS = function (smbios, func) { obj.smbiosfile.update({ _id: smbios._id }, smbios, { upsert: true }, func); }; - obj.RemoveSMBIOS = function (id) { obj.smbiosfile.remove({ _id: id }); }; - obj.GetSMBIOS = function (id, func) { xfind(obj.smbiosfile, { _id: id }, func); }; - - // Database actions on the Server Stats collection - obj.SetServerStats = function (data, func) { obj.serverstatsfile.insert(data, func); }; - obj.GetServerStats = function (hours, func) { var t = new Date(); t.setTime(t.getTime() - (60 * 60 * 1000 * hours)); xfind(obj.serverstatsfile, { time: { $gt: t } }, { _id: 0, cpu: 0 }, func); }; - - // Read a configuration file from the database - obj.getConfigFile = function (path, func) { obj.Get('cfile/' + path, func); } - - // Write a configuration file to the database - obj.setConfigFile = function (path, data, func) { obj.Set({ _id: 'cfile/' + path, type: 'cfile', data: data.toString('base64') }, func); } - - // List all configuration files - obj.listConfigFiles = function (func) { xfind(obj.file, { type: 'cfile' }).sort({ _id: 1 }).exec(func); } - - // Get all configuration files - obj.getAllConfigFiles = function (password, func) { - xfind(obj.file, { type: 'cfile' }, function (err, docs) { - if (err != null) { func(null); return; } - var r = null; - for (var i = 0; i < docs.length; i++) { - var name = docs[i]._id.split('/')[1]; - var data = obj.decryptData(password, docs[i].data); - if (data != null) { if (r == null) { r = {}; } r[name] = data; } - } - func(r); - }); - } - } else { - // Database actions on the main collection (NeDB and MongoJS) - obj.Set = function (data, func) { obj.file.update({ _id: data._id }, data, { upsert: true }, func); }; - obj.Get = function (id, func) { - if (arguments.length > 2) { - var parms = [func]; - for (var parmx = 2; parmx < arguments.length; ++parmx) { parms.push(arguments[parmx]); } - var func2 = function _func2(arg1, arg2) { - var userCallback = _func2.userArgs.shift(); - _func2.userArgs.unshift(arg2); - _func2.userArgs.unshift(arg1); - userCallback.apply(obj, _func2.userArgs); - }; - func2.userArgs = parms; - obj.file.find({ _id: id }, func2); - } - else { - obj.file.find({ _id: id }, func); - } - }; - obj.GetAll = function (func) { obj.file.find({}, func); }; - obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }, { type: 0 }, func); }; - obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { var x = { type: type, domain: domain, meshid: { $in: meshes } }; if (id) { x._id = id; } obj.file.find(x, { type: 0 }, func); }; - obj.GetAllType = function (type, func) { obj.file.find({ type: type }, func); }; - obj.GetAllIdsOfType = function (ids, domain, type, func) { obj.file.find({ type: type, domain: domain, _id: { $in: ids } }, func); }; - obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }, { type: 0 }, func); }; - obj.GetUserWithVerifiedEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }, func); }; - obj.Remove = function (id) { obj.file.remove({ _id: id }); }; - obj.RemoveAll = function (func) { obj.file.remove({}, { multi: true }, func); }; - obj.RemoveAllOfType = function (type, func) { obj.file.remove({ type: type }, { multi: true }, func); }; - obj.InsertMany = function (data, func) { obj.file.insert(data, func); }; - obj.RemoveMeshDocuments = function (id) { obj.file.remove({ meshid: id }, { multi: true }); obj.file.remove({ _id: 'nt' + id }); }; - obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; - obj.DeleteDomain = function (domain, func) { obj.file.remove({ domain: domain }, { multi: true }, func); }; - obj.SetUser = function (user) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); }; - obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; - obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); }; - obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); }; - obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } } - - // Database actions on the events collection - obj.GetAllEvents = function (func) { obj.eventsfile.find({}, func); }; - obj.StoreEvent = function (event) { obj.eventsfile.insert(event); }; - obj.GetEvents = function (ids, domain, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); } else { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); } }; - obj.GetEventsWithLimit = function (ids, domain, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } }; - obj.GetUserEvents = function (ids, domain, username, func) { - if (obj.databaseType == 1) { - obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); - } else { - obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); - } - }; - obj.GetUserEventsWithLimit = function (ids, domain, username, limit, func) { - if (obj.databaseType == 1) { - obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); - } else { - obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); - } - }; - obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); } }; - obj.RemoveAllEvents = function (domain) { obj.eventsfile.remove({ domain: domain }, { multi: true }); }; - obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.remove({ domain: domain, nodeid: nodeid }, { multi: true }); }; - - // Database actions on the power collection - obj.getAllPower = function (func) { obj.powerfile.find({}, func); }; - obj.storePowerEvent = function (event, multiServer, func) { if (multiServer != null) { event.server = multiServer.serverid; } obj.powerfile.insert(event, func); }; - obj.getPowerTimeline = function (nodeid, func) { if (obj.databaseType == 1) { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }).exec(func); } else { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }, func); } }; - obj.removeAllPowerEvents = function () { obj.powerfile.remove({}, { multi: true }); }; - obj.removeAllPowerEventsForNode = function (nodeid) { obj.powerfile.remove({ nodeid: nodeid }, { multi: true }); }; - - // Database actions on the SMBIOS collection - obj.SetSMBIOS = function (smbios, func) { obj.smbiosfile.update({ _id: smbios._id }, smbios, { upsert: true }, func); }; - obj.RemoveSMBIOS = function (id) { obj.smbiosfile.remove({ _id: id }); }; - obj.GetSMBIOS = function (id, func) { obj.smbiosfile.find({ _id: id }, func); }; - - // Database actions on the Server Stats collection - obj.SetServerStats = function (data, func) { obj.serverstatsfile.insert(data, func); }; - obj.GetServerStats = function (hours, func) { var t = new Date(); t.setTime(t.getTime() - (60 * 60 * 1000 * hours)); obj.serverstatsfile.find({ time: { $gt: t } }, { _id: 0, cpu: 0 }, func); }; - - // Read a configuration file from the database - obj.getConfigFile = function (path, func) { obj.Get('cfile/' + path, func); } - - // Write a configuration file to the database - obj.setConfigFile = function (path, data, func) { obj.Set({ _id: 'cfile/' + path, type: 'cfile', data: data.toString('base64') }, func); } - - // List all configuration files - obj.listConfigFiles = function (func) { obj.file.find({ type: 'cfile' }).sort({ _id: 1 }).exec(func); } - - // Get all configuration files - obj.getAllConfigFiles = function (password, func) { - obj.file.find({ type: 'cfile' }, function (err, docs) { - if (err != null) { func(null); return; } - var r = null; - for (var i = 0; i < docs.length; i++) { - var name = docs[i]._id.split('/')[1]; - var data = obj.decryptData(password, docs[i].data); - if (data != null) { if (r == null) { r = {}; } r[name] = data; } - } - func(r); - }); - } - } - - // Get encryption key obj.getEncryptDataKey = function (password) { if (typeof password != 'string') return null; @@ -349,8 +163,8 @@ module.exports.CreateDB = function (parent, func) { // Get the number of records in the database for various types, this is the slow NeDB way. // WARNING: This is a terrible query for database performance. Only do this when needed. This query will look at almost every document in the database. obj.getStats = function (func) { - if (obj.databaseType == 2) { - // MongoDB version + if (obj.databaseType > 1) { + // MongoJS or MongoDB version (not tested on MongoDB) obj.file.aggregate([{ "$group": { _id: "$type", count: { $sum: 1 } } }], function (err, docs) { var counters = {}, totalCount = 0; for (var i in docs) { if (docs[i]._id != null) { counters[docs[i]._id] = docs[i].count; totalCount += docs[i].count; } } @@ -384,24 +198,20 @@ module.exports.CreateDB = function (parent, func) { if (typeof obj.parent.args.dbexpire.statsevents == 'number') { expireServerStatsSeconds = obj.parent.args.dbexpire.statsevents; } } - if (obj.parent.args.mongo) { + if (obj.parent.args.xmongodb) { // Use MongoDB obj.databaseType = 3; - Datastore = require('mongodb').MongoClient; - Datastore.connect(obj.parent.args.mongo, function (err, client) { + require('mongodb').MongoClient.connect(obj.parent.args.xmongodb, { useNewUrlParser: true }, function (err, client) { if (err != null) { console.log("Unable to connect to database: " + err); process.exit(); return; } - var dbname = 'meshcentral'; - if (obj.parent.args.mongodbname) { dbname = obj.parent.args.mongodbname; } + Datastore = client; + const dbname = (obj.parent.args.mongodbname) ? (obj.parent.args.mongodbname) : 'meshcentral'; + const dbcollectionname = (obj.parent.args.mongodbcol) ? (obj.parent.args.mongodbcol) : 'meshcentral'; const db = client.db(dbname); - var dbcollection = 'meshcentral'; - if (obj.parent.args.mongodbcol) { dbcollection = obj.parent.args.mongodbcol; } - // Setup MongoDB main collection and indexes - obj.file = db.collection(dbcollection); - /* - obj.file.getIndexes(function (err, indexes) { + obj.file = db.collection(dbcollectionname); + obj.file.indexes(function (err, indexes) { // Check if we need to reset indexes var indexesByName = {}, indexCount = 0; for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; } @@ -414,11 +224,10 @@ module.exports.CreateDB = function (parent, func) { }); } }); - */ /* // Setup the changeStream on the MongoDB main collection - obj.fileChangeStream = obj.file.watch(); + obj.fileChangeStream = obj.file.watch({ fullDocument: 'updateLookup' }); obj.fileChangeStream.on('change', function (next) { // Process next document console.log('change', next); @@ -427,8 +236,7 @@ module.exports.CreateDB = function (parent, func) { // Setup MongoDB events collection and indexes obj.eventsfile = db.collection('events'); // Collection containing all events - /* - obj.eventsfile.getIndexes(function (err, indexes) { + obj.eventsfile.indexes(function (err, indexes) { // Check if we need to reset indexes var indexesByName = {}, indexCount = 0; for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; } @@ -449,12 +257,10 @@ module.exports.CreateDB = function (parent, func) { }); } }); - */ // Setup MongoDB power events collection and indexes obj.powerfile = db.collection('power'); // Collection containing all power events - /* - obj.powerfile.getIndexes(function (err, indexes) { + obj.powerfile.indexes(function (err, indexes) { // Check if we need to reset indexes var indexesByName = {}, indexCount = 0; for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; } @@ -475,15 +281,13 @@ module.exports.CreateDB = function (parent, func) { }); } }); - */ // Setup MongoDB smbios collection, no indexes needed obj.smbiosfile = db.collection('smbios'); // Collection containing all smbios information // Setup MongoDB server stats collection obj.serverstatsfile = db.collection('serverstats'); // Collection of server stats - /* - obj.serverstatsfile.getIndexes(function (err, indexes) { + obj.serverstatsfile.indexes(function (err, indexes) { // Check if we need to reset indexes var indexesByName = {}, indexCount = 0; for (var i in indexes) { indexesByName[indexes[i].name] = indexes[i]; indexCount++; } @@ -504,9 +308,8 @@ module.exports.CreateDB = function (parent, func) { }); } }); - */ - func(obj); // Completed setup of MongoDB + setupFunctions(func); // Completed setup of MongoDB }); } else if (obj.parent.args.mongodb) { // Use MongoJS @@ -607,7 +410,7 @@ module.exports.CreateDB = function (parent, func) { } }); - func(obj); // Completed setup of MongoJS + setupFunctions(func); // Completed setup of MongoJS } else { // Use NeDB (The default) obj.databaseType = 1; @@ -667,7 +470,202 @@ module.exports.CreateDB = function (parent, func) { 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 - func(obj); // Completed setup of NeDB + setupFunctions(func); // Completed setup of NeDB + } + + function setupFunctions(func) { + if (obj.databaseType == 3) { + // Database actions on the main collection (MongoDB) + obj.Set = function (data, func) { obj.file.updateOne({ _id: data._id }, { $set: data }, { upsert: true }, func); }; + obj.Get = function (id, func) { + if (arguments.length > 2) { + var parms = [func]; + for (var parmx = 2; parmx < arguments.length; ++parmx) { parms.push(arguments[parmx]); } + var func2 = function _func2(arg1, arg2) { + var userCallback = _func2.userArgs.shift(); + _func2.userArgs.unshift(arg2); + _func2.userArgs.unshift(arg1); + userCallback.apply(obj, _func2.userArgs); + }; + func2.userArgs = parms; + obj.file.find({ _id: id }).toArray(func2); + } else { + obj.file.find({ _id: id }).toArray(func); + } + }; + obj.GetAll = function (func) { obj.file.find({}).toArray(func); }; + obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }, { type: 0 }).toArray(func); }; + obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { var x = { type: type, domain: domain, meshid: { $in: meshes } }; if (id) { x._id = id; } obj.file.find(x, { type: 0 }).toArray(func); }; + obj.GetAllType = function (type, func) { obj.file.find({ type: type }).toArray(func); }; + obj.GetAllIdsOfType = function (ids, domain, type, func) { obj.file.find({ type: type, domain: domain, _id: { $in: ids } }).toArray(func); }; + obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }, { type: 0 }).toArray(func); }; + obj.GetUserWithVerifiedEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }).toArray(func); }; + obj.Remove = function (id) { obj.file.deleteOne({ _id: id }); }; + obj.RemoveAll = function (func) { obj.file.deleteMany({}, { multi: true }, func); }; + obj.RemoveAllOfType = function (type, func) { obj.file.deleteMany({ type: type }, { multi: true }, func); }; + obj.InsertMany = function (data, func) { obj.file.insertMany(data, func); }; + obj.RemoveMeshDocuments = function (id) { obj.file.deleteMany({ meshid: id }, { multi: true }); obj.file.remove({ _id: 'nt' + id }); }; + obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; + obj.DeleteDomain = function (domain, func) { obj.file.deleteMany({ domain: domain }, { multi: true }, func); }; + obj.SetUser = function (user) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); }; + obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; + obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }).toArray(func); }; + obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find(obj.file, { type: 'node', meshid: meshid, 'intelamt.uuid': uuid }).toArray(func); }; + obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } } + + // Database actions on the events collection + obj.GetAllEvents = function (func) { obj.eventsfile.find({}).toArray(func); }; + obj.StoreEvent = function (event) { obj.eventsfile.insertOne(event); }; + obj.GetEvents = function (ids, domain, func) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); }; + obj.GetEventsWithLimit = function (ids, domain, limit, func) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; + obj.GetUserEvents = function (ids, domain, username, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); }; + obj.GetUserEventsWithLimit = function (ids, domain, username, limit, func) { obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).toArray(func); }; + obj.RemoveAllEvents = function (domain) { obj.eventsfile.deleteMany({ domain: domain }, { multi: true }); }; + obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.deleteMany({ domain: domain, nodeid: nodeid }, { multi: true }); }; + + // Database actions on the power collection + obj.getAllPower = function (func) { obj.powerfile.find({}).toArray(func); }; + obj.storePowerEvent = function (event, multiServer, func) { if (multiServer != null) { event.server = multiServer.serverid; } obj.powerfile.insertOne(event, func); }; + obj.getPowerTimeline = function (nodeid, func) { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }).toArray(func); }; + obj.removeAllPowerEvents = function () { obj.powerfile.deleteMany({}, { multi: true }); }; + obj.removeAllPowerEventsForNode = function (nodeid) { obj.powerfile.deleteMany({ nodeid: nodeid }, { multi: true }); }; + + // Database actions on the SMBIOS collection + obj.SetSMBIOS = function (smbios, func) { obj.smbiosfile.updateOne({ _id: smbios._id }, { $set: smbios }, { upsert: true }, func); }; + obj.RemoveSMBIOS = function (id) { obj.smbiosfile.deleteOne({ _id: id }); }; + obj.GetSMBIOS = function (id, func) { obj.smbiosfile.find({ _id: id }).toArray(func); }; + + // Database actions on the Server Stats collection + obj.SetServerStats = function (data, func) { obj.serverstatsfile.insertOne(data, func); }; + obj.GetServerStats = function (hours, func) { var t = new Date(); t.setTime(t.getTime() - (60 * 60 * 1000 * hours)); obj.serverstatsfile.find({ time: { $gt: t } }, { _id: 0, cpu: 0 }).toArray(func); }; + + // Read a configuration file from the database + obj.getConfigFile = function (path, func) { obj.Get('cfile/' + path, func); } + + // Write a configuration file to the database + obj.setConfigFile = function (path, data, func) { obj.Set({ _id: 'cfile/' + path, type: 'cfile', data: data.toString('base64') }, func); } + + // List all configuration files + obj.listConfigFiles = function (func) { obj.file.find({ type: 'cfile' }).sort({ _id: 1 }).toArray(func); } + + // Get all configuration files + obj.getAllConfigFiles = function (password, func) { + obj.file.find({ type: 'cfile' }).toArray(function (err, docs) { + if (err != null) { func(null); return; } + var r = null; + for (var i = 0; i < docs.length; i++) { + var name = docs[i]._id.split('/')[1]; + var data = obj.decryptData(password, docs[i].data); + if (data != null) { if (r == null) { r = {}; } r[name] = data; } + } + func(r); + }); + } + } else { + // Database actions on the main collection (NeDB and MongoJS) + obj.Set = function (data, func) { obj.file.update({ _id: data._id }, data, { upsert: true }, func); }; + obj.Get = function (id, func) { + if (arguments.length > 2) { + var parms = [func]; + for (var parmx = 2; parmx < arguments.length; ++parmx) { parms.push(arguments[parmx]); } + var func2 = function _func2(arg1, arg2) { + var userCallback = _func2.userArgs.shift(); + _func2.userArgs.unshift(arg2); + _func2.userArgs.unshift(arg1); + userCallback.apply(obj, _func2.userArgs); + }; + func2.userArgs = parms; + obj.file.find({ _id: id }, func2); + } + else { + obj.file.find({ _id: id }, func); + } + }; + obj.GetAll = function (func) { obj.file.find({}, func); }; + obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }, { type: 0 }, func); }; + obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { var x = { type: type, domain: domain, meshid: { $in: meshes } }; if (id) { x._id = id; } obj.file.find(x, { type: 0 }, func); }; + obj.GetAllType = function (type, func) { obj.file.find({ type: type }, func); }; + obj.GetAllIdsOfType = function (ids, domain, type, func) { obj.file.find({ type: type, domain: domain, _id: { $in: ids } }, func); }; + obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }, { type: 0 }, func); }; + obj.GetUserWithVerifiedEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }, func); }; + obj.Remove = function (id) { obj.file.remove({ _id: id }); }; + obj.RemoveAll = function (func) { obj.file.remove({}, { multi: true }, func); }; + obj.RemoveAllOfType = function (type, func) { obj.file.remove({ type: type }, { multi: true }, func); }; + obj.InsertMany = function (data, func) { obj.file.insert(data, func); }; + obj.RemoveMeshDocuments = function (id) { obj.file.remove({ meshid: id }, { multi: true }); obj.file.remove({ _id: 'nt' + id }); }; + obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); }; + obj.DeleteDomain = function (domain, func) { obj.file.remove({ domain: domain }, { multi: true }, func); }; + obj.SetUser = function (user) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); }; + obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } }; + obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); }; + obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); }; + obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } } + + // Database actions on the events collection + obj.GetAllEvents = function (func) { obj.eventsfile.find({}, func); }; + obj.StoreEvent = function (event) { obj.eventsfile.insert(event); }; + obj.GetEvents = function (ids, domain, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); } else { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); } }; + obj.GetEventsWithLimit = function (ids, domain, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); } }; + obj.GetUserEvents = function (ids, domain, username, func) { + if (obj.databaseType == 1) { + obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).exec(func); + } else { + obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }, func); + } + }; + obj.GetUserEventsWithLimit = function (ids, domain, username, limit, func) { + if (obj.databaseType == 1) { + obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit).exec(func); + } else { + obj.eventsfile.find({ domain: domain, $or: [{ ids: { $in: ids } }, { username: username }] }, { type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).limit(limit, func); + } + }; + obj.GetNodeEventsWithLimit = function (nodeid, domain, limit, func) { if (obj.databaseType == 1) { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit).exec(func); } else { obj.eventsfile.find({ domain: domain, nodeid: nodeid }, { type: 0, etype: 0, _id: 0, domain: 0, ids: 0, node: 0, nodeid: 0 }).sort({ time: -1 }).limit(limit, func); } }; + obj.RemoveAllEvents = function (domain) { obj.eventsfile.remove({ domain: domain }, { multi: true }); }; + obj.RemoveAllNodeEvents = function (domain, nodeid) { obj.eventsfile.remove({ domain: domain, nodeid: nodeid }, { multi: true }); }; + + // Database actions on the power collection + obj.getAllPower = function (func) { obj.powerfile.find({}, func); }; + obj.storePowerEvent = function (event, multiServer, func) { if (multiServer != null) { event.server = multiServer.serverid; } obj.powerfile.insert(event, func); }; + obj.getPowerTimeline = function (nodeid, func) { if (obj.databaseType == 1) { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }).exec(func); } else { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }, { _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }, func); } }; + obj.removeAllPowerEvents = function () { obj.powerfile.remove({}, { multi: true }); }; + obj.removeAllPowerEventsForNode = function (nodeid) { obj.powerfile.remove({ nodeid: nodeid }, { multi: true }); }; + + // Database actions on the SMBIOS collection + obj.SetSMBIOS = function (smbios, func) { obj.smbiosfile.update({ _id: smbios._id }, smbios, { upsert: true }, func); }; + obj.RemoveSMBIOS = function (id) { obj.smbiosfile.remove({ _id: id }); }; + obj.GetSMBIOS = function (id, func) { obj.smbiosfile.find({ _id: id }, func); }; + + // Database actions on the Server Stats collection + obj.SetServerStats = function (data, func) { obj.serverstatsfile.insert(data, func); }; + obj.GetServerStats = function (hours, func) { var t = new Date(); t.setTime(t.getTime() - (60 * 60 * 1000 * hours)); obj.serverstatsfile.find({ time: { $gt: t } }, { _id: 0, cpu: 0 }, func); }; + + // Read a configuration file from the database + obj.getConfigFile = function (path, func) { obj.Get('cfile/' + path, func); } + + // Write a configuration file to the database + obj.setConfigFile = function (path, data, func) { obj.Set({ _id: 'cfile/' + path, type: 'cfile', data: data.toString('base64') }, func); } + + // List all configuration files + obj.listConfigFiles = function (func) { obj.file.find({ type: 'cfile' }).sort({ _id: 1 }).exec(func); } + + // Get all configuration files + obj.getAllConfigFiles = function (password, func) { + obj.file.find({ type: 'cfile' }, function (err, docs) { + if (err != null) { func(null); return; } + var r = null; + for (var i = 0; i < docs.length; i++) { + var name = docs[i]._id.split('/')[1]; + var data = obj.decryptData(password, docs[i].data); + if (data != null) { if (r == null) { r = {}; } r[name] = data; } + } + func(r); + }); + } + } + + func(obj); // Completed function setup } return obj; diff --git a/package.json b/package.json index bbb4c7d6..bb71bb16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.3.3-x", + "version": "0.3.3-z", "keywords": [ "Remote Management", "Intel AMT", @@ -38,6 +38,7 @@ "ipcheck": "^0.1.0", "meshcentral": "*", "minimist": "^1.2.0", + "mongojs": "^2.6.0", "multiparty": "^4.2.1", "nedb": "^1.8.0", "node-forge": "^0.7.6", diff --git a/views/default-min.handlebars b/views/default-min.handlebars index ad60ec06..903e9818 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1 +1 @@ -
{{{logoutControl}}}
My Devices | My Account | My Events | My Files | My Users | My Server |
{{{logoutControl}}}
My Devices | My Account | My Events | My Files | My Users | My Server |