From ac53c7ae3cb67ba84c4551e3c36866166c83fc8d Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Wed, 6 Sep 2017 18:10:24 -0700 Subject: [PATCH] Added server self-update support along with many fixes. --- agents/MeshCommander-Small.gz | Bin 0 -> 38045 bytes agents/webapppush.js | 172 ++++++++++++++++++++++++++++++++++ meshagent.js | 2 +- meshcentral.js | 53 ++++++++--- package.json | 2 +- views/default.handlebars | 16 +++- webserver.js | 7 ++ 7 files changed, 234 insertions(+), 18 deletions(-) create mode 100644 agents/MeshCommander-Small.gz create mode 100644 agents/webapppush.js diff --git a/agents/MeshCommander-Small.gz b/agents/MeshCommander-Small.gz new file mode 100644 index 0000000000000000000000000000000000000000..ebbcae97a14963ffc3789c006de315cf812e0bbc GIT binary patch literal 38045 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

JB|mB6_Kdb!u&tiqJnar*aM@BK*wI>KM9 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 BOo#vg literal 0 HcmV?d00001 diff --git a/agents/webapppush.js b/agents/webapppush.js new file mode 100644 index 00000000..4e076ce1 --- /dev/null +++ b/agents/webapppush.js @@ -0,0 +1,172 @@ +/* +Copyright 2017 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +// Polyfill String.endsWith +if (!String.prototype.endsWith) { + String.prototype.endsWith = function (searchString, position) { + var subjectString = this.toString(); + if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; } + position -= searchString.length; + var lastIndex = subjectString.lastIndexOf(searchString, position); + return lastIndex !== -1 && lastIndex === position; + }; +} + +// Replace a string with a number if the string is an exact number +function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) == x)) { x = parseInt(x); } return x; } + +// Convert decimal to hex +function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); } + +// Convert a raw string to a hex string +function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r += char2hex(input.charCodeAt(i)); } return r; } + +// Convert a buffer into a string +function buf2rstr(buf) { var r = ''; for (var i = 0; i < buf.length; i++) { r += String.fromCharCode(buf[i]); } return r; } + +// Convert a hex string to a raw string // TODO: Do this using Buffer(), will be MUCH faster +function hex2rstr(d) { + if (typeof d != "string" || d.length == 0) return ''; + var r = '', m = ('' + d).match(/../g), t; + while (t = m.shift()) r += String.fromCharCode('0x' + t); + return r +} + +// Convert an object to string with all functions +function objToString(x, p, ret) { + if (ret == undefined) ret = ''; + if (p == undefined) p = 0; + if (x == null) { return '[null]'; } + if (p > 8) { return '[...]'; } + if (x == undefined) { return '[undefined]'; } + if (typeof x == 'string') { if (p == 0) return x; return '"' + x + '"'; } + if (typeof x == 'buffer') { return '[buffer]'; } + if (typeof x != 'object') { return x; } + var r = '{' + (ret ? '\r\n' : ' '); + for (var i in x) { r += (addPad(p + 2, ret) + i + ': ' + objToString(x[i], p + 2, ret) + (ret ? '\r\n' : ' ')); } + return r + addPad(p, ret) + '}'; +} + +// Return p number of spaces +function addPad(p, ret) { var r = ''; for (var i = 0; i < p; i++) { r += ret; } return r; } + +// Split a string taking into account the quoats. Used for command line parsing +function splitArgs(str) { + var myArray = [], myRegexp = /[^\s"]+|"([^"]*)"/gi; + do { var match = myRegexp.exec(str); if (match != null) { myArray.push(match[1] ? match[1] : match[0]); } } while (match != null); + return myArray; +} + +// Parse arguments string array into an object +function parseArgs(argv) { + var results = { '_': [] }, current = null; + for (var i = 1, len = argv.length; i < len; i++) { + var x = argv[i]; + if (x.length > 2 && x[0] == '-' && x[1] == '-') { + if (current != null) { results[current] = true; } + current = x.substring(2); + } else { + if (current != null) { results[current] = toNumberIfNumber(x); current = null; } else { results['_'].push(toNumberIfNumber(x)); } + } + } + if (current != null) { results[current] = true; } + return results; +} + +// Parge a URL string into an options object +function parseUrl(url) { + var x = url.split('/'); + if (x.length < 4) return null; + var y = x[2].split(':'); + var options = {}; + var options = { protocol: x[0], hostname: y[0], path: '/' + x.splice(3).join('/') }; + if (y.length == 1) { options.port = ((x[0] == 'https:') || (x[0] == 'wss:')) ? 443 : 80; } else { options.port = parseInt(y[1]); } + if (isNaN(options.port) == true) return null; + return options; +} + +// Read a entire file into a buffer +function readFileToBuffer(filePath) { + try { + var fs = require('fs'); + var stats = fs.statSync(filePath); + if (stats == null) { return null; } + var fileData = new Buffer(stats.size); + var fd = fs.openSync(filePath, 'r'); + fs.readSync(fd, fileData, 0, stats.size, 0); + fs.closeSync(fd); + return fileData; + } catch (e) { return null; } +} + +// Performs an HTTP get on a URL and return the data back +function makeHttpGetRequest(url, func) { + var http = require('http'); + var request = http.get(url, function (res) { + var htmlData = ''; + res.on('data', function (d) { htmlData += d; }); + res.on('end', function (d) { func(res.statusCode, htmlData); }); + }).on('error', function (e) { func(0, null); }); +} + +// Performs an HTTP get on a URL and return the data back (Alternative implementation) +function makeHttpGetRequest2(url, func) { + var http = require('http'); + var options = http.parseUri(url); + options.username = 'admin'; + options.password = 'P@ssw0rd'; + var request = http.request(options, function (res) { + var htmlData = ''; + res.on('data', function (d) { htmlData += d; }); + res.on('end', function () { func(res.statusCode, htmlData); }); + }); + request.on('error', function (e) { func(0, null); }); + request.end(); +} + +// Performs an HTTP get on a URL and return the data back (Alternative implementation) +function intelAmtSetStorage(url, buffer, func) { + var http = require('http'); + var options = http.parseUri(url); + options.user = 'admin'; // TODO: Does not support HTTP digest auth yet!!!!!!!!!!!!!!!! + options.pass = 'P@ssw0rd'; + var request = http.request(options, function (res) { + var htmlData = ''; + res.on('data', function (d) { htmlData += d; }); + res.on('end', function () { func(res.statusCode, htmlData); }); + }); + request.on('error', function (e) { func(0, null); }); + request.end(); +} + +//console.log(objToString(db2, 2, ' ')); + +console.log('--- Start ---'); + +var fileData = readFileToBuffer('MeshCommander-Small.gz'); +if (fileData != null) { + makeHttpGetRequest2('http://192.168.2.105:16992/index.htm', function (status, htmlData) { console.log(status, htmlData); }); + + /* + intelAmtSetStorage('http://192.168.2.105:16992/amt-storage/index.htm', fileData, function (status, htmlData) { + console.log('intelAmtSetStorage', status, htmlData); + }); + */ +} + +console.log('--- End ---'); +//process.exit(2); \ No newline at end of file diff --git a/meshagent.js b/meshagent.js index fb46b238..8f4054a9 100644 --- a/meshagent.js +++ b/meshagent.js @@ -300,7 +300,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { // We have a location in the database for this remote IP var iploc = nodes[0], x = {}; x.publicip = iploc.ip; - x.iploc = iploc.loc + ',' + (Math.floor((new Date(command.value.date)) / 1000)); + x.iploc = iploc.loc + ',' + (Math.floor((new Date(iploc.date)) / 1000)); ChangeAgentLocationInfo(x); } else { // Check if we need to ask for the IP location diff --git a/meshcentral.js b/meshcentral.js index f17a6082..f90c7e3f 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -34,6 +34,8 @@ function CreateMeshCentralServer() { obj.meshAgentBinaries = {}; // Mesh Agent Binaries, Architecture type --> { hash:(sha256 hash), size:(binary size), path:(binary path) } obj.meshAgentInstallScripts = {}; // Mesh Install Scripts, Script ID -- { hash:(sha256 hash), size:(binary size), path:(binary path) } obj.multiServer = null; + obj.currentVer = null; + obj.maintenanceTimer = null; // Create data and files folders if needed try { obj.fs.mkdirSync(obj.datapath); } catch (e) { } @@ -54,7 +56,7 @@ function CreateMeshCentralServer() { 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', 'mpsport', 'redirport', 'cert', 'deletedomain', 'deletedefaultdomain', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport']; + var validArguments = ['_', 'notls', 'user', 'port', 'mpsport', 'redirport', 'cert', 'deletedomain', 'deletedefaultdomain', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate']; for (var arg in obj.args) { 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; } @@ -123,6 +125,14 @@ function CreateMeshCentralServer() { } else if (xprocess.xrestart == 2) { console.log('Expected exit...'); process.exit(); // User CTRL-C exit. + } else if (xprocess.xrestart == 3) { + // Server self-update exit + var child_process = require('child_process'); + var xxprocess = child_process.exec('npm install meshcentral', { cwd: obj.path.join(__dirname, '../..') }, function (error, stdout, stderr) { }); + xxprocess.data = ''; + xxprocess.stdout.on('data', function (data) { xxprocess.data += data; }); + xxprocess.stderr.on('data', function (data) { xxprocess.data += data; }); + xxprocess.on('close', function (code) { console.log('Update completed...'); setTimeout(function () { obj.launchChildServer(startLine); }, 1000); }); } else { if (error != null) { // This is an un-expected restart @@ -131,7 +141,7 @@ function CreateMeshCentralServer() { } } }); - xprocess.stdout.on('data', function (data) { if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } if (data.indexOf('Updating settings folder...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Server Ctrl-C exit...') >= 0) { xprocess.xrestart = 2; } console.log(data); }); + xprocess.stdout.on('data', function (data) { if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } if (data.indexOf('Updating settings folder...') >= 0) { xprocess.xrestart = 1; } else if (data.indexOf('Server Ctrl-C exit...') >= 0) { xprocess.xrestart = 2; } else if (data.indexOf('Starting self upgrade...') >= 0) { xprocess.xrestart = 3; } console.log(data); }); xprocess.stderr.on('data', function (data) { if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); } obj.fs.appendFileSync('mesherrors.txt', '-------- ' + new Date().toLocaleString() + ' --------\r\n\r\n' + data + '\r\n\r\n\r\n'); }); xprocess.on('close', function (code) { if ((code != 0) && (code != 123)) { /* console.log("Exited with code " + code); */ } }); } @@ -140,25 +150,22 @@ function CreateMeshCentralServer() { obj.getLatestServerVersion = function (callback) { if (callback == undefined) return; var child_process = require('child_process'); - var xprocess = child_process.exec('npm view meshcentral dist-tags.latest', function (error, stdout, stderr) { - if (xprocess.xrestart == true) { - setTimeout(function () { obj.launchChildServer(startLine); }, 500); // If exit with restart requested, restart the server. - } else { - if (error != null) { console.log('ERROR: Unable to start MeshCentral: ' + error); process.exit(); } - } - }); + var xprocess = child_process.exec('npm view meshcentral dist-tags.latest', function (error, stdout, stderr) { }); xprocess.data = ''; xprocess.stdout.on('data', function (data) { xprocess.data += data; }); xprocess.stderr.on('data', function (data) { }); xprocess.on('close', function (code) { var currentVer = null; - try { currentVer = JSON.parse(require('fs').readFileSync('package.json', 'utf8')).version; } catch (e) { } + try { currentVer = JSON.parse(require('fs').readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { } var latestVer = null; if (code == 0) { try { latestVer = xprocess.data.split(' ').join('').split('\r').join('').split('\n').join(''); } catch (e) { } } callback(currentVer, latestVer); }); } + // Initiate server self-update + obj.performServerUpdate = function () { console.log('Starting self upgrade...'); process.exit(200); } + obj.StartEx = function () { // Look to see if data and/or file path is specified if (obj.args.datapath) { obj.datapath = obj.args.datapath; } @@ -310,6 +317,9 @@ function CreateMeshCentralServer() { obj.mpsserver = require('./mpsserver.js').CreateMpsServer(obj, obj.db, obj.args, obj.certificates); } + // Start periodic maintenance + obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour + // Dispatch an event that the server is now running obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' }) @@ -319,7 +329,28 @@ function CreateMeshCentralServer() { }); }); } - + + // Perform maintenance operations (called every hour) + obj.maintenanceActions = function () { + // Check if we need to perform server self-update + if (obj.args.selfupdate == true) { + obj.db.getValueOfTheDay('performSelfUpdate', 1, function (performSelfUpdate) { + if (performSelfUpdate.value > 0) { + performSelfUpdate.value--; + obj.db.Set(performSelfUpdate); + obj.getLatestServerVersion(function (currentVer, latestVer) { if (currentVer != latestVer) { obj.performServerUpdate(); return; } }); + } + }); + } + + // Clear old event entries and power entires + obj.db.clearOldEntries('event', 30); // Clear all event entires that are older than 30 days. + obj.db.clearOldEntries('power', 10); // Clear all event entires that are older than 10 days. If a node is connected longer than 10 days, current power state will be used for everything. + + // Perform other database cleanup + obj.db.cleanup(); + } + // Stop the Meshcentral server obj.Stop = function (restoreFile) { // If the database is not setup, exit now. diff --git a/package.json b/package.json index 07dea7e9..c01763b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.0.7-g", + "version": "0.0.7-n", "keywords": [ "Remote Management", "Intel AMT", diff --git a/views/default.handlebars b/views/default.handlebars index a3e58efa..805025cc 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -616,7 +616,6 @@ var features = {{{features}}}; var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}"; var amtScanResults = null; - //var xxmap = null; function startup() { // Guard against other site's top frames (web bugs). @@ -852,14 +851,17 @@ } case 'serverversion': { if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerUpdate')) { - console.log(message); var x = '

