diff --git a/db.js b/db.js
index 2ba15fcf..998a78d1 100644
--- a/db.js
+++ b/db.js
@@ -176,6 +176,15 @@ module.exports.CreateDB = function (parent) {
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); };
+ // Read a file from the database
+ obj.getFile = function (path, func) { obj.Get('cfile/' + path, func); }
+
+ // Write a file to the database
+ obj.setFile = function (path, data, func) { obj.Set({ _id: 'cfile/' + path, type: 'cfile', data: data.toString('base64') }, func); }
+
+ // List all files
+ obj.listFiles = function (func) { obj.file.find({ type: 'cfile' }).sort({ _id: 1 }).exec(func); }
+
// Get the number of records in the database for various types, this is the slow NeDB way. TODO: MongoDB can use group() to do this faster.
obj.getStats = function (func) {
obj.file.count({ type: 'node' }, function (err, nodeCount) {
diff --git a/meshcentral.js b/meshcentral.js
index 348ed2b6..98158e8e 100644
--- a/meshcentral.js
+++ b/meshcentral.js
@@ -95,7 +95,7 @@ function CreateMeshCentralServer(config, args) {
try { require('./pass').hash('test', function () { }); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
// Check for invalid arguments
- var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore'];
+ var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles'];
for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
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.
@@ -291,6 +291,61 @@ function CreateMeshCentralServer(config, args) {
if (obj.args.showiplocations) { obj.db.GetAllType('iploc', function (err, docs) { console.log(docs); process.exit(); }); return; }
if (obj.args.logintoken) { obj.getLoginToken(obj.args.logintoken, function (r) { console.log(r); process.exit(); }); return; }
if (obj.args.logintokenkey) { obj.showLoginTokenKey(function (r) { console.log(r); process.exit(); }); return; }
+ if (obj.args.dblistconfigfiles) { obj.db.GetAllType('cfile', function (err, docs) { if (err == null) { if (docs.length == 0) { console.log('No files found.'); } else { for (var i in docs) { console.log(docs[i]._id.split('/')[1] + ', ' + Buffer.from(docs[i].data, 'base64').length + ' bytes.'); } } } else { console.log('Unable to read from database.'); } process.exit(); }); return; }
+ if (obj.args.dbshowconfigfile) { obj.db.getFile(obj.args.dbshowconfigfile, function (err, docs) { if (err == null) { if (docs.length == 0) { console.log('File not found.'); } else { console.log(Buffer.from(docs[0].data, 'base64').toString()); } } else { console.log('Unable to read from database.'); } process.exit(); }); return; }
+ if (obj.args.dbdeleteconfigfiles) { console.log('Delating all configuration files from the database...'); obj.db.RemoveAllOfType('cfile', function () { console.log('Done.'); process.exit(); }); } // Delete all configuration files from database
+
+ // Push all relevent files from meshcentral-data into the database
+ if (obj.args.dbpushconfigfiles) {
+ if (typeof obj.args.dbpushconfigfiles != 'string') {
+ console.log('Usage: --dbpulldatafiles (path) This will import files from folder into the database');
+ console.log(' --dbpulldatafiles * This will import files from meshcentral-data into the db.');
+ process.exit();
+ } else {
+ if (obj.args.dbpushconfigfiles == '*') { obj.args.dbpushconfigfiles = obj.datapath; }
+ obj.fs.readdir(obj.datapath, (err, files) => {
+ var lockCount = 1
+ for (var i in files) {
+ const file = files[i];
+ if (file.endsWith('.json') || file.endsWith('.key') || file.endsWith('.crt')) {
+ const path = obj.path.join(obj.args.dbpushconfigfiles, files[i]), binary = Buffer.from(obj.fs.readFileSync(path, { encoding: 'binary' }), 'binary');
+ console.log('Pushing ' + file + ', ' + binary.length + ' bytes.');
+ lockCount++;
+ obj.db.setFile(file, binary, function () { if ((--lockCount) == 0) { console.log('Done.'); process.exit(); } });
+ }
+ }
+ if (--lockCount == 0) { process.exit(); }
+ })
+ }
+ return;
+ }
+
+ // Pull all database files into meshcentral-data
+ if (obj.args.dbpullconfigfiles) {
+ if (typeof obj.args.dbpullconfigfiles != 'string') {
+ console.log('Usage: --dbpulldatafiles (path)');
+ process.exit();
+ } else {
+ obj.db.GetAllType('cfile', function (err, docs) {
+ if (err == null) {
+ if (docs.length == 0) {
+ console.log('File not found.');
+ } else {
+ for (var i in docs) {
+ const file = docs[i]._id.split('/')[1], binary = Buffer.from(docs[i].data, 'base64');
+ obj.fs.writeFileSync(obj.path.join(obj.args.dbpullconfigfiles, file), binary);
+ console.log('Pulling ' + file + ', ' + binary.length + ' bytes.');
+ }
+ }
+ } else {
+ console.log('Unable to read from database.');
+ }
+ process.exit();
+ });
+ }
+ return;
+ }
+
if (obj.args.dbexport) {
// Export the entire database to a JSON file
if (obj.args.dbexport == true) { obj.args.dbexport = obj.getConfigFilePath('meshcentral.db.json'); }
diff --git a/sample-config.json b/sample-config.json
index 3e30ef31..3111728f 100644
--- a/sample-config.json
+++ b/sample-config.json
@@ -7,7 +7,8 @@
"_LANonly": true,
"_Minify": 1,
"_SessionTime": 30,
- "_SessionKey": "MyReallySecretPassword",
+ "_SessionKey": "MyReallySecretPassword1",
+ "_DbEncryptKey": "MyReallySecretPassword2",
"_Port": 443,
"_RedirPort": 80,
"_AllowLoginToken": true,
diff --git a/views/default.handlebars b/views/default.handlebars
index 05f842b3..b5294b5d 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -1282,7 +1282,7 @@
if (isPrivateIP(currentNode.lastaddr)) {
x += addHtmlValue2('Last agent address', currentNode.lastaddr.split(':')[0]);
} else {
- x += addHtmlValue2('Last agent address', '' + currentNode.lastaddr.split(':')[0] + '');
+ x += addHtmlValue2('Last agent address', '' + currentNode.lastaddr.split(':')[0] + '');
}
}
@@ -1293,11 +1293,11 @@
if (net.name) { x += addHtmlValue2('Name', '' + EscapeHtml(net.name) + ''); }
if (net.desc) { x += addHtmlValue2('Description', EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
if (net.dnssuffix) { x += addHtmlValue2('DNS suffix', EscapeHtml(net.dnssuffix)); }
- if (net.mac) { x += addHtmlValue2('MAC address', EscapeHtml(net.mac.toUpperCase())); }
+ if (net.mac) { x += addHtmlValue2('MAC address', '' + EscapeHtml(net.mac.toLowerCase()) + ''); }
if (net.v4addr) { x += addHtmlValue2('IPv4 address', EscapeHtml(net.v4addr)); }
if (net.v4mask) { x += addHtmlValue2('IPv4 mask', EscapeHtml(net.v4mask)); }
if (net.v4gateway) { x += addHtmlValue2('IPv4 gateway', EscapeHtml(net.v4gateway)); }
- if (net.gatewaymac) { x += addHtmlValue2('Gateway MAC', EscapeHtml(net.gatewaymac)); }
+ if (net.gatewaymac) { x += addHtmlValue2('Gateway MAC', '' + EscapeHtml(net.gatewaymac.toLowerCase()) + ''); }
}
x += '';
QH('d2netinfo', x);