mirror of
https://github.com/Ylianst/MeshAgent
synced 2025-12-17 08:43:21 +00:00
1018 lines
38 KiB
JavaScript
1018 lines
38 KiB
JavaScript
/*
|
|
Copyright 2022 Intel Corporation
|
|
@author Bryan Roe
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
_MSH = function _MSH() { return ({}); };
|
|
process.coreDumpLocation = process.platform == 'win32' ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp');
|
|
|
|
var updateSource = null;
|
|
var promise = require('promise');
|
|
|
|
try
|
|
{
|
|
Object.defineProperty(Array.prototype, 'getParameterEx',
|
|
{
|
|
value: function (name, defaultValue)
|
|
{
|
|
var i, ret;
|
|
for (i = 0; i < this.length; ++i)
|
|
{
|
|
if (this[i].startsWith(name + '='))
|
|
{
|
|
ret = this[i].substring(name.length + 1);
|
|
if (ret.startsWith('"')) { ret = ret.substring(1, ret.length - 1); }
|
|
return (ret);
|
|
}
|
|
else if (this[i] == name)
|
|
{
|
|
ret = this[i];
|
|
return (ret);
|
|
}
|
|
}
|
|
return (defaultValue);
|
|
}
|
|
});
|
|
Object.defineProperty(Array.prototype, 'getParameter',
|
|
{
|
|
value: function (name, defaultValue)
|
|
{
|
|
return (this.getParameterEx('--' + name, defaultValue));
|
|
}
|
|
});
|
|
}
|
|
catch (x)
|
|
{ }
|
|
|
|
var Writable = require('stream').Writable;
|
|
var meshcore = null;
|
|
var TunnelPromises = [];
|
|
|
|
const MeshCommand_AuthRequest = 1; // Server web certificate public key sha384 hash + agent or server nonce
|
|
const MeshCommand_AuthVerify = 2; // Agent or server signature
|
|
const MeshCommand_AuthInfo = 3; // Agent information
|
|
const MeshCommand_AuthConfirm = 4; // Server confirm to the agent that is it authenticated
|
|
const MeshCommand_ServerId = 5; // Optional, agent sends the expected serverid to the server. Useful if the server has many server certificates.
|
|
const MeshCommand_CoreModule = 10; // New core modules to be used instead of the old one, if empty, remove the core module
|
|
const MeshCommand_CompressedCoreModule = 20;
|
|
const MeshCommand_CoreModuleHash = 11; // Request/return the SHA384 hash of the core module
|
|
const MeshCommand_AgentCommitDate = 30; // Commit Date that the agent was built with
|
|
const MeshCommand_AgentHash = 12; // Request/return the SHA384 hash of the agent executable
|
|
const MeshCommand_AgentUpdate = 13; // Indicate the start and end of the mesh agent binary transfer
|
|
const MeshCommand_AgentUpdateBlock = 14; // Part of the mesh agent sent from the server to the agent, confirmation/flowcontrol from agent to server
|
|
const MeshCommand_AgentTag = 15; // Send the mesh agent tag to the server
|
|
const MeshCommand_CoreOk = 16; // Sent by the server to indicate the meshcore is ok
|
|
const MeshCommand_HostInfo = 31; // Host OS and CPU Architecture
|
|
|
|
const PLATFORMS = ['UNKNOWN', 'DESKTOP', 'LAPTOP', 'MOBILE', 'SERVER', 'DISK', 'ROUTER', 'PI', 'VIRTUAL'];
|
|
var agentConnectionCount = 0;
|
|
var updateState = 0;
|
|
const consoleMode = process.argv.getParameter('console') != null;
|
|
|
|
var digest_realm;
|
|
var digest_username;
|
|
var digest_password;
|
|
|
|
|
|
// Check Permissions... Need Root/Elevated Permissions
|
|
if (!require('user-sessions').isRoot())
|
|
{
|
|
console.log('self-test.js requires elevated permissions to run.');
|
|
process.exit();
|
|
}
|
|
if (process.argv.getParameter('AltBinary') != null)
|
|
{
|
|
var alt = process.argv.getParameter('AltBinary');
|
|
if (require('fs').existsSync(alt))
|
|
{
|
|
updateSource = alt;
|
|
}
|
|
}
|
|
|
|
if (process.argv.getParameter('help') != null)
|
|
{
|
|
console.log("\nself-test is a Self-Contained test harnass for testing the MeshAgent and MeshCore functions");
|
|
console.log('\n Available options:');
|
|
console.log(' --AgentsFolder= The path to the agents folder of the Server Repository');
|
|
console.log(' --console If specified, enables console command mode');
|
|
console.log(' --PrivacyBar If specified, causes the agent to spawn a privacy bar');
|
|
console.log(' --verbose= Specifies the verbosity level of the displayed output. Default = 0');
|
|
console.log('');
|
|
process.exit();
|
|
}
|
|
if (process.argv.getParameter('AgentsFolder') == null)
|
|
{
|
|
console.log('\nRequired parameter: AgentsFolder, was not specified.');
|
|
process.exit();
|
|
}
|
|
else
|
|
{
|
|
if(!require('fs').existsSync(process.argv.getParameter('AgentsFolder')))
|
|
{
|
|
console.log('\nThe specified folder does not exist: ' + process.argv.getParameter('AgentsFolder'));
|
|
process.exit();
|
|
}
|
|
}
|
|
|
|
var promises =
|
|
{
|
|
CommitInfo: null,
|
|
AgentInfo: null,
|
|
netinfo: null,
|
|
smbios: null,
|
|
cpuinfo: null,
|
|
ps: null,
|
|
help: null,
|
|
services: null,
|
|
setclip: null,
|
|
getclip: null,
|
|
digest: null,
|
|
digest_auth: null,
|
|
digest_authint: null,
|
|
};
|
|
|
|
function generateRandomNumber(lower, upper)
|
|
{
|
|
return (Math.floor(Math.random() * (upper - lower)) + lower);
|
|
}
|
|
function generateRandomLetter()
|
|
{
|
|
return (String.fromCharCode(generateRandomNumber(97, 122)));
|
|
}
|
|
function generateRandomString(len)
|
|
{
|
|
var ret = '', i;
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
ret += generateRandomLetter();
|
|
}
|
|
return (ret);
|
|
}
|
|
function generateRandomRealm()
|
|
{
|
|
realm = generateRandomString(generateRandomNumber(1, 5)) + '.' + generateRandomString(generateRandomNumber(8, 20)) + '.com';
|
|
return (realm);
|
|
}
|
|
function resetPromises()
|
|
{
|
|
var i;
|
|
for(i in promises)
|
|
{
|
|
promises[i] = new promise(promise.defaultInit);
|
|
}
|
|
}
|
|
|
|
process.stdout.write('Generating Certificate...');
|
|
var cert = require('tls').generateCertificate('test', { certType: 2, noUsages: 1 });
|
|
var server = require('https').createServer({ pfx: cert, passphrase: 'test' });
|
|
server.listen();
|
|
|
|
process.stdout.write('\rGenerating Certificate... [DONE]\n');
|
|
|
|
var loadedCert = require('tls').loadCertificate({ pfx: cert, passphrase: 'test' });
|
|
var der = loadedCert.toDER();
|
|
global._test = [];
|
|
|
|
if (process.argv.getParameter('NoInstall') != null)
|
|
{
|
|
require('clipboard')(loadedCert.getKeyHash().toString('hex'));
|
|
console.log('Certificate Fingerprint saved to clipboard...');
|
|
}
|
|
|
|
server.on('connection', function (c)
|
|
{
|
|
global._test.push(c);
|
|
console.info1('inbound connection received');
|
|
});
|
|
server.on('request', function (imsg, rsp)
|
|
{
|
|
if (imsg.method == 'GET' && imsg.url == '/update')
|
|
{
|
|
var accumulator = new Writable(
|
|
{
|
|
write: function write(chunk, flush)
|
|
{
|
|
this.sent += chunk.length;
|
|
var pct = Math.floor((this.sent / this.total) * 100);
|
|
if (pct % 5 == 0)
|
|
{
|
|
process.stdout.write('\rPushing Update via HTTPS...[' + pct + '%]');
|
|
}
|
|
flush();
|
|
},
|
|
final: function final(flush)
|
|
{
|
|
process.stdout.write('\n');
|
|
flush();
|
|
}
|
|
});
|
|
accumulator.sent = 0;
|
|
|
|
process.stdout.write('Pushing Update via HTTPS...[0%]');
|
|
var update = require('fs').createReadStream(getCurrentUpdatePath(), { flags: 'rb' });
|
|
accumulator.total = require('fs').statSync(getCurrentUpdatePath()).size;
|
|
|
|
update.pipe(rsp);
|
|
update.pipe(accumulator);
|
|
}
|
|
if (imsg.method == 'POST')
|
|
{
|
|
var username, qop;
|
|
if (imsg.Digest_IsAuthenticated(digest_realm))
|
|
{
|
|
username = imsg.Digest_GetUsername();
|
|
qop = imsg.Digest_GetQOP();
|
|
|
|
imsg.on('end', function ()
|
|
{
|
|
switch (imsg.url)
|
|
{
|
|
case '/auth':
|
|
if (qop != 'auth') { promises.digest_auth.reject('Received Incorrect QOP: ' + qop); }
|
|
break;
|
|
case '/auth-int':
|
|
if (qop != 'auth-int') { promises.digest_authint.reject('Received Incorrect QOP: ' + qop); }
|
|
break;
|
|
}
|
|
if (imsg.Digest_ValidatePassword(digest_password))
|
|
{
|
|
rsp.statusCode = 200;
|
|
rsp.setHeader('Content-Type', 'text/html');
|
|
rsp.end('<html>Success!</html>');
|
|
}
|
|
else
|
|
{
|
|
rsp.Digest_writeUnauthorized(digest_realm);
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
imsg.on('end', function ()
|
|
{
|
|
switch (imsg.url)
|
|
{
|
|
case '/':
|
|
rsp.Digest_writeUnauthorized(digest_realm);
|
|
break;
|
|
case '/auth':
|
|
rsp.Digest_writeUnauthorized(digest_realm, { qop: 'auth' });
|
|
break;
|
|
case '/auth-int':
|
|
rsp.Digest_writeUnauthorized(digest_realm, { qop: 'auth-int, auth' });
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
server.on('upgrade', function (msg, sck, head)
|
|
{
|
|
console.info1('upgrade requested');
|
|
|
|
switch(msg.url)
|
|
{
|
|
case '/tunnel':
|
|
var p = TunnelPromises.shift();
|
|
clearTimeout(p.timeout);
|
|
p.resolve(sck.upgradeWebSocket());
|
|
return;
|
|
break;
|
|
case '/agent.ashx': // No-Op, because we'll continue processing after the switch statement
|
|
break;
|
|
default:
|
|
return; // We will not handle other requests
|
|
break;
|
|
}
|
|
|
|
|
|
resetPromises();
|
|
global._client = sck.upgradeWebSocket();
|
|
global._client.on('data', function (buffer)
|
|
{
|
|
this.processCommand(buffer);
|
|
});
|
|
global._client.on('end', function ()
|
|
{
|
|
console.log('Agent Disconnected...');
|
|
});
|
|
global._client.command = function command(j)
|
|
{
|
|
this.write(JSON.stringify(j));
|
|
}
|
|
global._client.console = function console(str)
|
|
{
|
|
this.command(
|
|
{
|
|
action: 'msg',
|
|
type: 'console',
|
|
value: str,
|
|
sessionid: 'none',
|
|
rights: 4294967295,
|
|
consent: 0
|
|
});
|
|
}
|
|
global._client.processCommand = function processCommand(buffer)
|
|
{
|
|
if (buffer[0] == '{' || buffer[0] == 123)
|
|
{
|
|
// JSON Command
|
|
this.processJSON(JSON.parse(buffer.toString()));
|
|
return;
|
|
}
|
|
|
|
var cmd = buffer.readUInt16BE(0);
|
|
switch(cmd)
|
|
{
|
|
case MeshCommand_AgentCommitDate: // Agent Commit Date
|
|
promises.CommitInfo.resolve(buffer.slice(2).toString());
|
|
console.log("Connected Agent's Commit Date: " + buffer.slice(2).toString());
|
|
break;
|
|
case MeshCommand_HostInfo:
|
|
promises.AgentInfo.resolve(buffer.slice(2).toString());
|
|
console.log("Connected Agent Info: " + buffer.slice(2).toString());
|
|
break;
|
|
case MeshCommand_ServerId:
|
|
console.info1("Connected Agent's ServerID: " + buffer.slice(2).toString('hex'));
|
|
break;
|
|
case MeshCommand_AuthRequest:
|
|
//typedef struct MeshCommand_BinaryPacket_AuthRequest
|
|
//{
|
|
// unsigned short command;
|
|
// char serverHash[UTIL_SHA384_HASHSIZE];
|
|
// char serverNonce[UTIL_SHA384_HASHSIZE];
|
|
//}MeshCommand_BinaryPacket_AuthRequest;
|
|
var serverHash = buffer.slice(2, 50).toString('hex');
|
|
this.agentNonce = Buffer.alloc(48);
|
|
buffer.slice(50, 98).copy(this.agentNonce);
|
|
|
|
console.info2('Agent Sent Nonce: ' + this.agentNonce.toString('hex'));
|
|
console.info2('Agent Sent ServerID: ' + serverHash);
|
|
|
|
this.serverNonce = Buffer.alloc(48);
|
|
this.serverNonce.randomFill();
|
|
|
|
var authBuffer = Buffer.alloc(98);
|
|
authBuffer.writeUInt16BE(1); // AuthRequest
|
|
loadedCert.getKeyHash().copy(authBuffer, 2); // ServerHash
|
|
this.serverNonce.copy(authBuffer, 50); // ServerNonce
|
|
this.write(authBuffer);
|
|
|
|
break;
|
|
case MeshCommand_AuthVerify:
|
|
console.info2('AUTH-VERIFY');
|
|
|
|
var hash = require('SHA384Stream').create();
|
|
hash.on('hash', function (h)
|
|
{
|
|
this._hashedValue = Buffer.alloc(h.length);
|
|
h.copy(this._hashedValue);
|
|
});
|
|
var y = Buffer.from(cert.digest.split(':').join(''), 'hex');
|
|
hash.write(y); // ServerHash
|
|
hash.write(this.agentNonce);
|
|
hash.write(this.serverNonce);
|
|
hash.end();
|
|
|
|
|
|
console.info2('SERVER/SIGN => ' + y.toString('hex'), y.length);
|
|
console.info2('SERVER/SIGN/AgentNonce => ' + this.agentNonce.toString('hex'), this.agentNonce.length);
|
|
console.info2('SERVER/SIGN/ServerNonce => ' + this.serverNonce.toString('hex'), this.serverNonce.length);
|
|
console.info2('SERVER/SIGN/RESULT => ' + hash._hashedValue.toString('hex'));
|
|
|
|
var RSA = require('RSA');
|
|
var signature = RSA.sign(RSA.TYPES.SHA384, loadedCert, hash._hashedValue);
|
|
var verifyBuffer = Buffer.alloc(4 + der.length + signature.length);
|
|
verifyBuffer.writeUInt16BE(2); // AUTH-VERIFY
|
|
verifyBuffer.writeUInt16BE(der.length, 2); // CERT-LEN
|
|
der.copy(verifyBuffer, 4); // CERT
|
|
signature.copy(verifyBuffer, 4 + der.length);
|
|
|
|
this.write(verifyBuffer);
|
|
break;
|
|
case MeshCommand_AuthInfo:
|
|
//typedef struct MeshCommand_BinaryPacket_AuthInfo
|
|
//{
|
|
// unsigned short command;
|
|
// unsigned int infoVersion;
|
|
// unsigned int agentId;
|
|
// unsigned int agentVersion;
|
|
// unsigned int platformType;
|
|
// char MeshID[UTIL_SHA384_HASHSIZE];
|
|
// unsigned int capabilities;
|
|
// unsigned short hostnameLen;
|
|
// char hostname[];
|
|
//}MeshCommand_BinaryPacket_AuthInfo;
|
|
|
|
var agentID = buffer.readUInt32BE(6);
|
|
var platformType = buffer.readUInt32BE(14);
|
|
var hostname = buffer.slice(72);
|
|
|
|
console.log('AgentID: ' + getSystemName(agentID));
|
|
try
|
|
{
|
|
console.log('PlaformType: ' + PLATFORMS[platformType]);
|
|
}
|
|
catch(zz)
|
|
{
|
|
}
|
|
console.log('Hostname: ' + hostname);
|
|
|
|
// Send AuthConfirm
|
|
var b = Buffer.alloc(4);
|
|
b.writeUInt16BE(MeshCommand_AuthConfirm);
|
|
b.writeUInt16BE(1, 2);
|
|
this.write(b);
|
|
|
|
// Ask for Agent Hash
|
|
var b = Buffer.alloc(4);
|
|
b.writeUInt16BE(MeshCommand_AgentHash);
|
|
b.writeUInt16BE(1, 2);
|
|
this.write(b);
|
|
|
|
// Ask for Module Hash
|
|
var b = Buffer.alloc(4);
|
|
b.writeUInt16BE(MeshCommand_CoreModuleHash);
|
|
b.writeUInt16BE(1, 2);
|
|
this.write(b);
|
|
break;
|
|
case MeshCommand_AgentTag:
|
|
console.log('AgentTag: ' + buffer.slice(4));
|
|
break;
|
|
case MeshCommand_AgentHash:
|
|
var hash = buffer.slice(4).toString('hex');
|
|
console.info1('AgentHash=' + hash);
|
|
console.info1('');
|
|
break;
|
|
case MeshCommand_CoreModuleHash:
|
|
var hash = buffer.slice(4).toString('hex');
|
|
console.info1('CoreModuleHash[' + hash.length + ']=' + hash);
|
|
|
|
if (updateState == 0)
|
|
{
|
|
updateState = 1;
|
|
var mc = Buffer.from(meshcore);
|
|
var targetHash = require('SHA384Stream').create();
|
|
|
|
var b = Buffer.alloc(mc.length + 48 + 4 + 4);
|
|
b.writeUInt16BE(MeshCommand_CoreModule);
|
|
b.writeUInt16BE(1, 2);
|
|
mc.copy(b, 56);
|
|
targetHash.syncHash(b.slice(52)).copy(b, 4);
|
|
console.info1('TargetHash[' + b.slice(4, 52).toString('hex') + ']');
|
|
|
|
if (hash == b.slice(4, 52).toString('hex'))
|
|
{
|
|
// Mesh Core OK
|
|
var b = Buffer.alloc(4);
|
|
b.writeUInt16BE(MeshCommand_CoreOk);
|
|
b.writeUInt16BE(1, 2);
|
|
this.write(b);
|
|
|
|
this.runCommands();
|
|
}
|
|
else
|
|
{
|
|
this.write(b);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (process.argv.getParameter('NoInstall') == null)
|
|
{
|
|
console.log('Service PID: ' + getPID());
|
|
}
|
|
this.runCommands();
|
|
break;
|
|
case MeshCommand_AuthConfirm:
|
|
console.log('Agent Authenticated');
|
|
break;
|
|
default:
|
|
console.log('Command: ' + cmd);
|
|
break;
|
|
}
|
|
};
|
|
global._client.processJSON = function processJSON(j)
|
|
{
|
|
console.info2(JSON.stringify(j, null, 1));
|
|
|
|
switch(j.action)
|
|
{
|
|
case 'agentupdatedownloaded':
|
|
console.log('Agent reports successfully downloaded update');
|
|
break;
|
|
case 'coreinfo':
|
|
console.log('');
|
|
console.log('Agent is running core: ' + j.value);
|
|
console.log('');
|
|
break;
|
|
case 'msg':
|
|
switch(j.type)
|
|
{
|
|
case 'console':
|
|
if (j.value != 'Command returned an exception error: TypeError: cyclic input') { console.log('Agent: ' + j.value); }
|
|
if (j.value == "PrivacyBarClosed") { endTest(); }
|
|
if (j.value.startsWith('Available commands:')) { promises.help.resolve(j.value); }
|
|
break;
|
|
case 'cpuinfo':
|
|
promises.cpuinfo.resolve(j);
|
|
break;
|
|
case 'ps':
|
|
promises.ps.resolve(j);
|
|
break;
|
|
case 'services':
|
|
promises.services.resolve(j);
|
|
break;
|
|
case 'setclip':
|
|
promises.setclip.resolve(j);
|
|
break;
|
|
case 'getclip':
|
|
promises.getclip.resolve(j);
|
|
break;
|
|
}
|
|
break;
|
|
case 'sessions':
|
|
break;
|
|
case 'netinfo':
|
|
console.info1(j.action, JSON.stringify(j, null, 1));
|
|
promises.netinfo.resolve(j);
|
|
break;
|
|
case 'smbios':
|
|
console.info1(j.action, JSON.stringify(j, null, 1));
|
|
promises.smbios.resolve(j);
|
|
break;
|
|
case 'result':
|
|
console.info1(JSON.stringify(j, null, 1));
|
|
|
|
if (promises[j.id] != null)
|
|
{
|
|
if (promises[j.id].timeout != null)
|
|
{
|
|
clearTimeout(promises[j.id].timeout);
|
|
}
|
|
if (j.result===true)
|
|
{
|
|
promises[j.id].resolve(j);
|
|
}
|
|
else
|
|
{
|
|
promises[j.id].reject(j.reason == null ? '' : j.reason);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
console.info1(j.action, JSON.stringify(j, null, 1));
|
|
break;
|
|
}
|
|
}
|
|
|
|
global._client.runCommands = function runCommands()
|
|
{
|
|
if (process.argv.getParameter('PrivacyBar') != null)
|
|
{
|
|
this.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'console', value: 'eval "global._n=require(\'notifybar-desktop\')(\'Self Test Privacy Bar\', require(\'MeshAgent\')._tsid);global._n.on(\'close\', function (){sendConsoleText(\'PrivacyBarClosed\');});"' });
|
|
return;
|
|
}
|
|
if(consoleMode)
|
|
{
|
|
console.log("\nEntering CONSOLE mode. Type 'exit' when done.");
|
|
this.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'console', value: 'help' });
|
|
process.stdin.on('data', function (c)
|
|
{
|
|
if (c == null || c.toString() == null) { return; }
|
|
if (c.toString().toLowerCase().trim() == 'exit')
|
|
{
|
|
console.log('EXITING console mode');
|
|
endTest();
|
|
}
|
|
else
|
|
{
|
|
global._client.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'console', value: c.toString().trim() });
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Run thru the main tests, becuase no special options were sent
|
|
//
|
|
console.log('\nRunning Meshcore Tests:');
|
|
if (console.getInfoLevel() == 0) { console.setDestination(console.Destinations.DISABLED); }
|
|
|
|
process.stdout.write(' Agent sent version information to server................');
|
|
|
|
promises.CommitInfo.then(function ()
|
|
{
|
|
process.stdout.write('[OK]\n');
|
|
process.stdout.write(' Agent sent AgentInfo to server..........................');
|
|
return (promises.AgentInfo);
|
|
}).then(function ()
|
|
{
|
|
process.stdout.write('[OK]\n');
|
|
process.stdout.write(' Agent sent Network Info to server.......................[WAITING]');
|
|
return (promises.netinfo);
|
|
}).then(function ()
|
|
{
|
|
process.stdout.write('\r');
|
|
process.stdout.write(' Agent sent Network Info to server.......................[OK] \n');
|
|
process.stdout.write(' Agent sent SMBIOS info to server........................[WAITING]');
|
|
switch(process.platform)
|
|
{
|
|
case 'linux':
|
|
case 'win32':
|
|
return (promises.smbios);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}).then(function ()
|
|
{
|
|
process.stdout.write('\r');
|
|
switch (process.platform)
|
|
{
|
|
case 'linux':
|
|
case 'win32':
|
|
process.stdout.write(' Agent sent SMBIOS info to server........................[OK] \n');
|
|
break;
|
|
default:
|
|
process.stdout.write(' Agent sent SMBIOS info to server........................[NA] \n');
|
|
break;
|
|
}
|
|
process.stdout.write(' Tunnel Test.............................................[WAITING]');
|
|
return (createTunnel(0, 0));
|
|
}).then(function (t)
|
|
{
|
|
process.stdout.write('\r Tunnel Test.............................................[OK] \n');
|
|
t.end();
|
|
}).then(function ()
|
|
{
|
|
global._client.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'console', value: 'help' });
|
|
process.stdout.write(' Console Test (Help).....................................[WAITING]');
|
|
return (promises.help);
|
|
}).then(function (v)
|
|
{
|
|
//var vals = v.substring(19).split('\n').join('').split('\r').join('').split('.').join('').split(' ').join('');
|
|
process.stdout.write('\r Console Test (Help).....................................[OK] \n');
|
|
process.stdout.write(' CPUINFO Test............................................[WAITING]');
|
|
global._client.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'cpuinfo' });
|
|
return (promises.cpuinfo);
|
|
}).then(function (v)
|
|
{
|
|
process.stdout.write('\r CPUINFO Test............................................[OK] \n');
|
|
process.stdout.write(' PS Test.................................................[WAITING]');
|
|
global._client.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'ps' });
|
|
return (promises.ps);
|
|
}).then(function (v)
|
|
{
|
|
var p;
|
|
try
|
|
{
|
|
p = JSON.parse(v.value);
|
|
}
|
|
catch(e)
|
|
{
|
|
process.stdout.write('\r PS Test.................................................[FAILED] \n');
|
|
process.stdout.write(' => ' + e + '\n');
|
|
return;
|
|
}
|
|
process.stdout.write('\r PS Test.................................................[OK] \n');
|
|
process.stdout.write(' => ' + p.keys().length + ' processes retrieved.\n');
|
|
|
|
process.stdout.write(' Service Enumeration Test................................[WAITING]');
|
|
global._client.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'services' });
|
|
return (promises.services);
|
|
}).then(function (v)
|
|
{
|
|
var services;
|
|
try
|
|
{
|
|
services = JSON.parse(v.value);
|
|
}
|
|
catch (x)
|
|
{
|
|
process.stdout.write('\r Service Enumeration Test................................[INVALID JSON]\n');
|
|
process.stdout.write(' => ' + x + '\n');
|
|
return;
|
|
}
|
|
process.stdout.write('\r Service Enumeration Test................................[OK] \n');
|
|
process.stdout.write('\r => ' + services.length + ' services retrieved.\n');
|
|
}).then(function ()
|
|
{
|
|
process.stdout.write(' Clipboard Test..........................................[WAITING]');
|
|
var b = Buffer.alloc(16);
|
|
b.randomFill();
|
|
global._cliptest = b.toString('base64');
|
|
global._client.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'setclip', data: global._cliptest });
|
|
return (promises.setclip);
|
|
}).then(function (v)
|
|
{
|
|
console.info1(JSON.stringify(v));
|
|
if (!v.success)
|
|
{
|
|
process.stdout.write('\r Clipboard Test..........................................[FAILED TO SET]\n');
|
|
return;
|
|
}
|
|
global._client.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'getclip' });
|
|
return (promises.getclip);
|
|
}).then(function (v)
|
|
{
|
|
if(v.data == global._cliptest)
|
|
{
|
|
process.stdout.write('\r Clipboard Test..........................................[OK] \n');
|
|
}
|
|
else
|
|
{
|
|
process.stdout.write('\r Clipboard Test..........................................[FAILED] \n');
|
|
process.stdout.write(' => Expected: ' + global._cliptest + '\n');
|
|
process.stdout.write(' => Received: ' + v.data + '\n');
|
|
}
|
|
}).then(function ()
|
|
{
|
|
digest_realm = generateRandomRealm();
|
|
digest_username = generateRandomString(generateRandomNumber(5, 10));
|
|
digest_password = generateRandomString(generateRandomNumber(8, 20));
|
|
|
|
process.stdout.write(' HTTP Digest Test\n');
|
|
process.stdout.write(' => Basic.............................................[WAITING]');
|
|
|
|
sendEval("var digest = require('http-digest').create('" + digest_username + "', '" + digest_password + "');");
|
|
sendEval("digest.http = require('http');");
|
|
sendEval("var options = { protocol: 'https:', host: '127.0.0.1', port: " + server.address().port + ", path: '/', method: 'POST', rejectUnauthorized: false };");
|
|
sendEval("var req = digest.request(options);");
|
|
sendEval("req.on('error', function (e) { selfTestResponse('digest', false, JSON.stringify(e)); req = null; });");
|
|
sendEval("req.on('response', function (imsg) { selfTestResponse('digest', true); });");
|
|
sendEval("req.end('TestData');");
|
|
|
|
return (promises.digest);
|
|
}).then(function (v)
|
|
{
|
|
process.stdout.write('\r => Basic.............................................[OK] \n');
|
|
process.stdout.write(' => QOP = auth........................................[WAITING]');
|
|
|
|
digest_realm = generateRandomRealm();
|
|
digest_username = generateRandomString(generateRandomNumber(5, 10));
|
|
digest_password = generateRandomString(generateRandomNumber(8, 20));
|
|
|
|
sendEval("digest = require('http-digest').create('" + digest_username + "', '" + digest_password + "');");
|
|
sendEval("digest.http = require('http');");
|
|
sendEval("var options = { protocol: 'https:', host: '127.0.0.1', port: " + server.address().port + ", path: '/auth', method: 'POST', rejectUnauthorized: false };");
|
|
sendEval("var req = digest.request(options);");
|
|
sendEval("req.on('error', function (e) { selfTestResponse('digest_auth', false, JSON.stringify(e)); req = null; });");
|
|
sendEval("req.on('response', function (imsg) { selfTestResponse('digest_auth', true); });");
|
|
sendEval("req.end('TestData');");
|
|
|
|
return (promises.digest_auth);
|
|
}).then(function ()
|
|
{
|
|
process.stdout.write('\r => QOP = auth........................................[OK] \n');
|
|
process.stdout.write(' => QOP = auth-int....................................[WAITING]');
|
|
|
|
digest_realm = generateRandomRealm();
|
|
digest_username = generateRandomString(generateRandomNumber(5, 10));
|
|
digest_password = generateRandomString(generateRandomNumber(8, 20));
|
|
|
|
sendEval("digest = require('http-digest').create('" + digest_username + "', '" + digest_password + "');");
|
|
sendEval("digest.http = require('http');");
|
|
sendEval("var options = { protocol: 'https:', host: '127.0.0.1', port: " + server.address().port + ", path: '/auth-int', method: 'POST', rejectUnauthorized: false };");
|
|
sendEval("var req = digest.request(options);");
|
|
sendEval("req.on('error', function (e) { selfTestResponse('digest_authint', false, JSON.stringify(e)); req = null; });");
|
|
sendEval("req.on('response', function (imsg) { selfTestResponse('digest_authint', true); });");
|
|
sendEval("req.end('TestData');");
|
|
|
|
return (promises.digest_authint);
|
|
}).then(function ()
|
|
{
|
|
process.stdout.write('\r => QOP = auth-int....................................[OK] \n');
|
|
}).then(function ()
|
|
{
|
|
process.stdout.write('\nTesting Complete\n\n');
|
|
endTest();
|
|
}).catch(function (e)
|
|
{
|
|
process.stdout.write('\nTesting Failed (' + e + ')\n\n');
|
|
endTest();
|
|
});
|
|
|
|
};
|
|
});
|
|
|
|
function createTunnel(rights, consent)
|
|
{
|
|
var ret = new promise(promise.defaultInit);
|
|
TunnelPromises.push(ret);
|
|
|
|
ret.parent = global._client;
|
|
ret.timeout = setTimeout(function ()
|
|
{
|
|
ret.reject('timeout');
|
|
}, 2000);
|
|
ret.options = { action: 'msg', type: 'tunnel', rights: rights, consent: consent, username: '(test script)', value: 'wss://127.0.0.1:' + server.address().port + '/tunnel' };
|
|
global._client.command(ret.options);
|
|
return (ret);
|
|
}
|
|
function getSystemName(id)
|
|
{
|
|
var ret = 'unknown';
|
|
switch(id)
|
|
{
|
|
default:
|
|
ret = 'ARCHID=' + id;
|
|
break;
|
|
case 1:
|
|
ret = 'Windows Console 32 bit';
|
|
break;
|
|
case 2:
|
|
ret = 'Windows Console 64 bit';
|
|
break;
|
|
case 3:
|
|
ret = 'Windows Service 32 bit';
|
|
break;
|
|
case 4:
|
|
ret = 'Windows Service 64 bit';
|
|
break;
|
|
case 16:
|
|
ret = 'macOS Intel Silicon 64 bit';
|
|
break;
|
|
case 29:
|
|
ret = 'macOS Apple Silicon 64 bit';
|
|
break;
|
|
case 5:
|
|
ret = 'Linux x86 32 bit';
|
|
break;
|
|
case 6:
|
|
ret = 'Linux x86 64 bit';
|
|
break;
|
|
case 7:
|
|
ret = 'Linux MIPSEL';
|
|
break;
|
|
case 9:
|
|
ret = 'Linux ARM 32 bit';
|
|
break;
|
|
case 13:
|
|
ret = 'Linux ARM 32 bit PogoPlug';
|
|
break;
|
|
case 15:
|
|
ret = 'Linux x86 32 bit POKY';
|
|
break;
|
|
case 18:
|
|
ret = 'Linux x86 64 bit POKY';
|
|
break;
|
|
case 19:
|
|
ret = 'Linux x86 32 bit NOKVM';
|
|
break;
|
|
case 20:
|
|
ret = 'Linux x86 64 bit NOKVM';
|
|
break;
|
|
case 24:
|
|
ret = 'Linux ARM/HF 32 bit (Linaro)';
|
|
break;
|
|
case 26:
|
|
ret = 'Linux ARM 64 bit';
|
|
break;
|
|
case 32:
|
|
ret = 'Linux ARM 64 bit (glibc/2.24)';
|
|
break;
|
|
case 27:
|
|
ret = 'Linux ARM/HF 32 bit NOKVM';
|
|
break;
|
|
case 30:
|
|
ret = 'FreeBSD x86 64 bit';
|
|
break;
|
|
case 31:
|
|
ret = 'FreeBSD x86 32 bit';
|
|
break;
|
|
case 37:
|
|
ret = 'OpenBSD x86 64 bit';
|
|
break;
|
|
case 33:
|
|
ret = 'Alpine Linux x86 64 bit (MUSL)';
|
|
break;
|
|
case 25:
|
|
ret = 'Linux ARM/HF 32 bit';
|
|
break;
|
|
case 28:
|
|
ret = 'Linux MIPS24KC/MUSL (OpenWRT)';
|
|
break;
|
|
case 36:
|
|
ret = 'Linux x86/MUSL 64 bit (OpenWRT)';
|
|
break;
|
|
case 40:
|
|
ret = 'Linux MIPSEL24KC/MUSL (OpenWRT)';
|
|
break;
|
|
case 41:
|
|
ret = 'Linux ARMADA/CORTEX-A53/MUSL (OpenWRT)';
|
|
break;
|
|
case 35:
|
|
ret = 'Linux ARMADA370/HF';
|
|
break;
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
function getPID()
|
|
{
|
|
var s = require('service-manager').manager.getService('TestAgent');
|
|
var ret = 0;
|
|
switch(process.platform)
|
|
{
|
|
case 'win32':
|
|
ret = s.status.pid;
|
|
s.close();
|
|
break;
|
|
default:
|
|
if (s.pid != null)
|
|
{
|
|
try
|
|
{
|
|
ret = s.pid();
|
|
}
|
|
catch (x)
|
|
{
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
function endTest()
|
|
{
|
|
global._client.removeAllListeners('end');
|
|
|
|
console.log('==> End of Test');
|
|
var params = ['--meshServiceName=TestAgent'];
|
|
var paramsString = JSON.stringify(params);
|
|
|
|
require('agent-installer').fullUninstall(paramsString);
|
|
console.setDestination(console.Destinations.STDOUT);
|
|
}
|
|
function sendEval(cmd)
|
|
{
|
|
global._client.command({ sessionid: 'user//foo//bar', rights: 4294967295, consent: 64, action: 'msg', type: 'console', value: 'eval "' + cmd + '"' });
|
|
}
|
|
|
|
if (process.argv.getParameter('AgentsFolder') != null)
|
|
{
|
|
var folder = process.argv.getParameter('AgentsFolder');
|
|
|
|
if (folder.endsWith('/')) { folder = folder.split('/'); folder.pop(); folder = folder.join('/'); }
|
|
if (folder.endsWith('\\')) { folder = folder.split('\\'); folder.pop(); folder = folder.join('\\'); }
|
|
|
|
meshcore = require('fs').readFileSync(folder + (process.platform == 'win32' ? '\\' : '/') + 'meshcore.js').toString();
|
|
var modules = folder + (process.platform == 'win32' ? '\\' : '/') + 'modules_meshcore';
|
|
var modules_folder = require('fs').readdirSync(modules);
|
|
var i, tmp, m;
|
|
|
|
var lines = ['var addedModules = [];'];
|
|
lines.push("function selfTestResponse(id, result, reason) { require('MeshAgent').SendCommand({ action: 'result', id: id, result: result, reason: reason }); }");
|
|
for (i = 0; i < modules_folder.length; ++i)
|
|
{
|
|
tmp = require('fs').readFileSync(modules + (process.platform == 'win32' ? '\\' : '/') + modules_folder[i]);
|
|
lines.push('try { addModule("' + (m = modules_folder[i].split('.').shift()) + '", Buffer.from("' + tmp.toString('base64') + '", "base64").toString()); addedModules.push("' + m + '");} catch (x) { }');
|
|
}
|
|
|
|
meshcore = lines.join('\n') + meshcore;
|
|
}
|
|
|
|
if (process.argv.getParameter('verbose') != null)
|
|
{
|
|
console.setInfoLevel(parseInt(process.argv.getParameter('verbose')));
|
|
}
|
|
|
|
if (process.argv.getParameter('NoInstall') == null)
|
|
{
|
|
//
|
|
// Start by installing agent as service
|
|
//
|
|
var params = ['--__skipExit=1', '--logUpdate=1', '--meshServiceName=TestAgent'];
|
|
var options =
|
|
{
|
|
files:
|
|
[
|
|
{
|
|
newName: (process.platform == 'win32' ? 'MeshAgent.msh' : 'meshagent.msh'),
|
|
_buffer: 'logUpdate=1\nMeshID=0x43FEF862BF941B2BBE5964CC7CA02573BBFB94D5A717C5AA3FC103558347D0BE26840ACBD30FFF981F7F5A2083D0DABC\nMeshServer=wss://127.0.0.1:' + server.address().port + '/agent.ashx\nmeshServiceName=TestAgent\nServerID=' + loadedCert.getKeyHash().toString('hex')
|
|
}
|
|
],
|
|
binary: updateSource,
|
|
noParams: true
|
|
};
|
|
require('agent-installer').fullInstallEx(params, options);
|
|
console.setDestination(console.Destinations.STDOUT);
|
|
}
|
|
console.log('\nWaiting for Agent Connection...');
|
|
|
|
|