mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	Added SMTP email support, email verification and password reset support
This commit is contained in:
		
							parent
							
								
									e740045b39
								
							
						
					
					
						commit
						72ee422623
					
				
					 24 changed files with 2586 additions and 166 deletions
				
			
		| 
						 | 
				
			
			@ -21,10 +21,14 @@
 | 
			
		|||
  <PropertyGroup Condition="'$(Configuration)' == 'Release'" />
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="agents\meshcore.js" />
 | 
			
		||||
    <Compile Include="agents\modules_meshcmd\amt_heci.js" />
 | 
			
		||||
    <Compile Include="agents\modules_meshcore\amt_heci.js" />
 | 
			
		||||
    <Compile Include="agents\modules_meshcore\WifiScanner.js" />
 | 
			
		||||
    <Compile Include="agents\tinycore.js" />
 | 
			
		||||
    <Compile Include="amtevents.js" />
 | 
			
		||||
    <Compile Include="amtscanner.js" />
 | 
			
		||||
    <Compile Include="amtscript.js" />
 | 
			
		||||
    <Compile Include="meshmail.js" />
 | 
			
		||||
    <Compile Include="meshscanner.js" />
 | 
			
		||||
    <Compile Include="certoperations.js" />
 | 
			
		||||
    <Compile Include="common.js" />
 | 
			
		||||