'; - QH('d2verinfo', x); + if (message.current == message.latest) { + setDialogMode(2, "MeshCentral Version", 1, null, x); + } else { + setDialogMode(2, "MeshCentral Version", 3, server_showVersionDlgEx, x + '
Select OK to start server self-update.'); + } } break; } @@ -1187,7 +1189,7 @@ QV('devMapToolbar', view == 3); QV('devListToolbarSort', view < 3); if (view == 3) { - setTimeout( function() { xxmap.map.updateSize();}, 200); + setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200); // TODO } else { // 3 wide or list view @@ -3688,10 +3690,14 @@ function server_showVersionDlg() { if (xxdialogMode) return; - setDialogMode(2, "MeshCentral Version", 1, null, "
Loading...
", 'MeshCentralServerUpdate'); + setDialogMode(2, "MeshCentral Version", 1, null, "Loading...", 'MeshCentralServerUpdate'); meshserver.Send({ action: 'serverversion' }); } + function server_showVersionDlgEx() { + meshserver.Send({ action: 'serverupdate' }); + } + // // MY MESHS // diff --git a/webserver.js b/webserver.js index 57143b12..2345e940 100644 --- a/webserver.js +++ b/webserver.js @@ -1165,6 +1165,13 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate obj.parent.getLatestServerVersion(function (currentVersion, latestVersion) { ws.send(JSON.stringify({ action: 'serverversion', current: currentVersion, latest: latestVersion })); }); break; } + case 'serverupdate': + { + // Perform server update + if ((user.siteadmin & 16) == 0) break; + obj.parent.performServerUpdate(); + break; + } case 'createmesh': { // Create mesh