mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1439 lines
		
	
	
	
		
			78 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1439 lines
		
	
	
	
		
			78 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
 | 
						|
var http = require('http');
 | 
						|
var childProcess = require('child_process');
 | 
						|
var meshCoreObj = { action: 'coreinfo', value: "MeshCore Recovery", caps: 14 }; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
 | 
						|
var nextTunnelIndex = 1;
 | 
						|
var tunnels = {};
 | 
						|
var fs = require('fs');
 | 
						|
 | 
						|
var needStreamFix = (new Date(process.versions.meshAgent) < new Date('2020-01-21 13:27:45.000-08:00'));
 | 
						|
 | 
						|
try
 | 
						|
{
 | 
						|
    Object.defineProperty(Array.prototype, 'find', {
 | 
						|
        value: function (func)
 | 
						|
        {
 | 
						|
            var i = 0;
 | 
						|
            for(i=0;i<this.length;++i)
 | 
						|
            {
 | 
						|
                if(func(this[i]))
 | 
						|
                {
 | 
						|
                    return (this[i]);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return (null);
 | 
						|
        }
 | 
						|
    });
 | 
						|
}
 | 
						|
catch(x)
 | 
						|
{
 | 
						|
 | 
						|
}
 | 
						|
try
 | 
						|
{
 | 
						|
    Object.defineProperty(Array.prototype, 'findIndex', {
 | 
						|
        value: function (func)
 | 
						|
        {
 | 
						|
            var i = 0;
 | 
						|
            for (i = 0; i < this.length; ++i)
 | 
						|
            {
 | 
						|
                if (func(this[i], i, this))
 | 
						|
                {
 | 
						|
                    return (i);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return (-1);
 | 
						|
        }
 | 
						|
    });
 | 
						|
}
 | 
						|
catch (x)
 | 
						|
{
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
if (process.platform != 'win32')
 | 
						|
{
 | 
						|
    var ch = require('child_process');
 | 
						|
    ch._execFile = ch.execFile;
 | 
						|
    ch.execFile = function execFile(path, args, options)
 | 
						|
    {
 | 
						|
        if (options && options.type && options.type == ch.SpawnTypes.TERM && options.env)
 | 
						|
        {
 | 
						|
            options.env['TERM'] = 'xterm-256color';
 | 
						|
        }
 | 
						|
        return (this._execFile(path, args, options));
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
function _getPotentialServiceNames()
 | 
						|
{
 | 
						|
    var registry = require('win-registry');
 | 
						|
    var ret = [];
 | 
						|
    var K = registry.QueryKey(registry.HKEY.LocalMachine, 'SYSTEM\\CurrentControlSet\\Services');
 | 
						|
    var service, s;
 | 
						|
    while (K.subkeys.length > 0)
 | 
						|
    {
 | 
						|
        service = K.subkeys.shift();
 | 
						|
        try
 | 
						|
        {
 | 
						|
            s = registry.QueryKey(registry.HKEY.LocalMachine, 'SYSTEM\\CurrentControlSet\\Services\\' + service, 'ImagePath');
 | 
						|
            if (s.startsWith(process.execPath) || s.startsWith('"' + process.execPath + '"'))
 | 
						|
            {
 | 
						|
                ret.push(service);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        catch (x)
 | 
						|
        {
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return (ret);
 | 
						|
}
 | 
						|
function _verifyServiceName(names)
 | 
						|
{
 | 
						|
    var i;
 | 
						|
    var s;
 | 
						|
    var ret = null;
 | 
						|
    for (i = 0; i < names.length; ++i)
 | 
						|
    {
 | 
						|
        try
 | 
						|
        {
 | 
						|
            s = require('service-manager').manager.getService(names[i]);
 | 
						|
            if (s.isMe())
 | 
						|
            {
 | 
						|
                ret = names[i];
 | 
						|
                s.close();
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            s.close();
 | 
						|
        }
 | 
						|
        catch (z) { }
 | 
						|
    }
 | 
						|
    return (ret);
 | 
						|
}
 | 
						|
 | 
						|
function windows_getCommandLine()
 | 
						|
{
 | 
						|
    var parms = [];
 | 
						|
    var GM = require('_GenericMarshal');
 | 
						|
    var k32 = GM.CreateNativeProxy('kernel32.dll');
 | 
						|
    var s32 = GM.CreateNativeProxy('shell32.dll');
 | 
						|
    k32.CreateMethod('GetCommandLineW');
 | 
						|
    k32.CreateMethod('LocalFree');
 | 
						|
    s32.CreateMethod('CommandLineToArgvW');
 | 
						|
    var v = k32.GetCommandLineW();
 | 
						|
    var i;
 | 
						|
    var len = GM.CreateVariable(4);
 | 
						|
    var val = s32.CommandLineToArgvW(v, len);
 | 
						|
    len = len.toBuffer().readInt32LE(0);
 | 
						|
    if (len > 0)
 | 
						|
    {
 | 
						|
        for (i = 0; i < len; ++i)
 | 
						|
        {
 | 
						|
            parms.push(val.Deref(i * GM.PointerSize, GM.PointerSize).Deref().Wide2UTF8);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    k32.LocalFree(val);
 | 
						|
    return (parms);
 | 
						|
}
 | 
						|
 | 
						|
if (require('MeshAgent').ARCHID == null)
 | 
						|
{
 | 
						|
    var id = null;
 | 
						|
    switch (process.platform)
 | 
						|
    {
 | 
						|
        case 'win32':
 | 
						|
            id = require('_GenericMarshal').PointerSize == 4 ? 3 : 4;
 | 
						|
            break;
 | 
						|
        case 'freebsd':
 | 
						|
            id = require('_GenericMarshal').PointerSize == 4 ? 31 : 30;
 | 
						|
            break;
 | 
						|
        case 'darwin':
 | 
						|
            try
 | 
						|
            {
 | 
						|
                id = require('os').arch() == 'x64' ? 16 : 29;
 | 
						|
            }
 | 
						|
            catch (xx)
 | 
						|
            {
 | 
						|
                id = 16;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    if (id != null) { Object.defineProperty(require('MeshAgent'), 'ARCHID', { value: id }); }
 | 
						|
}
 | 
						|
 | 
						|
//attachDebugger({ webport: 9994, wait: 1 }).then(function (p) { console.log('Debug on port: ' + p); });
 | 
						|
 | 
						|
function sendConsoleText(msg, sessionid)
 | 
						|
{
 | 
						|
    if (sessionid != null)
 | 
						|
    {
 | 
						|
        require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: msg, sessionid: sessionid });
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: msg });
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
function sendAgentMessage(msg, icon)
 | 
						|
{
 | 
						|
    if (sendAgentMessage.messages == null)
 | 
						|
    {
 | 
						|
        sendAgentMessage.messages = {};
 | 
						|
        sendAgentMessage.nextid = 1;
 | 
						|
    }
 | 
						|
    sendAgentMessage.messages[sendAgentMessage.nextid++] = { msg: msg, icon: icon };
 | 
						|
    require('MeshAgent').SendCommand({ action: 'sessions', type: 'msg', value: sendAgentMessage.messages });
 | 
						|
}
 | 
						|
 | 
						|
// Add to the server event log
 | 
						|
function MeshServerLog(msg, state)
 | 
						|
{
 | 
						|
    if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
 | 
						|
    if (state)
 | 
						|
    {
 | 
						|
        if (state.userid) { msg.userid = state.userid; }
 | 
						|
        if (state.username) { msg.username = state.username; }
 | 
						|
        if (state.sessionid) { msg.sessionid = state.sessionid; }
 | 
						|
        if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
 | 
						|
    }
 | 
						|
    require('MeshAgent').SendCommand(msg);
 | 
						|
}
 | 
						|
 | 
						|
// Add to the server event log, use internationalized events
 | 
						|
function MeshServerLogEx(id, args, msg, state)
 | 
						|
{
 | 
						|
    var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
 | 
						|
    if (state)
 | 
						|
    {
 | 
						|
        if (state.userid) { msg.userid = state.userid; }
 | 
						|
        if (state.username) { msg.username = state.username; }
 | 
						|
        if (state.sessionid) { msg.sessionid = state.sessionid; }
 | 
						|
        if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
 | 
						|
    }
 | 
						|
    require('MeshAgent').SendCommand(msg);
 | 
						|
}
 | 
						|
 | 
						|
function getOpenDescriptors()
 | 
						|
{
 | 
						|
    switch(process.platform)
 | 
						|
    {
 | 
						|
        case "freebsd":
 | 
						|
            var child = require('child_process').execFile('/bin/sh', ['sh']);
 | 
						|
            child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
 | 
						|
            child.stderr.on('data', function (c) { });
 | 
						|
 | 
						|
            child.stdin.write("procstat -f " + process.pid + " | tr '\\n' '`' | awk -F'`' '");
 | 
						|
            child.stdin.write('{');
 | 
						|
            child.stdin.write('   DEL="";');
 | 
						|
            child.stdin.write('   printf "[";');
 | 
						|
            child.stdin.write('   for(i=1;i<NF;++i)');
 | 
						|
            child.stdin.write('   {');
 | 
						|
            child.stdin.write('      A=split($i,B," ");');
 | 
						|
            child.stdin.write('      if(B[3] ~ /^[0-9]/)');
 | 
						|
            child.stdin.write('      {');
 | 
						|
            child.stdin.write('         printf "%s%s", DEL, B[3];');
 | 
						|
            child.stdin.write('         DEL=",";');
 | 
						|
            child.stdin.write('      }');
 | 
						|
            child.stdin.write('   }');
 | 
						|
            child.stdin.write('   printf "]";');
 | 
						|
            child.stdin.write("}'");
 | 
						|
 | 
						|
            child.stdin.write('\nexit\n');
 | 
						|
            child.waitExit();
 | 
						|
 | 
						|
            try
 | 
						|
            {
 | 
						|
                return(JSON.parse(child.stdout.str.trim()));
 | 
						|
            }
 | 
						|
            catch(e)
 | 
						|
            {
 | 
						|
                return ([]);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case "linux":
 | 
						|
            var child = require('child_process').execFile('/bin/sh', ['sh']);
 | 
						|
            child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
 | 
						|
            child.stderr.on('data', function (c) { });
 | 
						|
 | 
						|
            child.stdin.write("ls /proc/" + process.pid + "/fd | tr '\\n' '`' | awk -F'`' '");
 | 
						|
            child.stdin.write('{');
 | 
						|
            child.stdin.write('   printf "[";');
 | 
						|
            child.stdin.write('   DEL="";');
 | 
						|
            child.stdin.write('   for(i=1;i<NF;++i)');
 | 
						|
            child.stdin.write('   {');
 | 
						|
            child.stdin.write('      printf "%s%s",DEL,$i;');
 | 
						|
            child.stdin.write('      DEL=",";');
 | 
						|
            child.stdin.write('   }');
 | 
						|
            child.stdin.write('   printf "]";');
 | 
						|
            child.stdin.write("}'");
 | 
						|
            child.stdin.write('\nexit\n');
 | 
						|
            child.waitExit();
 | 
						|
 | 
						|
            try
 | 
						|
            {
 | 
						|
                return (JSON.parse(child.stdout.str.trim()));
 | 
						|
            }
 | 
						|
            catch (e)
 | 
						|
            {
 | 
						|
                return ([]);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            return ([]);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
function pathjoin() {
 | 
						|
    var x = [];
 | 
						|
    for (var i in arguments) {
 | 
						|
        var w = arguments[i];
 | 
						|
        if (w != null) {
 | 
						|
            while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
 | 
						|
            if (i != 0) {
 | 
						|
                while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
 | 
						|
            }
 | 
						|
            x.push(w);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (x.length == 0) return '/';
 | 
						|
    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; }
 | 
						|
 | 
						|
 | 
						|
function closeDescriptors(libc, descriptors)
 | 
						|
{
 | 
						|
    var fd = null;
 | 
						|
    while(descriptors.length>0)
 | 
						|
    {
 | 
						|
        fd = descriptors.pop();
 | 
						|
        if(fd > 2)
 | 
						|
        {
 | 
						|
            libc.close(fd);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
function linux_execv(name, agentfilename, sessionid)
 | 
						|
{
 | 
						|
    var libs = require('monitor-info').getLibInfo('libc');
 | 
						|
    var libc = null;
 | 
						|
 | 
						|
    if ((libs.length == 0 || libs.length == null) && require('MeshAgent').ARCHID == 33)
 | 
						|
    {
 | 
						|
        var child = require('child_process').execFile('/bin/sh', ['sh']);
 | 
						|
        child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
 | 
						|
        child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
 | 
						|
        child.stdin.write("ls /lib/libc.* | tr '\\n' '`' | awk -F'`' '{ " + ' printf "["; DEL=""; for(i=1;i<NF;++i) { printf "%s{\\"path\\":\\"%s\\"}",DEL,$i; DEL=""; } printf "]"; }\'\nexit\n');
 | 
						|
        child.waitExit();
 | 
						|
 | 
						|
        try
 | 
						|
        {
 | 
						|
            libs = JSON.parse(child.stdout.str.trim());
 | 
						|
        }
 | 
						|
        catch(e)
 | 
						|
        {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    while (libs.length > 0)
 | 
						|
    {
 | 
						|
        try {
 | 
						|
            libc = require('_GenericMarshal').CreateNativeProxy(libs.pop().path);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        catch (e) {
 | 
						|
            libc = null;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (libc != null) {
 | 
						|
        try
 | 
						|
        {
 | 
						|
            libc.CreateMethod('execv');
 | 
						|
            libc.CreateMethod('close');
 | 
						|
        }
 | 
						|
        catch (e) {
 | 
						|
            libc = null;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (libc == null) {
 | 
						|
        // Couldn't find libc.so, fallback to using service manager to restart agent
 | 
						|
        if (sessionid != null) { sendConsoleText('Restarting service via service-manager...', sessionid) }
 | 
						|
        try {
 | 
						|
            // restart service
 | 
						|
            var s = require('service-manager').manager.getService(name);
 | 
						|
            s.restart();
 | 
						|
        }
 | 
						|
        catch (zz) {
 | 
						|
            sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
 | 
						|
            sendAgentMessage('Self Update encountered an error trying to restart service', 3);
 | 
						|
        }
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (sessionid != null) { sendConsoleText('Restarting service via execv()...', sessionid) }
 | 
						|
 | 
						|
    var i;
 | 
						|
    var args;
 | 
						|
    var argtmp = [];
 | 
						|
    var argarr = [process.execPath];
 | 
						|
    var path = require('_GenericMarshal').CreateVariable(process.execPath);
 | 
						|
 | 
						|
    if (require('MeshAgent').getStartupOptions != null) {
 | 
						|
        var options = require('MeshAgent').getStartupOptions();
 | 
						|
        for (i in options) {
 | 
						|
            argarr.push('--' + i + '="' + options[i] + '"');
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    args = require('_GenericMarshal').CreateVariable((1 + argarr.length) * require('_GenericMarshal').PointerSize);
 | 
						|
    for (i = 0; i < argarr.length; ++i) {
 | 
						|
        var arg = require('_GenericMarshal').CreateVariable(argarr[i]);
 | 
						|
        argtmp.push(arg);
 | 
						|
        arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
 | 
						|
    }
 | 
						|
 | 
						|
    var descriptors = getOpenDescriptors();
 | 
						|
    closeDescriptors(libc, descriptors);
 | 
						|
 | 
						|
    libc.execv(path, args);
 | 
						|
    if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
 | 
						|
    sendAgentMessage('Self Update failed because execv() failed', 3);
 | 
						|
}
 | 
						|
 | 
						|
function bsd_execv(name, agentfilename, sessionid) {
 | 
						|
    var child = require('child_process').execFile('/bin/sh', ['sh']);
 | 
						|
    child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
 | 
						|
    child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
 | 
						|
    child.stdin.write("cat /usr/lib/libc.so | awk '");
 | 
						|
    child.stdin.write('{');
 | 
						|
    child.stdin.write(' a=split($0, tok, "(");');
 | 
						|
    child.stdin.write(' if(a>1)');
 | 
						|
    child.stdin.write(' {');
 | 
						|
    child.stdin.write('     split(tok[2], b, ")");');
 | 
						|
    child.stdin.write('     split(b[1], c, " ");');
 | 
						|
    child.stdin.write('     print c[1];');
 | 
						|
    child.stdin.write(' }');
 | 
						|
    child.stdin.write("}'\nexit\n");
 | 
						|
    child.waitExit();
 | 
						|
    if (child.stdout.str.trim() == '') {
 | 
						|
        if (sessionid != null) { sendConsoleText('Self Update failed because cannot find libc.so', sessionid) }
 | 
						|
        sendAgentMessage('Self Update failed because cannot find libc.so', 3);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    var libc = null;
 | 
						|
    try
 | 
						|
    {
 | 
						|
        libc = require('_GenericMarshal').CreateNativeProxy(child.stdout.str.trim());
 | 
						|
        libc.CreateMethod('execv');
 | 
						|
        libc.CreateMethod('close');
 | 
						|
    }
 | 
						|
    catch (e) {
 | 
						|
        if (sessionid != null) { sendConsoleText('Self Update failed: ' + e.toString(), sessionid) }
 | 
						|
        sendAgentMessage('Self Update failed: ' + e.toString(), 3);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    var i;
 | 
						|
    var path = require('_GenericMarshal').CreateVariable(process.execPath);
 | 
						|
    var argarr = [process.execPath];
 | 
						|
    var argtmp = [];
 | 
						|
    var args;
 | 
						|
    var options = require('MeshAgent').getStartupOptions();
 | 
						|
    for (i in options) {
 | 
						|
        argarr.push('--' + i + '="' + options[i] + '"');
 | 
						|
    }
 | 
						|
    args = require('_GenericMarshal').CreateVariable((1 + argarr.length) * require('_GenericMarshal').PointerSize);
 | 
						|
    for (i = 0; i < argarr.length; ++i) {
 | 
						|
        var arg = require('_GenericMarshal').CreateVariable(argarr[i]);
 | 
						|
        argtmp.push(arg);
 | 
						|
        arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
 | 
						|
    }
 | 
						|
 | 
						|
    if (sessionid != null) { sendConsoleText('Restarting service via execv()', sessionid) }
 | 
						|
 | 
						|
    var descriptors = getOpenDescriptors();
 | 
						|
    closeDescriptors(libc, descriptors);
 | 
						|
 | 
						|
    libc.execv(path, args);
 | 
						|
    if (sessionid != null) { sendConsoleText('Self Update failed because execv() failed', sessionid) }
 | 
						|
    sendAgentMessage('Self Update failed because execv() failed', 3);
 | 
						|
}
 | 
						|
 | 
						|
function windows_execve(name, agentfilename, sessionid) {
 | 
						|
    var libc;
 | 
						|
    try {
 | 
						|
        libc = require('_GenericMarshal').CreateNativeProxy('msvcrt.dll');
 | 
						|
        libc.CreateMethod('_wexecve');
 | 
						|
    }
 | 
						|
    catch (xx) {
 | 
						|
        sendConsoleText('Self Update failed because msvcrt.dll is missing', sessionid);
 | 
						|
        sendAgentMessage('Self Update failed because msvcrt.dll is missing', 3);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    var cwd = process.cwd();
 | 
						|
    if (!cwd.endsWith('\\'))
 | 
						|
    {
 | 
						|
        cwd += '\\';
 | 
						|
    }
 | 
						|
    var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true });
 | 
						|
    var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize);
 | 
						|
    var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true });
 | 
						|
    var arg2 = require('_GenericMarshal').CreateVariable('/C wmic service "' + name + '" call stopservice & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCk7CiAgICByZXF1aXJlKCdwcm9jZXNzLW1hbmFnZXInKS5lbnVtZXJhdGVQcm9jZXNzZXMoKS50aGVuKGZ1bmN0aW9uIChwcm9jKQogICAgewogICAgICAgIGZvciAodmFyIHAgaW4gcHJvYykKICAgICAgICB7CiAgICAgICAgICAgIGlmIChwcm9jW3BdLnBhdGggPT0gc2VydmljZUxvY2F0aW9uKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBwcm9jZXNzLmtpbGwocHJvY1twXS5waWQpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHByb2Nlc3MuZXhpdCgpOwogICAgfSk7Cn0KY2F0Y2goZSkKewogICAgcHJvY2Vzcy5leGl0KCk7Cn0=' +
 | 
						|
        ' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & wmic service "' + name + '" call startservice & erase "' + cwd + agentfilename + '.update.exe"', { wide: true });
 | 
						|
 | 
						|
    if (name == null)
 | 
						|
    {
 | 
						|
        // We can continue with self update for Temp/Console Mode on Windows
 | 
						|
        var db = null;
 | 
						|
        var update = cwd + agentfilename + '.update.exe';
 | 
						|
        var updatedb = cwd + agentfilename + '.update.db';
 | 
						|
        var parms = windows_getCommandLine(); parms.shift();
 | 
						|
        
 | 
						|
        var updatesource = parms.find(function (v) { return (v.startsWith('--updateSourcePath=')); });
 | 
						|
        if (updatesource == null)
 | 
						|
        {
 | 
						|
            parms.push('--updateSourcePath="' + cwd + agentfilename + '"');
 | 
						|
            updatesource = (cwd + agentfilename).split('.exe'); updatesource.pop(); updatesource = updatesource.join('.exe');
 | 
						|
            db = updatesource + '.db';
 | 
						|
            updatesource = (' & move "' + updatedb + '" "' + db + '"') + (' & erase "' + updatedb + '" & move "' + update + '" "' + updatesource + '.exe"');
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            updatesource = updatesource.substring(19).split('.exe');
 | 
						|
            updatesource.pop(); updatesource = updatesource.join('.exe');
 | 
						|
            db = updatesource + '.db';
 | 
						|
            updatesource = (' & move "' + update + '" "' + updatesource + '.exe" & move "' + updatedb + '" "' + db + '" & erase "' + updatedb + '"') + (' & echo move "' + update + '" "' + updatesource + '.exe" & echo move "' + updatedb + '" "' + db + '"');
 | 
						|
        }
 | 
						|
 | 
						|
        var tmp = '/C echo copy "' + db + '" "' + updatedb + '" & copy "' + db + '" "' + updatedb + '"' + ' & "' + update + '" ' + parms.join(' ') + updatesource + ' & erase "' + update + '" & echo ERASE "' + update + '"';
 | 
						|
        arg2 = require('_GenericMarshal').CreateVariable(tmp, { wide: true });
 | 
						|
    }
 | 
						|
 | 
						|
    arg1.pointerBuffer().copy(args.toBuffer());
 | 
						|
    arg2.pointerBuffer().copy(args.toBuffer(), require('_GenericMarshal').PointerSize);
 | 
						|
 | 
						|
    libc._wexecve(cmd, args, 0);
 | 
						|
}
 | 
						|
 | 
						|
// Start a JavaScript based Agent Self-Update
 | 
						|
function agentUpdate_Start(updateurl, updateoptions) {
 | 
						|
    // If this value is null
 | 
						|
    var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
 | 
						|
 | 
						|
    // If the url starts with *, switch it to use the same protoco, host and port as the control channel.
 | 
						|
    if (updateurl != null) {
 | 
						|
        updateurl = getServerTargetUrlEx(updateurl);
 | 
						|
        if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
 | 
						|
    }
 | 
						|
 | 
						|
    if (agentUpdate_Start._selfupdate != null)
 | 
						|
    {
 | 
						|
        // We were already called, so we will ignore this duplicate request
 | 
						|
        if (sessionid != null) { sendConsoleText('Self update already in progress...', sessionid); }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        if (agentUpdate_Start._retryCount == null) { agentUpdate_Start._retryCount = 0; }
 | 
						|
        if (require('MeshAgent').ARCHID == null && updateurl == null) {
 | 
						|
            // This agent doesn't have the ability to tell us which ARCHID it is, so we don't know which agent to pull
 | 
						|
            sendConsoleText('Unable to initiate update, agent ARCHID is not defined', sessionid);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            var agentfilename = process.execPath.split(process.platform == 'win32' ? '\\' : '/').pop(); // Local File Name, ie: MeshAgent.exe
 | 
						|
            var name = require('MeshAgent').serviceName;
 | 
						|
            if (name == null) { name = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; }
 | 
						|
            if (process.platform == 'win32')
 | 
						|
            {
 | 
						|
                // Special Processing for Temporary/Console Mode Agents on Windows
 | 
						|
                var parms = windows_getCommandLine();
 | 
						|
                if (parms.findIndex(function (val) { return (val.toUpperCase() == 'RUN' || val.toUpperCase() == 'CONNECT');})>=0)
 | 
						|
                {
 | 
						|
                    // This is a Temporary/Console Mode Agent
 | 
						|
                    sendConsoleText('This is a temporary/console agent, checking for conflicts with background services...');
 | 
						|
 | 
						|
                    // Check to see if our binary conflicts with an installed agent
 | 
						|
                    var agents = _getPotentialServiceNames();
 | 
						|
                    if(_getPotentialServiceNames().length>0)
 | 
						|
                    {
 | 
						|
                        sendConsoleText('Self update cannot continue because the installed agent (' + agents[0] + ') conflicts with the currently running Temp/Console agent...', sessionid);
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
 | 
						|
 | 
						|
                    sendConsoleText('No conflicts detected...');
 | 
						|
                    name = null;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    // Not running in Temp/Console Mode... No Op here....
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                // Non Windows Self Update
 | 
						|
                try
 | 
						|
                {
 | 
						|
                    var s = require('service-manager').manager.getService(name);
 | 
						|
                    if (!s.isMe())
 | 
						|
                    {
 | 
						|
                        if (process.platform == 'win32') { s.close(); }
 | 
						|
                        sendConsoleText('Self Update cannot continue, this agent is not an instance of background service (' + name + ')', sessionid);
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
                    if (process.platform == 'win32') { s.close(); }
 | 
						|
                }
 | 
						|
                catch (zz)
 | 
						|
                {
 | 
						|
                    sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
 | 
						|
                    sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if ((sessionid != null) && (updateurl != null)) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
 | 
						|
            var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
 | 
						|
            options.protocol = 'https:';
 | 
						|
            if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); sendConsoleText('Downloading update from: ' + options.path, sessionid); }
 | 
						|
            options.rejectUnauthorized = false;
 | 
						|
            options.checkServerIdentity = function checkServerIdentity(certs) {
 | 
						|
                // If the tunnel certificate matches the control channel certificate, accept the connection
 | 
						|
                try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
 | 
						|
                try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
 | 
						|
 | 
						|
                // Check that the certificate is the one expected by the server, fail if not.
 | 
						|
                if (checkServerIdentity.servertlshash == null) {
 | 
						|
                    if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) { return; }
 | 
						|
                    sendConsoleText('Self Update failed, because the url cannot be verified: ' + updateurl, sessionid);
 | 
						|
                    sendAgentMessage('Self Update failed, because the url cannot be verified: ' + updateurl, 3);
 | 
						|
                    throw new Error('BadCert');
 | 
						|
                }
 | 
						|
                if (certs[0].digest == null) { return; }
 | 
						|
                if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) {
 | 
						|
                    sendConsoleText('Self Update failed, because the supplied certificate does not match', sessionid);
 | 
						|
                    sendAgentMessage('Self Update failed, because the supplied certificate does not match', 3);
 | 
						|
                    throw new Error('BadCert')
 | 
						|
                }
 | 
						|
            }
 | 
						|
            options.checkServerIdentity.servertlshash = (updateoptions != null ? updateoptions.tlshash : null);
 | 
						|
            agentUpdate_Start._selfupdate = require('https').get(options);
 | 
						|
            agentUpdate_Start._selfupdate.on('error', function (e) {
 | 
						|
                sendConsoleText('Self Update failed, because there was a problem trying to download the update from ' + updateurl, sessionid);
 | 
						|
                sendAgentMessage('Self Update failed, because there was a problem trying to download the update from ' + updateurl, 3);
 | 
						|
                agentUpdate_Start._selfupdate = null;
 | 
						|
            });
 | 
						|
            agentUpdate_Start._selfupdate.on('response', function (img)
 | 
						|
            {
 | 
						|
                var self = this;
 | 
						|
                this._file = require('fs').createWriteStream(agentfilename + (process.platform=='win32'?'.update.exe':'.update'), { flags: 'wb' });
 | 
						|
                this._filehash = require('SHA384Stream').create();
 | 
						|
                this._filehash.on('hash', function (h)
 | 
						|
                {
 | 
						|
                    if (updateoptions != null && updateoptions.hash != null)
 | 
						|
                    {
 | 
						|
                        if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase())
 | 
						|
                        {
 | 
						|
                            if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); }
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            agentUpdate_Start._retryCount++;
 | 
						|
                            sendConsoleText('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + '), URL: ' + updateurl, sessionid);
 | 
						|
                            sendAgentMessage('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + '), URL: ' + updateurl, 3);
 | 
						|
                            agentUpdate_Start._selfupdate = null;
 | 
						|
 | 
						|
                            if (agentUpdate_Start._retryCount < 4)
 | 
						|
                            {
 | 
						|
                                // Retry the download again
 | 
						|
                                sendConsoleText('Self Update will try again in 60 seconds...', sessionid);
 | 
						|
                                agentUpdate_Start._timeout = setTimeout(agentUpdate_Start, 60000, updateurl, updateoptions);
 | 
						|
                            }
 | 
						|
                            else
 | 
						|
                            {
 | 
						|
                                sendConsoleText('Self Update giving up, too many failures...', sessionid);
 | 
						|
                                sendAgentMessage('Self Update giving up, too many failures...', 3);
 | 
						|
                            }
 | 
						|
                            return;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid);
 | 
						|
                    }
 | 
						|
 | 
						|
                    // Send an indication to the server that we got the update download correctly.
 | 
						|
                    try { require('MeshAgent').SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { }
 | 
						|
 | 
						|
                    if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); }
 | 
						|
                    if (process.platform == 'win32')
 | 
						|
                    {
 | 
						|
                        // Use _wexecve() equivalent to perform the update
 | 
						|
                        windows_execve(name, agentfilename, sessionid);
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        var m = require('fs').statSync(process.execPath).mode;
 | 
						|
                        require('fs').chmodSync(process.cwd() + agentfilename + '.update', m);
 | 
						|
 | 
						|
                        // remove binary
 | 
						|
                        require('fs').unlinkSync(process.execPath);
 | 
						|
 | 
						|
                        // copy update
 | 
						|
                        require('fs').copyFileSync(process.cwd() + agentfilename + '.update', process.execPath);
 | 
						|
                        require('fs').chmodSync(process.execPath, m);
 | 
						|
 | 
						|
                        // erase update
 | 
						|
                        require('fs').unlinkSync(process.cwd() + agentfilename + '.update');
 | 
						|
 | 
						|
                        switch (process.platform)
 | 
						|
                        {
 | 
						|
                            case 'freebsd':
 | 
						|
                                bsd_execv(name, agentfilename, sessionid);
 | 
						|
                                break;
 | 
						|
                            case 'linux':
 | 
						|
                                linux_execv(name, agentfilename, sessionid);
 | 
						|
                                break;
 | 
						|
                            default:
 | 
						|
                                try
 | 
						|
                                {
 | 
						|
                                    // restart service
 | 
						|
                                    var s = require('service-manager').manager.getService(name);
 | 
						|
                                    s.restart();
 | 
						|
                                }
 | 
						|
                                catch (zz)
 | 
						|
                                {
 | 
						|
                                    sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
 | 
						|
                                    sendAgentMessage('Self Update encountered an error trying to restart service', 3);
 | 
						|
                                }
 | 
						|
                                break;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                });
 | 
						|
 | 
						|
                if (!needStreamFix)
 | 
						|
                {
 | 
						|
                    img.pipe(this._file);
 | 
						|
                    img.pipe(this._filehash);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    img.once('data', function (buffer)
 | 
						|
                    {
 | 
						|
                        if(this.immediate)
 | 
						|
                        {
 | 
						|
                            clearImmediate(this.immediate);
 | 
						|
                            this.immediate = null;
 | 
						|
 | 
						|
                            // No need to apply fix
 | 
						|
                            self._file.write(buffer);
 | 
						|
                            self._filehash.write(buffer);
 | 
						|
 | 
						|
                            this.pipe(self._file);
 | 
						|
                            this.pipe(self._filehash);
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            // Need to apply fix
 | 
						|
                            this.pipe(self._file);
 | 
						|
                            this.pipe(self._filehash);
 | 
						|
                        }
 | 
						|
                    });
 | 
						|
                    this.immediate = setImmediate(function (self)
 | 
						|
                    {
 | 
						|
                        self.immediate = null;
 | 
						|
                    },this);
 | 
						|
                }
 | 
						|
            });
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// Return p number of spaces 
 | 
						|
function addPad(p, ret) { var r = ''; for (var i = 0; i < p; i++) { r += ret; } return r; }
 | 
						|
 | 
						|
setInterval(function () { sendConsoleText('Timer!'); }, 2000);
 | 
						|
 | 
						|
var path =
 | 
						|
    {
 | 
						|
        join: function () {
 | 
						|
            var x = [];
 | 
						|
            for (var i in arguments) {
 | 
						|
                var w = arguments[i];
 | 
						|
                if (w != null) {
 | 
						|
                    while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
 | 
						|
                    if (i != 0) { while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } }
 | 
						|
                    x.push(w);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (x.length == 0) return '/';
 | 
						|
            return x.join('/');
 | 
						|
        }
 | 
						|
    };
 | 
						|
// Convert an object to string with all functions
 | 
						|
function objToString(x, p, pad, 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) { if (i != '_ObjectID') { r += (addPad(p + 2, pad) + i + ': ' + objToString(x[i], p + 2, pad, ret) + (ret ? '\r\n' : ' ')); } }
 | 
						|
    return r + addPad(p, pad) + '}';
 | 
						|
}
 | 
						|
 | 
						|
// 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;
 | 
						|
}
 | 
						|
 | 
						|
// Get server target url with a custom path
 | 
						|
function getServerTargetUrl(path) {
 | 
						|
    var x = require('MeshAgent').ServerUrl;
 | 
						|
    //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
 | 
						|
    if (x == null) { return null; }
 | 
						|
    if (path == null) { path = ''; }
 | 
						|
    x = http.parseUri(x);
 | 
						|
    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;
 | 
						|
}
 | 
						|
 | 
						|
require('MeshAgent').on('Connected', function () {
 | 
						|
    require('os').name().then(function (v) {
 | 
						|
        //sendConsoleText("Mesh Agent Recovery Console, OS: " + v);
 | 
						|
        require('MeshAgent').SendCommand(meshCoreObj);
 | 
						|
    });
 | 
						|
});
 | 
						|
 | 
						|
// Called when receiving control data on websocket
 | 
						|
function onTunnelControlData(data, ws) {
 | 
						|
    var obj;
 | 
						|
    if (ws == null) { ws = this; }
 | 
						|
    if (typeof data == 'string') { try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON: ' + data); return; } }
 | 
						|
    else if (typeof data == 'object') { obj = data; } else { return; }
 | 
						|
    //sendConsoleText('onTunnelControlData(' + ws.httprequest.protocol + '): ' + JSON.stringify(data));
 | 
						|
    //console.log('onTunnelControlData: ' + JSON.stringify(data));
 | 
						|
 | 
						|
    if (obj.action) {
 | 
						|
        switch (obj.action) {
 | 
						|
            case 'lock': {
 | 
						|
                // Lock the current user out of the desktop
 | 
						|
                try {
 | 
						|
                    if (process.platform == 'win32') {
 | 
						|
                        MeshServerLog("Locking remote user out of desktop", ws.httprequest);
 | 
						|
                        var child = require('child_process');
 | 
						|
                        child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
 | 
						|
                    }
 | 
						|
                } catch (e) { }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            default:
 | 
						|
                // Unknown action, ignore it.
 | 
						|
                break;
 | 
						|
        }
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (obj.type) {
 | 
						|
        case 'options': {
 | 
						|
            // These are additional connection options passed in the control channel.
 | 
						|
            //sendConsoleText('options: ' + JSON.stringify(obj));
 | 
						|
            delete obj.type;
 | 
						|
            ws.httprequest.xoptions = obj;
 | 
						|
 | 
						|
            // Set additional user consent options if present
 | 
						|
            if ((obj != null) && (typeof obj.consent == 'number')) { ws.httprequest.consent |= obj.consent; }
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        case 'close': {
 | 
						|
            // We received the close on the websocket
 | 
						|
            //sendConsoleText('Tunnel #' + ws.tunnel.index + ' WebSocket control close');
 | 
						|
            try { ws.close(); } catch (e) { }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        case 'termsize': {
 | 
						|
            // Indicates a change in terminal size
 | 
						|
            if (process.platform == 'win32') {
 | 
						|
                if (ws.httprequest._dispatcher == null) return;
 | 
						|
                if (ws.httprequest._dispatcher.invoke) { ws.httprequest._dispatcher.invoke('resizeTerminal', [obj.cols, obj.rows]); }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                if (ws.httprequest.process == null || ws.httprequest.process.pty == 0) return;
 | 
						|
                if (ws.httprequest.process.tcsetsize) { ws.httprequest.process.tcsetsize(obj.rows, obj.cols); }
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
require('MeshAgent').AddCommandHandler(function (data) {
 | 
						|
    if (typeof data == 'object') {
 | 
						|
        // If this is a console command, parse it and call the console handler
 | 
						|
        switch (data.action) {
 | 
						|
            case 'agentupdate':
 | 
						|
                agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid });
 | 
						|
                break;
 | 
						|
            case 'msg':
 | 
						|
                {
 | 
						|
                    switch (data.type) {
 | 
						|
                        case 'console': { // Process a console command
 | 
						|
                            if ((typeof data.rights != 'number') || ((data.rights & 8) == 0) || ((data.rights & 16) == 0)) break; // Check console rights (Remote Control and Console)
 | 
						|
                            if (data.value && data.sessionid) {
 | 
						|
                                var args = splitArgs(data.value);
 | 
						|
                                processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
 | 
						|
                            }
 | 
						|
                            break;
 | 
						|
                        }
 | 
						|
                        case 'tunnel':
 | 
						|
                            {
 | 
						|
                                if (data.value != null) { // Process a new tunnel connection request
 | 
						|
                                    // Create a new tunnel object
 | 
						|
                                    if (data.rights != 4294967295) {
 | 
						|
                                        MeshServerLog('Tunnel Error: RecoveryCore requires admin rights for tunnels');
 | 
						|
                                        break;
 | 
						|
                                    }
 | 
						|
 | 
						|
                                    var xurl = getServerTargetUrlEx(data.value);
 | 
						|
                                    if (xurl != null)
 | 
						|
                                    {
 | 
						|
                                        xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters
 | 
						|
                                        var woptions = http.parseUri(xurl);
 | 
						|
                                        woptions.rejectUnauthorized = 0;
 | 
						|
                                        woptions.perMessageDeflate = false;
 | 
						|
                                        woptions.checkServerIdentity = function checkServerIdentity(certs) {
 | 
						|
                                            // If the tunnel certificate matches the control channel certificate, accept the connection
 | 
						|
                                            try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
 | 
						|
                                            try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
 | 
						|
 | 
						|
                                            // Check that the certificate is the one expected by the server, fail if not.
 | 
						|
                                            if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
 | 
						|
                                        }
 | 
						|
                                        woptions.checkServerIdentity.servertlshash = data.servertlshash;
 | 
						|
 | 
						|
 | 
						|
                                        //sendConsoleText(JSON.stringify(woptions));
 | 
						|
                                        var tunnel = http.request(woptions);
 | 
						|
                                        tunnel.on('upgrade', function (response, s, head) {
 | 
						|
                                            if (require('MeshAgent').idleTimeout != null) {
 | 
						|
                                                s.setTimeout(require('MeshAgent').idleTimeout * 1000);
 | 
						|
                                                s.on('timeout', function () {
 | 
						|
                                                    this.ping();
 | 
						|
                                                    this.setTimeout(require('MeshAgent').idleTimeout * 1000);
 | 
						|
                                                });
 | 
						|
                                            }
 | 
						|
 | 
						|
                                            this.s = s;
 | 
						|
                                            s.httprequest = this;
 | 
						|
                                            s.tunnel = this;
 | 
						|
                                            s.on('end', function () {
 | 
						|
                                                if (tunnels[this.httprequest.index] == null) return; // Stop duplicate calls.
 | 
						|
 | 
						|
                                                // If there is a upload or download active on this connection, close the file
 | 
						|
                                                if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; delete this.httprequest.uploadFileid; delete this.httprequest.uploadFilePath; }
 | 
						|
                                                if (this.httprequest.downloadFile) { delete this.httprequest.downloadFile; }
 | 
						|
 | 
						|
                                                //sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
 | 
						|
                                                delete tunnels[this.httprequest.index];
 | 
						|
 | 
						|
                                                // Clean up WebSocket
 | 
						|
                                                this.removeAllListeners('data');
 | 
						|
                                            });
 | 
						|
                                            s.on('data', function (data) {
 | 
						|
                                                // If this is upload data, save it to file
 | 
						|
                                                if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123)) {
 | 
						|
                                                    // Save the data to file being uploaded.
 | 
						|
                                                    if (data[0] == 0) {
 | 
						|
                                                        // If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
 | 
						|
                                                        try { fs.writeSync(this.httprequest.uploadFile, data, 1, data.length - 1); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
 | 
						|
                                                    } else {
 | 
						|
                                                        // If data does not start with zero, save as-is.
 | 
						|
                                                        try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
 | 
						|
                                                    }
 | 
						|
                                                    this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
 | 
						|
                                                    return;
 | 
						|
                                                }
 | 
						|
 | 
						|
                                                if (this.httprequest.state == 0) {
 | 
						|
                                                    // Check if this is a relay connection
 | 
						|
                                                    if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
 | 
						|
                                                }
 | 
						|
                                                else {
 | 
						|
                                                    // Handle tunnel data
 | 
						|
                                                    if (this.httprequest.protocol == 0) {   // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user), 10 = FileTransfer
 | 
						|
                                                        // Take a look at the protocol
 | 
						|
                                                        if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
 | 
						|
                                                        this.httprequest.protocol = parseInt(data);
 | 
						|
                                                        if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
 | 
						|
                                                        if (this.httprequest.protocol == 10) {
 | 
						|
                                                            //
 | 
						|
                                                            // Basic file transfer
 | 
						|
                                                            //
 | 
						|
                                                            var stats = null;
 | 
						|
                                                            if ((process.platform != 'win32') && (this.httprequest.xoptions.file.startsWith('/') == false)) { this.httprequest.xoptions.file = '/' + this.httprequest.xoptions.file; }
 | 
						|
                                                            try { stats = require('fs').statSync(this.httprequest.xoptions.file) } catch (e) { }
 | 
						|
                                                            try { if (stats) { this.httprequest.downloadFile = fs.createReadStream(this.httprequest.xoptions.file, { flags: 'rbN' }); } } catch (e) { }
 | 
						|
                                                            if (this.httprequest.downloadFile) {
 | 
						|
                                                                //sendConsoleText('BasicFileTransfer, ok, ' + this.httprequest.xoptions.file + ', ' + JSON.stringify(stats));
 | 
						|
                                                                this.write(JSON.stringify({ op: 'ok', size: stats.size }));
 | 
						|
                                                                this.httprequest.downloadFile.pipe(this);
 | 
						|
                                                                this.httprequest.downloadFile.end = function () { }
 | 
						|
                                                            } else {
 | 
						|
                                                                //sendConsoleText('BasicFileTransfer, cancel, ' + this.httprequest.xoptions.file);
 | 
						|
                                                                this.write(JSON.stringify({ op: 'cancel' }));
 | 
						|
                                                            }
 | 
						|
                                                        }
 | 
						|
                                                        else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9)) {
 | 
						|
                                                            //
 | 
						|
                                                            // Remote Terminal
 | 
						|
                                                            //
 | 
						|
                                                            if (process.platform == "win32") {
 | 
						|
                                                                var cols = 80, rows = 25;
 | 
						|
                                                                if (this.httprequest.xoptions) {
 | 
						|
                                                                    if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
 | 
						|
                                                                    if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
 | 
						|
                                                                }
 | 
						|
 | 
						|
                                                                // Admin Terminal
 | 
						|
                                                                if (require('win-virtual-terminal').supported) {
 | 
						|
                                                                    // ConPTY PseudoTerminal
 | 
						|
                                                                    // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
 | 
						|
 | 
						|
                                                                    // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
 | 
						|
                                                                    this.httprequest._dispatcher = require('win-dispatcher').dispatch({ modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: 'Start', args: [cols, rows] } });
 | 
						|
                                                                    this.httprequest._dispatcher.ws = this;
 | 
						|
                                                                    this.httprequest._dispatcher.on('connection', function (c) {
 | 
						|
                                                                        this.ws._term = c;
 | 
						|
                                                                        c.pipe(this.ws, { dataTypeSkip: 1 });
 | 
						|
                                                                        this.ws.pipe(c, { dataTypeSkip: 1 });
 | 
						|
                                                                    });
 | 
						|
                                                                }
 | 
						|
                                                                else {
 | 
						|
                                                                    // Legacy Terminal
 | 
						|
                                                                    this.httprequest._term = require('win-terminal').Start(80, 25);
 | 
						|
                                                                    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 () { sendConsoleText('Terminal was closed'); }); });
 | 
						|
                                                                }
 | 
						|
                                                            }
 | 
						|
                                                            else {
 | 
						|
                                                                var env = { HISTCONTROL: 'ignoreboth' };
 | 
						|
                                                                if (process.env['LANG']) { env['LANG'] = process.env['LANG']; }
 | 
						|
                                                                if (process.env['PATH']) { env['PATH'] = process.env['PATH']; }
 | 
						|
                                                                if (this.httprequest.xoptions)
 | 
						|
                                                                {
 | 
						|
                                                                    if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
 | 
						|
                                                                    if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
 | 
						|
                                                                }
 | 
						|
                                                                var options = { type: childProcess.SpawnTypes.TERM, env: env };
 | 
						|
 | 
						|
                                                                if (require('fs').existsSync('/bin/bash')) {
 | 
						|
                                                                    this.httprequest.process = childProcess.execFile('/bin/bash', ['bash'], options); // Start bash
 | 
						|
                                                                }
 | 
						|
                                                                else {
 | 
						|
                                                                    this.httprequest.process = childProcess.execFile('/bin/sh', ['sh'], options); // Start sh
 | 
						|
                                                                }
 | 
						|
 | 
						|
                                                                // Spaces at the beginning of lines are needed to hide commands from the command history
 | 
						|
                                                                if (process.platform == 'linux') { this.httprequest.process.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
 | 
						|
                                                                this.httprequest.process.tunnel = this;
 | 
						|
                                                                this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
 | 
						|
                                                                this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
 | 
						|
                                                                this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
 | 
						|
                                                                this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
 | 
						|
                                                                this.prependListener('end', function () { this.httprequest.process.kill(); });
 | 
						|
                                                            }
 | 
						|
                                                        }
 | 
						|
                                                    }
 | 
						|
                                                    else if (this.httprequest.protocol == 5) {
 | 
						|
                                                        // Process files commands
 | 
						|
                                                        var cmd = null;
 | 
						|
                                                        try { cmd = JSON.parse(data); } catch (e) { };
 | 
						|
                                                        if (cmd == null) { return; }
 | 
						|
                                                        if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { return; } // If this is control data, handle it now.
 | 
						|
                                                        if (cmd.action == undefined) { return; }
 | 
						|
                                                        console.log('action: ', cmd.action);
 | 
						|
 | 
						|
                                                        //sendConsoleText('CMD: ' + JSON.stringify(cmd));
 | 
						|
 | 
						|
                                                        if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
 | 
						|
                                                        //console.log(objToString(cmd, 0, ' '));
 | 
						|
                                                        switch (cmd.action) {
 | 
						|
                                                            case 'ls':
 | 
						|
                                                                // Send the folder content to the browser
 | 
						|
                                                                var response = getDirectoryInfo(cmd.path);
 | 
						|
                                                                if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
 | 
						|
                                                                this.write(Buffer.from(JSON.stringify(response)));
 | 
						|
                                                                break;
 | 
						|
                                                            case 'mkdir':
 | 
						|
                                                                {
 | 
						|
                                                                    // Create a new empty folder
 | 
						|
                                                                    fs.mkdirSync(cmd.path);
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'rm':
 | 
						|
                                                                {
 | 
						|
                                                                    // Delete, possibly recursive delete
 | 
						|
                                                                    for (var i in cmd.delfiles) {
 | 
						|
                                                                        try { deleteFolderRecursive(path.join(cmd.path, cmd.delfiles[i]), cmd.rec); } catch (e) { }
 | 
						|
                                                                    }
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'rename':
 | 
						|
                                                                {
 | 
						|
                                                                    // Rename a file or folder
 | 
						|
                                                                    var oldfullpath = path.join(cmd.path, cmd.oldname);
 | 
						|
                                                                    var newfullpath = path.join(cmd.path, cmd.newname);
 | 
						|
                                                                    try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'findfile':
 | 
						|
                                                                {
 | 
						|
                                                                    // Search for files
 | 
						|
                                                                    var r = require('file-search').find('"' + cmd.path + '"', cmd.filter);
 | 
						|
                                                                    if (!r.cancel) { r.cancel = function cancel() { this.child.kill(); }; }
 | 
						|
                                                                    this._search = r;
 | 
						|
                                                                    r.socket = this;
 | 
						|
                                                                    r.socket.reqid = cmd.reqid; // Search request id. This is used to send responses and cancel the request.
 | 
						|
                                                                    r.socket.path = cmd.path;   // Search path
 | 
						|
                                                                    r.on('result', function (str) { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: str.substring(this.socket.path.length), reqid: this.socket.reqid }))); } catch (ex) { } });
 | 
						|
                                                                    r.then(function () { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: null, reqid: this.socket.reqid }))); } catch (ex) { } });
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'cancelfindfile':
 | 
						|
                                                                {
 | 
						|
                                                                    if (this._search) { this._search.cancel(); this._search = null; }
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'download':
 | 
						|
                                                                {
 | 
						|
                                                                    // Download a file
 | 
						|
                                                                    var sendNextBlock = 0;
 | 
						|
                                                                    if (cmd.sub == 'start') { // Setup the download
 | 
						|
                                                                        if ((cmd.path == null) && (cmd.ask == 'coredump')) { // If we are asking for the coredump file, set the right path.
 | 
						|
                                                                            if (process.platform == 'win32') {
 | 
						|
                                                                                if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
 | 
						|
                                                                            } else {
 | 
						|
                                                                                if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
 | 
						|
                                                                            }
 | 
						|
                                                                        }
 | 
						|
                                                                        MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
 | 
						|
                                                                        if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
 | 
						|
                                                                        this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
 | 
						|
                                                                        try { this.filedownload.f = fs.openSync(this.filedownload.path, 'rbN'); } catch (e) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
 | 
						|
                                                                        if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
 | 
						|
                                                                    } else if ((this.filedownload != null) && (cmd.id == this.filedownload.id)) { // Download commands
 | 
						|
                                                                        if (cmd.sub == 'startack') { sendNextBlock = ((typeof cmd.ack == 'number') ? cmd.ack : 8); } else if (cmd.sub == 'stop') { delete this.filedownload; } else if (cmd.sub == 'ack') { sendNextBlock = 1; }
 | 
						|
                                                                    }
 | 
						|
                                                                    // Send the next download block(s)
 | 
						|
                                                                    while (sendNextBlock > 0) {
 | 
						|
                                                                        sendNextBlock--;
 | 
						|
                                                                        var buf = Buffer.alloc(16384);
 | 
						|
                                                                        var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
 | 
						|
                                                                        this.filedownload.ptr += len;
 | 
						|
                                                                        if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
 | 
						|
                                                                        this.write(buf.slice(0, len + 4)); // Write as binary
 | 
						|
                                                                    }
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'upload':
 | 
						|
                                                                {
 | 
						|
                                                                    // Upload a file, browser to agent
 | 
						|
                                                                    if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
 | 
						|
                                                                    if (cmd.path == undefined) break;
 | 
						|
                                                                    var filepath = cmd.name ? pathjoin(cmd.path, cmd.name) : cmd.path;
 | 
						|
                                                                    this.httprequest.uploadFilePath = filepath;
 | 
						|
                                                                    MeshServerLogEx(50, [filepath], 'Upload: \"' + filepath + '\"', this.httprequest);
 | 
						|
                                                                    try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
 | 
						|
                                                                    this.httprequest.uploadFileid = cmd.reqid;
 | 
						|
                                                                    if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'uploaddone':
 | 
						|
                                                                {
 | 
						|
                                                                    // Indicates that an upload is done
 | 
						|
                                                                    if (this.httprequest.uploadFile) {
 | 
						|
                                                                        fs.closeSync(this.httprequest.uploadFile);
 | 
						|
                                                                        this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
 | 
						|
                                                                        delete this.httprequest.uploadFile;
 | 
						|
                                                                        delete this.httprequest.uploadFileid;
 | 
						|
                                                                        delete this.httprequest.uploadFilePath;
 | 
						|
                                                                    }
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'uploadcancel':
 | 
						|
                                                                {
 | 
						|
                                                                    // Indicates that an upload is canceled
 | 
						|
                                                                    if (this.httprequest.uploadFile) {
 | 
						|
                                                                        fs.closeSync(this.httprequest.uploadFile);
 | 
						|
                                                                        fs.unlinkSync(this.httprequest.uploadFilePath);
 | 
						|
                                                                        this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
 | 
						|
                                                                        delete this.httprequest.uploadFile;
 | 
						|
                                                                        delete this.httprequest.uploadFileid;
 | 
						|
                                                                        delete this.httprequest.uploadFilePath;
 | 
						|
                                                                    }
 | 
						|
                                                                    break;
 | 
						|
                                                                }
 | 
						|
                                                            case 'copy': {
 | 
						|
                                                                // Copy a bunch of files from scpath to dspath
 | 
						|
                                                                for (var i in cmd.names) {
 | 
						|
                                                                    var sc = path.join(cmd.scpath, cmd.names[i]), ds = path.join(cmd.dspath, cmd.names[i]);
 | 
						|
                                                                    if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
 | 
						|
                                                                }
 | 
						|
                                                                break;
 | 
						|
                                                            }
 | 
						|
                                                            case 'move': {
 | 
						|
                                                                // Move a bunch of files from scpath to dspath
 | 
						|
                                                                for (var i in cmd.names) {
 | 
						|
                                                                    var sc = path.join(cmd.scpath, cmd.names[i]), ds = path.join(cmd.dspath, cmd.names[i]);
 | 
						|
                                                                    if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
 | 
						|
                                                                }
 | 
						|
                                                                break;
 | 
						|
                                                            }
 | 
						|
                                                        }
 | 
						|
                                                    }
 | 
						|
                                                }
 | 
						|
                                            });
 | 
						|
                                        });
 | 
						|
                                        tunnel.onerror = function (e) { sendConsoleText("ERROR: " + JSON.stringify(e)); }
 | 
						|
                                        tunnel.sessionid = data.sessionid;
 | 
						|
                                        tunnel.rights = data.rights;
 | 
						|
                                        tunnel.state = 0;
 | 
						|
                                        tunnel.url = xurl;
 | 
						|
                                        tunnel.protocol = 0;
 | 
						|
                                        tunnel.tcpaddr = data.tcpaddr;
 | 
						|
                                        tunnel.tcpport = data.tcpport;
 | 
						|
                                        tunnel.end();
 | 
						|
                                        // Put the tunnel in the tunnels list
 | 
						|
                                        var index = nextTunnelIndex++;
 | 
						|
                                        tunnel.index = index;
 | 
						|
                                        tunnels[index] = tunnel;
 | 
						|
 | 
						|
                                        //sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                                break;
 | 
						|
                            }
 | 
						|
 | 
						|
                        default:
 | 
						|
                            // Unknown action, ignore it.
 | 
						|
                            break;
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            default:
 | 
						|
                // Unknown action, ignore it.
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
});
 | 
						|
 | 
						|
function processConsoleCommand(cmd, args, rights, sessionid) {
 | 
						|
    try {
 | 
						|
        var response = null;
 | 
						|
        switch (cmd)
 | 
						|
        {
 | 
						|
            default:
 | 
						|
                { // This is an unknown command, return an error message
 | 
						|
                    response = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            case 'commandline':
 | 
						|
                {
 | 
						|
                    if (process.platform == 'win32')
 | 
						|
                    {
 | 
						|
                        response = JSON.stringify(windows_getCommandLine(), null, 1);
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        response = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case 'help':
 | 
						|
                response = "Available commands are: agentupdate, agentupdateex, dbkeys, dbget, dbset, dbcompact, eval, netinfo, osinfo, setdebug, versions.";
 | 
						|
                break;
 | 
						|
            case '_descriptors':
 | 
						|
                response = 'Open Descriptors: ' + JSON.stringify(getOpenDescriptors());
 | 
						|
                break;
 | 
						|
            case 'versions':
 | 
						|
                response = JSON.stringify(process.versions, null, '  ');
 | 
						|
                break;
 | 
						|
            case 'agentupdate':
 | 
						|
                // Request that the server send a agent update command
 | 
						|
                require('MeshAgent').SendCommand({ action: 'agentupdate', sessionid: sessionid });
 | 
						|
                break;
 | 
						|
            case 'agentupdateex':
 | 
						|
                // Perform an direct agent update without requesting any information from the server, this should not typically be used.
 | 
						|
                if (args['_'].length == 1) {
 | 
						|
                    if (args['_'][0].startsWith('https://')) { agentUpdate_Start(args['_'][0], { sessionid: sessionid }); } else { response = "Usage: agentupdateex https://server/path"; }
 | 
						|
                } else {
 | 
						|
                    agentUpdate_Start(null, { sessionid: sessionid });
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case 'eval':
 | 
						|
                { // Eval JavaScript
 | 
						|
                    if (args['_'].length < 1) {
 | 
						|
                        response = 'Proper usage: eval "JavaScript code"'; // Display correct command usage
 | 
						|
                    } else {
 | 
						|
                        response = JSON.stringify(require('MeshAgent').eval(args['_'][0])); // This can only be run by trusted administrator.
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            case 'setdebug':
 | 
						|
                {
 | 
						|
                    if (args['_'].length < 1) { response = 'Proper usage: setdebug (target), 0 = Disabled, 1 = StdOut, 2 = This Console, * = All Consoles, 4 = WebLog, 8 = Logfile'; } // Display usage
 | 
						|
                    else { if (args['_'][0] == '*') { console.setDestination(2); } else { console.setDestination(parseInt(args['_'][0]), sessionid); } }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            case 'osinfo': { // Return the operating system information
 | 
						|
                var i = 1;
 | 
						|
                if (args['_'].length > 0) { i = parseInt(args['_'][0]); if (i > 8) { i = 8; } response = 'Calling ' + i + ' times.'; }
 | 
						|
                for (var j = 0; j < i; j++) {
 | 
						|
                    var pr = require('os').name();
 | 
						|
                    pr.sessionid = sessionid;
 | 
						|
                    pr.then(function (v) {
 | 
						|
                        sendConsoleText("OS: " + v + (process.platform == 'win32' ? (require('win-virtual-terminal').supported ? ' [ConPTY: YES]' : ' [ConPTY: NO]') : ''), this.sessionid);
 | 
						|
                    });
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case 'dbkeys': { // Return all data store keys
 | 
						|
                response = JSON.stringify(db.Keys);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case 'dbget': { // Return the data store value for a given key
 | 
						|
                if (db == null) { response = "Database not accessible."; break; }
 | 
						|
                if (args['_'].length != 1) {
 | 
						|
                    response = "Proper usage: dbget (key)"; // Display the value for a given database key
 | 
						|
                } else {
 | 
						|
                    response = db.Get(args['_'][0]);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case 'dbset': { // Set a data store key and value pair
 | 
						|
                if (db == null) { response = "Database not accessible."; break; }
 | 
						|
                if (args['_'].length != 2) {
 | 
						|
                    response = "Proper usage: dbset (key) (value)"; // Set a database key
 | 
						|
                } else {
 | 
						|
                    var r = db.Put(args['_'][0], args['_'][1]);
 | 
						|
                    response = "Key set: " + r;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case 'dbcompact': { // Compact the data store
 | 
						|
                if (db == null) { response = "Database not accessible."; break; }
 | 
						|
                var r = db.Compact();
 | 
						|
                response = "Database compacted: " + r;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case 'tunnels': { // Show the list of current tunnels
 | 
						|
                response = '';
 | 
						|
                for (var i in tunnels) { response += "Tunnel #" + i + ", " + tunnels[i].url + '\r\n'; }
 | 
						|
                if (response == '') { response = "No websocket sessions."; }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case 'netinfo': { // Show network interface information
 | 
						|
                //response = objToString(mesh.NetInfo, 0, ' ');
 | 
						|
                var interfaces = require('os').networkInterfaces();
 | 
						|
                response = objToString(interfaces, 0, ' ', true);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case 'name':
 | 
						|
                {
 | 
						|
                    response = 'Service Name = ' + require('MeshAgent').serviceName;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    } catch (e) { response = "Command returned an exception error: " + e; console.log(e); }
 | 
						|
    if (response != null) { sendConsoleText(response, sessionid); }
 | 
						|
}
 | 
						|
 | 
						|
// Get a formated response for a given directory path
 | 
						|
function getDirectoryInfo(reqpath) {
 | 
						|
    var response = { path: reqpath, dir: [] };
 | 
						|
    if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32')) {
 | 
						|
        // List all the drives in the root, or the root itself
 | 
						|
        var results = null;
 | 
						|
        try { results = fs.readDrivesSync(); } catch (e) { } // TODO: Anyway to get drive total size and free space? Could draw a progress bar.
 | 
						|
        if (results != null) {
 | 
						|
            for (var i = 0; i < results.length; ++i) {
 | 
						|
                var drive = { n: results[i].name, t: 1 };
 | 
						|
                if (results[i].type == 'REMOVABLE') { drive.dt = 'removable'; } // TODO: See if this is USB/CDROM or something else, we can draw icons.
 | 
						|
                response.dir.push(drive);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        // List all the files and folders in this path
 | 
						|
        if (reqpath == '') { reqpath = '/'; }
 | 
						|
        var results = null, xpath = path.join(reqpath, '*');
 | 
						|
        //if (process.platform == "win32") { xpath = xpath.split('/').join('\\'); }
 | 
						|
        try { results = fs.readdirSync(xpath); } catch (e) { }
 | 
						|
        if (results != null) {
 | 
						|
            for (var i = 0; i < results.length; ++i) {
 | 
						|
                if ((results[i] != '.') && (results[i] != '..')) {
 | 
						|
                    var stat = null, p = path.join(reqpath, results[i]);
 | 
						|
                    //if (process.platform == "win32") { p = p.split('/').join('\\'); }
 | 
						|
                    try { stat = fs.statSync(p); } catch (e) { } // TODO: Get file size/date
 | 
						|
                    if ((stat != null) && (stat != undefined)) {
 | 
						|
                        if (stat.isDirectory() == true) {
 | 
						|
                            response.dir.push({ n: results[i], t: 2, d: stat.mtime });
 | 
						|
                        } else {
 | 
						|
                            response.dir.push({ n: results[i], t: 3, s: stat.size, d: stat.mtime });
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return response;
 | 
						|
}
 | 
						|
// Delete a directory with a files and directories within it
 | 
						|
function deleteFolderRecursive(path, rec) {
 | 
						|
    if (fs.existsSync(path)) {
 | 
						|
        if (rec == true) {
 | 
						|
            fs.readdirSync(path.join(path, '*')).forEach(function (file, index) {
 | 
						|
                var curPath = path.join(path, file);
 | 
						|
                if (fs.statSync(curPath).isDirectory()) { // recurse
 | 
						|
                    deleteFolderRecursive(curPath, true);
 | 
						|
                } else { // delete file
 | 
						|
                    fs.unlinkSync(curPath);
 | 
						|
                }
 | 
						|
            });
 | 
						|
        }
 | 
						|
        fs.unlinkSync(path);
 | 
						|
    }
 | 
						|
};
 |