| 
						 | 
				
			
			@ -158,10 +162,13 @@
 | 
			
		|||
    <Content Include="views\default.handlebars" />
 | 
			
		||||
    <Content Include="views\download.handlebars" />
 | 
			
		||||
    <Content Include="views\login.handlebars" />
 | 
			
		||||
    <Content Include="views\message.handlebars" />
 | 
			
		||||
    <Content Include="views\terms.handlebars" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Folder Include="agents\" />
 | 
			
		||||
    <Folder Include="agents\modules_meshcmd\" />
 | 
			
		||||
    <Folder Include="agents\modules_meshcore\" />
 | 
			
		||||
    <Folder Include="public" />
 | 
			
		||||
    <Folder Include="public\clickonce\" />
 | 
			
		||||
    <Folder Include="public\clickonce\minirouter\" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -31,15 +31,35 @@ function createMeshCore(agent) {
 | 
			
		|||
    var net = require('net');
 | 
			
		||||
    var fs = require('fs');
 | 
			
		||||
    var rtc = require('ILibWebRTC');
 | 
			
		||||
    var amtMei = null, amtLms = null, amtLmsState = 0;
 | 
			
		||||
    var amtMeiConnected = 0, amtMeiState = null, amtMeiTmpState = null;
 | 
			
		||||
    var wifiScannerLib = null;
 | 
			
		||||
    var wifiScanner = null;
 | 
			
		||||
    var networkMonitor = null;
 | 
			
		||||
 | 
			
		||||
    // Try to load up the network monitor
 | 
			
		||||
    try {
 | 
			
		||||
        networkMonitor = require('NetworkMonitor');
 | 
			
		||||
        networkMonitor.on('change', function () { sendNetworkUpdateNagle(); });
 | 
			
		||||
        networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
 | 
			
		||||
        networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
 | 
			
		||||
    } catch (e) { networkMonitor = null; }
 | 
			
		||||
 | 
			
		||||
    // Try to load up the MEI module
 | 
			
		||||
    try {
 | 
			
		||||
        var amtMeiLib = require('amt_heci');
 | 
			
		||||
        amtMeiConnected = 1;
 | 
			
		||||
        amtMei = new amtMeiLib();
 | 
			
		||||
        amtMei.on('error', function (e) { amtMeiLib = null; amtMei = null; sendPeriodicServerUpdate(); });
 | 
			
		||||
        amtMei.on('connect', function () { amtMeiConnected = 2; getAmtInfo(); });
 | 
			
		||||
    } catch (e) { amtMeiLib = null; amtMei = null; amtMeiConnected = -1; }
 | 
			
		||||
 | 
			
		||||
    // Try to load up the WIFI scanner
 | 
			
		||||
    try {
 | 
			
		||||
        wifiScannerLib = require('WifiScanner');
 | 
			
		||||
        var wifiScannerLib = require('WifiScanner');
 | 
			
		||||
        wifiScanner = new wifiScannerLib();
 | 
			
		||||
        wifiScanner.on('accessPoint', function (data) { sendConsoleText(JSON.stringify(data)); });
 | 
			
		||||
    } catch (e) { }
 | 
			
		||||
    } catch (e) { wifiScannerLib = null; wifiScanner = null; }
 | 
			
		||||
 | 
			
		||||
    // If we are running in Duktape, agent will be null
 | 
			
		||||
    if (agent == null) {
 | 
			
		||||
| 
						 | 
				
			
			@ -656,7 +676,7 @@ function createMeshCore(agent) {
 | 
			
		|||
            var response = null;
 | 
			
		||||
            switch (cmd) {
 | 
			
		||||
                case 'help': { // Displays available commands
 | 
			
		||||
                    response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, modules, scanwifi.';
 | 
			
		||||
                    response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi.';
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'notify': { // Send a notification message to the mesh
 | 
			
		||||
| 
						 | 
				
			
			@ -671,9 +691,11 @@ function createMeshCore(agent) {
 | 
			
		|||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'info': { // Return information about the agent and agent core module
 | 
			
		||||
                    response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.\r\nServer URL: ' + mesh.ServerUrl + '.\r\n';
 | 
			
		||||
                    response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
 | 
			
		||||
                    if (amtLmsState >= 0) { response += '\r\nBuilt -in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amtLmsState] + '.'; }
 | 
			
		||||
                    response += '\r\nModules: ' + JSON.stringify(addedModules) + '';
 | 
			
		||||
                    var oldNodeId = db.Get('OldNodeId');
 | 
			
		||||
                    if (oldNodeId != null) { response += 'OldNodeID: ' + oldNodeId + '.\r\n'; }
 | 
			
		||||
                    if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; }
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'selfinfo': { // Return self information block
 | 
			
		||||
| 
						 | 
				
			
			@ -849,12 +871,8 @@ function createMeshCore(agent) {
 | 
			
		|||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'amt': { // Show Intel AMT status
 | 
			
		||||
                    //response = 'KVM: ' + mesh.hasKVM + ', HECI: ' + mesh.hasHECI + ', MicroLMS: ' + mesh.activeMicroLMS + '\r\n';
 | 
			
		||||
                    //response += JSON.stringify(mesh.MEInfo);
 | 
			
		||||
                    if (mesh.hasHECI == 1) {
 | 
			
		||||
                        var meinfo = mesh.MEInfo;
 | 
			
		||||
                        delete meinfo.TrustedHashes;
 | 
			
		||||
                        response = objToString(meinfo, 0, '.');
 | 
			
		||||
                    if (amtMeiState != null) {
 | 
			
		||||
                        response = objToString(amtMeiState, 0, '.');
 | 
			
		||||
                    } else {
 | 
			
		||||
                        response = 'This mesh agent does not support Intel AMT.';
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -902,10 +920,6 @@ function createMeshCore(agent) {
 | 
			
		|||
                    response = JSON.stringify(http.parseUri(args['_'][0]));
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'modules': {
 | 
			
		||||
                    response = "Modules: " + JSON.stringify(addedModules);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'scanwifi': {
 | 
			
		||||
                    if (wifiScanner != null) {
 | 
			
		||||
                        var wifiPresent = wifiScanner.hasWireless;
 | 
			
		||||
| 
						 | 
				
			
			@ -943,7 +957,7 @@ function createMeshCore(agent) {
 | 
			
		|||
            var oldNodeId = db.Get('OldNodeId');
 | 
			
		||||
            if (oldNodeId != null) { mesh.SendCommand({ action: 'mc1migration', oldnodeid: oldNodeId }); }
 | 
			
		||||
            sendPeriodicServerUpdate(true);
 | 
			
		||||
            if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 60000); } // Should be a long time, like 20 minutes. For now, 1 minute.
 | 
			
		||||
            //if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 60000); } // Should be a long time, like 20 minutes. For now, 1 minute.
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -952,23 +966,24 @@ function createMeshCore(agent) {
 | 
			
		|||
    function buildSelfInfo() {
 | 
			
		||||
        var r = { "action": "coreinfo", "value": obj.meshCoreInfo, "caps": obj.meshCoreCapabilities };
 | 
			
		||||
        if (mesh.hasHECI == 1) {
 | 
			
		||||
            var meinfo = mesh.MEInfo;
 | 
			
		||||
            var meinfo = amtMeiState;
 | 
			
		||||
            var amtPresent = false, intelamt = {};
 | 
			
		||||
            if (meinfo.Versions && meinfo.Versions.AMT) { intelamt.ver = meinfo.Versions.AMT; amtPresent = true; }
 | 
			
		||||
            if (meinfo.ProvisioningState) { intelamt.state = meinfo.ProvisioningState; amtPresent = true; }
 | 
			
		||||
            if (meinfo.flags) { intelamt.flags = meinfo.Flags; amtPresent = true; }
 | 
			
		||||
            if (meinfo.OsHostname) { intelamt.host = meinfo.OsHostname; amtPresent = true; }
 | 
			
		||||
            if (amtPresent == true) { r.intelamt = intelamt }
 | 
			
		||||
            if (meinfo != null) {
 | 
			
		||||
                if (meinfo.Versions && meinfo.Versions.AMT) { intelamt.ver = meinfo.Versions.AMT; amtPresent = true; }
 | 
			
		||||
                if (meinfo.ProvisioningState) { intelamt.state = meinfo.ProvisioningState; amtPresent = true; }
 | 
			
		||||
                if (meinfo.flags) { intelamt.flags = meinfo.Flags; amtPresent = true; }
 | 
			
		||||
                if (meinfo.OsHostname) { intelamt.host = meinfo.OsHostname; amtPresent = true; }
 | 
			
		||||
                if (amtPresent == true) { r.intelamt = intelamt }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return JSON.stringify(r);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Called periodically to check if we need to send updates to the server
 | 
			
		||||
    function sendPeriodicServerUpdate(force) {
 | 
			
		||||
        // Update the self information data
 | 
			
		||||
        var selfInfo = buildSelfInfo();
 | 
			
		||||
        var selfInfoStr = JSON.stringify(selfInfo);
 | 
			
		||||
        if ((force == true) || (selfInfoStr != lastSelfInfo)) { mesh.SendCommand(selfInfo); lastSelfInfo = selfInfoStr; }
 | 
			
		||||
    // Update the server with the latest network interface information
 | 
			
		||||
    var sendNetworkUpdateNagleTimer = null;
 | 
			
		||||
    function sendNetworkUpdateNagle() { if (sendNetworkUpdateNagleTimer != null) { clearTimeout(sendNetworkUpdateNagleTimer); sendNetworkUpdateNagleTimer = null; } sendNetworkUpdateNagleTimer = setTimeout(sendNetworkUpdate, 5000); }
 | 
			
		||||
    function sendNetworkUpdate(force) {
 | 
			
		||||
        sendNetworkUpdateNagleTimer = null;
 | 
			
		||||
 | 
			
		||||
        // Update the network interfaces information data
 | 
			
		||||
        var netInfo = mesh.NetInfo;
 | 
			
		||||
| 
						 | 
				
			
			@ -977,6 +992,32 @@ function createMeshCore(agent) {
 | 
			
		|||
        if ((force == true) || (clearGatewayMac(netInfoStr) != clearGatewayMac(lastNetworkInfo))) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Called periodically to check if we need to send updates to the server
 | 
			
		||||
    function sendPeriodicServerUpdate(force) {
 | 
			
		||||
        if (amtMeiConnected != 1) { // If we are pending MEI connection, hold off on updating the server on self-info
 | 
			
		||||
            // Update the self information data
 | 
			
		||||
            var selfInfo = buildSelfInfo(), selfInfoStr = JSON.stringify(selfInfo);
 | 
			
		||||
            if ((force == true) || (selfInfoStr != lastSelfInfo)) { mesh.SendCommand(selfInfo); lastSelfInfo = selfInfoStr; }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Update network information
 | 
			
		||||
        sendNetworkUpdateNagle(force);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get Intel AMT information using MEI
 | 
			
		||||
    function getAmtInfo(func) {
 | 
			
		||||
        if (amtMei == null || amtMeiConnected != 2) { if (func != null) { func(null); } return; }
 | 
			
		||||
        amtMeiTmpState = { Flags: 0 }; // Flags: 1=EHBC, 2=CCM, 4=ACM
 | 
			
		||||
        amtMei.getProtocolVersion(function (result) { if (result != null) { amtMeiTmpState.MeiVersion = result; } });
 | 
			
		||||
        amtMei.getVersion(function (val) { amtMeiTmpState.Versions = {}; for (var version in val.Versions) { amtMeiTmpState.Versions[val.Versions[version].Description] = val.Versions[version].Version; } });
 | 
			
		||||
        amtMei.getProvisioningMode(function (result) { amtMeiTmpState.ProvisioningMode = result.mode; });
 | 
			
		||||
        amtMei.getProvisioningState(function (result) { amtMeiTmpState.ProvisioningState = result.state; });
 | 
			
		||||
        amtMei.getEHBCState(function (result) { if (result.EHBC == true) { amtMeiTmpState.Flags += 1; } });
 | 
			
		||||
        amtMei.getControlMode(function (result) { if (result.controlMode == 1) { amtMeiTmpState.Flags += 2; } if (result.controlMode == 2) { amtMeiTmpState.Flags += 4; } });
 | 
			
		||||
        //amtMei.getMACAddresses(function (result) { amtMeiTmpState.mac = result; });
 | 
			
		||||
        amtMei.getDnsSuffix(function (result) { if (result != null) { amtMeiTmpState.dns = result; } amtMeiState = amtMeiTmpState; sendPeriodicServerUpdate(); if (func != null) { func(amtMeiState); } });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Called on MicroLMS Intel AMT user notification
 | 
			
		||||
    function handleAmtNotification(notification) {
 | 
			
		||||
        var amtMessage = notification.messageId;
 | 
			
		||||
| 
						 | 
				
			
			@ -1021,7 +1062,7 @@ function createMeshCore(agent) {
 | 
			
		|||
        // Setup the mesh agent event handlers
 | 
			
		||||
        mesh.AddCommandHandler(handleServerCommand);
 | 
			
		||||
        mesh.AddConnectHandler(handleServerConnection);
 | 
			
		||||
        mesh.lmsNotification = handleAmtNotification;
 | 
			
		||||
        //mesh.lmsNotification = handleAmtNotification; // TODO
 | 
			
		||||
        sendPeriodicServerUpdate(); // TODO: Check if connected before sending
 | 
			
		||||
 | 
			
		||||
        // Parse input arguments
 | 
			
		||||
| 
						 | 
				
			
			@ -1030,6 +1071,15 @@ function createMeshCore(agent) {
 | 
			
		|||
 | 
			
		||||
        //console.log('Stopping.');
 | 
			
		||||
        //process.exit();
 | 
			
		||||
 | 
			
		||||
        // Launch LMS
 | 
			
		||||
        try {
 | 
			
		||||
            var lme_heci = require('lme_heci');
 | 
			
		||||
            amtLmsState = 1;
 | 
			
		||||
            amtLms = new lme_heci();
 | 
			
		||||
            amtLms.on('error', function (e) { amtLmsState = 0; amtLms = null; });
 | 
			
		||||
            amtLms.on('connect', function () { amtLmsState = 2; });
 | 
			
		||||
        } catch (e) { amtLmsState = -1; amtLms = null; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    obj.stop = function () {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										281
									
								
								agents/modules_meshcmd/amt_heci.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								agents/modules_meshcmd/amt_heci.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,281 @@
 | 
			
		|||
var Q = require('queue');
 | 
			
		||||
 | 
			
		||||
function amt_heci() {
 | 
			
		||||
    var emitterUtils = require('events').inherits(this);
 | 
			
		||||
    emitterUtils.createEvent('error');
 | 
			
		||||
    emitterUtils.createEvent('connect');
 | 
			
		||||
 | 
			
		||||
    var heci = require('heci');
 | 
			
		||||
 | 
			
		||||
    this._amt = heci.create();
 | 
			
		||||
    this._amt.BiosVersionLen = 65;
 | 
			
		||||
    this._amt.UnicodeStringLen = 20;
 | 
			
		||||
 | 
			
		||||
    this._amt.rq = new Q();
 | 
			
		||||
    this._amt.Parent = this;
 | 
			
		||||
    this._amt.on('error', function (e) { this.Parent.emit('error', e); });
 | 
			
		||||
    this._amt.on('connect', function () {
 | 
			
		||||
        this.Parent.emit('connect');
 | 
			
		||||
        this.on('data', function (chunk) {
 | 
			
		||||
            //console.log("Received: " + chunk.length + " bytes");
 | 
			
		||||
            var header = this.Parent.getCommand(chunk);
 | 
			
		||||
            //console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse);
 | 
			
		||||
 | 
			
		||||
            var user = this.rq.deQueue();
 | 
			
		||||
            var params = user.optional;
 | 
			
		||||
            var callback = user.func;
 | 
			
		||||
 | 
			
		||||
            params.unshift(header);
 | 
			
		||||
            callback.apply(this.Parent, params);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 });
 | 
			
		||||
 | 
			
		||||
    this.getCommand = function (chunk) {
 | 
			
		||||
        var command = chunk.length == 0 ? (this._amt.rq.peekQueue().cmd | 0x800000) : chunk.readUInt32LE(4);
 | 
			
		||||
        var ret = { IsResponse: (command & 0x800000) == 0x800000 ? true : false, Command: (command & 0x7FFFFF), Status: chunk.length != 0 ? chunk.readUInt32LE(12) : -1, Data: chunk.length != 0 ? chunk.slice(16) : null };
 | 
			
		||||
        return (ret);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.sendCommand = function () {
 | 
			
		||||
        if (arguments.length < 3 || typeof (arguments[0]) != 'number' || typeof (arguments[1]) != 'object' || typeof (arguments[2]) != 'function') { throw ('invalid parameters'); }
 | 
			
		||||
        var args = [];
 | 
			
		||||
        for (var i = 3; i < arguments.length; ++i) { args.push(arguments[i]); }
 | 
			
		||||
 | 
			
		||||
        this._amt.rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args });
 | 
			
		||||
 | 
			
		||||
        var header = Buffer.from('010100000000000000000000', 'hex');
 | 
			
		||||
        header.writeUInt32LE(arguments[0] | 0x04000000, 4);
 | 
			
		||||
        header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8);
 | 
			
		||||
 | 
			
		||||
        this._amt.write(arguments[1] == null ? header : Buffer.concat([header, arguments[1]]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.getVersion = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(26, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4);
 | 
			
		||||
                for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) {
 | 
			
		||||
                    val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() };
 | 
			
		||||
                    v = v.slice(4 + (2 * this._amt.UnicodeStringLen));
 | 
			
		||||
                }
 | 
			
		||||
                opt.unshift(val);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.getProvisioningState = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(17, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var result = {};
 | 
			
		||||
                result.state = header.Data.readUInt32LE(0);
 | 
			
		||||
                if (result.state < 3) { result.stateStr = ["PRE", "IN", "POST"][result.state]; }
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getProvisioningMode = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(8, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var result = {};
 | 
			
		||||
                result.mode = header.Data.readUInt32LE(0);
 | 
			
		||||
                if (result.mode < 4) { result.modeStr = ["NONE", "ENTERPRISE", "SMALL_BUSINESS", "REMOTE_ASSISTANCE"][result.mode]; }
 | 
			
		||||
                result.legacy = header.Data.readUInt32LE(4) == 0 ? false : true;
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getEHBCState = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(132, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                opt.unshift({ EHBC: header.Data.readUInt32LE(0) != 0 });
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getControlMode = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(107, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var result = {};
 | 
			
		||||
                result.controlMode = header.Data.readUInt32LE(0);
 | 
			
		||||
                if (result.controlMode < 3) { result.controlModeStr = ["NONE_RPAT", "CLIENT", "ADMIN", "REMOTE_ASSISTANCE"][result.controlMode]; }
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getMACAddresses = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(37, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                opt.unshift({ DedicatedMAC: header.Data.slice(0, 6).toString('hex:'), HostMAC: header.Data.slice(6, 12).toString('hex:') });
 | 
			
		||||
            } else { opt.unshift({ DedicatedMAC: null, HostMAC: null }); }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getDnsSuffix = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(54, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var resultLen = header.Data.readUInt16LE(0);
 | 
			
		||||
                if (resultLen > 0) { opt.unshift(header.Data.slice(2, 2 + resultLen).toString()); } else { opt.unshift(null); }
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getHashHandles = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x2C, null, function (header, fn, opt) {
 | 
			
		||||
            var result = [];
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var resultLen = header.Data.readUInt32LE(0);
 | 
			
		||||
                for (var i = 0; i < resultLen; ++i) {
 | 
			
		||||
                    result.push(header.Data.readUInt32LE(4 + (4 * i)));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            opt.unshift(result);
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getCertHashEntry = function (handle, callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
 | 
			
		||||
        var data = new Buffer(4);
 | 
			
		||||
        data.writeUInt32LE(handle, 0);
 | 
			
		||||
 | 
			
		||||
        this.sendCommand(0x2D, data, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var result = {};
 | 
			
		||||
                result.isDefault = header.Data.readUInt32LE(0);
 | 
			
		||||
                result.isActive = header.Data.readUInt32LE(4);
 | 
			
		||||
                result.hashAlgorithm = header.Data.readUInt8(72);
 | 
			
		||||
                if (result.hashAlgorithm < 4) {
 | 
			
		||||
                    result.hashAlgorithmStr = ["MD5", "SHA1", "SHA256", "SHA512"][result.hashAlgorithm];
 | 
			
		||||
                    result.hashAlgorithmSize = [16, 20, 32, 64][result.hashAlgorithm];
 | 
			
		||||
                    result.certificateHash = header.Data.slice(8, 8 + result.hashAlgorithmSize).toString('hex');
 | 
			
		||||
                }
 | 
			
		||||
                result.name = header.Data.slice(73 + 2, 73 + 2 + header.Data.readUInt16LE(73)).toString();
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getCertHashEntries = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
 | 
			
		||||
        this.getHashHandles(function (handles, fn, opt) {
 | 
			
		||||
            var entries = [];
 | 
			
		||||
            this.getCertHashEntry(handles.shift(), this._getHashEntrySink, fn, opt, entries, handles);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this._getHashEntrySink = function (result, fn, opt, entries, handles) {
 | 
			
		||||
        entries.push(result);
 | 
			
		||||
        if (handles.length > 0) {
 | 
			
		||||
            this.getCertHashEntry(handles.shift(), this._getHashEntrySink, fn, opt, entries, handles);
 | 
			
		||||
        } else {
 | 
			
		||||
            opt.unshift(entries);
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    this.getLocalSystemAccount = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) {
 | 
			
		||||
            if (header.Data.length == 68) { opt.unshift({ user: header.Data.slice(0, 34).toString(), pass: header.Data.slice(34, 67).toString(), raw: header.Data }); } else { opt.unshift(null); }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.unprovision = function (mode, callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        var data = new Buffer(4);
 | 
			
		||||
        data.writeUInt32LE(mode, 0);
 | 
			
		||||
        this.sendCommand(16, data, function (header, fn, opt) {
 | 
			
		||||
            opt.unshift(header.Status);
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.startConfiguration = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x29, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.stopConfiguration = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x5E, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.openUserInitiatedConnection = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x44, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.closeUserInitiatedConnection = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x45, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.getRemoteAccessConnectionStatus = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x46, data, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var hostname = v.slice(14, header.Data.readUInt16LE(12) + 14).toString()
 | 
			
		||||
                opt.unshift({ status: header.Status, networkStatus: header.Data.readUInt32LE(0), remoteAccessStatus: header.Data.readUInt32LE(4), remoteAccessTrigger: header.Data.readUInt32LE(8), mpsHostname: hostname, raw: header.Data });
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift({ status: header.Status });
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.getProtocolVersion = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { opt.push(arguments[i]); }
 | 
			
		||||
 | 
			
		||||
        heci.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) {
 | 
			
		||||
            if (status == 0) {
 | 
			
		||||
                var result = buffer.readUInt8(0).toString() + '.' + buffer.readUInt8(1).toString() + '.' + buffer.readUInt8(2).toString() + '.' + buffer.readUInt16BE(3).toString();
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
                fn.apply(self, opt);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
                fn.apply(self, opt);
 | 
			
		||||
            }
 | 
			
		||||
        }, this, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = amt_heci;
 | 
			
		||||
							
								
								
									
										354
									
								
								agents/modules_meshcmd/lme_heci.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								agents/modules_meshcmd/lme_heci.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,354 @@
 | 
			
		|||
 | 
			
		||||
var MemoryStream = require('MemoryStream');
 | 
			
		||||
var lme_id = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var APF_DISCONNECT = 1;
 | 
			
		||||
var APF_SERVICE_REQUEST = 5;
 | 
			
		||||
var APF_SERVICE_ACCEPT = 6;
 | 
			
		||||
var APF_USERAUTH_REQUEST = 50;
 | 
			
		||||
var APF_USERAUTH_FAILURE = 51;
 | 
			
		||||
var APF_USERAUTH_SUCCESS = 52;
 | 
			
		||||
var APF_GLOBAL_REQUEST = 80;
 | 
			
		||||
var APF_REQUEST_SUCCESS = 81;
 | 
			
		||||
var APF_REQUEST_FAILURE = 82;
 | 
			
		||||
var APF_CHANNEL_OPEN = 90;
 | 
			
		||||
var APF_CHANNEL_OPEN_CONFIRMATION = 91;
 | 
			
		||||
var APF_CHANNEL_OPEN_FAILURE = 92;
 | 
			
		||||
var APF_CHANNEL_WINDOW_ADJUST = 93;
 | 
			
		||||
var APF_CHANNEL_DATA = 94;
 | 
			
		||||
var APF_CHANNEL_CLOSE = 97;
 | 
			
		||||
var APF_PROTOCOLVERSION = 192;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function lme_object()
 | 
			
		||||
{
 | 
			
		||||
    this.ourId = ++lme_id;
 | 
			
		||||
    this.amtId = -1;
 | 
			
		||||
    this.LME_CHANNEL_STATUS = 'LME_CS_FREE';
 | 
			
		||||
    this.txWindow = 0;
 | 
			
		||||
    this.rxWindow = 0;
 | 
			
		||||
    this.localPort = 0;
 | 
			
		||||
    this.errorCount = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function stream_bufferedWrite()
 | 
			
		||||
{
 | 
			
		||||
    var emitterUtils = require('events').inherits(this);
 | 
			
		||||
    this.buffer = [];
 | 
			
		||||
    this._readCheckImmediate = undefined;
 | 
			
		||||
 | 
			
		||||
    // Writable Events
 | 
			
		||||
    emitterUtils.createEvent('close');
 | 
			
		||||
    emitterUtils.createEvent('drain');
 | 
			
		||||
    emitterUtils.createEvent('error');
 | 
			
		||||
    emitterUtils.createEvent('finish');
 | 
			
		||||
    emitterUtils.createEvent('pipe');
 | 
			
		||||
    emitterUtils.createEvent('unpipe');
 | 
			
		||||
 | 
			
		||||
    // Readable Events
 | 
			
		||||
    emitterUtils.createEvent('readable');
 | 
			
		||||
    this.isEmpty = function ()
 | 
			
		||||
    {
 | 
			
		||||
        return (this.buffer.length == 0);
 | 
			
		||||
    };
 | 
			
		||||
    this.isWaiting = function ()
 | 
			
		||||
    {
 | 
			
		||||
        return (this._readCheckImmediate == undefined);
 | 
			
		||||
    };
 | 
			
		||||
    this.write = function (chunk)
 | 
			
		||||
    {
 | 
			
		||||
        for (var args in arguments)
 | 
			
		||||
        {
 | 
			
		||||
            if (typeof (arguments[args]) == 'function') { this.once('drain', arguments[args]); break; }
 | 
			
		||||
        }
 | 
			
		||||
        var tmp = Buffer.alloc(chunk.length);
 | 
			
		||||
        chunk.copy(tmp);
 | 
			
		||||
        this.buffer.push({ offset: 0, data: tmp });
 | 
			
		||||
        this.emit('readable');
 | 
			
		||||
        return (this.buffer.length == 0 ? true : false);
 | 
			
		||||
    };
 | 
			
		||||
    this.read = function ()
 | 
			
		||||
    {
 | 
			
		||||
        var size = arguments.length == 0 ? undefined : arguments[0];
 | 
			
		||||
        var bytesRead = 0;
 | 
			
		||||
        var list = [];
 | 
			
		||||
        while((size == undefined || bytesRead < size) && this.buffer.length > 0)
 | 
			
		||||
        {
 | 
			
		||||
            var len = this.buffer[0].data.length - this.buffer[0].offset;
 | 
			
		||||
            var offset = this.buffer[0].offset;
 | 
			
		||||
 | 
			
		||||
            if(len > (size - bytesRead))
 | 
			
		||||
            {
 | 
			
		||||
                // Only reading a subset
 | 
			
		||||
                list.push(this.buffer[0].data.slice(offset, offset + size - bytesRead));
 | 
			
		||||
                this.buffer[0].offset += (size - bytesRead);
 | 
			
		||||
                bytesRead += (size - bytesRead);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // Reading the entire thing
 | 
			
		||||
                list.push(this.buffer[0].data.slice(offset));
 | 
			
		||||
                bytesRead += len;
 | 
			
		||||
                this.buffer.shift();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this._readCheckImmediate = setImmediate(function (buffered)
 | 
			
		||||
        {
 | 
			
		||||
            buffered._readCheckImmediate = undefined;
 | 
			
		||||
            if(buffered.buffer.length == 0)
 | 
			
		||||
            {
 | 
			
		||||
                // drained
 | 
			
		||||
                buffered.emit('drain');
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // not drained
 | 
			
		||||
                buffered.emit('readable');
 | 
			
		||||
            }
 | 
			
		||||
        }, this);
 | 
			
		||||
        return (Buffer.concat(list));
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function lme_heci()
 | 
			
		||||
{
 | 
			
		||||
    var emitterUtils = require('events').inherits(this);
 | 
			
		||||
    emitterUtils.createEvent('error');
 | 
			
		||||
    emitterUtils.createEvent('connect');
 | 
			
		||||
 | 
			
		||||
    var heci = require('heci');
 | 
			
		||||
    this.INITIAL_RXWINDOW_SIZE = 4096;
 | 
			
		||||
 | 
			
		||||
    this._LME = heci.create();
 | 
			
		||||
    this._LME.LMS = this;
 | 
			
		||||
    this._LME.on('error', function (e) { this.Parent.emit('error', e); });
 | 
			
		||||
    this._LME.on('connect', function ()
 | 
			
		||||
    {
 | 
			
		||||
        this.LMS.emit('connect');
 | 
			
		||||
        this.on('data', function (chunk)
 | 
			
		||||
        {
 | 
			
		||||
            // this = HECI
 | 
			
		||||
            var cmd = chunk.readUInt8(0);
 | 
			
		||||
           
 | 
			
		||||
            switch(cmd)
 | 
			
		||||
            {
 | 
			
		||||
                default:
 | 
			
		||||
                    //console.log('Received ' + chunk.length + ' bytes of data for LMS');
 | 
			
		||||
                    //console.log('Command = ' + cmd);
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_SERVICE_REQUEST:     
 | 
			
		||||
                    var nameLen = chunk.readUInt32BE(1);
 | 
			
		||||
                    var name = chunk.slice(5, nameLen + 5);
 | 
			
		||||
                    //console.log("Service Request for: " + name);
 | 
			
		||||
                    if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com')
 | 
			
		||||
                    {
 | 
			
		||||
                        var outBuffer = Buffer.alloc(5 + nameLen);
 | 
			
		||||
                        outBuffer.writeUInt8(6, 0);
 | 
			
		||||
                        outBuffer.writeUInt32BE(nameLen, 1);
 | 
			
		||||
                        outBuffer.write(name.toString(), 5);
 | 
			
		||||
                        this.write(outBuffer);
 | 
			
		||||
                        //console.log('Answering APF_SERVICE_REQUEST');
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //console.log('UNKNOWN APF_SERVICE_REQUEST');
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_GLOBAL_REQUEST:    
 | 
			
		||||
                    var nameLen = chunk.readUInt32BE(1);
 | 
			
		||||
                    var name = chunk.slice(5, nameLen + 5).toString();
 | 
			
		||||
                    
 | 
			
		||||
                    switch(name)
 | 
			
		||||
                    {
 | 
			
		||||
                        case 'tcpip-forward':
 | 
			
		||||
                            var len = chunk.readUInt32BE(nameLen + 6);
 | 
			
		||||
                            var port = chunk.readUInt32BE(nameLen + 10 + len);
 | 
			
		||||
                            //console.log("[" + chunk.length + "/" + len + "] APF_GLOBAL_REQUEST for: " + name + " on port " + port);
 | 
			
		||||
                            if (this[name] == undefined)
 | 
			
		||||
                            {
 | 
			
		||||
                                this[name] = {};
 | 
			
		||||
                            }
 | 
			
		||||
                            this[name][port] = require('net').createServer();
 | 
			
		||||
                            this[name][port].HECI = this;
 | 
			
		||||
                            this[name][port].listen({ port: port });
 | 
			
		||||
                            this[name][port].on('connection', function (socket)
 | 
			
		||||
                            {
 | 
			
		||||
                                //console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
 | 
			
		||||
                                this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort);
 | 
			
		||||
                            });
 | 
			
		||||
                            var outBuffer = Buffer.alloc(5);
 | 
			
		||||
                            outBuffer.writeUInt8(81, 0);
 | 
			
		||||
                            outBuffer.writeUInt32BE(port, 1);
 | 
			
		||||
                            this.write(outBuffer);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'cancel-tcpip-forward':
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'udp-send-to@amt.intel.com':
 | 
			
		||||
                            break;
 | 
			
		||||
                        default:
 | 
			
		||||
                            //console.log("Unknown APF_GLOBAL_REQUEST for: " + name);
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_CHANNEL_OPEN_CONFIRMATION:    
 | 
			
		||||
			        var rChannel = chunk.readUInt32BE(1);
 | 
			
		||||
			        var sChannel = chunk.readUInt32BE(5);
 | 
			
		||||
			        var wSize = chunk.readUInt32BE(9);
 | 
			
		||||
			        //console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
 | 
			
		||||
			        if (this.sockets[rChannel] != undefined)
 | 
			
		||||
			        {
 | 
			
		||||
			            this.sockets[rChannel].lme.amtId = sChannel;
 | 
			
		||||
			            this.sockets[rChannel].lme.rxWindow = wSize;
 | 
			
		||||
			            this.sockets[rChannel].lme.txWindow = wSize;
 | 
			
		||||
			            this.sockets[rChannel].lme.LME_CHANNEL_STATUS = 'LME_CS_CONNECTED';
 | 
			
		||||
			            //console.log('LME_CS_CONNECTED');
 | 
			
		||||
			            this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
 | 
			
		||||
			            this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
 | 
			
		||||
			            this.sockets[rChannel].bufferedStream.on('readable', function ()
 | 
			
		||||
			            {
 | 
			
		||||
			                if(this.socket.lme.txWindow > 0)
 | 
			
		||||
			                {
 | 
			
		||||
			                    var buffer = this.read(this.socket.lme.txWindow);
 | 
			
		||||
			                    var packet = Buffer.alloc(9 + buffer.length);
 | 
			
		||||
			                    packet.writeUInt8(APF_CHANNEL_DATA, 0);
 | 
			
		||||
			                    packet.writeUInt32BE(this.socket.lme.amtId, 1);
 | 
			
		||||
			                    packet.writeUInt32BE(buffer.length, 5);
 | 
			
		||||
			                    buffer.copy(packet, 9);
 | 
			
		||||
			                    this.socket.lme.txWindow -= buffer.length;
 | 
			
		||||
			                    this.socket.HECI.write(packet);
 | 
			
		||||
			                }
 | 
			
		||||
			            });
 | 
			
		||||
			            this.sockets[rChannel].bufferedStream.on('drain', function ()
 | 
			
		||||
			            {
 | 
			
		||||
			                this.socket.resume();
 | 
			
		||||
			            });
 | 
			
		||||
			            this.sockets[rChannel].on('data', function (chunk)
 | 
			
		||||
			            {
 | 
			
		||||
			                if (!this.bufferedStream.write(chunk)) { this.pause(); }
 | 
			
		||||
			            });
 | 
			
		||||
			            this.sockets[rChannel].on('end', function () 
 | 
			
		||||
			            {
 | 
			
		||||
			                var outBuffer = Buffer.alloc(5);
 | 
			
		||||
			                outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
 | 
			
		||||
			                outBuffer.writeUInt32BE(this.lme.amtId, 1);
 | 
			
		||||
			                this.HECI.write(outBuffer);
 | 
			
		||||
			            });
 | 
			
		||||
			            this.sockets[rChannel].resume();
 | 
			
		||||
			        }
 | 
			
		||||
 | 
			
		||||
		    	    break;
 | 
			
		||||
                case APF_PROTOCOLVERSION:   
 | 
			
		||||
                    var major = chunk.readUInt32BE(1);
 | 
			
		||||
                    var minor = chunk.readUInt32BE(5);
 | 
			
		||||
                    var reason = chunk.readUInt32BE(9);
 | 
			
		||||
                    var outBuffer = Buffer.alloc(93);
 | 
			
		||||
                    outBuffer.writeUInt8(192, 0);
 | 
			
		||||
                    outBuffer.writeUInt32BE(1, 1);
 | 
			
		||||
                    outBuffer.writeUInt32BE(0, 5);
 | 
			
		||||
                    outBuffer.writeUInt32BE(reason, 9);
 | 
			
		||||
                    //console.log('Answering PROTOCOL_VERSION');
 | 
			
		||||
                    this.write(outBuffer);
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_CHANNEL_WINDOW_ADJUST:
 | 
			
		||||
                    var rChannelId = chunk.readUInt32BE(1);
 | 
			
		||||
                    var bytesToAdd = chunk.readUInt32BE(5);
 | 
			
		||||
                    if (this.sockets[rChannelId] != undefined)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.sockets[rChannelId].lme.txWindow += bytesToAdd;
 | 
			
		||||
                        if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting())
 | 
			
		||||
                        {
 | 
			
		||||
                            this.sockets[rChannelId].bufferedStream.emit('readable');
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_WINDOW_ADJUST');
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_CHANNEL_DATA:
 | 
			
		||||
                    var rChannelId = chunk.readUInt32BE(1);
 | 
			
		||||
                    var dataLen = chunk.readUInt32BE(5);
 | 
			
		||||
                    var data = chunk.slice(9, 9 + dataLen);
 | 
			
		||||
                    if (this.sockets[rChannelId] != undefined)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.sockets[rChannelId].pendingBytes.push(data.length);
 | 
			
		||||
                        this.sockets[rChannelId].write(data, function ()
 | 
			
		||||
                        {
 | 
			
		||||
                            var written = this.pendingBytes.shift();
 | 
			
		||||
                            var outBuffer = Buffer.alloc(9);
 | 
			
		||||
                            outBuffer.writeUInt8(APF_CHANNEL_WINDOW_ADJUST, 0);
 | 
			
		||||
                            outBuffer.writeUInt32BE(this.lme.amtId, 1);
 | 
			
		||||
                            outBuffer.writeUInt32BE(written, 5);
 | 
			
		||||
                            this.HECI.write(outBuffer);
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_DATA');
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_CHANNEL_CLOSE:
 | 
			
		||||
                    var rChannelId = chunk.readUInt32BE(1);
 | 
			
		||||
                    if (this.sockets[rChannelId] != undefined)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.sockets[rChannelId].end();                    
 | 
			
		||||
                        var amtId = this.sockets[rChannelId].lme.amtId;
 | 
			
		||||
                        var buffer = Buffer.alloc(5);
 | 
			
		||||
                        delete this.sockets[rChannelId];
 | 
			
		||||
 | 
			
		||||
                        buffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
 | 
			
		||||
                        buffer.writeUInt32BE(amtId, 1);
 | 
			
		||||
                        this.write(buffer);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_CLOSE');
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
   
 | 
			
		||||
    this.bindDuplexStream = function (duplexStream, remoteFamily, localPort)
 | 
			
		||||
    {
 | 
			
		||||
        var socket = duplexStream;
 | 
			
		||||
        //console.log('New [' + remoteFamily + '] Virtual Connection/' + socket.localPort);
 | 
			
		||||
        socket.pendingBytes = [];
 | 
			
		||||
        socket.HECI = this._LME;
 | 
			
		||||
        socket.LMS = this;
 | 
			
		||||
        socket.lme = new lme_object();
 | 
			
		||||
        socket.lme.Socket = socket;
 | 
			
		||||
        var buffer = new MemoryStream();
 | 
			
		||||
        buffer.writeUInt8(0x5A);
 | 
			
		||||
        buffer.writeUInt32BE(15);
 | 
			
		||||
        buffer.write('forwarded-tcpip');
 | 
			
		||||
        buffer.writeUInt32BE(socket.lme.ourId);
 | 
			
		||||
        buffer.writeUInt32BE(this.INITIAL_RXWINDOW_SIZE);
 | 
			
		||||
        buffer.writeUInt32BE(0xFFFFFFFF);
 | 
			
		||||
        for (var i = 0; i < 2; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (remoteFamily == 'IPv6')
 | 
			
		||||
            {
 | 
			
		||||
                buffer.writeUInt32BE(3);
 | 
			
		||||
                buffer.write('::1');
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                buffer.writeUInt32BE(9);
 | 
			
		||||
                buffer.write('127.0.0.1');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            buffer.writeUInt32BE(localPort);
 | 
			
		||||
        }
 | 
			
		||||
        this._LME.write(buffer.buffer);
 | 
			
		||||
        if (this._LME.sockets == undefined) { this._LME.sockets = {}; }
 | 
			
		||||
        this._LME.sockets[socket.lme.ourId] = socket;
 | 
			
		||||
        socket.pause();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this._LME.connect(heci.GUIDS.LME, { noPipeline: 0 });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = lme_heci;
 | 
			
		||||
							
								
								
									
										266
									
								
								agents/modules_meshcore/WifiScanner.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								agents/modules_meshcore/WifiScanner.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,266 @@
 | 
			
		|||
var MemoryStream = require('MemoryStream');
 | 
			
		||||
var WindowsWireless = new Buffer([
 | 
			
		||||
0x0A, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x5F, 0x53, 0x63, 0x61, 0x6E, 0x28, 0x29, 0x0A, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x77, 0x6C, 0x61, 0x6E,
 | 
			
		||||
0x49, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
 | 
			
		||||
0x50, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x28, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x57, 0x6C, 0x61, 0x6E, 0x45,
 | 
			
		||||
0x6E, 0x75, 0x6D, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x77, 0x6C,
 | 
			
		||||
0x61, 0x6E, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x3D, 0x20,
 | 
			
		||||
0x77, 0x6C, 0x61, 0x6E, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x30, 0x2C, 0x20,
 | 
			
		||||
0x34, 0x29, 0x2E, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x20, 0x3D, 0x20, 0x77, 0x6C, 0x61, 0x6E, 0x49, 0x6E, 0x74, 0x65,
 | 
			
		||||
0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x38, 0x2C, 0x20, 0x35, 0x33, 0x32, 0x29, 0x3B, 0x0A, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x6E, 0x61, 0x6D, 0x65, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x31, 0x36, 0x2C, 0x20, 0x35, 0x31, 0x32,
 | 
			
		||||
0x29, 0x2E, 0x41, 0x6E, 0x73, 0x69, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3B, 0x0A, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x20, 0x28, 0x69, 0x6E, 0x66, 0x6F, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x35, 0x32, 0x38, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x56, 0x61,
 | 
			
		||||
0x6C, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x30, 0x3A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x4E, 0x4F, 0x54, 0x20, 0x52, 0x45, 0x41, 0x44, 0x59, 0x22, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x31, 0x3A, 0x0A, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x43, 0x4F, 0x4E, 0x4E, 0x45, 0x43, 0x54, 0x45, 0x44, 0x22, 0x3B, 0x0A,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20,
 | 
			
		||||
0x32, 0x3A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x41, 0x44, 0x2D, 0x48, 0x4F, 0x43, 0x22,
 | 
			
		||||
0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73,
 | 
			
		||||
0x65, 0x20, 0x33, 0x3A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x44, 0x49, 0x53, 0x43, 0x4F,
 | 
			
		||||
0x4E, 0x4E, 0x45, 0x43, 0x54, 0x49, 0x4E, 0x47, 0x22, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x34, 0x3A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65,
 | 
			
		||||
0x20, 0x3D, 0x20, 0x22, 0x44, 0x49, 0x53, 0x43, 0x4F, 0x4E, 0x4E, 0x45, 0x43, 0x54, 0x45, 0x44, 0x22, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62,
 | 
			
		||||
0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x35, 0x3A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x41, 0x53, 0x53, 0x4F, 0x43, 0x49, 0x41, 0x54, 0x49, 0x4E, 0x47, 0x22, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x36, 0x3A, 0x0A, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x44, 0x49, 0x53, 0x43, 0x4F, 0x56, 0x45, 0x52, 0x49, 0x4E, 0x47, 0x22, 0x3B,
 | 
			
		||||
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x61, 0x73, 0x65,
 | 
			
		||||
0x20, 0x37, 0x3A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, 0x20, 0x22, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4E,
 | 
			
		||||
0x54, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4E, 0x47, 0x22, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x3B, 0x0A, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x3A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74,
 | 
			
		||||
0x65, 0x20, 0x3D, 0x20, 0x22, 0x55, 0x4E, 0x4B, 0x4E, 0x4F, 0x57, 0x4E, 0x22, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B,
 | 
			
		||||
0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x67, 0x75, 0x69, 0x64, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x2E, 0x44, 0x65,
 | 
			
		||||
0x72, 0x65, 0x66, 0x28, 0x30, 0x2C, 0x20, 0x31, 0x36, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E,
 | 
			
		||||
0x57, 0x6C, 0x61, 0x6E, 0x53, 0x63, 0x61, 0x6E, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x2C, 0x20, 0x69, 0x67, 0x75, 0x69, 0x64, 0x2C, 0x20, 0x30, 0x2C, 0x20,
 | 
			
		||||
0x30, 0x2C, 0x20, 0x30, 0x29, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E,
 | 
			
		||||
0x20, 0x28, 0x74, 0x72, 0x75, 0x65, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6C, 0x73, 0x65, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x28, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x66,
 | 
			
		||||
0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x28, 0x5F, 0x73, 0x73, 0x69, 0x64, 0x2C, 0x20, 0x5F, 0x62, 0x73, 0x73, 0x69,
 | 
			
		||||
0x64, 0x2C, 0x20, 0x5F, 0x72, 0x73, 0x73, 0x69, 0x2C, 0x20, 0x5F, 0x6C, 0x71, 0x29, 0x0A, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x73, 0x73, 0x69, 0x64, 0x20, 0x3D,
 | 
			
		||||
0x20, 0x5F, 0x73, 0x73, 0x69, 0x64, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x62, 0x73, 0x73, 0x69, 0x64, 0x20, 0x3D, 0x20, 0x5F, 0x62, 0x73, 0x73, 0x69, 0x64, 0x3B,
 | 
			
		||||
0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x72, 0x73, 0x73, 0x69, 0x20, 0x3D, 0x20, 0x5F, 0x72, 0x73, 0x73, 0x69, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73,
 | 
			
		||||
0x2E, 0x6C, 0x71, 0x20, 0x3D, 0x20, 0x5F, 0x6C, 0x71, 0x3B, 0x0A, 0x7D, 0x0A, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x2E, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x74, 0x79,
 | 
			
		||||
0x70, 0x65, 0x2E, 0x74, 0x6F, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x3D, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x29, 0x0A, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72,
 | 
			
		||||
0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x73, 0x73, 0x69, 0x64, 0x20, 0x2B, 0x20, 0x22, 0x20, 0x5B, 0x22, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x62,
 | 
			
		||||
0x73, 0x73, 0x69, 0x64, 0x20, 0x2B, 0x20, 0x22, 0x5D, 0x3A, 0x20, 0x22, 0x20, 0x2B, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x6C, 0x71, 0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x66, 0x75, 0x6E, 0x63,
 | 
			
		||||
0x74, 0x69, 0x6F, 0x6E, 0x20, 0x4F, 0x6E, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x79, 0x28, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x61, 0x74, 0x61, 0x29, 0x0A,
 | 
			
		||||
0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x3D, 0x20, 0x4E,
 | 
			
		||||
0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x61, 0x74, 0x61, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x30, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x56, 0x61, 0x6C, 0x3B,
 | 
			
		||||
0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x43, 0x6F, 0x64, 0x65, 0x20, 0x3D, 0x20, 0x4E, 0x6F, 0x74, 0x69,
 | 
			
		||||
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x61, 0x74, 0x61, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x34, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x64, 0x61, 0x74, 0x61, 0x47, 0x75, 0x69, 0x64, 0x20, 0x3D, 0x20, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x61, 0x74,
 | 
			
		||||
0x61, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x38, 0x2C, 0x20, 0x31, 0x36, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x28, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69,
 | 
			
		||||
0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x26, 0x20, 0x30, 0x58, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x29, 0x20, 0x26, 0x26, 0x20, 0x28, 0x4E,
 | 
			
		||||
0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x43, 0x6F, 0x64, 0x65, 0x20, 0x3D, 0x3D, 0x20, 0x37, 0x29, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x73, 0x73, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x50, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68,
 | 
			
		||||
0x61, 0x6C, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x28, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20,
 | 
			
		||||
0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x50, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x47, 0x65, 0x74, 0x42,
 | 
			
		||||
0x53, 0x53, 0x4C, 0x69, 0x73, 0x74, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x50, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x2E, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x2C, 0x20, 0x64, 0x61, 0x74, 0x61, 0x47,
 | 
			
		||||
0x75, 0x69, 0x64, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x33, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x62, 0x73, 0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69,
 | 
			
		||||
0x66, 0x20, 0x28, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x53, 0x69, 0x7A, 0x65, 0x20, 0x3D, 0x20, 0x62, 0x73, 0x73, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28,
 | 
			
		||||
0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x30, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76,
 | 
			
		||||
0x61, 0x72, 0x20, 0x6E, 0x75, 0x6D, 0x49, 0x74, 0x65, 0x6D, 0x73, 0x20, 0x3D, 0x20, 0x62, 0x73, 0x73, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28,
 | 
			
		||||
0x34, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x28, 0x69, 0x20, 0x3D, 0x20,
 | 
			
		||||
0x30, 0x3B, 0x20, 0x69, 0x20, 0x3C, 0x20, 0x6E, 0x75, 0x6D, 0x49, 0x74, 0x65, 0x6D, 0x73, 0x3B, 0x20, 0x2B, 0x2B, 0x69, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x3D, 0x20, 0x62,
 | 
			
		||||
0x73, 0x73, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x38, 0x20, 0x2B, 0x20, 0x28, 0x33, 0x36, 0x30, 0x20, 0x2A, 0x20, 0x69, 0x29, 0x2C, 0x20,
 | 
			
		||||
0x33, 0x36, 0x30, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x73, 0x73, 0x69, 0x64, 0x20, 0x3D,
 | 
			
		||||
0x20, 0x69, 0x74, 0x65, 0x6D, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x34, 0x2C, 0x20, 0x33, 0x32, 0x29, 0x2E, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x74, 0x72, 0x69, 0x6D, 0x28, 0x29,
 | 
			
		||||
0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x62, 0x73, 0x73, 0x69, 0x64, 0x20, 0x3D, 0x20, 0x69, 0x74,
 | 
			
		||||
0x65, 0x6D, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x34, 0x30, 0x2C, 0x20, 0x36, 0x29, 0x2E, 0x48, 0x65, 0x78, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x32, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x73, 0x73, 0x69, 0x20, 0x3D, 0x20, 0x69, 0x74, 0x65, 0x6D, 0x2E, 0x44, 0x65, 0x72, 0x65,
 | 
			
		||||
0x66, 0x28, 0x35, 0x36, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61,
 | 
			
		||||
0x72, 0x20, 0x6C, 0x71, 0x20, 0x3D, 0x20, 0x69, 0x74, 0x65, 0x6D, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x36, 0x30, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x0A, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x50, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x2E, 0x65, 0x6D, 0x69, 0x74, 0x28,
 | 
			
		||||
0x27, 0x53, 0x63, 0x61, 0x6E, 0x27, 0x2C, 0x20, 0x6E, 0x65, 0x77, 0x20, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x28, 0x73, 0x73, 0x69, 0x64, 0x2C, 0x20, 0x62, 0x73,
 | 
			
		||||
0x73, 0x69, 0x64, 0x2C, 0x20, 0x72, 0x73, 0x73, 0x69, 0x2C, 0x20, 0x6C, 0x71, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x7D, 0x0A, 0x0A, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x57, 0x69, 0x72, 0x65,
 | 
			
		||||
0x6C, 0x65, 0x73, 0x73, 0x28, 0x29, 0x0A, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x65, 0x6D, 0x69, 0x74, 0x74, 0x65, 0x72, 0x55, 0x74, 0x69, 0x6C, 0x73, 0x20, 0x3D, 0x20,
 | 
			
		||||
0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x65, 0x76, 0x65, 0x6E, 0x74, 0x73, 0x27, 0x29, 0x2E, 0x69, 0x6E, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29,
 | 
			
		||||
0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x5F,
 | 
			
		||||
0x47, 0x65, 0x6E, 0x65, 0x72, 0x69, 0x63, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x27, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76,
 | 
			
		||||
0x65, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x72, 0x6F,
 | 
			
		||||
0x78, 0x79, 0x28, 0x22, 0x77, 0x6C, 0x61, 0x6E, 0x61, 0x70, 0x69, 0x2E, 0x64, 0x6C, 0x6C, 0x22, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69,
 | 
			
		||||
0x76, 0x65, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x28, 0x22, 0x57, 0x6C, 0x61, 0x6E, 0x4F, 0x70, 0x65, 0x6E, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x22,
 | 
			
		||||
0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x28,
 | 
			
		||||
0x22, 0x57, 0x6C, 0x61, 0x6E, 0x47, 0x65, 0x74, 0x4E, 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x42, 0x73, 0x73, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x2C, 0x20, 0x22, 0x47, 0x65, 0x74, 0x42, 0x53, 0x53,
 | 
			
		||||
0x4C, 0x69, 0x73, 0x74, 0x22, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4D, 0x65,
 | 
			
		||||
0x74, 0x68, 0x6F, 0x64, 0x28, 0x22, 0x57, 0x6C, 0x61, 0x6E, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x29,
 | 
			
		||||
0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x28, 0x22,
 | 
			
		||||
0x57, 0x6C, 0x61, 0x6E, 0x45, 0x6E, 0x75, 0x6D, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x22, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E,
 | 
			
		||||
0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x28, 0x22, 0x57, 0x6C, 0x61, 0x6E, 0x53, 0x63, 0x61, 0x6E, 0x22, 0x29, 0x3B, 0x0A,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x28, 0x22, 0x57, 0x6C,
 | 
			
		||||
0x61, 0x6E, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x22, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x6E, 0x65, 0x67,
 | 
			
		||||
0x6F, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6F, 0x69,
 | 
			
		||||
0x6E, 0x74, 0x65, 0x72, 0x28, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x68, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C,
 | 
			
		||||
0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x28, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69,
 | 
			
		||||
0x76, 0x65, 0x2E, 0x57, 0x6C, 0x61, 0x6E, 0x4F, 0x70, 0x65, 0x6E, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x28, 0x32, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x6E, 0x65, 0x67, 0x6F, 0x74, 0x69, 0x61, 0x74,
 | 
			
		||||
0x65, 0x64, 0x2C, 0x20, 0x68, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x20, 0x3D, 0x20, 0x68, 0x2E, 0x56, 0x61, 0x6C, 0x3B,
 | 
			
		||||
0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x5F, 0x4E, 0x4F, 0x54, 0x49, 0x46, 0x59, 0x5F, 0x50, 0x52, 0x4F, 0x58, 0x59, 0x5F, 0x4F, 0x42, 0x4A, 0x45, 0x43, 0x54, 0x20,
 | 
			
		||||
0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6C, 0x6C, 0x62, 0x61, 0x63, 0x6B, 0x50, 0x72, 0x6F,
 | 
			
		||||
0x78, 0x79, 0x28, 0x4F, 0x6E, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x79, 0x2C, 0x20, 0x32, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x5F, 0x4E, 0x4F, 0x54, 0x49, 0x46,
 | 
			
		||||
0x59, 0x5F, 0x50, 0x52, 0x4F, 0x58, 0x59, 0x5F, 0x4F, 0x42, 0x4A, 0x45, 0x43, 0x54, 0x2E, 0x50, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x3B, 0x0A, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x50, 0x72, 0x65, 0x76, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x2E,
 | 
			
		||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x28, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x20,
 | 
			
		||||
0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x57, 0x6C, 0x61, 0x6E, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x4E, 0x6F, 0x74, 0x69, 0x66, 0x69,
 | 
			
		||||
0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x2C, 0x20, 0x30, 0x58, 0x30, 0x30, 0x30, 0x30, 0x46, 0x46, 0x46, 0x46, 0x2C, 0x20,
 | 
			
		||||
0x30, 0x2C, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x5F, 0x4E, 0x4F, 0x54, 0x49, 0x46, 0x59, 0x5F, 0x50, 0x52, 0x4F, 0x58, 0x59, 0x5F, 0x4F, 0x42, 0x4A, 0x45, 0x43, 0x54, 0x2E, 0x43, 0x61, 0x6C,
 | 
			
		||||
0x6C, 0x62, 0x61, 0x63, 0x6B, 0x2C, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x5F, 0x4E, 0x4F, 0x54, 0x49, 0x46, 0x59, 0x5F, 0x50, 0x52, 0x4F, 0x58, 0x59, 0x5F, 0x4F, 0x42, 0x4A, 0x45, 0x43, 0x54,
 | 
			
		||||
0x2E, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x50, 0x72, 0x65, 0x76, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6D, 0x69,
 | 
			
		||||
0x74, 0x74, 0x65, 0x72, 0x55, 0x74, 0x69, 0x6C, 0x73, 0x2E, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6E, 0x74, 0x28, 0x27, 0x53, 0x63, 0x61, 0x6E, 0x27, 0x29, 0x3B, 0x0A, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x65, 0x6D, 0x69, 0x74, 0x74, 0x65, 0x72, 0x55, 0x74, 0x69, 0x6C, 0x73, 0x2E, 0x61, 0x64, 0x64, 0x4D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x28, 0x27, 0x53, 0x63, 0x61, 0x6E, 0x27,
 | 
			
		||||
0x2C, 0x20, 0x5F, 0x53, 0x63, 0x61, 0x6E, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x47, 0x65, 0x74, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64,
 | 
			
		||||
0x4E, 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x3D, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x28, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61,
 | 
			
		||||
0x6C, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x28, 0x29, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x69, 0x73,
 | 
			
		||||
0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x57, 0x6C, 0x61, 0x6E, 0x45, 0x6E, 0x75, 0x6D, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2E,
 | 
			
		||||
0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2E,
 | 
			
		||||
0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x30, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44,
 | 
			
		||||
0x65, 0x72, 0x65, 0x66, 0x28, 0x38, 0x2C, 0x20, 0x35, 0x33, 0x32, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x6E, 0x61, 0x6D, 0x65, 0x20,
 | 
			
		||||
0x3D, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x31, 0x36, 0x2C, 0x20, 0x35, 0x31, 0x32, 0x29, 0x2E, 0x41, 0x6E, 0x73, 0x69, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67,
 | 
			
		||||
0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x2E, 0x44, 0x65, 0x72, 0x65,
 | 
			
		||||
0x66, 0x28, 0x35, 0x32, 0x38, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x49, 0x6E, 0x74, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x28, 0x69, 0x6E,
 | 
			
		||||
0x66, 0x6F, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x35, 0x32, 0x38, 0x2C, 0x20, 0x34, 0x29, 0x2E, 0x49, 0x6E, 0x74, 0x56, 0x61, 0x6C, 0x20, 0x3D, 0x3D, 0x20, 0x31, 0x29, 0x20, 0x2F, 0x2F,
 | 
			
		||||
0x20, 0x43, 0x4F, 0x4E, 0x4E, 0x45, 0x43, 0x54, 0x45, 0x44, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x76, 0x61, 0x72, 0x20, 0x64, 0x61, 0x74, 0x61, 0x53, 0x69, 0x7A, 0x65, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x2E, 0x43, 0x72, 0x65,
 | 
			
		||||
0x61, 0x74, 0x65, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x28, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x70, 0x44,
 | 
			
		||||
0x61, 0x74, 0x61, 0x20, 0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72,
 | 
			
		||||
0x28, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x20, 0x3D, 0x20,
 | 
			
		||||
0x74, 0x68, 0x69, 0x73, 0x2E, 0x4D, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6C, 0x2E, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x28, 0x29, 0x3B, 0x0A, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x69, 0x67, 0x75, 0x69, 0x64, 0x20, 0x3D, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66,
 | 
			
		||||
0x28, 0x30, 0x2C, 0x20, 0x31, 0x36, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6C, 0x20,
 | 
			
		||||
0x3D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x4E, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2E, 0x57, 0x6C, 0x61, 0x6E, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65,
 | 
			
		||||
0x28, 0x74, 0x68, 0x69, 0x73, 0x2E, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x2C, 0x20, 0x69, 0x67, 0x75, 0x69, 0x64, 0x2C, 0x20, 0x37, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x64, 0x61, 0x74, 0x61, 0x53,
 | 
			
		||||
0x69, 0x7A, 0x65, 0x2C, 0x20, 0x70, 0x44, 0x61, 0x74, 0x61, 0x2C, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6C, 0x20, 0x3D, 0x3D, 0x20, 0x30, 0x29, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72, 0x20, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65,
 | 
			
		||||
0x64, 0x53, 0x53, 0x49, 0x44, 0x20, 0x3D, 0x20, 0x70, 0x44, 0x61, 0x74, 0x61, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x35, 0x32, 0x34, 0x2C,
 | 
			
		||||
0x20, 0x33, 0x32, 0x29, 0x2E, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x72,
 | 
			
		||||
0x20, 0x62, 0x73, 0x73, 0x69, 0x64, 0x20, 0x3D, 0x20, 0x70, 0x44, 0x61, 0x74, 0x61, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x35, 0x36, 0x30,
 | 
			
		||||
0x2C, 0x20, 0x36, 0x29, 0x2E, 0x48, 0x65, 0x78, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x76, 0x61, 0x72, 0x20, 0x6C, 0x71, 0x20, 0x3D, 0x20, 0x70, 0x44, 0x61, 0x74, 0x61, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x29, 0x2E, 0x44, 0x65, 0x72, 0x65, 0x66, 0x28, 0x35, 0x37, 0x36,
 | 
			
		||||
0x2C, 0x20, 0x34, 0x29, 0x2E, 0x49, 0x6E, 0x74, 0x56, 0x61, 0x6C, 0x3B, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
 | 
			
		||||
0x74, 0x75, 0x72, 0x6E, 0x20, 0x28, 0x6E, 0x65, 0x77, 0x20, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x28, 0x61, 0x73, 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64,
 | 
			
		||||
0x53, 0x53, 0x49, 0x44, 0x2C, 0x20, 0x62, 0x73, 0x73, 0x69, 0x64, 0x2C, 0x20, 0x30, 0x2C, 0x20, 0x6C, 0x71, 0x29, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x68, 0x72, 0x6F, 0x77, 0x20, 0x28, 0x22, 0x47, 0x65,
 | 
			
		||||
0x74, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4E, 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x73, 0x3A, 0x20, 0x46, 0x41, 0x49, 0x4C, 0x45, 0x44, 0x20, 0x28, 0x6E, 0x6F, 0x74, 0x20,
 | 
			
		||||
0x61, 0x73, 0x73, 0x6F, 0x63, 0x69, 0x61, 0x74, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x20, 0x6E, 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x29, 0x22, 0x29, 0x3B, 0x0A, 0x20, 0x20, 0x20, 0x20,
 | 
			
		||||
0x7D, 0x3B, 0x0A, 0x0A, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6E, 0x20, 0x28, 0x74, 0x68, 0x69, 0x73, 0x29, 0x3B, 0x0A, 0x7D, 0x0A, 0x0A, 0x6D, 0x6F, 0x64, 0x75, 0x6C,
 | 
			
		||||
0x65, 0x2E, 0x65, 0x78, 0x70, 0x6F, 0x72, 0x74, 0x73, 0x20, 0x3D, 0x20, 0x6E, 0x65, 0x77, 0x20, 0x57, 0x69, 0x72, 0x65, 0x6C, 0x65, 0x73, 0x73, 0x28, 0x29, 0x3B, 0x0A]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var WindowsChildScript = new Buffer([
 | 
			
		||||
0x76, 0x61, 0x72, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x43, 0x6F, 0x6E, 0x74,
 | 
			
		||||
0x61, 0x69, 0x6E, 0x65, 0x72, 0x27, 0x29, 0x3B, 0x0D, 0x0A, 0x76, 0x61, 0x72, 0x20, 0x57, 0x69, 0x72, 0x65, 0x6C, 0x65, 0x73, 0x73, 0x20, 0x3D, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65,
 | 
			
		||||
0x28, 0x27, 0x57, 0x69, 0x72, 0x65, 0x6C, 0x65, 0x73, 0x73, 0x27, 0x29, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x57, 0x69, 0x72, 0x65, 0x6C, 0x65, 0x73, 0x73, 0x2E, 0x6F, 0x6E, 0x28, 0x27, 0x53, 0x63,
 | 
			
		||||
0x61, 0x6E, 0x27, 0x2C, 0x20, 0x66, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x28, 0x61, 0x70, 0x29, 0x20, 0x7B, 0x20, 0x70, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x2E, 0x73, 0x65, 0x6E, 0x64,
 | 
			
		||||
0x28, 0x61, 0x70, 0x29, 0x3B, 0x20, 0x7D, 0x29, 0x3B, 0x0D, 0x0A, 0x57, 0x69, 0x72, 0x65, 0x6C, 0x65, 0x73, 0x73, 0x2E, 0x53, 0x63, 0x61, 0x6E, 0x28, 0x29, 0x3B, 0x0D, 0x0A]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function AccessPoint(_ssid, _bssid, _lq)
 | 
			
		||||
{
 | 
			
		||||
    this.ssid = _ssid;
 | 
			
		||||
    this.bssid = _bssid;
 | 
			
		||||
    this.lq = _lq;
 | 
			
		||||
}
 | 
			
		||||
AccessPoint.prototype.toString = function ()
 | 
			
		||||
{
 | 
			
		||||
    return (this.ssid + " [" + this.bssid + "]: " + this.lq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function WiFiScanner()
 | 
			
		||||
{
 | 
			
		||||
    var emitterUtils = require('events').inherits(this);
 | 
			
		||||
    emitterUtils.createEvent('accessPoint');
 | 
			
		||||
 | 
			
		||||
    this.hasWireless = function ()
 | 
			
		||||
    {
 | 
			
		||||
        var retVal = false;
 | 
			
		||||
        var interfaces = require('os').networkInterfaces();
 | 
			
		||||
        for (var name in interfaces)
 | 
			
		||||
        {
 | 
			
		||||
            if (interfaces[name][0].type == 'wireless') { retVal = true; break; }
 | 
			
		||||
        }
 | 
			
		||||
        return (retVal);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.Scan = function ()
 | 
			
		||||
    {
 | 
			
		||||
        if (process.platform == 'win32')
 | 
			
		||||
        {
 | 
			
		||||
            this.master = require('ScriptContainer').Create(15, ContainerPermissions.DEFAULT);
 | 
			
		||||
            this.master.parent = this;
 | 
			
		||||
            this.master.on('data', function (j) { this.parent.emit('accessPoint', new AccessPoint(j.ssid, j.bssid, j.lq)); });
 | 
			
		||||
 | 
			
		||||
            this.master.addModule('Wireless', WindowsWireless.toString());
 | 
			
		||||
            this.master.ExecuteString(WindowsChildScript.toString());
 | 
			
		||||
        }
 | 
			
		||||
        else if (process.platform == 'linux')
 | 
			
		||||
        {
 | 
			
		||||
            // Need to get the wireless interface name
 | 
			
		||||
            var interfaces = require('os').networkInterfaces();
 | 
			
		||||
            var wlan = null;
 | 
			
		||||
            for (var i in interfaces)
 | 
			
		||||
            {
 | 
			
		||||
                if (interfaces[i][0].type == 'wireless')
 | 
			
		||||
                {
 | 
			
		||||
                    wlan = i;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (wlan != null)
 | 
			
		||||
            {
 | 
			
		||||
                this.child = require('ILibProcessPipe').CreateProcess("/sbin/iwlist", "iwlist", wlan, "scan");
 | 
			
		||||
                this.child.parent = this;
 | 
			
		||||
                this.child.ms = new MemoryStream();
 | 
			
		||||
                this.child.ms.parent = this.child;
 | 
			
		||||
                this.child.on('data', function (buffer) { this.ms.write(buffer); });
 | 
			
		||||
                this.child.on('end', function () { this.ms.end(); });
 | 
			
		||||
                this.child.ms.on('end', function ()
 | 
			
		||||
                {
 | 
			
		||||
                    var str = this.buffer.toString();
 | 
			
		||||
                    tokens = str.split(' - Address: ');
 | 
			
		||||
                    for (var block in tokens)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (block == 0) continue;
 | 
			
		||||
                        var ln = tokens[block].split('\n');
 | 
			
		||||
                        var _bssid = ln[0];
 | 
			
		||||
                        var _lq;
 | 
			
		||||
                        var _ssid;
 | 
			
		||||
 | 
			
		||||
                        for (var lnblock in ln)
 | 
			
		||||
                        {
 | 
			
		||||
                            lnblock = ln[lnblock].trim();
 | 
			
		||||
                            lnblock = lnblock.trim();
 | 
			
		||||
                            if (lnblock.startsWith('ESSID:'))
 | 
			
		||||
                            {
 | 
			
		||||
                                _ssid = lnblock.slice(7, lnblock.length - 1);
 | 
			
		||||
                                if (_ssid == '<hidden>') { _ssid = ''; }
 | 
			
		||||
                            }
 | 
			
		||||
                            if (lnblock.startsWith('Signal level='))
 | 
			
		||||
                            {
 | 
			
		||||
                                _lq = lnblock.slice(13,lnblock.length-4);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        this.parent.parent.emit('accessPoint', new AccessPoint(_ssid, _bssid, _lq));
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = WiFiScanner;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										281
									
								
								agents/modules_meshcore/amt_heci.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								agents/modules_meshcore/amt_heci.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,281 @@
 | 
			
		|||
var Q = require('queue');
 | 
			
		||||
 | 
			
		||||
function amt_heci() {
 | 
			
		||||
    var emitterUtils = require('events').inherits(this);
 | 
			
		||||
    emitterUtils.createEvent('error');
 | 
			
		||||
    emitterUtils.createEvent('connect');
 | 
			
		||||
 | 
			
		||||
    var heci = require('heci');
 | 
			
		||||
 | 
			
		||||
    this._amt = heci.create();
 | 
			
		||||
    this._amt.BiosVersionLen = 65;
 | 
			
		||||
    this._amt.UnicodeStringLen = 20;
 | 
			
		||||
 | 
			
		||||
    this._amt.rq = new Q();
 | 
			
		||||
    this._amt.Parent = this;
 | 
			
		||||
    this._amt.on('error', function (e) { this.Parent.emit('error', e); });
 | 
			
		||||
    this._amt.on('connect', function () {
 | 
			
		||||
        this.Parent.emit('connect');
 | 
			
		||||
        this.on('data', function (chunk) {
 | 
			
		||||
            //console.log("Received: " + chunk.length + " bytes");
 | 
			
		||||
            var header = this.Parent.getCommand(chunk);
 | 
			
		||||
            //console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse);
 | 
			
		||||
 | 
			
		||||
            var user = this.rq.deQueue();
 | 
			
		||||
            var params = user.optional;
 | 
			
		||||
            var callback = user.func;
 | 
			
		||||
 | 
			
		||||
            params.unshift(header);
 | 
			
		||||
            callback.apply(this.Parent, params);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 });
 | 
			
		||||
 | 
			
		||||
    this.getCommand = function (chunk) {
 | 
			
		||||
        var command = chunk.length == 0 ? (this._amt.rq.peekQueue().cmd | 0x800000) : chunk.readUInt32LE(4);
 | 
			
		||||
        var ret = { IsResponse: (command & 0x800000) == 0x800000 ? true : false, Command: (command & 0x7FFFFF), Status: chunk.length != 0 ? chunk.readUInt32LE(12) : -1, Data: chunk.length != 0 ? chunk.slice(16) : null };
 | 
			
		||||
        return (ret);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.sendCommand = function () {
 | 
			
		||||
        if (arguments.length < 3 || typeof (arguments[0]) != 'number' || typeof (arguments[1]) != 'object' || typeof (arguments[2]) != 'function') { throw ('invalid parameters'); }
 | 
			
		||||
        var args = [];
 | 
			
		||||
        for (var i = 3; i < arguments.length; ++i) { args.push(arguments[i]); }
 | 
			
		||||
 | 
			
		||||
        this._amt.rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args });
 | 
			
		||||
 | 
			
		||||
        var header = Buffer.from('010100000000000000000000', 'hex');
 | 
			
		||||
        header.writeUInt32LE(arguments[0] | 0x04000000, 4);
 | 
			
		||||
        header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8);
 | 
			
		||||
 | 
			
		||||
        this._amt.write(arguments[1] == null ? header : Buffer.concat([header, arguments[1]]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.getVersion = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(26, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4);
 | 
			
		||||
                for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) {
 | 
			
		||||
                    val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() };
 | 
			
		||||
                    v = v.slice(4 + (2 * this._amt.UnicodeStringLen));
 | 
			
		||||
                }
 | 
			
		||||
                opt.unshift(val);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.getProvisioningState = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(17, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var result = {};
 | 
			
		||||
                result.state = header.Data.readUInt32LE(0);
 | 
			
		||||
                if (result.state < 3) { result.stateStr = ["PRE", "IN", "POST"][result.state]; }
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getProvisioningMode = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(8, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var result = {};
 | 
			
		||||
                result.mode = header.Data.readUInt32LE(0);
 | 
			
		||||
                if (result.mode < 4) { result.modeStr = ["NONE", "ENTERPRISE", "SMALL_BUSINESS", "REMOTE_ASSISTANCE"][result.mode]; }
 | 
			
		||||
                result.legacy = header.Data.readUInt32LE(4) == 0 ? false : true;
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getEHBCState = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(132, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                opt.unshift({ EHBC: header.Data.readUInt32LE(0) != 0 });
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getControlMode = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(107, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var result = {};
 | 
			
		||||
                result.controlMode = header.Data.readUInt32LE(0);
 | 
			
		||||
                if (result.controlMode < 3) { result.controlModeStr = ["NONE_RPAT", "CLIENT", "ADMIN", "REMOTE_ASSISTANCE"][result.controlMode]; }
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getMACAddresses = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(37, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                opt.unshift({ DedicatedMAC: header.Data.slice(0, 6).toString('hex:'), HostMAC: header.Data.slice(6, 12).toString('hex:') });
 | 
			
		||||
            } else { opt.unshift({ DedicatedMAC: null, HostMAC: null }); }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getDnsSuffix = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(54, null, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var resultLen = header.Data.readUInt16LE(0);
 | 
			
		||||
                if (resultLen > 0) { opt.unshift(header.Data.slice(2, 2 + resultLen).toString()); } else { opt.unshift(null); }
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getHashHandles = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x2C, null, function (header, fn, opt) {
 | 
			
		||||
            var result = [];
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var resultLen = header.Data.readUInt32LE(0);
 | 
			
		||||
                for (var i = 0; i < resultLen; ++i) {
 | 
			
		||||
                    result.push(header.Data.readUInt32LE(4 + (4 * i)));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            opt.unshift(result);
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getCertHashEntry = function (handle, callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
 | 
			
		||||
        var data = new Buffer(4);
 | 
			
		||||
        data.writeUInt32LE(handle, 0);
 | 
			
		||||
 | 
			
		||||
        this.sendCommand(0x2D, data, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var result = {};
 | 
			
		||||
                result.isDefault = header.Data.readUInt32LE(0);
 | 
			
		||||
                result.isActive = header.Data.readUInt32LE(4);
 | 
			
		||||
                result.hashAlgorithm = header.Data.readUInt8(72);
 | 
			
		||||
                if (result.hashAlgorithm < 4) {
 | 
			
		||||
                    result.hashAlgorithmStr = ["MD5", "SHA1", "SHA256", "SHA512"][result.hashAlgorithm];
 | 
			
		||||
                    result.hashAlgorithmSize = [16, 20, 32, 64][result.hashAlgorithm];
 | 
			
		||||
                    result.certificateHash = header.Data.slice(8, 8 + result.hashAlgorithmSize).toString('hex');
 | 
			
		||||
                }
 | 
			
		||||
                result.name = header.Data.slice(73 + 2, 73 + 2 + header.Data.readUInt16LE(73)).toString();
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this.getCertHashEntries = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
 | 
			
		||||
        this.getHashHandles(function (handles, fn, opt) {
 | 
			
		||||
            var entries = [];
 | 
			
		||||
            this.getCertHashEntry(handles.shift(), this._getHashEntrySink, fn, opt, entries, handles);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    };
 | 
			
		||||
    this._getHashEntrySink = function (result, fn, opt, entries, handles) {
 | 
			
		||||
        entries.push(result);
 | 
			
		||||
        if (handles.length > 0) {
 | 
			
		||||
            this.getCertHashEntry(handles.shift(), this._getHashEntrySink, fn, opt, entries, handles);
 | 
			
		||||
        } else {
 | 
			
		||||
            opt.unshift(entries);
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    this.getLocalSystemAccount = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) {
 | 
			
		||||
            if (header.Data.length == 68) { opt.unshift({ user: header.Data.slice(0, 34).toString(), pass: header.Data.slice(34, 67).toString(), raw: header.Data }); } else { opt.unshift(null); }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.unprovision = function (mode, callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        var data = new Buffer(4);
 | 
			
		||||
        data.writeUInt32LE(mode, 0);
 | 
			
		||||
        this.sendCommand(16, data, function (header, fn, opt) {
 | 
			
		||||
            opt.unshift(header.Status);
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.startConfiguration = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x29, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.stopConfiguration = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x5E, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.openUserInitiatedConnection = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x44, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.closeUserInitiatedConnection = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x45, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.getRemoteAccessConnectionStatus = function () {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
 | 
			
		||||
        this.sendCommand(0x46, data, function (header, fn, opt) {
 | 
			
		||||
            if (header.Status == 0) {
 | 
			
		||||
                var hostname = v.slice(14, header.Data.readUInt16LE(12) + 14).toString()
 | 
			
		||||
                opt.unshift({ status: header.Status, networkStatus: header.Data.readUInt32LE(0), remoteAccessStatus: header.Data.readUInt32LE(4), remoteAccessTrigger: header.Data.readUInt32LE(8), mpsHostname: hostname, raw: header.Data });
 | 
			
		||||
            } else {
 | 
			
		||||
                opt.unshift({ status: header.Status });
 | 
			
		||||
            }
 | 
			
		||||
            fn.apply(this, opt);
 | 
			
		||||
        }, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
    this.getProtocolVersion = function (callback) {
 | 
			
		||||
        var optional = [];
 | 
			
		||||
        for (var i = 1; i < arguments.length; ++i) { opt.push(arguments[i]); }
 | 
			
		||||
 | 
			
		||||
        heci.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) {
 | 
			
		||||
            if (status == 0) {
 | 
			
		||||
                var result = buffer.readUInt8(0).toString() + '.' + buffer.readUInt8(1).toString() + '.' + buffer.readUInt8(2).toString() + '.' + buffer.readUInt16BE(3).toString();
 | 
			
		||||
                opt.unshift(result);
 | 
			
		||||
                fn.apply(self, opt);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                opt.unshift(null);
 | 
			
		||||
                fn.apply(self, opt);
 | 
			
		||||
            }
 | 
			
		||||
        }, this, callback, optional);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = amt_heci;
 | 
			
		||||
							
								
								
									
										354
									
								
								agents/modules_meshcore/lme_heci.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								agents/modules_meshcore/lme_heci.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,354 @@
 | 
			
		|||
 | 
			
		||||
var MemoryStream = require('MemoryStream');
 | 
			
		||||
var lme_id = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var APF_DISCONNECT = 1;
 | 
			
		||||
var APF_SERVICE_REQUEST = 5;
 | 
			
		||||
var APF_SERVICE_ACCEPT = 6;
 | 
			
		||||
var APF_USERAUTH_REQUEST = 50;
 | 
			
		||||
var APF_USERAUTH_FAILURE = 51;
 | 
			
		||||
var APF_USERAUTH_SUCCESS = 52;
 | 
			
		||||
var APF_GLOBAL_REQUEST = 80;
 | 
			
		||||
var APF_REQUEST_SUCCESS = 81;
 | 
			
		||||
var APF_REQUEST_FAILURE = 82;
 | 
			
		||||
var APF_CHANNEL_OPEN = 90;
 | 
			
		||||
var APF_CHANNEL_OPEN_CONFIRMATION = 91;
 | 
			
		||||
var APF_CHANNEL_OPEN_FAILURE = 92;
 | 
			
		||||
var APF_CHANNEL_WINDOW_ADJUST = 93;
 | 
			
		||||
var APF_CHANNEL_DATA = 94;
 | 
			
		||||
var APF_CHANNEL_CLOSE = 97;
 | 
			
		||||
var APF_PROTOCOLVERSION = 192;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function lme_object()
 | 
			
		||||
{
 | 
			
		||||
    this.ourId = ++lme_id;
 | 
			
		||||
    this.amtId = -1;
 | 
			
		||||
    this.LME_CHANNEL_STATUS = 'LME_CS_FREE';
 | 
			
		||||
    this.txWindow = 0;
 | 
			
		||||
    this.rxWindow = 0;
 | 
			
		||||
    this.localPort = 0;
 | 
			
		||||
    this.errorCount = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function stream_bufferedWrite()
 | 
			
		||||
{
 | 
			
		||||
    var emitterUtils = require('events').inherits(this);
 | 
			
		||||
    this.buffer = [];
 | 
			
		||||
    this._readCheckImmediate = undefined;
 | 
			
		||||
 | 
			
		||||
    // Writable Events
 | 
			
		||||
    emitterUtils.createEvent('close');
 | 
			
		||||
    emitterUtils.createEvent('drain');
 | 
			
		||||
    emitterUtils.createEvent('error');
 | 
			
		||||
    emitterUtils.createEvent('finish');
 | 
			
		||||
    emitterUtils.createEvent('pipe');
 | 
			
		||||
    emitterUtils.createEvent('unpipe');
 | 
			
		||||
 | 
			
		||||
    // Readable Events
 | 
			
		||||
    emitterUtils.createEvent('readable');
 | 
			
		||||
    this.isEmpty = function ()
 | 
			
		||||
    {
 | 
			
		||||
        return (this.buffer.length == 0);
 | 
			
		||||
    };
 | 
			
		||||
    this.isWaiting = function ()
 | 
			
		||||
    {
 | 
			
		||||
        return (this._readCheckImmediate == undefined);
 | 
			
		||||
    };
 | 
			
		||||
    this.write = function (chunk)
 | 
			
		||||
    {
 | 
			
		||||
        for (var args in arguments)
 | 
			
		||||
        {
 | 
			
		||||
            if (typeof (arguments[args]) == 'function') { this.once('drain', arguments[args]); break; }
 | 
			
		||||
        }
 | 
			
		||||
        var tmp = Buffer.alloc(chunk.length);
 | 
			
		||||
        chunk.copy(tmp);
 | 
			
		||||
        this.buffer.push({ offset: 0, data: tmp });
 | 
			
		||||
        this.emit('readable');
 | 
			
		||||
        return (this.buffer.length == 0 ? true : false);
 | 
			
		||||
    };
 | 
			
		||||
    this.read = function ()
 | 
			
		||||
    {
 | 
			
		||||
        var size = arguments.length == 0 ? undefined : arguments[0];
 | 
			
		||||
        var bytesRead = 0;
 | 
			
		||||
        var list = [];
 | 
			
		||||
        while((size == undefined || bytesRead < size) && this.buffer.length > 0)
 | 
			
		||||
        {
 | 
			
		||||
            var len = this.buffer[0].data.length - this.buffer[0].offset;
 | 
			
		||||
            var offset = this.buffer[0].offset;
 | 
			
		||||
 | 
			
		||||
            if(len > (size - bytesRead))
 | 
			
		||||
            {
 | 
			
		||||
                // Only reading a subset
 | 
			
		||||
                list.push(this.buffer[0].data.slice(offset, offset + size - bytesRead));
 | 
			
		||||
                this.buffer[0].offset += (size - bytesRead);
 | 
			
		||||
                bytesRead += (size - bytesRead);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // Reading the entire thing
 | 
			
		||||
                list.push(this.buffer[0].data.slice(offset));
 | 
			
		||||
                bytesRead += len;
 | 
			
		||||
                this.buffer.shift();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this._readCheckImmediate = setImmediate(function (buffered)
 | 
			
		||||
        {
 | 
			
		||||
            buffered._readCheckImmediate = undefined;
 | 
			
		||||
            if(buffered.buffer.length == 0)
 | 
			
		||||
            {
 | 
			
		||||
                // drained
 | 
			
		||||
                buffered.emit('drain');
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // not drained
 | 
			
		||||
                buffered.emit('readable');
 | 
			
		||||
            }
 | 
			
		||||
        }, this);
 | 
			
		||||
        return (Buffer.concat(list));
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function lme_heci()
 | 
			
		||||
{
 | 
			
		||||
    var emitterUtils = require('events').inherits(this);
 | 
			
		||||
    emitterUtils.createEvent('error');
 | 
			
		||||
    emitterUtils.createEvent('connect');
 | 
			
		||||
 | 
			
		||||
    var heci = require('heci');
 | 
			
		||||
    this.INITIAL_RXWINDOW_SIZE = 4096;
 | 
			
		||||
 | 
			
		||||
    this._LME = heci.create();
 | 
			
		||||
    this._LME.LMS = this;
 | 
			
		||||
    this._LME.on('error', function (e) { this.Parent.emit('error', e); });
 | 
			
		||||
    this._LME.on('connect', function ()
 | 
			
		||||
    {
 | 
			
		||||
        this.LMS.emit('connect');
 | 
			
		||||
        this.on('data', function (chunk)
 | 
			
		||||
        {
 | 
			
		||||
            // this = HECI
 | 
			
		||||
            var cmd = chunk.readUInt8(0);
 | 
			
		||||
           
 | 
			
		||||
            switch(cmd)
 | 
			
		||||
            {
 | 
			
		||||
                default:
 | 
			
		||||
                    //console.log('Received ' + chunk.length + ' bytes of data for LMS');
 | 
			
		||||
                    //console.log('Command = ' + cmd);
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_SERVICE_REQUEST:     
 | 
			
		||||
                    var nameLen = chunk.readUInt32BE(1);
 | 
			
		||||
                    var name = chunk.slice(5, nameLen + 5);
 | 
			
		||||
                    //console.log("Service Request for: " + name);
 | 
			
		||||
                    if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com')
 | 
			
		||||
                    {
 | 
			
		||||
                        var outBuffer = Buffer.alloc(5 + nameLen);
 | 
			
		||||
                        outBuffer.writeUInt8(6, 0);
 | 
			
		||||
                        outBuffer.writeUInt32BE(nameLen, 1);
 | 
			
		||||
                        outBuffer.write(name.toString(), 5);
 | 
			
		||||
                        this.write(outBuffer);
 | 
			
		||||
                        //console.log('Answering APF_SERVICE_REQUEST');
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //console.log('UNKNOWN APF_SERVICE_REQUEST');
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_GLOBAL_REQUEST:    
 | 
			
		||||
                    var nameLen = chunk.readUInt32BE(1);
 | 
			
		||||
                    var name = chunk.slice(5, nameLen + 5).toString();
 | 
			
		||||
                    
 | 
			
		||||
                    switch(name)
 | 
			
		||||
                    {
 | 
			
		||||
                        case 'tcpip-forward':
 | 
			
		||||
                            var len = chunk.readUInt32BE(nameLen + 6);
 | 
			
		||||
                            var port = chunk.readUInt32BE(nameLen + 10 + len);
 | 
			
		||||
                            //console.log("[" + chunk.length + "/" + len + "] APF_GLOBAL_REQUEST for: " + name + " on port " + port);
 | 
			
		||||
                            if (this[name] == undefined)
 | 
			
		||||
                            {
 | 
			
		||||
                                this[name] = {};
 | 
			
		||||
                            }
 | 
			
		||||
                            this[name][port] = require('net').createServer();
 | 
			
		||||
                            this[name][port].HECI = this;
 | 
			
		||||
                            this[name][port].listen({ port: port });
 | 
			
		||||
                            this[name][port].on('connection', function (socket)
 | 
			
		||||
                            {
 | 
			
		||||
                                //console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
 | 
			
		||||
                                this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort);
 | 
			
		||||
                            });
 | 
			
		||||
                            var outBuffer = Buffer.alloc(5);
 | 
			
		||||
                            outBuffer.writeUInt8(81, 0);
 | 
			
		||||
                            outBuffer.writeUInt32BE(port, 1);
 | 
			
		||||
                            this.write(outBuffer);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'cancel-tcpip-forward':
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'udp-send-to@amt.intel.com':
 | 
			
		||||
                            break;
 | 
			
		||||
                        default:
 | 
			
		||||
                            //console.log("Unknown APF_GLOBAL_REQUEST for: " + name);
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_CHANNEL_OPEN_CONFIRMATION:    
 | 
			
		||||
			        var rChannel = chunk.readUInt32BE(1);
 | 
			
		||||
			        var sChannel = chunk.readUInt32BE(5);
 | 
			
		||||
			        var wSize = chunk.readUInt32BE(9);
 | 
			
		||||
			        //console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
 | 
			
		||||
			        if (this.sockets[rChannel] != undefined)
 | 
			
		||||
			        {
 | 
			
		||||
			            this.sockets[rChannel].lme.amtId = sChannel;
 | 
			
		||||
			            this.sockets[rChannel].lme.rxWindow = wSize;
 | 
			
		||||
			            this.sockets[rChannel].lme.txWindow = wSize;
 | 
			
		||||
			            this.sockets[rChannel].lme.LME_CHANNEL_STATUS = 'LME_CS_CONNECTED';
 | 
			
		||||
			            //console.log('LME_CS_CONNECTED');
 | 
			
		||||
			            this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
 | 
			
		||||
			            this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
 | 
			
		||||
			            this.sockets[rChannel].bufferedStream.on('readable', function ()
 | 
			
		||||
			            {
 | 
			
		||||
			                if(this.socket.lme.txWindow > 0)
 | 
			
		||||
			                {
 | 
			
		||||
			                    var buffer = this.read(this.socket.lme.txWindow);
 | 
			
		||||
			                    var packet = Buffer.alloc(9 + buffer.length);
 | 
			
		||||
			                    packet.writeUInt8(APF_CHANNEL_DATA, 0);
 | 
			
		||||
			                    packet.writeUInt32BE(this.socket.lme.amtId, 1);
 | 
			
		||||
			                    packet.writeUInt32BE(buffer.length, 5);
 | 
			
		||||
			                    buffer.copy(packet, 9);
 | 
			
		||||
			                    this.socket.lme.txWindow -= buffer.length;
 | 
			
		||||
			                    this.socket.HECI.write(packet);
 | 
			
		||||
			                }
 | 
			
		||||
			            });
 | 
			
		||||
			            this.sockets[rChannel].bufferedStream.on('drain', function ()
 | 
			
		||||
			            {
 | 
			
		||||
			                this.socket.resume();
 | 
			
		||||
			            });
 | 
			
		||||
			            this.sockets[rChannel].on('data', function (chunk)
 | 
			
		||||
			            {
 | 
			
		||||
			                if (!this.bufferedStream.write(chunk)) { this.pause(); }
 | 
			
		||||
			            });
 | 
			
		||||
			            this.sockets[rChannel].on('end', function () 
 | 
			
		||||
			            {
 | 
			
		||||
			                var outBuffer = Buffer.alloc(5);
 | 
			
		||||
			                outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
 | 
			
		||||
			                outBuffer.writeUInt32BE(this.lme.amtId, 1);
 | 
			
		||||
			                this.HECI.write(outBuffer);
 | 
			
		||||
			            });
 | 
			
		||||
			            this.sockets[rChannel].resume();
 | 
			
		||||
			        }
 | 
			
		||||
 | 
			
		||||
		    	    break;
 | 
			
		||||
                case APF_PROTOCOLVERSION:   
 | 
			
		||||
                    var major = chunk.readUInt32BE(1);
 | 
			
		||||
                    var minor = chunk.readUInt32BE(5);
 | 
			
		||||
                    var reason = chunk.readUInt32BE(9);
 | 
			
		||||
                    var outBuffer = Buffer.alloc(93);
 | 
			
		||||
                    outBuffer.writeUInt8(192, 0);
 | 
			
		||||
                    outBuffer.writeUInt32BE(1, 1);
 | 
			
		||||
                    outBuffer.writeUInt32BE(0, 5);
 | 
			
		||||
                    outBuffer.writeUInt32BE(reason, 9);
 | 
			
		||||
                    //console.log('Answering PROTOCOL_VERSION');
 | 
			
		||||
                    this.write(outBuffer);
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_CHANNEL_WINDOW_ADJUST:
 | 
			
		||||
                    var rChannelId = chunk.readUInt32BE(1);
 | 
			
		||||
                    var bytesToAdd = chunk.readUInt32BE(5);
 | 
			
		||||
                    if (this.sockets[rChannelId] != undefined)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.sockets[rChannelId].lme.txWindow += bytesToAdd;
 | 
			
		||||
                        if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting())
 | 
			
		||||
                        {
 | 
			
		||||
                            this.sockets[rChannelId].bufferedStream.emit('readable');
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_WINDOW_ADJUST');
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_CHANNEL_DATA:
 | 
			
		||||
                    var rChannelId = chunk.readUInt32BE(1);
 | 
			
		||||
                    var dataLen = chunk.readUInt32BE(5);
 | 
			
		||||
                    var data = chunk.slice(9, 9 + dataLen);
 | 
			
		||||
                    if (this.sockets[rChannelId] != undefined)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.sockets[rChannelId].pendingBytes.push(data.length);
 | 
			
		||||
                        this.sockets[rChannelId].write(data, function ()
 | 
			
		||||
                        {
 | 
			
		||||
                            var written = this.pendingBytes.shift();
 | 
			
		||||
                            var outBuffer = Buffer.alloc(9);
 | 
			
		||||
                            outBuffer.writeUInt8(APF_CHANNEL_WINDOW_ADJUST, 0);
 | 
			
		||||
                            outBuffer.writeUInt32BE(this.lme.amtId, 1);
 | 
			
		||||
                            outBuffer.writeUInt32BE(written, 5);
 | 
			
		||||
                            this.HECI.write(outBuffer);
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_DATA');
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case APF_CHANNEL_CLOSE:
 | 
			
		||||
                    var rChannelId = chunk.readUInt32BE(1);
 | 
			
		||||
                    if (this.sockets[rChannelId] != undefined)
 | 
			
		||||
                    {
 | 
			
		||||
                        this.sockets[rChannelId].end();                    
 | 
			
		||||
                        var amtId = this.sockets[rChannelId].lme.amtId;
 | 
			
		||||
                        var buffer = Buffer.alloc(5);
 | 
			
		||||
                        delete this.sockets[rChannelId];
 | 
			
		||||
 | 
			
		||||
                        buffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
 | 
			
		||||
                        buffer.writeUInt32BE(amtId, 1);
 | 
			
		||||
                        this.write(buffer);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_CLOSE');
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
   
 | 
			
		||||
    this.bindDuplexStream = function (duplexStream, remoteFamily, localPort)
 | 
			
		||||
    {
 | 
			
		||||
        var socket = duplexStream;
 | 
			
		||||
        //console.log('New [' + remoteFamily + '] Virtual Connection/' + socket.localPort);
 | 
			
		||||
        socket.pendingBytes = [];
 | 
			
		||||
        socket.HECI = this._LME;
 | 
			
		||||
        socket.LMS = this;
 | 
			
		||||
        socket.lme = new lme_object();
 | 
			
		||||
        socket.lme.Socket = socket;
 | 
			
		||||
        var buffer = new MemoryStream();
 | 
			
		||||
        buffer.writeUInt8(0x5A);
 | 
			
		||||
        buffer.writeUInt32BE(15);
 | 
			
		||||
        buffer.write('forwarded-tcpip');
 | 
			
		||||
        buffer.writeUInt32BE(socket.lme.ourId);
 | 
			
		||||
        buffer.writeUInt32BE(this.INITIAL_RXWINDOW_SIZE);
 | 
			
		||||
        buffer.writeUInt32BE(0xFFFFFFFF);
 | 
			
		||||
        for (var i = 0; i < 2; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            if (remoteFamily == 'IPv6')
 | 
			
		||||
            {
 | 
			
		||||
                buffer.writeUInt32BE(3);
 | 
			
		||||
                buffer.write('::1');
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                buffer.writeUInt32BE(9);
 | 
			
		||||
                buffer.write('127.0.0.1');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            buffer.writeUInt32BE(localPort);
 | 
			
		||||
        }
 | 
			
		||||
        this._LME.write(buffer.buffer);
 | 
			
		||||
        if (this._LME.sockets == undefined) { this._LME.sockets = {}; }
 | 
			
		||||
        this._LME.sockets[socket.lme.ourId] = socket;
 | 
			
		||||
        socket.pause();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this._LME.connect(heci.GUIDS.LME, { noPipeline: 0 });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = lme_heci;
 | 
			
		||||
							
								
								
									
										9
									
								
								db.js
									
										
									
									
									
								
							
							
						
						
									
										9
									
								
								db.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -71,6 +71,13 @@ module.exports.CreateDB = function (args, datapath) {
 | 
			
		|||
            if (err == null && docs.length > 0) { for (var i in docs) { meshlist.push(docs[i]._id); } }
 | 
			
		||||
            obj.file.remove({ meshid: { $exists: true, $nin: meshlist } }, { multi: true });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Clear up all users
 | 
			
		||||
        /*
 | 
			
		||||
        obj.GetAllType('user', function (err, docs) {
 | 
			
		||||
            for (var i in docs) { if (docs[i].subscriptions != null) { console.log('Clean user: ' + docs[i].name); obj.SetUser(docs[i]); } } // Remove "subscriptions" that should not be there.
 | 
			
		||||
        });
 | 
			
		||||
        */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    obj.Set = function (data) { obj.file.update({ _id: data._id }, data, { upsert: true }); }
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +87,8 @@ module.exports.CreateDB = function (args, datapath) {
 | 
			
		|||
    obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, func) { obj.file.find({ type: type, domain: domain, meshid: { $in: meshes } }, { type : 0 }, func); }
 | 
			
		||||
    obj.GetAllType = function (type, func) { obj.file.find({ type: type }, func); }
 | 
			
		||||
    obj.GetAllIdsOfType = function (ids, domain, type, func) { obj.file.find({ type: type, domain: domain, _id: { $in: ids } }, func); }
 | 
			
		||||
    obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }, { type: 0 }, func); }
 | 
			
		||||
    obj.GetUserWithVerifiedEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }, func); }
 | 
			
		||||
    obj.Remove = function (id) { obj.file.remove({ _id: id }); }
 | 
			
		||||
    obj.RemoveAll = function (func) { obj.file.remove({}, { multi: true }, func); }
 | 
			
		||||
    obj.InsertMany = function (data, func) { obj.file.insert(data, func); }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								meshagent.js
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								meshagent.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -64,14 +64,18 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                // TODO: Check if we have a mesh specific core. If so, use that.
 | 
			
		||||
                var agentMeshCoreHash = null;
 | 
			
		||||
                if (msg.length == 52) { agentMeshCoreHash = msg.substring(4, 52); }
 | 
			
		||||
                if (agentMeshCoreHash != obj.parent.parent.defaultMeshCoreHash) {
 | 
			
		||||
                if ((agentMeshCoreHash != obj.parent.parent.defaultMeshCoreHash) && (agentMeshCoreHash != obj.parent.parent.defaultMeshCoreNoMeiHash)) {
 | 
			
		||||
                    if (obj.agentCoreCheck < 5) { // This check is in place to avoid a looping core update.
 | 
			
		||||
                        if (obj.parent.parent.defaultMeshCoreHash == null) {
 | 
			
		||||
                            // Update no core
 | 
			
		||||
                            obj.send(obj.common.ShortToStr(10) + obj.common.ShortToStr(0)); // Command 10, ask mesh agent to clear the core
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Update new core
 | 
			
		||||
                            obj.send(obj.common.ShortToStr(10) + obj.common.ShortToStr(0) + obj.parent.parent.defaultMeshCoreHash + obj.parent.parent.defaultMeshCore); // Command 10, ask mesh agent to set the core
 | 
			
		||||
                            if (obj.agentExeInfo.amt == true) {
 | 
			
		||||
                                obj.send(obj.common.ShortToStr(10) + obj.common.ShortToStr(0) + obj.parent.parent.defaultMeshCoreHash + obj.parent.parent.defaultMeshCore); // Command 10, ask mesh agent to set the core (with MEI support)
 | 
			
		||||
                            } else {
 | 
			
		||||
                                obj.send(obj.common.ShortToStr(10) + obj.common.ShortToStr(0) + obj.parent.parent.defaultMeshCoreNoMeiHash + obj.parent.parent.defaultMeshCoreNoMei); // Command 10, ask mesh agent to set the core (No MEI)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        obj.agentCoreCheck++;
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -313,9 +317,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                    if (iplocs.length == 1) {
 | 
			
		||||
                        // We have a location in the database for this remote IP
 | 
			
		||||
                        var iploc = nodes[0], x = {};
 | 
			
		||||
                        x.publicip = iploc.ip;
 | 
			
		||||
                        x.iploc = iploc.loc + ',' + (Math.floor((new Date(iploc.date)) / 1000));
 | 
			
		||||
                        ChangeAgentLocationInfo(x);
 | 
			
		||||
                        if ((iploc != null) && (iploc.ip != null) && (iploc.loc != null)) {
 | 
			
		||||
                            x.publicip = iploc.ip;
 | 
			
		||||
                            x.iploc = iploc.loc + ',' + (Math.floor((new Date(iploc.date)) / 1000));
 | 
			
		||||
                            ChangeAgentLocationInfo(x);
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Check if we need to ask for the IP location
 | 
			
		||||
                        var doIpLocation = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										123
									
								
								meshcentral.js
									
										
									
									
									
								
							
							
						
						
									
										123
									
								
								meshcentral.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -11,6 +11,7 @@ function CreateMeshCentralServer() {
 | 
			
		|||
    obj.redirserver;
 | 
			
		||||
    obj.mpsserver;
 | 
			
		||||
    obj.swarmserver;
 | 
			
		||||
    obj.mailserver;
 | 
			
		||||
    obj.amtEventHandler;
 | 
			
		||||
    obj.amtScanner;
 | 
			
		||||
    obj.meshScanner;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,14 +29,18 @@ function CreateMeshCentralServer() {
 | 
			
		|||
    obj.config = {};                  // Configuration file
 | 
			
		||||
    obj.dbconfig = {};                // Persistance values, loaded from database
 | 
			
		||||
    obj.certificateOperations = require('./certoperations.js').CertificateOperations();
 | 
			
		||||
    obj.defaultMeshCmd = null;
 | 
			
		||||
    obj.defaultMeshCore = null;
 | 
			
		||||
    obj.defaultMeshCoreHash = null;
 | 
			
		||||
    obj.defaultMeshCoreNoMei = null;
 | 
			
		||||
    obj.defaultMeshCoreNoMeiHash = null;
 | 
			
		||||
    obj.meshAgentBinaries = {};       // Mesh Agent Binaries, Architecture type --> { hash:(sha384 hash), size:(binary size), path:(binary path) }
 | 
			
		||||
    obj.meshAgentInstallScripts = {}; // Mesh Install Scripts, Script ID -- { hash:(sha384 hash), size:(binary size), path:(binary path) }
 | 
			
		||||
    obj.multiServer = null;
 | 
			
		||||
    obj.currentVer = null;
 | 
			
		||||
    obj.maintenanceTimer = null;
 | 
			
		||||
    obj.serverId = null;
 | 
			
		||||
    obj.currentVer = null;
 | 
			
		||||
    try { obj.currentVer = JSON.parse(require('fs').readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { } // Fetch server version
 | 
			
		||||
 | 
			
		||||
    // Setup the default configuration and files paths
 | 
			
		||||
    if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) {
 | 
			
		||||
| 
						 | 
				
			
			@ -165,11 +170,9 @@ function CreateMeshCentralServer() {
 | 
			
		|||
        xprocess.stdout.on('data', function (data) { xprocess.data += data; });
 | 
			
		||||
        xprocess.stderr.on('data', function (data) { });
 | 
			
		||||
        xprocess.on('close', function (code) {
 | 
			
		||||
            var currentVer = null;
 | 
			
		||||
            try { currentVer = JSON.parse(require('fs').readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { }
 | 
			
		||||
            var latestVer = null;
 | 
			
		||||
            if (code == 0) { try { latestVer = xprocess.data.split(' ').join('').split('\r').join('').split('\n').join(''); } catch (e) { } }
 | 
			
		||||
            callback(currentVer, latestVer);
 | 
			
		||||
            callback(obj.currentVer, latestVer);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -288,8 +291,9 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Load the default mesh core
 | 
			
		||||
                // Load the default meshcore and meshcmd
 | 
			
		||||
                obj.updateMeshCore();
 | 
			
		||||
                obj.updateMeshCmd();
 | 
			
		||||
 | 
			
		||||
                // Load server certificates
 | 
			
		||||
                obj.certificateOperations.GetMeshServerCertificate(obj.datapath, obj.args, function (certs) {
 | 
			
		||||
| 
						 | 
				
			
			@ -348,6 +352,12 @@ function CreateMeshCentralServer() {
 | 
			
		|||
                                obj.swarmserver = require('./swarmserver.js').CreateSwarmServer(obj, obj.db, obj.args, obj.certificates);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            // Setup email server
 | 
			
		||||
                            if ((obj.config.smtp != null) && (obj.config.smtp.host != null) && (obj.config.smtp.from != null)) {
 | 
			
		||||
                                obj.mailserver = require('./meshmail.js').CreateMeshMain(obj);
 | 
			
		||||
                                //obj.mailserver.sendMail('ylian.saint-hilaire@intel.com', 'Test Subject', 'This is a sample test', 'This is a <b>sample</b> html test');
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            // Start periodic maintenance
 | 
			
		||||
                            obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -649,29 +659,64 @@ function CreateMeshCentralServer() {
 | 
			
		|||
        if (obj.fs.existsSync(obj.path.join(meshcorePath, 'meshcore.js')) == false) {
 | 
			
		||||
            meshcorePath = obj.path.join(__dirname, 'agents');
 | 
			
		||||
            if (obj.fs.existsSync(obj.path.join(meshcorePath, 'meshcore.js')) == false) {
 | 
			
		||||
                obj.defaultMeshCore = obj.defaultMeshCoreHash = null; if (func != null) { func(false); } // meshcore.js not found
 | 
			
		||||
                obj.defaultMeshCoreNoMei = obj.defaultMeshCoreNoMeiHash = obj.defaultMeshCore = obj.defaultMeshCoreHash = null; if (func != null) { func(false); } // meshcore.js not found
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Read meshcore.js and all .js files in the modules folder.
 | 
			
		||||
        var moduleAdditions = 'var addedModules = [];', modulesDir = null;
 | 
			
		||||
        var moduleAdditions = 'var addedModules = [];', moduleAdditionsNoMei = 'var addedModules = [];', modulesDir = null;
 | 
			
		||||
        var meshCore = obj.fs.readFileSync(obj.path.join(meshcorePath, 'meshcore.js')).toString();
 | 
			
		||||
        try { modulesDir = obj.fs.readdirSync(obj.path.join(meshcorePath, 'modules')); } catch (e) { }
 | 
			
		||||
        try { modulesDir = obj.fs.readdirSync(obj.path.join(meshcorePath, 'modules_meshcore')); } catch (e) { }
 | 
			
		||||
        if (modulesDir != null) {
 | 
			
		||||
            for (var i in modulesDir) {
 | 
			
		||||
                if (modulesDir[i].toLowerCase().endsWith('.js')) {
 | 
			
		||||
                    // Merge this module
 | 
			
		||||
                    var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3);
 | 
			
		||||
                    var moduleDataB64 = obj.fs.readFileSync(obj.path.join(meshcorePath, 'modules', modulesDir[i])).toString('base64');
 | 
			
		||||
                    var moduleDataB64 = obj.fs.readFileSync(obj.path.join(meshcorePath, 'modules_meshcore', modulesDir[i])).toString('base64');
 | 
			
		||||
                    moduleAdditions += 'try { addModule("' + moduleName + '", Buffer.from("' + moduleDataB64 + '", "base64")); addedModules.push("' + moduleName + '"); } catch (e) { }\r\n';
 | 
			
		||||
                    if ((moduleName != 'amt_heci') && (moduleName != 'lme_heci')) {
 | 
			
		||||
                        moduleAdditionsNoMei += 'try { addModule("' + moduleName + '", Buffer.from("' + moduleDataB64 + '", "base64")); addedModules.push("' + moduleName + '"); } catch (e) { }\r\n';
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set the new default meshcore.js with and without MEI support
 | 
			
		||||
        obj.defaultMeshCore = obj.common.IntToStr(0) + moduleAdditions + meshCore;
 | 
			
		||||
        obj.defaultMeshCoreHash = obj.crypto.createHash('sha384').update(obj.defaultMeshCore).digest("binary");
 | 
			
		||||
        obj.defaultMeshCoreNoMei = obj.common.IntToStr(0) + moduleAdditionsNoMei + meshCore;
 | 
			
		||||
        obj.defaultMeshCoreNoMeiHash = obj.crypto.createHash('sha384').update(obj.defaultMeshCoreNoMei).digest("binary");
 | 
			
		||||
        if (func != null) { func(true); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Update the default meshcmd
 | 
			
		||||
    obj.updateMeshCmd = function (func) {
 | 
			
		||||
        // Figure out where meshcmd.js is
 | 
			
		||||
        var meshcmdPath = obj.datapath;
 | 
			
		||||
        if (obj.fs.existsSync(obj.path.join(meshcmdPath, 'meshcmd.js')) == false) {
 | 
			
		||||
            meshcmdPath = obj.path.join(__dirname, 'agents');
 | 
			
		||||
            if (obj.fs.existsSync(obj.path.join(meshcmdPath, 'meshcmd.js')) == false) {
 | 
			
		||||
                obj.defaultMeshCmd = null; if (func != null) { func(false); } // meshcmd.js not found
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Read meshcore.js and all .js files in the modules folder.
 | 
			
		||||
        var moduleAdditions = 'var addedModules = [];', modulesDir = null;
 | 
			
		||||
        var meshCmd = obj.fs.readFileSync(obj.path.join(meshcmdPath, 'meshcmd.js')).toString().replace("'***Mesh*Cmd*Version***'", '\'' + obj.currentVer + '\'');
 | 
			
		||||
        try { modulesDir = obj.fs.readdirSync(obj.path.join(meshcmdPath, 'modules_meshcmd')); } catch (e) { }
 | 
			
		||||
        if (modulesDir != null) {
 | 
			
		||||
            for (var i in modulesDir) {
 | 
			
		||||
                if (modulesDir[i].toLowerCase().endsWith('.js')) {
 | 
			
		||||
                    // Merge this module
 | 
			
		||||
                    var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3);
 | 
			
		||||
                    var moduleDataB64 = obj.fs.readFileSync(obj.path.join(meshcmdPath, 'modules_meshcmd', modulesDir[i])).toString('base64');
 | 
			
		||||
                    moduleAdditions += 'try { addModule("' + moduleName + '", Buffer.from("' + moduleDataB64 + '", "base64")); addedModules.push("' + moduleName + '"); } catch (e) { }\r\n';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set the new default meshcore.js
 | 
			
		||||
        meshCore = obj.common.IntToStr(0) + moduleAdditions + meshCore; // Add the 4 bytes encoding type & flags (Set to 0 for raw)
 | 
			
		||||
        obj.defaultMeshCore = meshCore;
 | 
			
		||||
        obj.defaultMeshCoreHash = obj.crypto.createHash('sha384').update(meshCore).digest("binary");
 | 
			
		||||
        // Set the new default meshcmd.js
 | 
			
		||||
        obj.defaultMeshCmd = moduleAdditions + meshCmd;
 | 
			
		||||
        if (func != null) { func(true); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -711,31 +756,31 @@ function CreateMeshCentralServer() {
 | 
			
		|||
 | 
			
		||||
    // List of possible mesh agents
 | 
			
		||||
    var meshAgentsArchitectureNumbers = {
 | 
			
		||||
        1: { id: 1, localname: 'MeshConsole.exe', rname: 'MeshConsole.exe', desc: 'Windows x86-32 console', update: true },
 | 
			
		||||
        2: { id: 2, localname: 'MeshConsole64.exe', rname: 'MeshConsole.exe', desc: 'Windows x86-64 console', update: true },
 | 
			
		||||
        3: { id: 3, localname: 'MeshService.exe', rname: 'MeshAgent.exe', desc: 'Windows x86-32 service', update: true },
 | 
			
		||||
        4: { id: 4, localname: 'MeshService64.exe', rname: 'MeshAgent.exe', desc: 'Windows x86-64 service', update: true },
 | 
			
		||||
        5: { id: 5, localname: 'meshagent_x86', rname: 'meshagent', desc: 'Linux x86-32', update: true },
 | 
			
		||||
        6: { id: 6, localname: 'meshagent_x86-64', rname: 'meshagent', desc: 'Linux x86-64', update: true },
 | 
			
		||||
        7: { id: 7, localname: 'meshagent_mips', rname: 'meshagent', desc: 'Linux MIPS', update: true },
 | 
			
		||||
        8: { id: 8, localname: 'MeshAgent-Linux-XEN-x86-32', rname: 'meshagent', desc: 'XEN x86-64', update: true },
 | 
			
		||||
        9: { id: 9, localname: 'meshagent_arm', rname: 'meshagent', desc: 'Linux ARM5', update: true },
 | 
			
		||||
        10: { id: 10, localname: 'MeshAgent-Linux-ARM-PlugPC', rname: 'meshagent', desc: 'Linux ARM PlugPC', update: true },
 | 
			
		||||
        11: { id: 11, localname: 'MeshAgent-OSX-x86-32', rname: 'meshosx', desc: 'Apple OSX x86-32', update: true },
 | 
			
		||||
        12: { id: 12, localname: 'MeshAgent-Android-x86', rname: 'meshandroid', desc: 'Android x86-32', update: true },
 | 
			
		||||
        13: { id: 13, localname: 'meshagent_pogo', rname: 'meshagent', desc: 'Linux ARM PogoPlug', update: true },
 | 
			
		||||
        14: { id: 14, localname: 'MeshAgent-Android-APK', rname: 'meshandroid', desc: 'Android Market', update: false }, // Get this one from Google Play
 | 
			
		||||
        15: { id: 15, localname: 'meshagent_poky', rname: 'meshagent', desc: 'Linux Poky x86-32', update: true },
 | 
			
		||||
        16: { id: 16, localname: 'MeshAgent-OSX-x86-64', rname: 'meshosx', desc: 'Apple OSX x86-64', update: true },
 | 
			
		||||
        17: { id: 17, localname: 'MeshAgent-ChromeOS', rname: 'meshchrome', desc: 'Google ChromeOS', update: false }, // Get this one from Chrome store
 | 
			
		||||
        18: { id: 18, localname: 'meshagent_poky64', rname: 'meshagent', desc: 'Linux Poky x86-64', update: true },
 | 
			
		||||
        19: { id: 19, localname: 'meshagent_x86_nokvm', rname: 'meshagent', desc: 'Linux x86-32 NoKVM', update: true },
 | 
			
		||||
        20: { id: 20, localname: 'meshagent_x86-64_nokvm', rname: 'meshagent', desc: 'Linux x86-64 NoKVM', update: true },
 | 
			
		||||
        21: { id: 21, localname: 'MeshAgent-WinMinCore-Console-x86-32.exe', rname: 'MeshAgent.exe', desc: 'Windows MinCore Console x86-32', update: true },
 | 
			
		||||
        22: { id: 22, localname: 'MeshAgent-WinMinCore-Service-x86-64.exe', rname: 'MeshAgent.exe', desc: 'Windows MinCore Service x86-32', update: true },
 | 
			
		||||
        23: { id: 23, localname: 'MeshAgent-NodeJS', rname: 'meshagent', desc: 'NodeJS', update: false }, // Get this one from NPM
 | 
			
		||||
        24: { id: 24, localname: 'meshagent_arm-linaro', rname: 'meshagent', desc: 'Linux ARM Linaro', update: true },
 | 
			
		||||
        25: { id: 25, localname: 'meshagent_pi', rname: 'meshagent', desc: 'Linux ARM - Raspberry Pi', update: true } // "armv6l" and "armv7l"
 | 
			
		||||
        1: { id: 1, localname: 'MeshConsole.exe', rname: 'meshconsole.exe', desc: 'Windows x86-32 console', update: true, amt: true },
 | 
			
		||||
        2: { id: 2, localname: 'MeshConsole64.exe', rname: 'meshconsole.exe', desc: 'Windows x86-64 console', update: true, amt: true },
 | 
			
		||||
        3: { id: 3, localname: 'MeshService.exe', rname: 'meshagent.exe', desc: 'Windows x86-32 service', update: true, amt: true },
 | 
			
		||||
        4: { id: 4, localname: 'MeshService64.exe', rname: 'meshagent.exe', desc: 'Windows x86-64 service', update: true, amt: true },
 | 
			
		||||
        5: { id: 5, localname: 'meshagent_x86', rname: 'meshagent', desc: 'Linux x86-32', update: true, amt: true },
 | 
			
		||||
        6: { id: 6, localname: 'meshagent_x86-64', rname: 'meshagent', desc: 'Linux x86-64', update: true, amt: true },
 | 
			
		||||
        7: { id: 7, localname: 'meshagent_mips', rname: 'meshagent', desc: 'Linux MIPS', update: true, amt: false },
 | 
			
		||||
        8: { id: 8, localname: 'MeshAgent-Linux-XEN-x86-32', rname: 'meshagent', desc: 'XEN x86-64', update: true, amt: false },
 | 
			
		||||
        9: { id: 9, localname: 'meshagent_arm', rname: 'meshagent', desc: 'Linux ARM5', update: true, amt: false },
 | 
			
		||||
        10: { id: 10, localname: 'MeshAgent-Linux-ARM-PlugPC', rname: 'meshagent', desc: 'Linux ARM PlugPC', update: true, amt: false },
 | 
			
		||||
        11: { id: 11, localname: 'MeshAgent-OSX-x86-32', rname: 'meshosx', desc: 'Apple OSX x86-32', update: true, amt: false },
 | 
			
		||||
        12: { id: 12, localname: 'MeshAgent-Android-x86', rname: 'meshandroid', desc: 'Android x86-32', update: true, amt: false },
 | 
			
		||||
        13: { id: 13, localname: 'meshagent_pogo', rname: 'meshagent', desc: 'Linux ARM PogoPlug', update: true, amt: false },
 | 
			
		||||
        14: { id: 14, localname: 'MeshAgent-Android-APK', rname: 'meshandroid', desc: 'Android Market', update: false, amt: false }, // Get this one from Google Play
 | 
			
		||||
        15: { id: 15, localname: 'meshagent_poky', rname: 'meshagent', desc: 'Linux Poky x86-32', update: true, amt: false },
 | 
			
		||||
        16: { id: 16, localname: 'MeshAgent-OSX-x86-64', rname: 'meshagent', desc: 'Apple OSX x86-64', update: true, amt: false },
 | 
			
		||||
        17: { id: 17, localname: 'MeshAgent-ChromeOS', rname: 'meshagent', desc: 'Google ChromeOS', update: false, amt: false }, // Get this one from Chrome store
 | 
			
		||||
        18: { id: 18, localname: 'meshagent_poky64', rname: 'meshagent', desc: 'Linux Poky x86-64', update: true, amt: false },
 | 
			
		||||
        19: { id: 19, localname: 'meshagent_x86_nokvm', rname: 'meshagent', desc: 'Linux x86-32 NoKVM', update: true, amt: true },
 | 
			
		||||
        20: { id: 20, localname: 'meshagent_x86-64_nokvm', rname: 'meshagent', desc: 'Linux x86-64 NoKVM', update: true, amt: true },
 | 
			
		||||
        21: { id: 21, localname: 'MeshAgent-WinMinCore-Console-x86-32.exe', rname: 'meshagent.exe', desc: 'Windows MinCore Console x86-32', update: true, amt: false },
 | 
			
		||||
        22: { id: 22, localname: 'MeshAgent-WinMinCore-Service-x86-64.exe', rname: 'meshagent.exe', desc: 'Windows MinCore Service x86-32', update: true, amt: false },
 | 
			
		||||
        23: { id: 23, localname: 'MeshAgent-NodeJS', rname: 'meshagent', desc: 'NodeJS', update: false, amt: false }, // Get this one from NPM
 | 
			
		||||
        24: { id: 24, localname: 'meshagent_arm-linaro', rname: 'meshagent', desc: 'Linux ARM Linaro', update: true, amt: false },
 | 
			
		||||
        25: { id: 25, localname: 'meshagent_pi', rname: 'meshagent', desc: 'Linux ARM - Raspberry Pi', update: true, amt: false } // "armv6l" and "armv7l"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Update the list of available mesh agents
 | 
			
		||||
| 
						 | 
				
			
			@ -835,7 +880,7 @@ function InstallModule(modulename, func, tag1, tag2) {
 | 
			
		|||
process.on('SIGINT', function () { if (meshserver != null) { meshserver.Stop(); meshserver = null; } console.log('Server Ctrl-C exit...'); process.exit(); });
 | 
			
		||||
 | 
			
		||||
// Build the list of required modules
 | 
			
		||||
var modules = ['nedb', 'https', 'unzip', 'xmldom', 'express', 'mongojs', 'archiver', 'minimist', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-session', 'express-handlebars'];
 | 
			
		||||
var modules = ['nedb', 'https', 'unzip', 'xmldom', 'express', 'mongojs', 'archiver', 'minimist', 'nodemailer', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-session', 'express-handlebars'];
 | 
			
		||||
if (require('os').platform() == 'win32') { modules.push("node-windows"); }
 | 
			
		||||
 | 
			
		||||
// Run as a command line, if we are not using service arguments, don't need to install the service package.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										83
									
								
								meshmail.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								meshmail.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,83 @@
 | 
			
		|||
/**
 | 
			
		||||
* @description Meshcentral MeshMail
 | 
			
		||||
* @author Ylian Saint-Hilaire
 | 
			
		||||
* @version v0.0.1
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Construct a MeshAgent object, called upon connection
 | 
			
		||||
module.exports.CreateMeshMain = function (parent) {
 | 
			
		||||
    var obj = {};
 | 
			
		||||
    obj.pendingMails = [];
 | 
			
		||||
    obj.parent = parent;
 | 
			
		||||
    obj.retry = 0;
 | 
			
		||||
    obj.sendingMail = false;
 | 
			
		||||
    const nodemailer = require('nodemailer');
 | 
			
		||||
 | 
			
		||||
    // Default account email validation mail
 | 
			
		||||
    var accountCheckSubject = '[[[SERVERNAME]]] - Email Verification';
 | 
			
		||||
    var accountCheckMailHtml = '<div style="font-family:Arial,Helvetica,sans-serif"><table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8><tr><td><b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b></td></tr></table><p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting email verification, click on the following link to complete the process.</p><p style="margin-left:30px"><a href="[[[CALLBACKURL]]]">Click here to verify your e-mail address.</a></p>If you did not initiate this request, please ignore this mail.</div>';
 | 
			
		||||
    var accountCheckMailText = '[[[SERVERNAME]]] - Verification\r\n\r\nHi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is performing an e-mail verification. Nagivate to the following link to complete the process: [[[CALLBACKURL]]]\r\nIf you did not initiate this request, please ignore this mail.\r\n';
 | 
			
		||||
 | 
			
		||||
    // Default account reset mail
 | 
			
		||||
    var accountResetSubject = '[[[SERVERNAME]]] - Account Reset';
 | 
			
		||||
    var accountResetMailHtml = '<div style="font-family:Arial,Helvetica,sans-serif"><table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8><tr><td><b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b></td></tr></table><p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting an account password reset, click on the following link to complete the process.</p><p style="margin-left:30px"><a href="[[[CALLBACKURL]]]">Click here to reset your account password.</a></p>If you did not initiate this request, please ignore this mail.</div>';
 | 
			
		||||
    var accountResetMailText = '[[[SERVERNAME]]] - Account Reset\r\n\r\nHi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is requesting an account password reset. Nagivate to the following link to complete the process: [[[CALLBACKURL]]]\r\nIf you did not initiate this request, please ignore this mail.\r\n';
 | 
			
		||||
 | 
			
		||||
    // Setup mail server
 | 
			
		||||
    var options = { host: parent.config.smtp.host, secure: false, tls: { rejectUnauthorized: false } };
 | 
			
		||||
    if (parent.config.smtp.port != null) { options.port = parent.config.smtp.port; }
 | 
			
		||||
    obj.smtpServer = nodemailer.createTransport(options);
 | 
			
		||||
 | 
			
		||||
    // Perform all e-mail substitution
 | 
			
		||||
    function mailReplacements(text, domain, username, email, cookie) {
 | 
			
		||||
        var url = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + parent.certificates.CommonName + ':' + obj.parent.args.port + domain.url;
 | 
			
		||||
        if (cookie != null) { text = text.split('[[[CALLBACKURL]]]').join(url + 'checkmail?c=' + cookie) }
 | 
			
		||||
        return text.split('[[[USERNAME]]]').join(username).split('[[[SERVERURL]]]').join(url).split('[[[SERVERNAME]]]').join(domain.title);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Send a mail
 | 
			
		||||
    obj.sendMail = function (to, subject, text, html) {
 | 
			
		||||
        obj.pendingMails.push({ to: to, from: parent.config.smtp.from, subject: subject, text: text, html: html });
 | 
			
		||||
        sendNextMail();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Send account check mail
 | 
			
		||||
    obj.sendAccountCheckMail = function (domain, username, email) {
 | 
			
		||||
        if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, no reset possible.
 | 
			
		||||
        var cookie = obj.parent.webserver.encodeCookie({ u: domain.id + '/' + username, e: email, a: 1 });
 | 
			
		||||
        obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountCheckSubject, domain, username, email), text: mailReplacements(accountCheckMailText, domain, username, email, cookie), html: mailReplacements(accountCheckMailHtml, domain, username, email, cookie) });
 | 
			
		||||
        sendNextMail();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Send account reset mail
 | 
			
		||||
    obj.sendAccountResetMail = function (domain, username, email) {
 | 
			
		||||
        if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, don't validate the email address.
 | 
			
		||||
        var cookie = obj.parent.webserver.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 });
 | 
			
		||||
        obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountResetSubject, domain, username, email), text: mailReplacements(accountResetMailText, domain, username, email, cookie), html: mailReplacements(accountResetMailHtml, domain, username, email, cookie) });
 | 
			
		||||
        sendNextMail();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Send out the next mail in the pending list
 | 
			
		||||
    function sendNextMail() {
 | 
			
		||||
        if ((obj.sendingMail == true) || (obj.pendingMails.length == 0)) { return; }
 | 
			
		||||
 | 
			
		||||
        var mailToSend = obj.pendingMails[0];
 | 
			
		||||
        obj.sendingMail = true;
 | 
			
		||||
        //console.log('SMTP sending mail to ' + mailToSend.to + '.');
 | 
			
		||||
        obj.smtpServer.sendMail(mailToSend, function (err, info) {
 | 
			
		||||
            //console.log(JSON.stringify(err), JSON.stringify(info));
 | 
			
		||||
            obj.sendingMail = false;
 | 
			
		||||
            if (err == null) {
 | 
			
		||||
                obj.pendingMails.shift();
 | 
			
		||||
                obj.retry = 0;
 | 
			
		||||
                sendNextMail(); // Send the next mail
 | 
			
		||||
            } else {
 | 
			
		||||
                obj.retry++;
 | 
			
		||||
                //console.log('SMTP server failed, will try again in a minute (' + obj.retry + ').');
 | 
			
		||||
                setTimeout(sendNextMail, 60000); // Wait and try again
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	return obj;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								meshuser.js
									
										
									
									
									
								
							
							
						
						
									
										96
									
								
								meshuser.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -92,10 +92,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                                    if ((state.connectivity & 1) != 0) { var agent = obj.parent.wsagents[docs[i]._id]; if (agent != null) { docs[i].agct = agent.connectTime; } }
 | 
			
		||||
                                    if ((state.connectivity & 2) != 0) { var cira = obj.parent.parent.mpsserver.ciraConnections[docs[i]._id]; if (cira != null) { docs[i].cict = cira.tag.connectTime; } }
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                // Compress the meshid's
 | 
			
		||||
                                var meshid = docs[i].meshid;
 | 
			
		||||
                                if (!r[meshid]) { r[meshid] = []; }
 | 
			
		||||
                                delete docs[i].meshid;
 | 
			
		||||
 | 
			
		||||
                                // Remove Intel AMT credential if present
 | 
			
		||||
                                if (docs[i].intelamt != null && docs[i].intelamt.pass != null) { delete docs[i].intelamt.pass; }
 | 
			
		||||
 | 
			
		||||
                                r[meshid].push(docs[i]);
 | 
			
		||||
                            }
 | 
			
		||||
                            ws.send(JSON.stringify({ action: 'nodes', nodes: r }));
 | 
			
		||||
| 
						 | 
				
			
			@ -233,10 +238,66 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                        // Request a list of all users
 | 
			
		||||
                        if ((user.siteadmin & 2) == 0) break;
 | 
			
		||||
                        var docs = [];
 | 
			
		||||
                        for (var i in obj.parent.users) { if ((obj.parent.users[i].domain == domain.id) && (obj.parent.users[i].name != '~')) { docs.push(obj.parent.users[i]); } }
 | 
			
		||||
                        for (var i in obj.parent.users) {
 | 
			
		||||
                            if ((obj.parent.users[i].domain == domain.id) && (obj.parent.users[i].name != '~')) {
 | 
			
		||||
                                var userinfo = obj.common.Clone(obj.parent.users[i]);
 | 
			
		||||
                                delete userinfo.hash;
 | 
			
		||||
                                delete userinfo.passhint;
 | 
			
		||||
                                delete userinfo.salt;
 | 
			
		||||
                                delete userinfo.type;
 | 
			
		||||
                                delete userinfo.domain;
 | 
			
		||||
                                delete userinfo.subscriptions;
 | 
			
		||||
                                delete userinfo.passtype;
 | 
			
		||||
                                docs.push(userinfo);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        ws.send(JSON.stringify({ action: 'users', users: docs }));
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 'changeemail':
 | 
			
		||||
                    {
 | 
			
		||||
                        // Change the email address
 | 
			
		||||
                        if ((command.email != null) && (typeof command.email == 'string') && (command.email.length < 1024)) {
 | 
			
		||||
                            var x = command.email.split('@');
 | 
			
		||||
                            if ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2)) {
 | 
			
		||||
                                if (obj.parent.users[req.session.userid].email != command.email) {
 | 
			
		||||
                                    // Update the user's email
 | 
			
		||||
                                    var oldemail = user.email;
 | 
			
		||||
                                    user.email = command.email;
 | 
			
		||||
                                    user.emailVerified = false;
 | 
			
		||||
                                    obj.parent.db.SetUser(user);
 | 
			
		||||
 | 
			
		||||
                                    // Event the change
 | 
			
		||||
                                    var userinfo = obj.common.Clone(user);
 | 
			
		||||
                                    delete userinfo.hash;
 | 
			
		||||
                                    delete userinfo.passhint;
 | 
			
		||||
                                    delete userinfo.salt;
 | 
			
		||||
                                    delete userinfo.type;
 | 
			
		||||
                                    delete userinfo.domain;
 | 
			
		||||
                                    delete userinfo.subscriptions;
 | 
			
		||||
                                    delete userinfo.passtype;
 | 
			
		||||
                                    obj.parent.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Changed email of user ' + userinfo.name + ' from ' + oldemail + ' to ' + user.email, domain: domain.id })
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 'verifyemail':
 | 
			
		||||
                    {
 | 
			
		||||
                        // Send a account email verification email
 | 
			
		||||
                        if ((command.email != null) && (typeof command.email == 'string') && (command.email.length < 1024)) {
 | 
			
		||||
                            var x = command.email.split('@');
 | 
			
		||||
                            if ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2)) {
 | 
			
		||||
                                if (obj.parent.users[req.session.userid].email == command.email) {
 | 
			
		||||
                                    // Send the verification email
 | 
			
		||||
                                    if (obj.parent.parent.mailserver != null) {
 | 
			
		||||
                                        obj.parent.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email);
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                case 'wssessioncount':
 | 
			
		||||
                    {
 | 
			
		||||
                        // Request a list of all web socket user session count
 | 
			
		||||
| 
						 | 
				
			
			@ -307,12 +368,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                                if (command.quota != chguser.quota) { chguser.quota = command.quota; if (chguser.quota == null) { delete chguser.quota; } change = 1; }
 | 
			
		||||
                                if ((user.siteadmin == 0xFFFFFFFF) && (command.siteadmin != null) && (chguser.siteadmin != command.siteadmin)) { chguser.siteadmin = command.siteadmin; change = 1 }
 | 
			
		||||
                                if (change == 1) {
 | 
			
		||||
                                    obj.db.Set(chguser);
 | 
			
		||||
                                    obj.db.SetUser(chguser);
 | 
			
		||||
                                    obj.parent.parent.DispatchEvent([chguser._id], obj, 'resubscribe');
 | 
			
		||||
                                    var chguser2 = obj.common.Clone(chguser);
 | 
			
		||||
                                    delete chguser2.salt;
 | 
			
		||||
                                    delete chguser2.hash;
 | 
			
		||||
                                    obj.parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: chguser2, action: 'accountchange', msg: 'Account changed: ' + command.name, domain: domain.id })
 | 
			
		||||
                                    var userinfo = obj.common.Clone(chguser);
 | 
			
		||||
                                    delete userinfo.hash;
 | 
			
		||||
                                    delete userinfo.passhint;
 | 
			
		||||
                                    delete userinfo.salt;
 | 
			
		||||
                                    delete userinfo.type;
 | 
			
		||||
                                    delete userinfo.domain;
 | 
			
		||||
                                    delete userinfo.subscriptions;
 | 
			
		||||
                                    delete userinfo.passtype;
 | 
			
		||||
                                    obj.parent.parent.DispatchEvent(['*', 'server-users', user._id, chguser._id], obj, { etype: 'user', username: user.name, account: userinfo, action: 'accountchange', msg: 'Account changed: ' + command.name, domain: domain.id })
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -375,7 +441,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                                for (var j in links) {
 | 
			
		||||
                                    var xuser = obj.parent.users[j];
 | 
			
		||||
                                    delete xuser.links[meshes[i]._id];
 | 
			
		||||
                                    obj.db.Set(xuser);
 | 
			
		||||
                                    obj.db.SetUser(xuser);
 | 
			
		||||
                                    obj.parent.parent.DispatchEvent([xuser._id], obj, 'resubscribe');
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -426,7 +492,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
                            // Add mesh to user
 | 
			
		||||
                            if (newuser.links == null) newuser.links = {};
 | 
			
		||||
                            newuser.links[command.meshid] = { rights: command.meshadmin };
 | 
			
		||||
                            obj.db.Set(newuser);
 | 
			
		||||
                            obj.db.SetUser(newuser);
 | 
			
		||||
                            obj.parent.parent.DispatchEvent([newuser._id], obj, 'resubscribe');
 | 
			
		||||
 | 
			
		||||
                            // Add a user to the mesh
 | 
			
		||||
| 
						 | 
				
			
			@ -819,18 +885,18 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
 | 
			
		|||
            if (obj.parent.parent.multiServer != null) { obj.parent.parent.multiServer.DispatchMessage({ action: 'sessionEnd', sessionid: ws.sessionId }); }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Send server information
 | 
			
		||||
        if (obj.args.notls == true) {
 | 
			
		||||
            ws.send(JSON.stringify({ action: 'serverinfo', serverinfo: { name: obj.parent.certificates.CommonName, mpsport: obj.args.mpsport, mpspass: obj.args.mpspass, port: obj.args.port, https: false, emailcheck: obj.parent.parent.mailserver != null } }));
 | 
			
		||||
        } else {
 | 
			
		||||
            ws.send(JSON.stringify({ action: 'serverinfo', serverinfo: { name: obj.parent.certificates.CommonName, mpsport: obj.args.mpsport, mpspass: obj.args.mpspass, redirport: obj.args.redirport, port: obj.args.port, https: true, emailcheck: obj.parent.parent.mailserver != null } }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Send user information to web socket, this is the first thing we send
 | 
			
		||||
        var userinfo = obj.common.Clone(obj.parent.users[req.session.userid]);
 | 
			
		||||
        delete userinfo.salt;
 | 
			
		||||
        delete userinfo.hash;
 | 
			
		||||
        ws.send(JSON.stringify({ action: 'userinfo', userinfo: userinfo }));
 | 
			
		||||
 | 
			
		||||
        // Next, send server information
 | 
			
		||||
        if (obj.args.notls == true) {
 | 
			
		||||
            ws.send(JSON.stringify({ action: 'serverinfo', serverinfo: { name: obj.parent.certificates.CommonName, mpsport: obj.args.mpsport, mpspass: obj.args.mpspass, port: obj.args.port, https: false } }));
 | 
			
		||||
        } else {
 | 
			
		||||
            ws.send(JSON.stringify({ action: 'serverinfo', serverinfo: { name: obj.parent.certificates.CommonName, mpsport: obj.args.mpsport, mpspass: obj.args.mpspass, redirport: obj.args.redirport, port: obj.args.port, https: true } }));
 | 
			
		||||
        }
 | 
			
		||||
    } catch (e) { console.log(e); }
 | 
			
		||||
 | 
			
		||||
    // Read the folder and all sub-folders and serialize that into json.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "meshcentral",
 | 
			
		||||
  "version": "0.1.0-l",
 | 
			
		||||
  "version": "0.1.0-m",
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "Remote Management",
 | 
			
		||||
    "Intel AMT",
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +40,7 @@
 | 
			
		|||
    "nedb": "^1.8.0",
 | 
			
		||||
    "node-forge": "^0.6.49",
 | 
			
		||||
    "node-windows": "^0.1.14",
 | 
			
		||||
    "nodemailer": "^4.4.1",
 | 
			
		||||
    "unzip": "^0.1.11",
 | 
			
		||||
    "ws": "^3.2.0",
 | 
			
		||||
    "xmldom": "^0.1.27"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -376,6 +376,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
 | 
			
		|||
    obj.mousedown = function (e) { return obj.xxMouseDown(e); }
 | 
			
		||||
    obj.mouseup = function (e) { return obj.xxMouseUp(e); }
 | 
			
		||||
    obj.mousemove = function (e) { return obj.xxMouseMove(e); }
 | 
			
		||||
    obj.mousewheel = function (e) { return obj.xxMouseWheel(e); }
 | 
			
		||||
 | 
			
		||||
    obj.xxMsTouchEvent = function (evt) {
 | 
			
		||||
        if (evt.originalEvent.pointerType == 4) return; // If this is a mouse pointer, ignore this event. Touch & pen are ok.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -630,6 +630,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
 | 
			
		|||
        
 | 
			
		||||
        return obj.haltEvent(e);
 | 
			
		||||
    }
 | 
			
		||||
    obj.mousewheel = function (e) { }
 | 
			
		||||
    
 | 
			
		||||
    obj.getPositionOfControl = function (Control) {
 | 
			
		||||
        var Position = Array(2);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -150,12 +150,12 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
 | 
			
		|||
            // Detect if this is an HTTPS request, if it is, return a simple answer and disconnect. This is useful for debugging access to the MPS port.
 | 
			
		||||
            if (socket.tag.first == true) {
 | 
			
		||||
                if (socket.tag.accumulator.length < 3) return;
 | 
			
		||||
                if (socket.tag.accumulator.substring(0, 3) == 'GET') { console.log("Swarm Connection, HTTP GET detected: " + socket.remoteAddress); socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>MeshCentral2 legacy swarm server.<br />MeshCentral1 mesh agents should connect here for updates.</body></html>'); socket.end(); return; }
 | 
			
		||||
                if (socket.tag.accumulator.substring(0, 3) == 'GET') { /*console.log("Swarm Connection, HTTP GET detected: " + socket.remoteAddress);*/ socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>MeshCentral2 legacy swarm server.<br />MeshCentral1 mesh agents should connect here for updates.</body></html>'); socket.end(); return; }
 | 
			
		||||
                socket.tag.first = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // A client certificate is required
 | 
			
		||||
            if (!socket.tag.clientCert.subject) { console.log("Swarm Connection, no client cert: " + socket.remoteAddress); socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 legacy swarm server.\r\nNo client certificate given.'); socket.end(); return; }
 | 
			
		||||
            if (!socket.tag.clientCert.subject) { /*console.log("Swarm Connection, no client cert: " + socket.remoteAddress);*/ socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 legacy swarm server.\r\nNo client certificate given.'); socket.end(); return; }
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                // Parse all of the APF data we can
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -167,6 +167,8 @@
 | 
			
		|||
                    <div id="p2AccountActions">
 | 
			
		||||
                        <p><strong><img alt="" width=150 height=103 src=images/mainaccount.png style=margin-bottom:10px;margin-right:20px;float:right />Account actions</strong></p>
 | 
			
		||||
                        <p style="margin-left:40px">
 | 
			
		||||
                            <a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a><br />
 | 
			
		||||
                            <span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a><br /></span>
 | 
			
		||||
                            <a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><br />
 | 
			
		||||
                            <a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a><br />
 | 
			
		||||
                        </p>
 | 
			
		||||
| 
						 | 
				
			
			@ -686,6 +688,22 @@
 | 
			
		|||
            if (t != null) { desktopsettings = JSON.parse(t); }
 | 
			
		||||
            applyDesktopSettings();
 | 
			
		||||
 | 
			
		||||
            // Mouse Scroll on desktop
 | 
			
		||||
            if (navigator.userAgent.match(/mozilla/i)) {
 | 
			
		||||
                Q('Desk').addEventListener('DOMMouseScroll', function (e) {
 | 
			
		||||
                    return dmousewheel(e);
 | 
			
		||||
                    //if (loginState == 3) { SendMouseMsg(KeyAction.SCROLL, e); return false; }
 | 
			
		||||
                    //return true;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                Q('Desk').addEventListener('mousewheel', function (e) {
 | 
			
		||||
                    return dmousewheel(e);
 | 
			
		||||
                    //if (loginState == 3) { SendMouseMsg(KeyAction.SCROLL, e); return false; }
 | 
			
		||||
                    //return true;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Terminal special keys
 | 
			
		||||
            var x = '';
 | 
			
		||||
            for (var c = 1; c < 27; c++) x += "<option value='" + c + "'>Ctrl-" + String.fromCharCode(64 + c) + " (" + c + ")</option>";
 | 
			
		||||
| 
						 | 
				
			
			@ -760,13 +778,14 @@
 | 
			
		|||
 | 
			
		||||
        function onMessage(server, message) {
 | 
			
		||||
            switch (message.action) {
 | 
			
		||||
                case 'serverinfo': {
 | 
			
		||||
                    serverinfo = message.serverinfo;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'userinfo': {
 | 
			
		||||
                    userinfo = message.userinfo;
 | 
			
		||||
                    updateSiteAdmin();
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'serverinfo': {
 | 
			
		||||
                    serverinfo = message.serverinfo;
 | 
			
		||||
                    QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'users': {
 | 
			
		||||
| 
						 | 
				
			
			@ -910,6 +929,7 @@
 | 
			
		|||
                                if ((message.event.account.quota != userinfo.quota) || (((userinfo.siteadmin & 8) == 0) && ((message.event.account.siteadmin & 8) != 0))) { meshserver.Send({ action: 'files' }); }
 | 
			
		||||
                                userinfo = message.event.account;
 | 
			
		||||
                                if (oldsiteadmin != newsiteadmin) updateSiteAdmin();
 | 
			
		||||
                                QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
 | 
			
		||||
                            }
 | 
			
		||||
                            if (users == null) break;
 | 
			
		||||
                            users[message.event.account._id] = message.event.account;
 | 
			
		||||
| 
						 | 
				
			
			@ -2971,6 +2991,7 @@
 | 
			
		|||
        function dmousedown(e) { if (!xxdialogMode && desktop != undefined) desktop.m.mousedown(e) }
 | 
			
		||||
        function dmouseup(e) { if (!xxdialogMode && desktop != undefined) desktop.m.mouseup(e) }
 | 
			
		||||
        function dmousemove(e) { if (!xxdialogMode && desktop != undefined) desktop.m.mousemove(e) }
 | 
			
		||||
        function dmousewheel(e) { if (!xxdialogMode && desktop != undefined) { desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
 | 
			
		||||
        function drotate(x) { if (!xxdialogMode && desktop != undefined) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } }
 | 
			
		||||
 | 
			
		||||
        //
 | 
			
		||||
| 
						 | 
				
			
			@ -3646,6 +3667,34 @@
 | 
			
		|||
        // MY ACCOUNT
 | 
			
		||||
        //
 | 
			
		||||
 | 
			
		||||
        function account_showVerifyEmail() {
 | 
			
		||||
            if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return;
 | 
			
		||||
            var x = "Click ok to send a verification mail to:<br /><div style=padding:8px><b>" + EscapeHtml(userinfo.email) + "</b></div>Please wait a few minute to receive the verification.";
 | 
			
		||||
            setDialogMode(2, "Email Verification", 3, account_showVerifyEmailEx, x);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function account_showVerifyEmailEx() {
 | 
			
		||||
            meshserver.Send({ action: 'verifyemail', email: userinfo.email });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function account_showChangeEmail() {
 | 
			
		||||
            if (xxdialogMode) return;
 | 
			
		||||
            var x = "Change your account e-mail address here.<br /><br />";
 | 
			
		||||
            x += addHtmlValue('Email', '<input id=dp2email style=width:230px maxlength=32 onchange=account_validateEmail() onkeyup=account_validateEmail() />');
 | 
			
		||||
            setDialogMode(2, "Email Address Change", 3, account_changeEmail, x);
 | 
			
		||||
            if (userinfo.email != null) { Q('dp2email').value = userinfo.email; }
 | 
			
		||||
            account_validateEmail();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function account_validateEmail() {
 | 
			
		||||
            var x = Q('dp2email').value.split('@');
 | 
			
		||||
            QE('idx_dlgOkButton', (x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2) && (Q('dp2email').value.length < 1024) && (Q('dp2email').value != userinfo.email));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function account_changeEmail() {
 | 
			
		||||
            meshserver.Send({ action: 'changeemail', email: Q('dp2email').value });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function account_showDeleteAccount() {
 | 
			
		||||
            if (xxdialogMode) return;
 | 
			
		||||
            var x = "To delete this account, type in the account password in both boxes below and hit ok.<br /><br />";
 | 
			
		||||
| 
						 | 
				
			
			@ -4229,7 +4278,7 @@
 | 
			
		|||
                if ((user.quota != undefined) && ((user.siteadmin & 8) != 0)) { msg += ", " + (user.quota / 1024) + " k"; }
 | 
			
		||||
                if (user.name != userinfo.name) { msg += "</a>"; }
 | 
			
		||||
                if (user.email != null) {
 | 
			
		||||
                    msg = '<table style=width:100%><tr><td>' + EscapeHtml(user.name) + ', <a onclick=doemail(event,\"' + user.email + '\")>' + user.email + '</a><td align=right>' + msg + '</table>';
 | 
			
		||||
                    msg = '<table style=width:100%><tr><td>' + EscapeHtml(user.name) + ', <a onclick=doemail(event,\"' + user.email + '\")>' + user.email + '</a>' + (((serverinfo.emailcheck == true) && (user.emailVerified != true))?' (unverified)':'') + '<td align=right>' + msg + '</table>';
 | 
			
		||||
                } else {
 | 
			
		||||
                    msg = '<table style=width:100%><tr><td>' + EscapeHtml(user.name) + '<td align=right>' + msg + '</table>';
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,8 +53,12 @@
 | 
			
		|||
                                            <td align=right><input id=loginButton type=submit value="Log In" disabled="disabled" /></td>
 | 
			
		||||
                                        </tr>
 | 
			
		||||
                                    </table>
 | 
			
		||||
                                    <div id="newAccountDiv" style="display:none">
 | 
			
		||||
                                        <hr />Don't have an account? <a onclick=xgo(2) style=cursor:pointer>Create one</a>.
 | 
			
		||||
                                    <div id="hrAccountDiv" style="display:none"><hr /></div>
 | 
			
		||||
                                    <div id="resetAccountDiv" style="display:none;padding:2px">
 | 
			
		||||
                                        Forgot username/password? <a onclick=xgo(3) style=cursor:pointer>Reset account</a>.
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <div id="newAccountDiv" style="display:none;padding:2px">
 | 
			
		||||
                                        Don't have an account? <a onclick=xgo(2) style=cursor:pointer>Create one</a>.
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                </form>
 | 
			
		||||
                            </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -101,6 +105,29 @@
 | 
			
		|||
                                    <hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a>
 | 
			
		||||
                                </form>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div id=resetpanel style="background-color: #979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
 | 
			
		||||
                                <form action=resetaccount method=post>
 | 
			
		||||
                                    <div id=message3>
 | 
			
		||||
                                        {{{message}}}
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <div>
 | 
			
		||||
                                        <b>Account Reset</b>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <table>
 | 
			
		||||
                                        <tr>
 | 
			
		||||
                                            <td align=right width=100>Email:</td>
 | 
			
		||||
                                            <td><input id=remail type=text name=email onchange=validateReset() onkeyup=validateReset() /></td>
 | 
			
		||||
                                        </tr>
 | 
			
		||||
                                        <tr>
 | 
			
		||||
                                            <td colspan=2>
 | 
			
		||||
                                                <div style=float:right><input id=eresetButton type=submit value="Reset Account" disabled="disabled" /></div>
 | 
			
		||||
                                                <div id=passWarning style="padding-top:6px"></div>
 | 
			
		||||
                                            </td>
 | 
			
		||||
                                        </tr>
 | 
			
		||||
                                    </table>
 | 
			
		||||
                                    <hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a>
 | 
			
		||||
                                </form>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                </table>
 | 
			
		||||
| 
						 | 
				
			
			@ -141,6 +168,7 @@
 | 
			
		|||
    <script>
 | 
			
		||||
        var passhint = "{{{passhint}}}";
 | 
			
		||||
        var newAccountPass = {{{newAccountPass}}};
 | 
			
		||||
        var emailCheck = {{{emailcheck}}};
 | 
			
		||||
 | 
			
		||||
        function startup() {
 | 
			
		||||
            window.onresize = center;
 | 
			
		||||
| 
						 | 
				
			
			@ -151,6 +179,8 @@
 | 
			
		|||
            QV('newAccountDiv', '{{{newAccount}}}' != '0' );
 | 
			
		||||
            if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); }
 | 
			
		||||
            QV("newAccountPass", (newAccountPass == 1));
 | 
			
		||||
            QV("resetAccountDiv", (emailCheck == true));
 | 
			
		||||
            QV("hrAccountDiv", (emailCheck == true) || (newAccountPass == 1))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function showPassHint() {
 | 
			
		||||
| 
						 | 
				
			
			@ -168,6 +198,7 @@
 | 
			
		|||
            QV("showPassHintLink", false);
 | 
			
		||||
            QV('loginpanel', x == 1);
 | 
			
		||||
            QV('createpanel', x == 2);
 | 
			
		||||
            QV('resetpanel', x == 3);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function validateLogin() {
 | 
			
		||||
| 
						 | 
				
			
			@ -178,7 +209,7 @@
 | 
			
		|||
 | 
			
		||||
        function validateCreate() {
 | 
			
		||||
            setDialogMode(0);
 | 
			
		||||
            var ok = (Q('ausername').value.length > 0 && Q('aemail').value.length > 0 && Q('apassword1').value.length > 0 && (Q('apassword2').value == Q('apassword1').value));
 | 
			
		||||
            var ok = ((Q('ausername').value.length > 0) && (checkEmail(Q('aemail').value) == true) && (Q('apassword1').value.length > 0) && (Q('apassword2').value == Q('apassword1').value));
 | 
			
		||||
            if ((newAccountPass == 1) && (Q('anewaccountpass').value.length == 0)) { ok = false; }
 | 
			
		||||
            QE('createButton', ok);
 | 
			
		||||
            if (Q('apassword1').value == '') {
 | 
			
		||||
| 
						 | 
				
			
			@ -191,6 +222,19 @@
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function validateReset() {
 | 
			
		||||
            setDialogMode(0);
 | 
			
		||||
            QE('eresetButton', checkEmail(Q('remail').value));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Return true is the input string looks like an email address
 | 
			
		||||
        function checkEmail(str) {
 | 
			
		||||
            var x = str.split('@');
 | 
			
		||||
            var ok = ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2));
 | 
			
		||||
            if (ok == true) { var y = x[1].split('.'); for (var i in y) { if (y[i].length == 0) { ok = false; } } }
 | 
			
		||||
            return ok;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Return a password strength score
 | 
			
		||||
        function checkPasswordStrength(password) {
 | 
			
		||||
            var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										42
									
								
								views/message.handlebars
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								views/message.handlebars
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta http-equiv=X-UA-Compatible content="IE=edge" />
 | 
			
		||||
    <meta content="text/html;charset=utf-8" http-equiv=Content-Type />
 | 
			
		||||
    <meta name=viewport content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
 | 
			
		||||
    <meta name=apple-mobile-web-app-capable content=yes />
 | 
			
		||||
    <meta name=format-detection content="telephone=no" />
 | 
			
		||||
    <link type=text/css href="/styles/style.css" media="screen" rel="stylesheet" title="CSS" />
 | 
			
		||||
    <title>MeshCentral - {{{title3}}}</title>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <div id=container style=max-height:100vh>
 | 
			
		||||
        <div id=mastheadx></div>
 | 
			
		||||
        <div id=masthead style="background:url(/images/logoback.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden">
 | 
			
		||||
            <div style=float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px>
 | 
			
		||||
                <strong><font style="font-size:46px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div style=float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px>
 | 
			
		||||
                <strong><font style="font-size:14px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div id=page_content style=max-height:calc(100vh-138px)>
 | 
			
		||||
            <div id=column_l>
 | 
			
		||||
                <h1>{{{title3}}}</h1>
 | 
			
		||||
                <p style=margin-left:20px>{{{message}}}</p>
 | 
			
		||||
                <br />
 | 
			
		||||
            </div>
 | 
			
		||||
            <div id=footer>
 | 
			
		||||
                <table cellpadding=0 cellspacing=10 style=width:100%>
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td style=text-align:left></td>
 | 
			
		||||
                        <td style=text-align:right>
 | 
			
		||||
                            <a href=terms>Terms & Privacy</a>
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                </table>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										242
									
								
								webserver.js
									
										
									
									
									
								
							
							
						
						
									
										242
									
								
								webserver.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -326,40 +326,179 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';;
 | 
			
		||||
            res.redirect(domain.url);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Check if there is domain.newAccountToken, check if supplied token is valid
 | 
			
		||||
            if ((domain.newaccountspass != null) && (domain.newaccountspass != '') && (req.body.anewaccountpass != domain.newaccountspass)) {
 | 
			
		||||
                req.session.loginmode = 2;
 | 
			
		||||
                req.session.error = '<b style=color:#8C001A>Invalid account creation token.</b>';
 | 
			
		||||
                res.redirect(domain.url);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            // Check if user exists
 | 
			
		||||
            if (obj.users['user/' + domain.id + '/' + req.body.username.toLowerCase()]) {
 | 
			
		||||
                req.session.loginmode = 2;
 | 
			
		||||
                req.session.error = '<b style=color:#8C001A>Username already exists.</b>';
 | 
			
		||||
            } else {
 | 
			
		||||
                var hint = req.body.apasswordhint;
 | 
			
		||||
                if (hint.length > 250) hint = hint.substring(0, 250);
 | 
			
		||||
                var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Date.now(), login: Date.now(), domain: domain.id, passhint: hint };
 | 
			
		||||
                var usercount = 0;
 | 
			
		||||
                for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } }
 | 
			
		||||
                if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newaccounts == 2) { domain.newaccounts = 0; } } // If this is the first user, give the account site admin.
 | 
			
		||||
                obj.users[user._id] = user;
 | 
			
		||||
                req.session.userid = user._id;
 | 
			
		||||
                req.session.domainid = domain.id;
 | 
			
		||||
                // Create a user, generate a salt and hash the password
 | 
			
		||||
                require('./pass').hash(req.body.password1, function (err, salt, hash) {
 | 
			
		||||
                    if (err) throw err;
 | 
			
		||||
                    user.salt = salt;
 | 
			
		||||
                    user.hash = hash;
 | 
			
		||||
                    obj.db.SetUser(user);
 | 
			
		||||
                });
 | 
			
		||||
                obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, account: user, action: 'accountcreate', msg: 'Account created, email is ' + req.body.email, domain: domain.id })
 | 
			
		||||
            }
 | 
			
		||||
            res.redirect(domain.url);
 | 
			
		||||
            // Check if this email was already verified
 | 
			
		||||
            obj.db.GetUserWithVerifiedEmail(domain.id, req.body.email, function (err, docs) {
 | 
			
		||||
                if (docs.length > 0) {
 | 
			
		||||
                    req.session.loginmode = 2;
 | 
			
		||||
                    req.session.error = '<b style=color:#8C001A>Existing account with this email address.</b>';;
 | 
			
		||||
                    res.redirect(domain.url);
 | 
			
		||||
                } else {
 | 
			
		||||
                    // Check if there is domain.newAccountToken, check if supplied token is valid
 | 
			
		||||
                    if ((domain.newaccountspass != null) && (domain.newaccountspass != '') && (req.body.anewaccountpass != domain.newaccountspass)) {
 | 
			
		||||
                        req.session.loginmode = 2;
 | 
			
		||||
                        req.session.error = '<b style=color:#8C001A>Invalid account creation token.</b>';
 | 
			
		||||
                        res.redirect(domain.url);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    // Check if user exists
 | 
			
		||||
                    if (obj.users['user/' + domain.id + '/' + req.body.username.toLowerCase()]) {
 | 
			
		||||
                        req.session.loginmode = 2;
 | 
			
		||||
                        req.session.error = '<b style=color:#8C001A>Username already exists.</b>';
 | 
			
		||||
                    } else {
 | 
			
		||||
                        var hint = req.body.apasswordhint;
 | 
			
		||||
                        if (hint.length > 250) hint = hint.substring(0, 250);
 | 
			
		||||
                        var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Date.now(), login: Date.now(), domain: domain.id, passhint: hint };
 | 
			
		||||
                        var usercount = 0;
 | 
			
		||||
                        for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } }
 | 
			
		||||
                        if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newaccounts == 2) { domain.newaccounts = 0; } } // If this is the first user, give the account site admin.
 | 
			
		||||
                        obj.users[user._id] = user;
 | 
			
		||||
                        req.session.userid = user._id;
 | 
			
		||||
                        req.session.domainid = domain.id;
 | 
			
		||||
                        // Create a user, generate a salt and hash the password
 | 
			
		||||
                        require('./pass').hash(req.body.password1, function (err, salt, hash) {
 | 
			
		||||
                            if (err) throw err;
 | 
			
		||||
                            user.salt = salt;
 | 
			
		||||
                            user.hash = hash;
 | 
			
		||||
                            obj.db.SetUser(user);
 | 
			
		||||
                            if (obj.parent.mailserver != null) { obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email); }
 | 
			
		||||
                        });
 | 
			
		||||
                        obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, account: user, action: 'accountcreate', msg: 'Account created, email is ' + req.body.email, domain: domain.id })
 | 
			
		||||
                    }
 | 
			
		||||
                    res.redirect(domain.url);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Called to process an account reset request
 | 
			
		||||
    function handleResetAccountRequest(req, res) {
 | 
			
		||||
        var domain = checkUserIpAddress(req, res);
 | 
			
		||||
        if (domain == null) return;
 | 
			
		||||
        if (domain.newaccounts == 0) { res.sendStatus(401); return; }
 | 
			
		||||
        if (!req.body.email || checkEmail(req.body.email) == false) {
 | 
			
		||||
            req.session.loginmode = 3;
 | 
			
		||||
            req.session.error = '<b style=color:#8C001A>Invalid email.</b>';
 | 
			
		||||
            res.redirect(domain.url);
 | 
			
		||||
        } else {
 | 
			
		||||
            obj.db.GetUserWithVerifiedEmail(domain.id, req.body.email, function (err, docs) {
 | 
			
		||||
                if (docs.length == 0) {
 | 
			
		||||
                    req.session.loginmode = 3;
 | 
			
		||||
                    req.session.error = '<b style=color:#8C001A>Account not found.</b>';
 | 
			
		||||
                    res.redirect(domain.url);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var userFound = docs[0];
 | 
			
		||||
                    if (obj.parent.mailserver != null) {
 | 
			
		||||
                        obj.parent.mailserver.sendAccountResetMail(domain, userFound.name, userFound.email);
 | 
			
		||||
                        req.session.loginmode = 1;
 | 
			
		||||
                        req.session.error = '<b style=color:darkgreen>Hold on, reset mail sent.</b>';
 | 
			
		||||
                        res.redirect(domain.url);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        req.session.loginmode = 3;
 | 
			
		||||
                        req.session.error = '<b style=color:#8C001A>Unable to sent email.</b>';
 | 
			
		||||
                        res.redirect(domain.url);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Called to process a web based email verification request
 | 
			
		||||
    function handleCheckMailRequest(req, res) {
 | 
			
		||||
        var domain = checkUserIpAddress(req, res);
 | 
			
		||||
        if (domain == null) return;
 | 
			
		||||
        if (req.query.c != null) {
 | 
			
		||||
            var cookie = obj.decodeCookie(req.query.c, null, 30);
 | 
			
		||||
            if ((cookie != null) && (cookie.u != null) && (cookie.e != null)) {
 | 
			
		||||
                var idsplit = cookie.u.split('/');
 | 
			
		||||
                if ((idsplit.length != 2) || (idsplit[0] != domain.id)) {
 | 
			
		||||
                    res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'ERROR: Invalid domain. <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                } else {
 | 
			
		||||
                    obj.db.Get('user/' + cookie.u, function (err, docs) {
 | 
			
		||||
                        if (docs.length == 0) {
 | 
			
		||||
                            res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'ERROR: Invalid username \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                        } else {
 | 
			
		||||
                            var user = docs[0];
 | 
			
		||||
                            if (user.email != cookie.e) {
 | 
			
		||||
                                res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'ERROR: Invalid e-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                            } else {
 | 
			
		||||
                                if (cookie.a == 1) {
 | 
			
		||||
                                    // Account email verification
 | 
			
		||||
                                    if (user.emailVerified == true) {
 | 
			
		||||
                                        res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" already verified. <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        obj.db.GetUserWithVerifiedEmail(domain.id, user.email, function (err, docs) {
 | 
			
		||||
                                            if (docs.length > 0) {
 | 
			
		||||
                                                res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" already in use on a different account. Change the email address and try again. <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                                            } else {
 | 
			
		||||
                                                // Set the verified flag
 | 
			
		||||
                                                obj.users[user._id].emailVerified = true;
 | 
			
		||||
                                                user.emailVerified = true;
 | 
			
		||||
                                                obj.db.SetUser(user);
 | 
			
		||||
 | 
			
		||||
                                                // Event the change
 | 
			
		||||
                                                var userinfo = obj.common.Clone(user);
 | 
			
		||||
                                                delete userinfo.hash;
 | 
			
		||||
                                                delete userinfo.passhint;
 | 
			
		||||
                                                delete userinfo.salt;
 | 
			
		||||
                                                delete userinfo.type;
 | 
			
		||||
                                                delete userinfo.domain;
 | 
			
		||||
                                                delete userinfo.subscriptions;
 | 
			
		||||
                                                delete userinfo.passtype;
 | 
			
		||||
                                                obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + userinfo.email + ')', domain: domain.id })
 | 
			
		||||
 | 
			
		||||
                                                // Send the confirmation page
 | 
			
		||||
                                                res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Verified e-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                                            }
 | 
			
		||||
                                        });
 | 
			
		||||
                                    }
 | 
			
		||||
                                } else if (cookie.a == 2) {
 | 
			
		||||
                                    // Account reset
 | 
			
		||||
                                    if (user.emailVerified != true) {
 | 
			
		||||
                                        res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" not verified. <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        // Set a temporary password
 | 
			
		||||
                                        obj.crypto.randomBytes(16, function (err, buf) {
 | 
			
		||||
                                            var newpass = buf.toString('base64').split('=').join('').split('/').join('');
 | 
			
		||||
                                            require('./pass').hash(newpass, function (err, salt, hash) {
 | 
			
		||||
                                                if (err) throw err;
 | 
			
		||||
 | 
			
		||||
                                                // Change the password
 | 
			
		||||
                                                var userinfo = obj.users[user._id];
 | 
			
		||||
                                                userinfo.salt = salt;
 | 
			
		||||
                                                userinfo.hash = hash;
 | 
			
		||||
                                                userinfo.passchange = Date.now();
 | 
			
		||||
                                                userinfo.passhint = null;
 | 
			
		||||
                                                obj.db.SetUser(userinfo);
 | 
			
		||||
 | 
			
		||||
                                                // Event the change
 | 
			
		||||
                                                var userinfo = obj.common.Clone(userinfo);
 | 
			
		||||
                                                delete userinfo.hash;
 | 
			
		||||
                                                delete userinfo.passhint;
 | 
			
		||||
                                                delete userinfo.salt;
 | 
			
		||||
                                                delete userinfo.type;
 | 
			
		||||
                                                delete userinfo.domain;
 | 
			
		||||
                                                delete userinfo.subscriptions;
 | 
			
		||||
                                                delete userinfo.passtype;
 | 
			
		||||
                                                obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id })
 | 
			
		||||
 | 
			
		||||
                                                // Send the new password
 | 
			
		||||
                                                res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Password for \"' + EscapeHtml(user.name) + '\" has been reset to \"<b>' + EscapeHtml(newpass) + '</b>\", login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                                            });
 | 
			
		||||
                                        });
 | 
			
		||||
                                    }
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'ERROR: Invalid account check. <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'ERROR: Invalid account check, verification url is only valid for 30 minutes. <a href="' + domain.url + '">Go to login page</a>.' });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function handleDeleteAccountRequest(req, res) {
 | 
			
		||||
        var domain = checkUserIpAddress(req, res);
 | 
			
		||||
        if (domain == null) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +601,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.certificates.CommonName, serverRedirPort: args.redirport, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass, webcerthash: obj.webCertificateHashBase64 });
 | 
			
		||||
        } else {
 | 
			
		||||
            // Send back the login application
 | 
			
		||||
            res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == ''))?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
 | 
			
		||||
            res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port, emailcheck: obj.parent.mailserver != null });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -1184,19 +1323,16 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
        } else if (req.query.meshcmd != null) {
 | 
			
		||||
            // Send meshcmd for a specific platform back
 | 
			
		||||
            var argentInfo = obj.parent.meshAgentBinaries[req.query.meshcmd];
 | 
			
		||||
            if (argentInfo == null) { res.sendStatus(404); return; }
 | 
			
		||||
            if ((argentInfo == null) || (obj.parent.defaultMeshCmd == null)) { res.sendStatus(404); return; }
 | 
			
		||||
            // Load the agent
 | 
			
		||||
            obj.fs.readFile(argentInfo.path, function (err, agentexe) {
 | 
			
		||||
                if (err != null) { res.sendStatus(404); return; }
 | 
			
		||||
                // Load meshcmd.js
 | 
			
		||||
                obj.fs.readFile(obj.path.join(__dirname, 'agents', 'meshcmd.js'), function (err, meshcmdjs) {
 | 
			
		||||
                    if (err != null) { res.sendStatus(404); return; }
 | 
			
		||||
                    res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : '') });
 | 
			
		||||
                    var tail = new Buffer(8);
 | 
			
		||||
                    tail.writeInt32BE(meshcmdjs.length, 0);
 | 
			
		||||
                    tail.writeInt32BE(agentexe.length + meshcmdjs.length + 8, 4);
 | 
			
		||||
                    res.send(Buffer.concat([agentexe, meshcmdjs, tail]));
 | 
			
		||||
                });
 | 
			
		||||
                // Send out merged meshcmd
 | 
			
		||||
                res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=meshcmd' + ((req.query.meshcmd <= 4) ? '.exe' : '') });
 | 
			
		||||
                var meshcmdbuf = new Buffer(obj.parent.defaultMeshCmd, 'utf8'), tail = new Buffer(8);
 | 
			
		||||
                tail.writeInt32BE(meshcmdbuf.length, 0);
 | 
			
		||||
                tail.writeInt32BE(agentexe.length + meshcmdbuf.length + 8, 4);
 | 
			
		||||
                res.send(Buffer.concat([agentexe, meshcmdbuf, tail]));
 | 
			
		||||
            });
 | 
			
		||||
        } else if (req.query.meshaction != null) {
 | 
			
		||||
            var domain = checkUserIpAddress(req, res);
 | 
			
		||||
| 
						 | 
				
			
			@ -1226,12 +1362,13 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
        } else {
 | 
			
		||||
            // Send a list of available mesh agents
 | 
			
		||||
            var response = '<html><head><title>Mesh Agents</title><style>table,th,td { border:1px solid black;border-collapse:collapse;padding:3px; }</style></head><body><table>';
 | 
			
		||||
            response += '<tr style="background-color:lightgray"><th>ID</th><th>Description</th><th>Link</th><th>Size</th><th>SHA384</th></tr>';
 | 
			
		||||
            response += '<tr style="background-color:lightgray"><th>ID</th><th>Description</th><th>Link</th><th>Size</th><th>SHA384</th><th>MeshCmd</th></tr>';
 | 
			
		||||
            for (var agentid in obj.parent.meshAgentBinaries) {
 | 
			
		||||
                var agentinfo = obj.parent.meshAgentBinaries[agentid];
 | 
			
		||||
                response += '<tr><td>' + agentinfo.id + '</td><td>' + agentinfo.desc + '</td>';
 | 
			
		||||
                response += '<td><a target=_blank href="' + req.originalUrl + '?id=' + agentinfo.id + '">' + agentinfo.rname + '</a></td>';
 | 
			
		||||
                response += '<td>' + agentinfo.size + '</td><td>' + agentinfo.hash + '</td></tr>';
 | 
			
		||||
                response += '<td>' + agentinfo.size + '</td><td>' + agentinfo.hash + '</td>';
 | 
			
		||||
                response += '<td><a target=_blank href="' + req.originalUrl + '?meshcmd=' + agentinfo.id + '">' + agentinfo.rname.replace('agent', 'cmd') + '</a></td></tr>';
 | 
			
		||||
            }
 | 
			
		||||
            response += '</table></body></html>';
 | 
			
		||||
            res.send(response);
 | 
			
		||||
| 
						 | 
				
			
			@ -1298,6 +1435,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
        obj.app.post(url + 'changepassword', handlePasswordChangeRequest);
 | 
			
		||||
        obj.app.post(url + 'deleteaccount', handleDeleteAccountRequest);
 | 
			
		||||
        obj.app.post(url + 'createaccount', handleCreateAccountRequest);
 | 
			
		||||
        obj.app.post(url + 'resetaccount', handleResetAccountRequest);
 | 
			
		||||
        obj.app.get(url + 'checkmail', handleCheckMailRequest);
 | 
			
		||||
        obj.app.post(url + 'amtevents.ashx', obj.handleAmtEventRequest);
 | 
			
		||||
        obj.app.get(url + 'webrelay.ashx', function (req, res) { res.send('Websocket connection expected'); });
 | 
			
		||||
        obj.app.ws(url + 'webrelay.ashx', handleRelayWebSocket);
 | 
			
		||||
| 
						 | 
				
			
			@ -1416,6 +1555,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
        } catch (e) { if (called == false) { func(null); } }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return true is the input string looks like an email address
 | 
			
		||||
    function checkEmail(str) {
 | 
			
		||||
        var x = str.split('@');
 | 
			
		||||
        var ok = ((x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2));
 | 
			
		||||
        if (ok == true) { var y = x[1].split('.'); for (var i in y) { if (y[i].length == 0) { ok = false; } } }
 | 
			
		||||
        return ok;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Debug
 | 
			
		||||
    function Debug(lvl) {
 | 
			
		||||
        if (lvl > obj.parent.debugLevel) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1513,7 +1660,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Decode a cookie back into an object using a key. Return null if it's not a valid cookie.  (key must be 32 bytes long)
 | 
			
		||||
    obj.decodeCookie = function (cookie, key) {
 | 
			
		||||
    obj.decodeCookie = function (cookie, key, timeout) {
 | 
			
		||||
        try {
 | 
			
		||||
            if (key == null) { key = obj.serverKey; }
 | 
			
		||||
            cookie = new Buffer(cookie.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64');
 | 
			
		||||
| 
						 | 
				
			
			@ -1523,7 +1670,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
 | 
			
		|||
            if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { return null; }
 | 
			
		||||
            o.time = o.time * 1000; // Decode the cookie creation time
 | 
			
		||||
            o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
 | 
			
		||||
            if ((o.dtime > 120000) || (o.dtime < -30000)) return null; // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
 | 
			
		||||
            if (timeout == null) { timeout = 2; }
 | 
			
		||||
            if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) return null; // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
 | 
			
		||||
            return o;
 | 
			
		||||
        } catch (e) { return null; }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue