mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Improvements to plugin support.
This commit is contained in:
parent
5bc3da5bf6
commit
ac5b6a9d73
11 changed files with 15748 additions and 561 deletions
|
@ -37,12 +37,10 @@ var MESHRIGHT_NOFILES = 1024;
|
|||
var MESHRIGHT_NOAMT = 2048;
|
||||
var MESHRIGHT_LIMITEDINPUT = 4096;
|
||||
|
||||
function createMeshCore(agent)
|
||||
{
|
||||
function createMeshCore(agent) {
|
||||
var obj = {};
|
||||
|
||||
if (process.platform == 'darwin' && !process.versions)
|
||||
{
|
||||
if (process.platform == 'darwin' && !process.versions) {
|
||||
// This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = '';
|
||||
|
@ -51,21 +49,18 @@ function createMeshCore(agent)
|
|||
child.stdin.write(" if(c[1]==\"dict\"){ split(a[2], d, \"</dict>\"); if(split(d[1], truval, \"<true/>\")>1) { split(truval[1], kn1, \"<key>\"); split(kn1[2], kn2, \"</key>\"); print kn2[1]; } }");
|
||||
child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
|
||||
child.waitExit();
|
||||
if (child.stdout.str.trim() == 'Crashed')
|
||||
{
|
||||
if (child.stdout.str.trim() == 'Crashed') {
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = '';
|
||||
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
|
||||
child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
|
||||
child.waitExit();
|
||||
|
||||
if (parseInt(child.stdout.str.trim()) == process.pid)
|
||||
{
|
||||
if (parseInt(child.stdout.str.trim()) == process.pid) {
|
||||
// The currently running MeshAgent is us, so we can continue with the update
|
||||
var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
|
||||
var tokens = plist.split('<key>KeepAlive</key>');
|
||||
if (tokens[1].split('>')[0].split('<')[1] == 'dict')
|
||||
{
|
||||
if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
|
||||
var tmp = tokens[1].split('</dict>');
|
||||
tmp.shift();
|
||||
tokens[1] = '\n <true/>' + tmp.join('</dict>');
|
||||
|
@ -125,10 +120,8 @@ function createMeshCore(agent)
|
|||
if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (ee) { } }
|
||||
obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
|
||||
try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH }); } catch (e) { }
|
||||
obj.DAIPC.on('connection', function (c)
|
||||
{
|
||||
c._send = function (j)
|
||||
{
|
||||
obj.DAIPC.on('connection', function (c) {
|
||||
c._send = function (j) {
|
||||
var data = JSON.stringify(j);
|
||||
var packet = Buffer.alloc(data.length + 4);
|
||||
packet.writeUInt32LE(data.length + 4, 0);
|
||||
|
@ -138,32 +131,26 @@ function createMeshCore(agent)
|
|||
this._daipc = c;
|
||||
c.parent = this;
|
||||
c.on('end', function () { console.log('Connection Closed'); this.parent._daipc = null; });
|
||||
c.on('data', function (chunk)
|
||||
{
|
||||
c.on('data', function (chunk) {
|
||||
if (chunk.length < 4) { this.unshift(chunk); return; }
|
||||
var len = chunk.readUInt32LE(0);
|
||||
if (len > 8192) { this.parent._daipc = null; this.end(); return; }
|
||||
if (chunk.length < len) { this.unshift(chunk); return; }
|
||||
|
||||
|
||||
var data = chunk.slice(4, len);
|
||||
try
|
||||
{
|
||||
try {
|
||||
data = JSON.parse(data.toString());
|
||||
}
|
||||
catch(de)
|
||||
{
|
||||
catch (de) {
|
||||
this.parent._daipc = null; this.end(); return;
|
||||
}
|
||||
|
||||
|
||||
if (!data.cmd) { this.parent._daipc = null; this.end(); return; }
|
||||
|
||||
try
|
||||
{
|
||||
switch(data.cmd)
|
||||
{
|
||||
try {
|
||||
switch (data.cmd) {
|
||||
case 'query':
|
||||
switch(data.value)
|
||||
{
|
||||
switch (data.value) {
|
||||
case 'connection':
|
||||
data.result = require('MeshAgent').ConnectedServer;
|
||||
this._send(data);
|
||||
|
@ -176,32 +163,26 @@ function createMeshCore(agent)
|
|||
return;
|
||||
}
|
||||
}
|
||||
catch(xe)
|
||||
{
|
||||
catch (xe) {
|
||||
this.parent._daipc = null; this.end(); return;
|
||||
}
|
||||
});
|
||||
});
|
||||
function diagnosticAgent_uninstall()
|
||||
{
|
||||
function diagnosticAgent_uninstall() {
|
||||
require('service-manager').manager.uninstallService('meshagentDiagnostic');
|
||||
require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
|
||||
};
|
||||
function diagnosticAgent_installCheck(install)
|
||||
{
|
||||
try
|
||||
{
|
||||
function diagnosticAgent_installCheck(install) {
|
||||
try {
|
||||
var diag = require('service-manager').manager.getService('meshagentDiagnostic');
|
||||
return (diag);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
catch (e) {
|
||||
}
|
||||
if (!install) { return (null); }
|
||||
|
||||
var svc = null;
|
||||
try
|
||||
{
|
||||
try {
|
||||
require('service-manager').manager.installService(
|
||||
{
|
||||
name: 'meshagentDiagnostic',
|
||||
|
@ -213,8 +194,7 @@ function createMeshCore(agent)
|
|||
});
|
||||
svc = require('service-manager').manager.getService('meshagentDiagnostic');
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
catch (e) {
|
||||
return (null);
|
||||
}
|
||||
var proxyConfig = require('global-tunnel').proxyConfig;
|
||||
|
@ -227,12 +207,10 @@ function createMeshCore(agent)
|
|||
ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
|
||||
if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
|
||||
if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
|
||||
if (proxyConfig)
|
||||
{
|
||||
if (proxyConfig) {
|
||||
ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ddb.Put('ignoreProxyFile', '1');
|
||||
}
|
||||
|
||||
|
@ -242,7 +220,7 @@ function createMeshCore(agent)
|
|||
delete ddb;
|
||||
|
||||
// Set a recurrent task, to run the Diagnostic Agent every 2 days
|
||||
require('task-scheduler').create({name: 'meshagentDiagnostic/periodicStart', daily: 2, time: require('tls').generateRandomInteger('0', '23') + ':' + require('tls').generateRandomInteger('0', '59').padStart(2, '0'), service: 'meshagentDiagnostic'});
|
||||
require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: 2, time: require('tls').generateRandomInteger('0', '23') + ':' + require('tls').generateRandomInteger('0', '59').padStart(2, '0'), service: 'meshagentDiagnostic' });
|
||||
//require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
|
||||
|
||||
return (svc);
|
||||
|
@ -281,7 +259,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
obj.borderManager = new borderController();
|
||||
*/
|
||||
|
||||
|
||||
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
|
||||
var meshCoreObj = { "action": "coreinfo", "value": "MeshCore v6", "caps": 14 }; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript, 32 = Temporary Agent, 64 = Recovery Agent
|
||||
|
||||
|
@ -397,7 +375,7 @@ function createMeshCore(agent)
|
|||
});
|
||||
}
|
||||
} catch (ex) { sendConsoleText("ex1: " + ex); }
|
||||
|
||||
|
||||
// Try to load up the WIFI scanner
|
||||
try {
|
||||
var wifiScannerLib = require('wifi-scanner');
|
||||
|
@ -436,7 +414,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
catch (e) { return false; }
|
||||
}
|
||||
|
||||
|
||||
// Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
|
||||
function clearGatewayMac(str) {
|
||||
if (str == null) return null;
|
||||
|
@ -444,7 +422,7 @@ function createMeshCore(agent)
|
|||
for (var i in x.netif) { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } }
|
||||
return JSON.stringify(x);
|
||||
}
|
||||
|
||||
|
||||
function getIpLocationData(func) {
|
||||
// Get the location information for the cache if possible
|
||||
var publicLocationInfo = db.Get('publicLocationInfo');
|
||||
|
@ -483,7 +461,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Polyfill String.endsWith
|
||||
if (!String.prototype.endsWith) {
|
||||
String.prototype.endsWith = function (searchString, position) {
|
||||
|
@ -494,7 +472,7 @@ function createMeshCore(agent)
|
|||
return lastIndex !== -1 && lastIndex === position;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Polyfill path.join
|
||||
obj.path = {
|
||||
join: function () {
|
||||
|
@ -513,19 +491,19 @@ function createMeshCore(agent)
|
|||
return x.join('/');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 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 '';
|
||||
|
@ -533,7 +511,7 @@ function createMeshCore(agent)
|
|||
while (t = m.shift()) r += String.fromCharCode('0x' + t);
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
// Convert an object to string with all functions
|
||||
function objToString(x, p, pad, ret) {
|
||||
if (ret == undefined) ret = '';
|
||||
|
@ -548,17 +526,17 @@ function createMeshCore(agent)
|
|||
for (var i in x) { if (i != '_ObjectID') { r += (addPad(p + 2, pad) + i + ': ' + objToString(x[i], p + 2, pad, ret) + (ret ? '\r\n' : ' ')); } }
|
||||
return r + addPad(p, pad) + '}';
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
|
@ -574,7 +552,7 @@ function createMeshCore(agent)
|
|||
if (current != null) { results[current] = true; }
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
// Get server target url with a custom path
|
||||
function getServerTargetUrl(path) {
|
||||
var x = mesh.ServerUrl;
|
||||
|
@ -585,13 +563,13 @@ function createMeshCore(agent)
|
|||
if (x == null) return null;
|
||||
return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
|
||||
}
|
||||
|
||||
|
||||
// Get server url. If the url starts with "*/..." change it, it not use the url as is.
|
||||
function getServerTargetUrlEx(url) {
|
||||
if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
// Send a wake-on-lan packet
|
||||
function sendWakeOnLan(hexMac) {
|
||||
var count = 0;
|
||||
|
@ -600,7 +578,7 @@ function createMeshCore(agent)
|
|||
var magic = 'FFFFFFFFFFFF';
|
||||
for (var x = 1; x <= 16; ++x) { magic += hexMac; }
|
||||
var magicbin = Buffer.from(magic, 'hex');
|
||||
|
||||
|
||||
for (var adapter in interfaces) {
|
||||
if (interfaces.hasOwnProperty(adapter)) {
|
||||
for (var i = 0; i < interfaces[adapter].length; ++i) {
|
||||
|
@ -618,7 +596,7 @@ function createMeshCore(agent)
|
|||
} catch (e) { }
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// Handle a mesh agent command
|
||||
function handleServerCommand(data) {
|
||||
if (typeof data == 'object') {
|
||||
|
@ -722,7 +700,7 @@ function createMeshCore(agent)
|
|||
// Open a local web browser and return success/fail
|
||||
MeshServerLog('Opening: ' + data.url, data);
|
||||
sendConsoleText('OpenURL: ' + data.url);
|
||||
if (data.url) { mesh.SendCommand({ "action": "msg", "type":"openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
|
||||
if (data.url) { mesh.SendCommand({ "action": "msg", "type": "openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
|
||||
break;
|
||||
}
|
||||
case 'getclip': {
|
||||
|
@ -831,13 +809,25 @@ function createMeshCore(agent)
|
|||
}
|
||||
case 'ping': { mesh.SendCommand('{"action":"pong"}'); break; }
|
||||
case 'pong': { break; }
|
||||
case 'plugin': {
|
||||
if (typeof data.pluginaction == 'string') {
|
||||
try {
|
||||
MeshServerLog('Plugin called', data);
|
||||
// Not yet implemented
|
||||
// require(data.plugin.name).serveraction(data);
|
||||
} catch (e) {
|
||||
MeshServerLog('Error calling plugin', data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Unknown action, ignore it.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Called when a file changed in the file system
|
||||
/*
|
||||
function onFileWatcher(a, b) {
|
||||
|
@ -889,8 +879,8 @@ function createMeshCore(agent)
|
|||
pr.then(defragResult, defragResult);
|
||||
} else {
|
||||
*/
|
||||
results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
|
||||
func(results);
|
||||
results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
|
||||
func(results);
|
||||
//}
|
||||
} catch (ex) { func(null, ex); }
|
||||
}
|
||||
|
@ -934,7 +924,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
// Tunnel callback operations
|
||||
function onTunnelUpgrade(response, s, head) {
|
||||
this.s = s;
|
||||
|
@ -990,7 +980,7 @@ function createMeshCore(agent)
|
|||
peerTunnel.s.first = true;
|
||||
peerTunnel.s.resume();
|
||||
}
|
||||
|
||||
|
||||
// Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
|
||||
function onTcpRelayServerTunnelData(data) {
|
||||
if (this.first == true) { this.first = false; this.pipe(this.tcprelay); } // Pipe Server --> Target
|
||||
|
@ -1000,7 +990,7 @@ function createMeshCore(agent)
|
|||
if (tunnels[this.httprequest.index] == null) return; // Stop duplicate calls.
|
||||
//sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
|
||||
delete tunnels[this.httprequest.index];
|
||||
|
||||
|
||||
/*
|
||||
// Close the watcher if required
|
||||
if (this.httprequest.watcher != undefined) {
|
||||
|
@ -1032,7 +1022,7 @@ function createMeshCore(agent)
|
|||
function onTunnelData(data) {
|
||||
//console.log("OnTunnelData");
|
||||
//sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
|
||||
|
||||
|
||||
// If this is upload data, save it to file
|
||||
if (this.httprequest.uploadFile) {
|
||||
try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { this.write(new Buffer(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
|
||||
|
@ -1069,17 +1059,14 @@ function createMeshCore(agent)
|
|||
return;
|
||||
}
|
||||
|
||||
this.end = function ()
|
||||
{
|
||||
if (process.platform == "win32")
|
||||
{
|
||||
this.end = function () {
|
||||
if (process.platform == "win32") {
|
||||
// Unpipe the web socket
|
||||
this.unpipe(this.httprequest._term);
|
||||
if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
|
||||
|
||||
// Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
|
||||
if (this.rtcchannel)
|
||||
{
|
||||
if (this.rtcchannel) {
|
||||
this.rtcchannel.unpipe(this.httprequest._term);
|
||||
if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
|
||||
}
|
||||
|
@ -1087,27 +1074,21 @@ function createMeshCore(agent)
|
|||
// Clean up
|
||||
if (this.httprequest._term) { this.httprequest._term.end(); }
|
||||
this.httprequest._term = null;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
// TODO!!
|
||||
}
|
||||
};
|
||||
|
||||
// Remote terminal using native pipes
|
||||
if (process.platform == "win32")
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((this.httprequest.protocol == 6) && (require('win-terminal').PowerShellCapable() == true))
|
||||
{
|
||||
if (process.platform == "win32") {
|
||||
try {
|
||||
if ((this.httprequest.protocol == 6) && (require('win-terminal').PowerShellCapable() == true)) {
|
||||
this.httprequest._term = require('win-terminal').StartPowerShell(80, 25);
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
this.httprequest._term = require('win-terminal').Start(80, 25);
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
catch (e) {
|
||||
MeshServerLog('Failed to start remote terminal session, ' + e.toString() + ' (' + this.httprequest.remoteaddr + ')', this.httprequest);
|
||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
|
||||
this.end();
|
||||
|
@ -1116,14 +1097,11 @@ function createMeshCore(agent)
|
|||
this.httprequest._term.pipe(this, { dataTypeSkip: 1 });
|
||||
this.pipe(this.httprequest._term, { dataTypeSkip: 1, end: false });
|
||||
this.prependListener('end', function () { this.httprequest._term.end(function () { console.log('Terminal was closed'); }); });
|
||||
} else
|
||||
{
|
||||
if (fs.existsSync("/bin/bash"))
|
||||
{
|
||||
} else {
|
||||
if (fs.existsSync("/bin/bash")) {
|
||||
this.httprequest.process = childProcess.execFile("/bin/bash", ["bash", "-i"], { type: childProcess.SpawnTypes.TERM });
|
||||
if (process.platform == 'linux') { this.httprequest.process.stdin.write("alias ls='ls --color=auto'\nclear\n"); }
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
|
||||
if (process.platform == 'linux') { this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nPS1='\\u@\\h:\\w\\$ '\nclear\n"); }
|
||||
}
|
||||
|
@ -1176,8 +1154,7 @@ function createMeshCore(agent)
|
|||
this.removeAllListeners('data');
|
||||
this.on('data', onTunnelControlData);
|
||||
//this.write('MeshCore Terminal Hello');
|
||||
} else if (this.httprequest.protocol == 2)
|
||||
{
|
||||
} else if (this.httprequest.protocol == 2) {
|
||||
// Check user access rights for desktop
|
||||
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) {
|
||||
// Disengage this tunnel, user does not have the rights to do this!!
|
||||
|
@ -1209,7 +1186,7 @@ function createMeshCore(agent)
|
|||
if (this.desktop.kvm.connectionCount == 0) {
|
||||
// Display a toast message. This may not be supported on all platforms.
|
||||
// try { require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.'); } catch (ex) { }
|
||||
|
||||
|
||||
this.httprequest.desktop.kvm.end();
|
||||
}
|
||||
};
|
||||
|
@ -1225,8 +1202,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
|
||||
// Perform notification if needed. Toast messages may not be supported on all platforms.
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 8))
|
||||
{
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 8)) {
|
||||
// User Consent Prompt is required
|
||||
// Send a console message back using the console channel, "\n" is supported.
|
||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
|
||||
|
@ -1235,8 +1211,7 @@ function createMeshCore(agent)
|
|||
this.pause();
|
||||
|
||||
pr.then(
|
||||
function ()
|
||||
{
|
||||
function () {
|
||||
// Success
|
||||
MeshServerLog('Starting remote desktop after local user accepted (' + this.ws.httprequest.remoteaddr + ')', this.ws.httprequest);
|
||||
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
|
||||
|
@ -1247,15 +1222,13 @@ function createMeshCore(agent)
|
|||
this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
|
||||
this.ws.resume();
|
||||
},
|
||||
function (e)
|
||||
{
|
||||
function (e) {
|
||||
// User Consent Denied/Failed
|
||||
MeshServerLog('Failed to start remote desktop after local user rejected (' + this.ws.httprequest.remoteaddr + ')', this.ws.httprequest);
|
||||
this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// User Consent Prompt is not required
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 1)) {
|
||||
// User Notifications is required
|
||||
|
@ -1283,8 +1256,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
|
||||
// Perform notification if needed. Toast messages may not be supported on all platforms.
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 32))
|
||||
{
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 32)) {
|
||||
// User Consent Prompt is required
|
||||
// Send a console message back using the console channel, "\n" is supported.
|
||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
|
||||
|
@ -1361,7 +1333,7 @@ function createMeshCore(agent)
|
|||
var response = getDirectoryInfo(cmd.path);
|
||||
if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
|
||||
this.write(new Buffer(JSON.stringify(response)));
|
||||
|
||||
|
||||
/*
|
||||
// Start the directory watcher
|
||||
if ((cmd.path != '') && (samepath == false)) {
|
||||
|
@ -1479,6 +1451,23 @@ function createMeshCore(agent)
|
|||
// Unknown action, ignore it.
|
||||
break;
|
||||
}
|
||||
} else if (this.httprequest.protocol == 7) { // plugin data exchange
|
||||
var cmd = null;
|
||||
try { cmd = JSON.parse(data); } catch (e) { };
|
||||
if (cmd == null) { return; }
|
||||
if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
|
||||
if (cmd.action == undefined) return;
|
||||
|
||||
switch (cmd.action) {
|
||||
case 'plugin': {
|
||||
try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (e) { throw e; }
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// probably shouldn't happen, but just in case this feature is expanded
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
|
||||
}
|
||||
|
@ -1553,12 +1542,10 @@ function createMeshCore(agent)
|
|||
} else if (obj.type == 'webrtc0') { // Browser indicates we can start WebRTC switch-over.
|
||||
if (ws.httprequest.protocol == 1) { // Terminal
|
||||
// This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (process.platform == 'win32') {
|
||||
ws.httprequest._term.unpipe(ws);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ws.httprequest.process.stdout.unpipe(ws);
|
||||
ws.httprequest.process.stderr.unpipe(ws);
|
||||
}
|
||||
|
@ -1575,13 +1562,11 @@ function createMeshCore(agent)
|
|||
} else if (obj.type == 'webrtc1') {
|
||||
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
|
||||
// Switch the user input from websocket to webrtc at this point.
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (process.platform == 'win32') {
|
||||
ws.unpipe(ws.httprequest._term);
|
||||
ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ws.unpipe(ws.httprequest.process.stdin);
|
||||
ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
|
@ -1596,12 +1581,10 @@ function createMeshCore(agent)
|
|||
} else if (obj.type == 'webrtc2') {
|
||||
// Other side received websocket end of data marker, start sending data on WebRTC channel
|
||||
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (process.platform == 'win32') {
|
||||
ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
|
@ -1641,7 +1624,7 @@ function createMeshCore(agent)
|
|||
// Console state
|
||||
var consoleWebSockets = {};
|
||||
var consoleHttpRequest = null;
|
||||
|
||||
|
||||
// Console HTTP response
|
||||
function consoleHttpResponse(response) {
|
||||
response.data = function (data) { sendConsoleText(rstr2hex(buf2rstr(data)), this.sessionid); consoleHttpRequest = null; }
|
||||
|
@ -1684,7 +1667,7 @@ function createMeshCore(agent)
|
|||
var response = null;
|
||||
switch (cmd) {
|
||||
case 'help': { // Displays available commands
|
||||
var fin = '', f = '', availcommands = 'help,info,osinfo,args,print,type,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt';
|
||||
var fin = '', f = '', availcommands = 'help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt';
|
||||
availcommands = availcommands.split(',').sort();
|
||||
while (availcommands.length > 0) {
|
||||
if (f.length > 100) { fin += (f + ',\r\n'); f = ''; }
|
||||
|
@ -1802,7 +1785,7 @@ function createMeshCore(agent)
|
|||
case 'ps': {
|
||||
processManager.getProcesses(function (plist) {
|
||||
var x = '';
|
||||
for (var i in plist) { x += i + ', ' + plist[i].cmd + ((plist[i].user) ? (', ' + plist[i].user):'') + '\r\n'; }
|
||||
for (var i in plist) { x += i + ', ' + plist[i].cmd + ((plist[i].user) ? (', ' + plist[i].user) : '') + '\r\n'; }
|
||||
sendConsoleText(x, sessionid);
|
||||
});
|
||||
break;
|
||||
|
@ -1836,14 +1819,11 @@ function createMeshCore(agent)
|
|||
break;
|
||||
}
|
||||
case 'dump':
|
||||
if (args['_'].length < 1)
|
||||
{
|
||||
if (args['_'].length < 1) {
|
||||
response = 'Proper usage: dump [on/off/status]'; // Display correct command usage
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(args['_'][0].toLowerCase())
|
||||
{
|
||||
else {
|
||||
switch (args['_'][0].toLowerCase()) {
|
||||
case 'on':
|
||||
process.coreDumpLocation = process.platform == 'win32' ? process.execPath.replace('.exe', '.dmp') : (process.execPath + '.dmp');
|
||||
response = 'enabled';
|
||||
|
@ -1853,12 +1833,10 @@ function createMeshCore(agent)
|
|||
response = 'disabled';
|
||||
break;
|
||||
case 'status':
|
||||
if (process.coreDumpLocation)
|
||||
{
|
||||
if (process.coreDumpLocation) {
|
||||
response = 'Core Dump: [ENABLED' + (require('fs').existsSync(process.coreDumpLocation) ? (', (DMP file exists)]') : (']'));
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
response = 'Core Dump: [DISABLED]';
|
||||
}
|
||||
break;
|
||||
|
@ -1878,18 +1856,14 @@ function createMeshCore(agent)
|
|||
}
|
||||
case 'uninstallagent':
|
||||
var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
|
||||
if (!require('service-manager').manager.getService(agentName).isMe())
|
||||
{
|
||||
if (!require('service-manager').manager.getService(agentName).isMe()) {
|
||||
response = 'Uininstall failed, this instance is not the service instance';
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
else {
|
||||
try {
|
||||
diagnosticAgent_uninstall();
|
||||
}
|
||||
catch(x)
|
||||
{
|
||||
catch (x) {
|
||||
}
|
||||
var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
|
||||
this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true });
|
||||
|
@ -2068,7 +2042,7 @@ function createMeshCore(agent)
|
|||
if (httprequest != null) {
|
||||
httprequest.upgrade = onWebSocketUpgrade;
|
||||
httprequest.on('error', function (e) { sendConsoleText('ERROR: ' + JSON.stringify(e)); });
|
||||
|
||||
|
||||
var index = 1;
|
||||
while (consoleWebSockets[index]) { index++; }
|
||||
httprequest.sessionid = sessionid;
|
||||
|
@ -2256,40 +2230,31 @@ function createMeshCore(agent)
|
|||
}
|
||||
case 'diagnostic':
|
||||
{
|
||||
if (!mesh.DAIPC.listening)
|
||||
{
|
||||
if (!mesh.DAIPC.listening) {
|
||||
response = 'Unable to bind to Diagnostic IPC, most likely because the path (' + process.cwd() + ') is not on a local file system';
|
||||
break;
|
||||
}
|
||||
var diag = diagnosticAgent_installCheck();
|
||||
if (diag)
|
||||
{
|
||||
if (args['_'].length == 1 && args['_'][0] == 'uninstall')
|
||||
{
|
||||
if (diag) {
|
||||
if (args['_'].length == 1 && args['_'][0] == 'uninstall') {
|
||||
diagnosticAgent_uninstall();
|
||||
response = 'Diagnostic Agent uninstalled';
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
response = 'Diagnostic Agent installed at: ' + diag.appLocation();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args['_'].length == 1 && args['_'][0] == 'install')
|
||||
{
|
||||
else {
|
||||
if (args['_'].length == 1 && args['_'][0] == 'install') {
|
||||
diag = diagnosticAgent_installCheck(true);
|
||||
if (diag)
|
||||
{
|
||||
if (diag) {
|
||||
response = 'Diagnostic agent was installed at: ' + diag.appLocation();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
response = 'Diagnostic agent installation failed';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
response = 'Diagnostic Agent Not installed. To install: diagnostic install';
|
||||
}
|
||||
}
|
||||
|
@ -2297,27 +2262,27 @@ function createMeshCore(agent)
|
|||
break;
|
||||
}
|
||||
case 'apf': {
|
||||
if (meshCoreObj.intelamt!==null) {
|
||||
if (meshCoreObj.intelamt !== null) {
|
||||
if (args['_'].length == 1) {
|
||||
if (args['_'][0] == 'on') {
|
||||
response = 'Starting APF tunnel'
|
||||
var apfarg = {
|
||||
mpsurl: mesh.ServerUrl.replace('agent.ashx','apf.ashx'),
|
||||
mpsuser: Buffer.from(mesh.ServerInfo.MeshID,'hex').toString('base64').substring(0,16),
|
||||
mpspass: Buffer.from(mesh.ServerInfo.MeshID,'hex').toString('base64').substring(0,16),
|
||||
mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
|
||||
mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
|
||||
mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
|
||||
mpskeepalive: 60000,
|
||||
clientname: require('os').hostname(),
|
||||
clientaddress: '127.0.0.1',
|
||||
clientuuid: meshCoreObj.intelamt.uuid
|
||||
};
|
||||
var tobj = { debug: false }; //
|
||||
apftunnel= require('apfclient')(tobj,apfarg);
|
||||
apftunnel = require('apfclient')(tobj, apfarg);
|
||||
try {
|
||||
apftunnel.connect();
|
||||
response += "..success";
|
||||
} catch (e) {
|
||||
response += JSON.stringify(e);
|
||||
}
|
||||
}
|
||||
} else if (args['_'][0] == 'off') {
|
||||
response = 'Stopping APF tunnel';
|
||||
try {
|
||||
|
@ -2326,19 +2291,34 @@ function createMeshCore(agent)
|
|||
} catch (e) {
|
||||
response += JSON.stringify(e);
|
||||
}
|
||||
apftunnel=null;
|
||||
apftunnel = null;
|
||||
} else {
|
||||
response = 'Invalid command.\r\nCmd syntax: apf on|off';
|
||||
}
|
||||
} else {
|
||||
response = 'APF tunnel is '+ (apftunnel == null ? 'off': 'on' );
|
||||
} else {
|
||||
response = 'APF tunnel is ' + (apftunnel == null ? 'off' : 'on');
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
response = 'APF tunnel requires Intel AMT';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'plugin': {
|
||||
if (typeof args['_'][0] == 'string') {
|
||||
try {
|
||||
// Pass off the action to the plugin
|
||||
// for plugin creators, you'll want to have a plugindir/modules_meshcore/plugin.js
|
||||
// to control the output / actions here.
|
||||
response = require(args['_'][0]).consoleaction(args, rights, sessionid, mesh);
|
||||
} catch (e) {
|
||||
response = 'There was an error in the plugin (' + e + ')';
|
||||
}
|
||||
} else {
|
||||
response = 'Proper usage: plugin [pluginName] [args].';
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: { // This is an unknown command, return an error message
|
||||
response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
|
||||
break;
|
||||
|
@ -2347,7 +2327,7 @@ function createMeshCore(agent)
|
|||
} catch (e) { response = 'Command returned an exception error: ' + e; console.log(e); }
|
||||
if (response != null) { sendConsoleText(response, sessionid); }
|
||||
}
|
||||
|
||||
|
||||
// Send a mesh agent console command
|
||||
function sendConsoleText(text, sessionid) {
|
||||
if (typeof text == 'object') { text = JSON.stringify(text); }
|
||||
|
@ -2356,7 +2336,7 @@ function createMeshCore(agent)
|
|||
|
||||
// Called before the process exits
|
||||
//process.exit = function (code) { console.log("Exit with code: " + code.toString()); }
|
||||
|
||||
|
||||
// Called when the server connection state changes
|
||||
function handleServerConnection(state) {
|
||||
meshServerConnectionState = state;
|
||||
|
@ -2381,13 +2361,13 @@ function createMeshCore(agent)
|
|||
if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 1200000); } // 20 minutes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update the server with the latest network interface information
|
||||
var sendNetworkUpdateNagleTimer = null;
|
||||
function sendNetworkUpdateNagle() { if (sendNetworkUpdateNagleTimer != null) { clearTimeout(sendNetworkUpdateNagleTimer); sendNetworkUpdateNagleTimer = null; } sendNetworkUpdateNagleTimer = setTimeout(sendNetworkUpdate, 5000); }
|
||||
function sendNetworkUpdate(force) {
|
||||
sendNetworkUpdateNagleTimer = null;
|
||||
|
||||
|
||||
// Update the network interfaces information data
|
||||
var netInfo = mesh.NetInfo;
|
||||
if (netInfo) {
|
||||
|
@ -2396,7 +2376,7 @@ function createMeshCore(agent)
|
|||
if ((force == true) || (clearGatewayMac(netInfoStr) != clearGatewayMac(lastNetworkInfo))) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Called periodically to check if we need to send updates to the server
|
||||
function sendPeriodicServerUpdate(flags) {
|
||||
if (meshServerConnectionState == 0) return; // Not connected to server, do nothing.
|
||||
|
@ -2451,8 +2431,10 @@ function createMeshCore(agent)
|
|||
//if (process.platform == 'win32') { try { pr = require('win-info').pendingReboot(); } catch (ex) { pr = null; } } // Pending reboot
|
||||
if ((meshCoreObj.av == null) || (JSON.stringify(meshCoreObj.av) != JSON.stringify(av))) { meshCoreObj.av = av; mesh.SendCommand(meshCoreObj); }
|
||||
}
|
||||
|
||||
// TODO: add plugin hook here
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Starting function
|
||||
obj.start = function () {
|
||||
|
@ -2485,16 +2467,16 @@ function createMeshCore(agent)
|
|||
//userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
|
||||
} catch (ex) { }
|
||||
}
|
||||
|
||||
|
||||
obj.stop = function () {
|
||||
mesh.AddCommandHandler(null);
|
||||
mesh.AddConnectHandler(null);
|
||||
}
|
||||
|
||||
|
||||
function onWebSocketClosed() { sendConsoleText("WebSocket #" + this.httprequest.index + " closed.", this.httprequest.sessionid); delete consoleWebSockets[this.httprequest.index]; }
|
||||
function onWebSocketData(data) { sendConsoleText("Got WebSocket #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid); }
|
||||
function onWebSocketSendOk() { sendConsoleText("WebSocket #" + this.index + " SendOK.", this.sessionid); }
|
||||
|
||||
|
||||
function onWebSocketUpgrade(response, s, head) {
|
||||
sendConsoleText("WebSocket #" + this.index + " connected.", this.sessionid);
|
||||
this.s = s;
|
||||
|
|
351
agents/meshcore.min.js
vendored
351
agents/meshcore.min.js
vendored
|
@ -37,12 +37,10 @@ var MESHRIGHT_NOFILES = 1024;
|
|||
var MESHRIGHT_NOAMT = 2048;
|
||||
var MESHRIGHT_LIMITEDINPUT = 4096;
|
||||
|
||||
function createMeshCore(agent)
|
||||
{
|
||||
function createMeshCore(agent) {
|
||||
var obj = {};
|
||||
|
||||
if (process.platform == 'darwin' && !process.versions)
|
||||
{
|
||||
if (process.platform == 'darwin' && !process.versions) {
|
||||
// This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = '';
|
||||
|
@ -51,21 +49,18 @@ function createMeshCore(agent)
|
|||
child.stdin.write(" if(c[1]==\"dict\"){ split(a[2], d, \"</dict>\"); if(split(d[1], truval, \"<true/>\")>1) { split(truval[1], kn1, \"<key>\"); split(kn1[2], kn2, \"</key>\"); print kn2[1]; } }");
|
||||
child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
|
||||
child.waitExit();
|
||||
if (child.stdout.str.trim() == 'Crashed')
|
||||
{
|
||||
if (child.stdout.str.trim() == 'Crashed') {
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = '';
|
||||
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
|
||||
child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
|
||||
child.waitExit();
|
||||
|
||||
if (parseInt(child.stdout.str.trim()) == process.pid)
|
||||
{
|
||||
if (parseInt(child.stdout.str.trim()) == process.pid) {
|
||||
// The currently running MeshAgent is us, so we can continue with the update
|
||||
var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
|
||||
var tokens = plist.split('<key>KeepAlive</key>');
|
||||
if (tokens[1].split('>')[0].split('<')[1] == 'dict')
|
||||
{
|
||||
if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
|
||||
var tmp = tokens[1].split('</dict>');
|
||||
tmp.shift();
|
||||
tokens[1] = '\n <true/>' + tmp.join('</dict>');
|
||||
|
@ -125,10 +120,8 @@ function createMeshCore(agent)
|
|||
if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (ee) { } }
|
||||
obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
|
||||
try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH }); } catch (e) { }
|
||||
obj.DAIPC.on('connection', function (c)
|
||||
{
|
||||
c._send = function (j)
|
||||
{
|
||||
obj.DAIPC.on('connection', function (c) {
|
||||
c._send = function (j) {
|
||||
var data = JSON.stringify(j);
|
||||
var packet = Buffer.alloc(data.length + 4);
|
||||
packet.writeUInt32LE(data.length + 4, 0);
|
||||
|
@ -138,32 +131,26 @@ function createMeshCore(agent)
|
|||
this._daipc = c;
|
||||
c.parent = this;
|
||||
c.on('end', function () { console.log('Connection Closed'); this.parent._daipc = null; });
|
||||
c.on('data', function (chunk)
|
||||
{
|
||||
c.on('data', function (chunk) {
|
||||
if (chunk.length < 4) { this.unshift(chunk); return; }
|
||||
var len = chunk.readUInt32LE(0);
|
||||
if (len > 8192) { this.parent._daipc = null; this.end(); return; }
|
||||
if (chunk.length < len) { this.unshift(chunk); return; }
|
||||
|
||||
|
||||
var data = chunk.slice(4, len);
|
||||
try
|
||||
{
|
||||
try {
|
||||
data = JSON.parse(data.toString());
|
||||
}
|
||||
catch(de)
|
||||
{
|
||||
catch (de) {
|
||||
this.parent._daipc = null; this.end(); return;
|
||||
}
|
||||
|
||||
|
||||
if (!data.cmd) { this.parent._daipc = null; this.end(); return; }
|
||||
|
||||
try
|
||||
{
|
||||
switch(data.cmd)
|
||||
{
|
||||
try {
|
||||
switch (data.cmd) {
|
||||
case 'query':
|
||||
switch(data.value)
|
||||
{
|
||||
switch (data.value) {
|
||||
case 'connection':
|
||||
data.result = require('MeshAgent').ConnectedServer;
|
||||
this._send(data);
|
||||
|
@ -176,32 +163,26 @@ function createMeshCore(agent)
|
|||
return;
|
||||
}
|
||||
}
|
||||
catch(xe)
|
||||
{
|
||||
catch (xe) {
|
||||
this.parent._daipc = null; this.end(); return;
|
||||
}
|
||||
});
|
||||
});
|
||||
function diagnosticAgent_uninstall()
|
||||
{
|
||||
function diagnosticAgent_uninstall() {
|
||||
require('service-manager').manager.uninstallService('meshagentDiagnostic');
|
||||
require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
|
||||
};
|
||||
function diagnosticAgent_installCheck(install)
|
||||
{
|
||||
try
|
||||
{
|
||||
function diagnosticAgent_installCheck(install) {
|
||||
try {
|
||||
var diag = require('service-manager').manager.getService('meshagentDiagnostic');
|
||||
return (diag);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
catch (e) {
|
||||
}
|
||||
if (!install) { return (null); }
|
||||
|
||||
var svc = null;
|
||||
try
|
||||
{
|
||||
try {
|
||||
require('service-manager').manager.installService(
|
||||
{
|
||||
name: 'meshagentDiagnostic',
|
||||
|
@ -213,8 +194,7 @@ function createMeshCore(agent)
|
|||
});
|
||||
svc = require('service-manager').manager.getService('meshagentDiagnostic');
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
catch (e) {
|
||||
return (null);
|
||||
}
|
||||
var proxyConfig = require('global-tunnel').proxyConfig;
|
||||
|
@ -227,12 +207,10 @@ function createMeshCore(agent)
|
|||
ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
|
||||
if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
|
||||
if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
|
||||
if (proxyConfig)
|
||||
{
|
||||
if (proxyConfig) {
|
||||
ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ddb.Put('ignoreProxyFile', '1');
|
||||
}
|
||||
|
||||
|
@ -242,7 +220,7 @@ function createMeshCore(agent)
|
|||
delete ddb;
|
||||
|
||||
// Set a recurrent task, to run the Diagnostic Agent every 2 days
|
||||
require('task-scheduler').create({name: 'meshagentDiagnostic/periodicStart', daily: 2, time: require('tls').generateRandomInteger('0', '23') + ':' + require('tls').generateRandomInteger('0', '59').padStart(2, '0'), service: 'meshagentDiagnostic'});
|
||||
require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: 2, time: require('tls').generateRandomInteger('0', '23') + ':' + require('tls').generateRandomInteger('0', '59').padStart(2, '0'), service: 'meshagentDiagnostic' });
|
||||
//require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
|
||||
|
||||
return (svc);
|
||||
|
@ -281,7 +259,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
obj.borderManager = new borderController();
|
||||
*/
|
||||
|
||||
|
||||
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
|
||||
var meshCoreObj = { "action": "coreinfo", "value": "MeshCore v6", "caps": 14 }; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript, 32 = Temporary Agent, 64 = Recovery Agent
|
||||
|
||||
|
@ -397,7 +375,7 @@ function createMeshCore(agent)
|
|||
});
|
||||
}
|
||||
} catch (ex) { sendConsoleText("ex1: " + ex); }
|
||||
|
||||
|
||||
// Try to load up the WIFI scanner
|
||||
try {
|
||||
var wifiScannerLib = require('wifi-scanner');
|
||||
|
@ -436,7 +414,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
catch (e) { return false; }
|
||||
}
|
||||
|
||||
|
||||
// Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
|
||||
function clearGatewayMac(str) {
|
||||
if (str == null) return null;
|
||||
|
@ -444,7 +422,7 @@ function createMeshCore(agent)
|
|||
for (var i in x.netif) { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } }
|
||||
return JSON.stringify(x);
|
||||
}
|
||||
|
||||
|
||||
function getIpLocationData(func) {
|
||||
// Get the location information for the cache if possible
|
||||
var publicLocationInfo = db.Get('publicLocationInfo');
|
||||
|
@ -483,7 +461,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Polyfill String.endsWith
|
||||
if (!String.prototype.endsWith) {
|
||||
String.prototype.endsWith = function (searchString, position) {
|
||||
|
@ -494,7 +472,7 @@ function createMeshCore(agent)
|
|||
return lastIndex !== -1 && lastIndex === position;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Polyfill path.join
|
||||
obj.path = {
|
||||
join: function () {
|
||||
|
@ -513,19 +491,19 @@ function createMeshCore(agent)
|
|||
return x.join('/');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 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 '';
|
||||
|
@ -533,7 +511,7 @@ function createMeshCore(agent)
|
|||
while (t = m.shift()) r += String.fromCharCode('0x' + t);
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
// Convert an object to string with all functions
|
||||
function objToString(x, p, pad, ret) {
|
||||
if (ret == undefined) ret = '';
|
||||
|
@ -548,17 +526,17 @@ function createMeshCore(agent)
|
|||
for (var i in x) { if (i != '_ObjectID') { r += (addPad(p + 2, pad) + i + ': ' + objToString(x[i], p + 2, pad, ret) + (ret ? '\r\n' : ' ')); } }
|
||||
return r + addPad(p, pad) + '}';
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
|
@ -574,7 +552,7 @@ function createMeshCore(agent)
|
|||
if (current != null) { results[current] = true; }
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
// Get server target url with a custom path
|
||||
function getServerTargetUrl(path) {
|
||||
var x = mesh.ServerUrl;
|
||||
|
@ -585,13 +563,13 @@ function createMeshCore(agent)
|
|||
if (x == null) return null;
|
||||
return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
|
||||
}
|
||||
|
||||
|
||||
// Get server url. If the url starts with "*/..." change it, it not use the url as is.
|
||||
function getServerTargetUrlEx(url) {
|
||||
if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
// Send a wake-on-lan packet
|
||||
function sendWakeOnLan(hexMac) {
|
||||
var count = 0;
|
||||
|
@ -600,7 +578,7 @@ function createMeshCore(agent)
|
|||
var magic = 'FFFFFFFFFFFF';
|
||||
for (var x = 1; x <= 16; ++x) { magic += hexMac; }
|
||||
var magicbin = Buffer.from(magic, 'hex');
|
||||
|
||||
|
||||
for (var adapter in interfaces) {
|
||||
if (interfaces.hasOwnProperty(adapter)) {
|
||||
for (var i = 0; i < interfaces[adapter].length; ++i) {
|
||||
|
@ -618,7 +596,7 @@ function createMeshCore(agent)
|
|||
} catch (e) { }
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// Handle a mesh agent command
|
||||
function handleServerCommand(data) {
|
||||
if (typeof data == 'object') {
|
||||
|
@ -722,7 +700,7 @@ function createMeshCore(agent)
|
|||
// Open a local web browser and return success/fail
|
||||
MeshServerLog('Opening: ' + data.url, data);
|
||||
sendConsoleText('OpenURL: ' + data.url);
|
||||
if (data.url) { mesh.SendCommand({ "action": "msg", "type":"openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
|
||||
if (data.url) { mesh.SendCommand({ "action": "msg", "type": "openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
|
||||
break;
|
||||
}
|
||||
case 'getclip': {
|
||||
|
@ -834,11 +812,10 @@ function createMeshCore(agent)
|
|||
case 'plugin': {
|
||||
if (typeof data.pluginaction == 'string') {
|
||||
try {
|
||||
|
||||
MeshServerLog('Plugin called', data);
|
||||
/* Not yet implmented
|
||||
require(data.plugin.name).serveraction(data);*/
|
||||
} catch(e) {
|
||||
// Not yet implemented
|
||||
// require(data.plugin.name).serveraction(data);
|
||||
} catch (e) {
|
||||
MeshServerLog('Error calling plugin', data);
|
||||
}
|
||||
}
|
||||
|
@ -850,7 +827,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Called when a file changed in the file system
|
||||
/*
|
||||
function onFileWatcher(a, b) {
|
||||
|
@ -902,8 +879,8 @@ function createMeshCore(agent)
|
|||
pr.then(defragResult, defragResult);
|
||||
} else {
|
||||
*/
|
||||
results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
|
||||
func(results);
|
||||
results.hash = require('SHA384Stream').create().syncHash(JSON.stringify(results)).toString('hex');
|
||||
func(results);
|
||||
//}
|
||||
} catch (ex) { func(null, ex); }
|
||||
}
|
||||
|
@ -947,7 +924,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
// Tunnel callback operations
|
||||
function onTunnelUpgrade(response, s, head) {
|
||||
this.s = s;
|
||||
|
@ -1003,7 +980,7 @@ function createMeshCore(agent)
|
|||
peerTunnel.s.first = true;
|
||||
peerTunnel.s.resume();
|
||||
}
|
||||
|
||||
|
||||
// Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
|
||||
function onTcpRelayServerTunnelData(data) {
|
||||
if (this.first == true) { this.first = false; this.pipe(this.tcprelay); } // Pipe Server --> Target
|
||||
|
@ -1013,7 +990,7 @@ function createMeshCore(agent)
|
|||
if (tunnels[this.httprequest.index] == null) return; // Stop duplicate calls.
|
||||
//sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
|
||||
delete tunnels[this.httprequest.index];
|
||||
|
||||
|
||||
/*
|
||||
// Close the watcher if required
|
||||
if (this.httprequest.watcher != undefined) {
|
||||
|
@ -1045,7 +1022,7 @@ function createMeshCore(agent)
|
|||
function onTunnelData(data) {
|
||||
//console.log("OnTunnelData");
|
||||
//sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
|
||||
|
||||
|
||||
// If this is upload data, save it to file
|
||||
if (this.httprequest.uploadFile) {
|
||||
try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { this.write(new Buffer(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
|
||||
|
@ -1082,17 +1059,14 @@ function createMeshCore(agent)
|
|||
return;
|
||||
}
|
||||
|
||||
this.end = function ()
|
||||
{
|
||||
if (process.platform == "win32")
|
||||
{
|
||||
this.end = function () {
|
||||
if (process.platform == "win32") {
|
||||
// Unpipe the web socket
|
||||
this.unpipe(this.httprequest._term);
|
||||
if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
|
||||
|
||||
// Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
|
||||
if (this.rtcchannel)
|
||||
{
|
||||
if (this.rtcchannel) {
|
||||
this.rtcchannel.unpipe(this.httprequest._term);
|
||||
if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
|
||||
}
|
||||
|
@ -1100,27 +1074,21 @@ function createMeshCore(agent)
|
|||
// Clean up
|
||||
if (this.httprequest._term) { this.httprequest._term.end(); }
|
||||
this.httprequest._term = null;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
// TODO!!
|
||||
}
|
||||
};
|
||||
|
||||
// Remote terminal using native pipes
|
||||
if (process.platform == "win32")
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((this.httprequest.protocol == 6) && (require('win-terminal').PowerShellCapable() == true))
|
||||
{
|
||||
if (process.platform == "win32") {
|
||||
try {
|
||||
if ((this.httprequest.protocol == 6) && (require('win-terminal').PowerShellCapable() == true)) {
|
||||
this.httprequest._term = require('win-terminal').StartPowerShell(80, 25);
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
this.httprequest._term = require('win-terminal').Start(80, 25);
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
catch (e) {
|
||||
MeshServerLog('Failed to start remote terminal session, ' + e.toString() + ' (' + this.httprequest.remoteaddr + ')', this.httprequest);
|
||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
|
||||
this.end();
|
||||
|
@ -1129,14 +1097,11 @@ function createMeshCore(agent)
|
|||
this.httprequest._term.pipe(this, { dataTypeSkip: 1 });
|
||||
this.pipe(this.httprequest._term, { dataTypeSkip: 1, end: false });
|
||||
this.prependListener('end', function () { this.httprequest._term.end(function () { console.log('Terminal was closed'); }); });
|
||||
} else
|
||||
{
|
||||
if (fs.existsSync("/bin/bash"))
|
||||
{
|
||||
} else {
|
||||
if (fs.existsSync("/bin/bash")) {
|
||||
this.httprequest.process = childProcess.execFile("/bin/bash", ["bash", "-i"], { type: childProcess.SpawnTypes.TERM });
|
||||
if (process.platform == 'linux') { this.httprequest.process.stdin.write("alias ls='ls --color=auto'\nclear\n"); }
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
|
||||
if (process.platform == 'linux') { this.httprequest.process.stdin.write("stty erase ^H\nalias ls='ls --color=auto'\nPS1='\\u@\\h:\\w\\$ '\nclear\n"); }
|
||||
}
|
||||
|
@ -1189,8 +1154,7 @@ function createMeshCore(agent)
|
|||
this.removeAllListeners('data');
|
||||
this.on('data', onTunnelControlData);
|
||||
//this.write('MeshCore Terminal Hello');
|
||||
} else if (this.httprequest.protocol == 2)
|
||||
{
|
||||
} else if (this.httprequest.protocol == 2) {
|
||||
// Check user access rights for desktop
|
||||
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) {
|
||||
// Disengage this tunnel, user does not have the rights to do this!!
|
||||
|
@ -1222,7 +1186,7 @@ function createMeshCore(agent)
|
|||
if (this.desktop.kvm.connectionCount == 0) {
|
||||
// Display a toast message. This may not be supported on all platforms.
|
||||
// try { require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.'); } catch (ex) { }
|
||||
|
||||
|
||||
this.httprequest.desktop.kvm.end();
|
||||
}
|
||||
};
|
||||
|
@ -1238,8 +1202,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
|
||||
// Perform notification if needed. Toast messages may not be supported on all platforms.
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 8))
|
||||
{
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 8)) {
|
||||
// User Consent Prompt is required
|
||||
// Send a console message back using the console channel, "\n" is supported.
|
||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
|
||||
|
@ -1248,8 +1211,7 @@ function createMeshCore(agent)
|
|||
this.pause();
|
||||
|
||||
pr.then(
|
||||
function ()
|
||||
{
|
||||
function () {
|
||||
// Success
|
||||
MeshServerLog('Starting remote desktop after local user accepted (' + this.ws.httprequest.remoteaddr + ')', this.ws.httprequest);
|
||||
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
|
||||
|
@ -1260,15 +1222,13 @@ function createMeshCore(agent)
|
|||
this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
|
||||
this.ws.resume();
|
||||
},
|
||||
function (e)
|
||||
{
|
||||
function (e) {
|
||||
// User Consent Denied/Failed
|
||||
MeshServerLog('Failed to start remote desktop after local user rejected (' + this.ws.httprequest.remoteaddr + ')', this.ws.httprequest);
|
||||
this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// User Consent Prompt is not required
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 1)) {
|
||||
// User Notifications is required
|
||||
|
@ -1296,8 +1256,7 @@ function createMeshCore(agent)
|
|||
}
|
||||
|
||||
// Perform notification if needed. Toast messages may not be supported on all platforms.
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 32))
|
||||
{
|
||||
if (this.httprequest.consent && (this.httprequest.consent & 32)) {
|
||||
// User Consent Prompt is required
|
||||
// Send a console message back using the console channel, "\n" is supported.
|
||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
|
||||
|
@ -1374,7 +1333,7 @@ function createMeshCore(agent)
|
|||
var response = getDirectoryInfo(cmd.path);
|
||||
if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
|
||||
this.write(new Buffer(JSON.stringify(response)));
|
||||
|
||||
|
||||
/*
|
||||
// Start the directory watcher
|
||||
if ((cmd.path != '') && (samepath == false)) {
|
||||
|
@ -1493,25 +1452,22 @@ function createMeshCore(agent)
|
|||
break;
|
||||
}
|
||||
} else if (this.httprequest.protocol == 7) { // plugin data exchange
|
||||
var cmd = null;
|
||||
try { cmd = JSON.parse(data); } catch (e) { };
|
||||
if (cmd == null) { return; }
|
||||
if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
|
||||
if (cmd.action == undefined) { return; }
|
||||
var cmd = null;
|
||||
try { cmd = JSON.parse(data); } catch (e) { };
|
||||
if (cmd == null) { return; }
|
||||
if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
|
||||
if (cmd.action == undefined) return;
|
||||
|
||||
switch (cmd.action) {
|
||||
case 'plugin': {
|
||||
try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (e) { throw e; }
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// probably shouldn't happen, but just in case this feature is expanded
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd.action) {
|
||||
case 'plugin': {
|
||||
try {
|
||||
require(cmd.plugin).consoleaction(cmd, null, null, this);
|
||||
} catch (e) { throw e; }
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// probably shouldn't happen, but just in case this feature is expanded
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
|
||||
}
|
||||
|
@ -1586,12 +1542,10 @@ function createMeshCore(agent)
|
|||
} else if (obj.type == 'webrtc0') { // Browser indicates we can start WebRTC switch-over.
|
||||
if (ws.httprequest.protocol == 1) { // Terminal
|
||||
// This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (process.platform == 'win32') {
|
||||
ws.httprequest._term.unpipe(ws);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ws.httprequest.process.stdout.unpipe(ws);
|
||||
ws.httprequest.process.stderr.unpipe(ws);
|
||||
}
|
||||
|
@ -1608,13 +1562,11 @@ function createMeshCore(agent)
|
|||
} else if (obj.type == 'webrtc1') {
|
||||
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
|
||||
// Switch the user input from websocket to webrtc at this point.
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (process.platform == 'win32') {
|
||||
ws.unpipe(ws.httprequest._term);
|
||||
ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ws.unpipe(ws.httprequest.process.stdin);
|
||||
ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
|
@ -1629,12 +1581,10 @@ function createMeshCore(agent)
|
|||
} else if (obj.type == 'webrtc2') {
|
||||
// Other side received websocket end of data marker, start sending data on WebRTC channel
|
||||
if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (process.platform == 'win32') {
|
||||
ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
|
||||
}
|
||||
|
@ -1674,7 +1624,7 @@ function createMeshCore(agent)
|
|||
// Console state
|
||||
var consoleWebSockets = {};
|
||||
var consoleHttpRequest = null;
|
||||
|
||||
|
||||
// Console HTTP response
|
||||
function consoleHttpResponse(response) {
|
||||
response.data = function (data) { sendConsoleText(rstr2hex(buf2rstr(data)), this.sessionid); consoleHttpRequest = null; }
|
||||
|
@ -1835,7 +1785,7 @@ function createMeshCore(agent)
|
|||
case 'ps': {
|
||||
processManager.getProcesses(function (plist) {
|
||||
var x = '';
|
||||
for (var i in plist) { x += i + ', ' + plist[i].cmd + ((plist[i].user) ? (', ' + plist[i].user):'') + '\r\n'; }
|
||||
for (var i in plist) { x += i + ', ' + plist[i].cmd + ((plist[i].user) ? (', ' + plist[i].user) : '') + '\r\n'; }
|
||||
sendConsoleText(x, sessionid);
|
||||
});
|
||||
break;
|
||||
|
@ -1869,14 +1819,11 @@ function createMeshCore(agent)
|
|||
break;
|
||||
}
|
||||
case 'dump':
|
||||
if (args['_'].length < 1)
|
||||
{
|
||||
if (args['_'].length < 1) {
|
||||
response = 'Proper usage: dump [on/off/status]'; // Display correct command usage
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(args['_'][0].toLowerCase())
|
||||
{
|
||||
else {
|
||||
switch (args['_'][0].toLowerCase()) {
|
||||
case 'on':
|
||||
process.coreDumpLocation = process.platform == 'win32' ? process.execPath.replace('.exe', '.dmp') : (process.execPath + '.dmp');
|
||||
response = 'enabled';
|
||||
|
@ -1886,12 +1833,10 @@ function createMeshCore(agent)
|
|||
response = 'disabled';
|
||||
break;
|
||||
case 'status':
|
||||
if (process.coreDumpLocation)
|
||||
{
|
||||
if (process.coreDumpLocation) {
|
||||
response = 'Core Dump: [ENABLED' + (require('fs').existsSync(process.coreDumpLocation) ? (', (DMP file exists)]') : (']'));
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
response = 'Core Dump: [DISABLED]';
|
||||
}
|
||||
break;
|
||||
|
@ -1911,18 +1856,14 @@ function createMeshCore(agent)
|
|||
}
|
||||
case 'uninstallagent':
|
||||
var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
|
||||
if (!require('service-manager').manager.getService(agentName).isMe())
|
||||
{
|
||||
if (!require('service-manager').manager.getService(agentName).isMe()) {
|
||||
response = 'Uininstall failed, this instance is not the service instance';
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
else {
|
||||
try {
|
||||
diagnosticAgent_uninstall();
|
||||
}
|
||||
catch(x)
|
||||
{
|
||||
catch (x) {
|
||||
}
|
||||
var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
|
||||
this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true });
|
||||
|
@ -2101,7 +2042,7 @@ function createMeshCore(agent)
|
|||
if (httprequest != null) {
|
||||
httprequest.upgrade = onWebSocketUpgrade;
|
||||
httprequest.on('error', function (e) { sendConsoleText('ERROR: ' + JSON.stringify(e)); });
|
||||
|
||||
|
||||
var index = 1;
|
||||
while (consoleWebSockets[index]) { index++; }
|
||||
httprequest.sessionid = sessionid;
|
||||
|
@ -2289,40 +2230,31 @@ function createMeshCore(agent)
|
|||
}
|
||||
case 'diagnostic':
|
||||
{
|
||||
if (!mesh.DAIPC.listening)
|
||||
{
|
||||
if (!mesh.DAIPC.listening) {
|
||||
response = 'Unable to bind to Diagnostic IPC, most likely because the path (' + process.cwd() + ') is not on a local file system';
|
||||
break;
|
||||
}
|
||||
var diag = diagnosticAgent_installCheck();
|
||||
if (diag)
|
||||
{
|
||||
if (args['_'].length == 1 && args['_'][0] == 'uninstall')
|
||||
{
|
||||
if (diag) {
|
||||
if (args['_'].length == 1 && args['_'][0] == 'uninstall') {
|
||||
diagnosticAgent_uninstall();
|
||||
response = 'Diagnostic Agent uninstalled';
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
response = 'Diagnostic Agent installed at: ' + diag.appLocation();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args['_'].length == 1 && args['_'][0] == 'install')
|
||||
{
|
||||
else {
|
||||
if (args['_'].length == 1 && args['_'][0] == 'install') {
|
||||
diag = diagnosticAgent_installCheck(true);
|
||||
if (diag)
|
||||
{
|
||||
if (diag) {
|
||||
response = 'Diagnostic agent was installed at: ' + diag.appLocation();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
response = 'Diagnostic agent installation failed';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
response = 'Diagnostic Agent Not installed. To install: diagnostic install';
|
||||
}
|
||||
}
|
||||
|
@ -2330,27 +2262,27 @@ function createMeshCore(agent)
|
|||
break;
|
||||
}
|
||||
case 'apf': {
|
||||
if (meshCoreObj.intelamt!==null) {
|
||||
if (meshCoreObj.intelamt !== null) {
|
||||
if (args['_'].length == 1) {
|
||||
if (args['_'][0] == 'on') {
|
||||
response = 'Starting APF tunnel'
|
||||
var apfarg = {
|
||||
mpsurl: mesh.ServerUrl.replace('agent.ashx','apf.ashx'),
|
||||
mpsuser: Buffer.from(mesh.ServerInfo.MeshID,'hex').toString('base64').substring(0,16),
|
||||
mpspass: Buffer.from(mesh.ServerInfo.MeshID,'hex').toString('base64').substring(0,16),
|
||||
mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
|
||||
mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
|
||||
mpspass: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
|
||||
mpskeepalive: 60000,
|
||||
clientname: require('os').hostname(),
|
||||
clientaddress: '127.0.0.1',
|
||||
clientuuid: meshCoreObj.intelamt.uuid
|
||||
};
|
||||
var tobj = { debug: false }; //
|
||||
apftunnel= require('apfclient')(tobj,apfarg);
|
||||
apftunnel = require('apfclient')(tobj, apfarg);
|
||||
try {
|
||||
apftunnel.connect();
|
||||
response += "..success";
|
||||
} catch (e) {
|
||||
response += JSON.stringify(e);
|
||||
}
|
||||
}
|
||||
} else if (args['_'][0] == 'off') {
|
||||
response = 'Stopping APF tunnel';
|
||||
try {
|
||||
|
@ -2359,14 +2291,14 @@ function createMeshCore(agent)
|
|||
} catch (e) {
|
||||
response += JSON.stringify(e);
|
||||
}
|
||||
apftunnel=null;
|
||||
apftunnel = null;
|
||||
} else {
|
||||
response = 'Invalid command.\r\nCmd syntax: apf on|off';
|
||||
}
|
||||
} else {
|
||||
response = 'APF tunnel is '+ (apftunnel == null ? 'off': 'on' );
|
||||
} else {
|
||||
response = 'APF tunnel is ' + (apftunnel == null ? 'off' : 'on');
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
response = 'APF tunnel requires Intel AMT';
|
||||
}
|
||||
|
@ -2375,17 +2307,16 @@ function createMeshCore(agent)
|
|||
case 'plugin': {
|
||||
if (typeof args['_'][0] == 'string') {
|
||||
try {
|
||||
// pass off the action to the plugin
|
||||
// Pass off the action to the plugin
|
||||
// for plugin creators, you'll want to have a plugindir/modules_meshcore/plugin.js
|
||||
// to control the output / actions here.
|
||||
response = require(args['_'][0]).consoleaction(args, rights, sessionid, mesh);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
response = 'There was an error in the plugin (' + e + ')';
|
||||
}
|
||||
} else {
|
||||
response = 'Proper usage: plugin [pluginName] [args].';
|
||||
response = 'Proper usage: plugin [pluginName] [args].';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: { // This is an unknown command, return an error message
|
||||
|
@ -2396,7 +2327,7 @@ function createMeshCore(agent)
|
|||
} catch (e) { response = 'Command returned an exception error: ' + e; console.log(e); }
|
||||
if (response != null) { sendConsoleText(response, sessionid); }
|
||||
}
|
||||
|
||||
|
||||
// Send a mesh agent console command
|
||||
function sendConsoleText(text, sessionid) {
|
||||
if (typeof text == 'object') { text = JSON.stringify(text); }
|
||||
|
@ -2405,7 +2336,7 @@ function createMeshCore(agent)
|
|||
|
||||
// Called before the process exits
|
||||
//process.exit = function (code) { console.log("Exit with code: " + code.toString()); }
|
||||
|
||||
|
||||
// Called when the server connection state changes
|
||||
function handleServerConnection(state) {
|
||||
meshServerConnectionState = state;
|
||||
|
@ -2430,13 +2361,13 @@ function createMeshCore(agent)
|
|||
if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 1200000); } // 20 minutes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update the server with the latest network interface information
|
||||
var sendNetworkUpdateNagleTimer = null;
|
||||
function sendNetworkUpdateNagle() { if (sendNetworkUpdateNagleTimer != null) { clearTimeout(sendNetworkUpdateNagleTimer); sendNetworkUpdateNagleTimer = null; } sendNetworkUpdateNagleTimer = setTimeout(sendNetworkUpdate, 5000); }
|
||||
function sendNetworkUpdate(force) {
|
||||
sendNetworkUpdateNagleTimer = null;
|
||||
|
||||
|
||||
// Update the network interfaces information data
|
||||
var netInfo = mesh.NetInfo;
|
||||
if (netInfo) {
|
||||
|
@ -2445,7 +2376,7 @@ function createMeshCore(agent)
|
|||
if ((force == true) || (clearGatewayMac(netInfoStr) != clearGatewayMac(lastNetworkInfo))) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Called periodically to check if we need to send updates to the server
|
||||
function sendPeriodicServerUpdate(flags) {
|
||||
if (meshServerConnectionState == 0) return; // Not connected to server, do nothing.
|
||||
|
@ -2500,10 +2431,10 @@ function createMeshCore(agent)
|
|||
//if (process.platform == 'win32') { try { pr = require('win-info').pendingReboot(); } catch (ex) { pr = null; } } // Pending reboot
|
||||
if ((meshCoreObj.av == null) || (JSON.stringify(meshCoreObj.av) != JSON.stringify(av))) { meshCoreObj.av = av; mesh.SendCommand(meshCoreObj); }
|
||||
}
|
||||
|
||||
|
||||
// TODO: add plugin hook here
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Starting function
|
||||
obj.start = function () {
|
||||
|
@ -2536,16 +2467,16 @@ function createMeshCore(agent)
|
|||
//userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
|
||||
} catch (ex) { }
|
||||
}
|
||||
|
||||
|
||||
obj.stop = function () {
|
||||
mesh.AddCommandHandler(null);
|
||||
mesh.AddConnectHandler(null);
|
||||
}
|
||||
|
||||
|
||||
function onWebSocketClosed() { sendConsoleText("WebSocket #" + this.httprequest.index + " closed.", this.httprequest.sessionid); delete consoleWebSockets[this.httprequest.index]; }
|
||||
function onWebSocketData(data) { sendConsoleText("Got WebSocket #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid); }
|
||||
function onWebSocketSendOk() { sendConsoleText("WebSocket #" + this.index + " SendOK.", this.sessionid); }
|
||||
|
||||
|
||||
function onWebSocketUpgrade(response, s, head) {
|
||||
sendConsoleText("WebSocket #" + this.index + " connected.", this.sessionid);
|
||||
this.s = s;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue