mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-11-22 12:52:50 +03:00
1. Updated recovery core 'files' implementation
2. Removed dead code from recovery core 3. Fixed bug in switch statement in meshcore
This commit is contained in:
parent
fb9c146ccc
commit
70df889935
@ -2551,144 +2551,132 @@ function createMeshCore(agent)
|
||||
if (coreDumpPath != null) { db.Put('CoreDumpTime', require('fs').statSync(coreDumpPath).mtime); }
|
||||
break;
|
||||
}
|
||||
case 'rename': {
|
||||
// Rename a file or folder
|
||||
var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
|
||||
var newfullpath = obj.path.join(cmd.path, cmd.newname);
|
||||
MeshServerLogEx(48, [oldfullpath, cmd.newname], 'Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
|
||||
try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
|
||||
break;
|
||||
}
|
||||
case 'findfile': {
|
||||
// Search for files
|
||||
var r = require('file-search').find('"' + cmd.path + '"', cmd.filter);
|
||||
if (!r.cancel) { r.cancel = function cancel() { this.child.kill(); }; }
|
||||
this._search = r;
|
||||
r.socket = this;
|
||||
r.socket.reqid = cmd.reqid; // Search request id. This is used to send responses and cancel the request.
|
||||
r.socket.path = cmd.path; // Search path
|
||||
r.on('result', function (str) { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: str.substring(this.socket.path.length), reqid: this.socket.reqid }))); } catch (ex) { } });
|
||||
r.then(function () { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: null, reqid: this.socket.reqid }))); } catch (ex) { } });
|
||||
break;
|
||||
}
|
||||
case 'cancelfindfile': {
|
||||
if (this._search) { this._search.cancel(); this._search = null; }
|
||||
}
|
||||
case 'download': {
|
||||
// Download a file
|
||||
var sendNextBlock = 0;
|
||||
if (cmd.sub == 'start')
|
||||
{ // Setup the download
|
||||
if ((cmd.path == null) && (cmd.ask == 'coredump'))
|
||||
{ // If we are asking for the coredump file, set the right path.
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
|
||||
} else
|
||||
{
|
||||
if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
|
||||
case 'rename':
|
||||
{
|
||||
// Rename a file or folder
|
||||
var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
|
||||
var newfullpath = obj.path.join(cmd.path, cmd.newname);
|
||||
MeshServerLogEx(48, [oldfullpath, cmd.newname], 'Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
|
||||
try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
|
||||
break;
|
||||
}
|
||||
case 'findfile':
|
||||
{
|
||||
// Search for files
|
||||
var r = require('file-search').find('"' + cmd.path + '"', cmd.filter);
|
||||
if (!r.cancel) { r.cancel = function cancel() { this.child.kill(); }; }
|
||||
this._search = r;
|
||||
r.socket = this;
|
||||
r.socket.reqid = cmd.reqid; // Search request id. This is used to send responses and cancel the request.
|
||||
r.socket.path = cmd.path; // Search path
|
||||
r.on('result', function (str) { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: str.substring(this.socket.path.length), reqid: this.socket.reqid }))); } catch (ex) { } });
|
||||
r.then(function () { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: null, reqid: this.socket.reqid }))); } catch (ex) { } });
|
||||
break;
|
||||
}
|
||||
case 'cancelfindfile':
|
||||
{
|
||||
if (this._search) { this._search.cancel(); this._search = null; }
|
||||
break;
|
||||
}
|
||||
case 'download':
|
||||
{
|
||||
// Download a file
|
||||
var sendNextBlock = 0;
|
||||
if (cmd.sub == 'start')
|
||||
{ // Setup the download
|
||||
if ((cmd.path == null) && (cmd.ask == 'coredump'))
|
||||
{ // If we are asking for the coredump file, set the right path.
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
|
||||
} else
|
||||
{
|
||||
if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
|
||||
}
|
||||
}
|
||||
MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
|
||||
if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
|
||||
this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
|
||||
try { this.filedownload.f = fs.openSync(this.filedownload.path, 'rbN'); } catch (e) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
|
||||
if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
|
||||
} else if ((this.filedownload != null) && (cmd.id == this.filedownload.id))
|
||||
{ // Download commands
|
||||
if (cmd.sub == 'startack') { sendNextBlock = ((typeof cmd.ack == 'number') ? cmd.ack : 8); } else if (cmd.sub == 'stop') { delete this.filedownload; } else if (cmd.sub == 'ack') { sendNextBlock = 1; }
|
||||
}
|
||||
// Send the next download block(s)
|
||||
while (sendNextBlock > 0)
|
||||
{
|
||||
sendNextBlock--;
|
||||
var buf = Buffer.alloc(16384);
|
||||
var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
|
||||
this.filedownload.ptr += len;
|
||||
if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
|
||||
this.write(buf.slice(0, len + 4)); // Write as binary
|
||||
}
|
||||
MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
|
||||
if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
|
||||
this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
|
||||
try { this.filedownload.f = fs.openSync(this.filedownload.path, 'rbN'); } catch (e) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
|
||||
if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
|
||||
} else if ((this.filedownload != null) && (cmd.id == this.filedownload.id))
|
||||
{ // Download commands
|
||||
if (cmd.sub == 'startack') { sendNextBlock = ((typeof cmd.ack == 'number') ? cmd.ack : 8); } else if (cmd.sub == 'stop') { delete this.filedownload; } else if (cmd.sub == 'ack') { sendNextBlock = 1; }
|
||||
}
|
||||
// Send the next download block(s)
|
||||
while (sendNextBlock > 0)
|
||||
{
|
||||
sendNextBlock--;
|
||||
var buf = Buffer.alloc(16384);
|
||||
var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
|
||||
this.filedownload.ptr += len;
|
||||
if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
|
||||
this.write(buf.slice(0, len + 4)); // Write as binary
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case 'download': {
|
||||
// Packet download of a file, agent to browser
|
||||
if (cmd.path == undefined) break;
|
||||
var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
|
||||
//console.log('Download: ' + filepath);
|
||||
try { this.httprequest.downloadFile = fs.openSync(filepath, 'rbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'downloaderror', reqid: cmd.reqid }))); break; }
|
||||
this.httprequest.downloadFileId = cmd.reqid;
|
||||
this.httprequest.downloadFilePtr = 0;
|
||||
if (this.httprequest.downloadFile) { this.write(Buffer.from(JSON.stringify({ action: 'downloadstart', reqid: this.httprequest.downloadFileId }))); }
|
||||
break;
|
||||
}
|
||||
case 'download2': {
|
||||
// Stream download of a file, agent to browser
|
||||
case 'upload':
|
||||
{
|
||||
// Upload a file, browser to agent
|
||||
if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
|
||||
if (cmd.path == undefined) break;
|
||||
var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
|
||||
try { this.httprequest.downloadFile = fs.createReadStream(filepath, { flags: 'rbN' }); } catch (e) { console.log(e); }
|
||||
this.httprequest.downloadFile.pipe(this);
|
||||
this.httprequest.downloadFile.end = function () { }
|
||||
this.httprequest.uploadFilePath = filepath;
|
||||
MeshServerLogEx(50, [filepath], 'Upload: \"' + filepath + '\"', this.httprequest);
|
||||
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
|
||||
this.httprequest.uploadFileid = cmd.reqid;
|
||||
if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case 'upload': {
|
||||
// Upload a file, browser to agent
|
||||
if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
|
||||
if (cmd.path == undefined) break;
|
||||
var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
|
||||
this.httprequest.uploadFilePath = filepath;
|
||||
MeshServerLogEx(50, [filepath], 'Upload: \"' + filepath + '\"', this.httprequest);
|
||||
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
|
||||
this.httprequest.uploadFileid = cmd.reqid;
|
||||
if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
|
||||
break;
|
||||
}
|
||||
case 'uploaddone': {
|
||||
// Indicates that an upload is done
|
||||
if (this.httprequest.uploadFile)
|
||||
case 'uploaddone':
|
||||
{
|
||||
fs.closeSync(this.httprequest.uploadFile);
|
||||
this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
|
||||
delete this.httprequest.uploadFile;
|
||||
delete this.httprequest.uploadFileid;
|
||||
delete this.httprequest.uploadFilePath;
|
||||
// Indicates that an upload is done
|
||||
if (this.httprequest.uploadFile)
|
||||
{
|
||||
fs.closeSync(this.httprequest.uploadFile);
|
||||
this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
|
||||
delete this.httprequest.uploadFile;
|
||||
delete this.httprequest.uploadFileid;
|
||||
delete this.httprequest.uploadFilePath;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'uploadcancel': {
|
||||
// Indicates that an upload is canceled
|
||||
if (this.httprequest.uploadFile)
|
||||
case 'uploadcancel':
|
||||
{
|
||||
fs.closeSync(this.httprequest.uploadFile);
|
||||
fs.unlinkSync(this.httprequest.uploadFilePath);
|
||||
this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
|
||||
delete this.httprequest.uploadFile;
|
||||
delete this.httprequest.uploadFileid;
|
||||
delete this.httprequest.uploadFilePath;
|
||||
// Indicates that an upload is canceled
|
||||
if (this.httprequest.uploadFile)
|
||||
{
|
||||
fs.closeSync(this.httprequest.uploadFile);
|
||||
fs.unlinkSync(this.httprequest.uploadFilePath);
|
||||
this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
|
||||
delete this.httprequest.uploadFile;
|
||||
delete this.httprequest.uploadFileid;
|
||||
delete this.httprequest.uploadFilePath;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'copy': {
|
||||
// Copy a bunch of files from scpath to dspath
|
||||
for (var i in cmd.names)
|
||||
case 'copy':
|
||||
{
|
||||
var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
|
||||
MeshServerLogEx(51, [sc, ds], 'Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
|
||||
if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
|
||||
// Copy a bunch of files from scpath to dspath
|
||||
for (var i in cmd.names)
|
||||
{
|
||||
var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
|
||||
MeshServerLogEx(51, [sc, ds], 'Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
|
||||
if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'move': {
|
||||
// Move a bunch of files from scpath to dspath
|
||||
for (var i in cmd.names)
|
||||
case 'move':
|
||||
{
|
||||
var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
|
||||
MeshServerLogEx(52, [sc, ds], 'Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
|
||||
if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
|
||||
// Move a bunch of files from scpath to dspath
|
||||
for (var i in cmd.names)
|
||||
{
|
||||
var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
|
||||
MeshServerLogEx(52, [sc, ds], 'Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
|
||||
if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'zip':
|
||||
// Zip a bunch of files
|
||||
if (this.zip != null) return; // Zip operating is currently running, exit now.
|
||||
|
@ -56,6 +56,55 @@ function sendAgentMessage(msg, icon)
|
||||
require('MeshAgent').SendCommand({ action: 'sessions', type: 'msg', value: sendAgentMessage.messages });
|
||||
}
|
||||
|
||||
// Add to the server event log
|
||||
function MeshServerLog(msg, state)
|
||||
{
|
||||
if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
|
||||
if (state)
|
||||
{
|
||||
if (state.userid) { msg.userid = state.userid; }
|
||||
if (state.username) { msg.username = state.username; }
|
||||
if (state.sessionid) { msg.sessionid = state.sessionid; }
|
||||
if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
|
||||
}
|
||||
require('MeshAgent').SendCommand(msg);
|
||||
}
|
||||
|
||||
// Add to the server event log, use internationalized events
|
||||
function MeshServerLogEx(id, args, msg, state)
|
||||
{
|
||||
var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
|
||||
if (state)
|
||||
{
|
||||
if (state.userid) { msg.userid = state.userid; }
|
||||
if (state.username) { msg.username = state.username; }
|
||||
if (state.sessionid) { msg.sessionid = state.sessionid; }
|
||||
if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
|
||||
}
|
||||
require('MeshAgent').SendCommand(msg);
|
||||
}
|
||||
|
||||
function pathjoin()
|
||||
{
|
||||
var x = [];
|
||||
for (var i in arguments)
|
||||
{
|
||||
var w = arguments[i];
|
||||
if (w != null)
|
||||
{
|
||||
while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
|
||||
if (i != 0)
|
||||
{
|
||||
while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
|
||||
}
|
||||
x.push(w);
|
||||
}
|
||||
}
|
||||
if (x.length == 0) return '/';
|
||||
return x.join('/');
|
||||
}
|
||||
|
||||
|
||||
function bsd_execv(name, agentfilename, sessionid)
|
||||
{
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
@ -370,29 +419,6 @@ require('MeshAgent').on('Connected', function () {
|
||||
});
|
||||
});
|
||||
|
||||
// Tunnel callback operations
|
||||
function onTunnelUpgrade(response, s, head) {
|
||||
this.s = s;
|
||||
s.httprequest = this;
|
||||
s.end = onTunnelClosed;
|
||||
s.tunnel = this;
|
||||
|
||||
//sendConsoleText('onTunnelUpgrade');
|
||||
|
||||
if (this.tcpport != null) {
|
||||
// This is a TCP relay connection, pause now and try to connect to the target.
|
||||
s.pause();
|
||||
s.data = onTcpRelayServerTunnelData;
|
||||
var connectionOptions = { port: parseInt(this.tcpport) };
|
||||
if (this.tcpaddr != null) { connectionOptions.host = this.tcpaddr; } else { connectionOptions.host = '127.0.0.1'; }
|
||||
s.tcprelay = net.createConnection(connectionOptions, onTcpRelayTargetTunnelConnect);
|
||||
s.tcprelay.peerindex = this.index;
|
||||
} else {
|
||||
// This is a normal connect for KVM/Terminal/Files
|
||||
s.data = onTunnelData;
|
||||
}
|
||||
}
|
||||
|
||||
// Called when receiving control data on websocket
|
||||
function onTunnelControlData(data, ws)
|
||||
{
|
||||
@ -491,15 +517,44 @@ require('MeshAgent').AddCommandHandler(function (data)
|
||||
if (data.value != null)
|
||||
{ // Process a new tunnel connection request
|
||||
// Create a new tunnel object
|
||||
if (data.rights != 4294967295)
|
||||
{
|
||||
MeshServerLog('Tunnel Error: RecoveryCore requires admin rights for tunnels');
|
||||
break;
|
||||
}
|
||||
|
||||
var xurl = getServerTargetUrlEx(data.value);
|
||||
if (xurl != null)
|
||||
{
|
||||
var woptions = http.parseUri(xurl);
|
||||
woptions.rejectUnauthorized = 0;
|
||||
woptions.perMessageDeflate = false;
|
||||
woptions.checkServerIdentity = function checkServerIdentity(certs)
|
||||
{
|
||||
// If the tunnel certificate matches the control channel certificate, accept the connection
|
||||
try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
|
||||
try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
|
||||
|
||||
// Check that the certificate is the one expected by the server, fail if not.
|
||||
if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) { throw new Error('BadCert') }
|
||||
}
|
||||
woptions.checkServerIdentity.servertlshash = data.servertlshash;
|
||||
|
||||
|
||||
//sendConsoleText(JSON.stringify(woptions));
|
||||
var tunnel = http.request(woptions);
|
||||
tunnel.on('upgrade', function (response, s, head)
|
||||
{
|
||||
if (require('MeshAgent').idleTimeout != null)
|
||||
{
|
||||
s.setTimeout(require('MeshAgent').idleTimeout * 1000);
|
||||
s.on('timeout', function ()
|
||||
{
|
||||
this.ping();
|
||||
this.setTimeout(require('MeshAgent').idleTimeout * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
this.s = s;
|
||||
s.httprequest = this;
|
||||
s.tunnel = this;
|
||||
@ -508,9 +563,8 @@ require('MeshAgent').AddCommandHandler(function (data)
|
||||
if (tunnels[this.httprequest.index] == null) return; // Stop duplicate calls.
|
||||
|
||||
// If there is a upload or download active on this connection, close the file
|
||||
if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); this.httprequest.uploadFile = undefined; }
|
||||
if (this.httprequest.downloadFile) { fs.closeSync(this.httprequest.downloadFile); this.httprequest.downloadFile = undefined; }
|
||||
|
||||
if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; delete this.httprequest.uploadFileid; delete this.httprequest.uploadFilePath; }
|
||||
if (this.httprequest.downloadFile) { delete this.httprequest.downloadFile; }
|
||||
|
||||
//sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
|
||||
delete tunnels[this.httprequest.index];
|
||||
@ -521,29 +575,62 @@ require('MeshAgent').AddCommandHandler(function (data)
|
||||
s.on('data', function (data)
|
||||
{
|
||||
// If this is upload data, save it to file
|
||||
if (this.httprequest.uploadFile)
|
||||
if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123))
|
||||
{
|
||||
try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
|
||||
this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data
|
||||
// Save the data to file being uploaded.
|
||||
if (data[0] == 0)
|
||||
{
|
||||
// If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
|
||||
try { fs.writeSync(this.httprequest.uploadFile, data, 1, data.length - 1); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
|
||||
} else
|
||||
{
|
||||
// If data does not start with zero, save as-is.
|
||||
try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
|
||||
}
|
||||
this.write(Buffer.from(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data.
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.httprequest.state == 0)
|
||||
{
|
||||
// Check if this is a relay connection
|
||||
if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid); }
|
||||
} else
|
||||
if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle tunnel data
|
||||
if (this.httprequest.protocol == 0)
|
||||
{
|
||||
if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
|
||||
{ // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user), 10 = FileTransfer
|
||||
// Take a look at the protocol
|
||||
if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
|
||||
this.httprequest.protocol = parseInt(data);
|
||||
if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
|
||||
if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9))
|
||||
if (this.httprequest.protocol == 10)
|
||||
{
|
||||
// Remote terminal using native pipes
|
||||
//
|
||||
// Basic file transfer
|
||||
//
|
||||
var stats = null;
|
||||
if ((process.platform != 'win32') && (this.httprequest.xoptions.file.startsWith('/') == false)) { this.httprequest.xoptions.file = '/' + this.httprequest.xoptions.file; }
|
||||
try { stats = require('fs').statSync(this.httprequest.xoptions.file) } catch (e) { }
|
||||
try { if (stats) { this.httprequest.downloadFile = fs.createReadStream(this.httprequest.xoptions.file, { flags: 'rbN' }); } } catch (e) { }
|
||||
if (this.httprequest.downloadFile)
|
||||
{
|
||||
//sendConsoleText('BasicFileTransfer, ok, ' + this.httprequest.xoptions.file + ', ' + JSON.stringify(stats));
|
||||
this.write(JSON.stringify({ op: 'ok', size: stats.size }));
|
||||
this.httprequest.downloadFile.pipe(this);
|
||||
this.httprequest.downloadFile.end = function () { }
|
||||
} else
|
||||
{
|
||||
//sendConsoleText('BasicFileTransfer, cancel, ' + this.httprequest.xoptions.file);
|
||||
this.write(JSON.stringify({ op: 'cancel' }));
|
||||
}
|
||||
}
|
||||
else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9))
|
||||
{
|
||||
//
|
||||
// Remote Terminal
|
||||
//
|
||||
if (process.platform == "win32")
|
||||
{
|
||||
var cols = 80, rows = 25;
|
||||
@ -630,36 +717,124 @@ require('MeshAgent').AddCommandHandler(function (data)
|
||||
if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
|
||||
this.write(Buffer.from(JSON.stringify(response)));
|
||||
break;
|
||||
case 'mkdir': {
|
||||
// Create a new empty folder
|
||||
fs.mkdirSync(cmd.path);
|
||||
break;
|
||||
}
|
||||
case 'rm': {
|
||||
// Delete, possibly recursive delete
|
||||
for (var i in cmd.delfiles)
|
||||
case 'mkdir':
|
||||
{
|
||||
try { deleteFolderRecursive(path.join(cmd.path, cmd.delfiles[i]), cmd.rec); } catch (e) { }
|
||||
// Create a new empty folder
|
||||
fs.mkdirSync(cmd.path);
|
||||
break;
|
||||
}
|
||||
case 'rm':
|
||||
{
|
||||
// Delete, possibly recursive delete
|
||||
for (var i in cmd.delfiles)
|
||||
{
|
||||
try { deleteFolderRecursive(path.join(cmd.path, cmd.delfiles[i]), cmd.rec); } catch (e) { }
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'rename':
|
||||
{
|
||||
// Rename a file or folder
|
||||
var oldfullpath = path.join(cmd.path, cmd.oldname);
|
||||
var newfullpath = path.join(cmd.path, cmd.newname);
|
||||
try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
|
||||
break;
|
||||
}
|
||||
case 'findfile':
|
||||
{
|
||||
// Search for files
|
||||
var r = require('file-search').find('"' + cmd.path + '"', cmd.filter);
|
||||
if (!r.cancel) { r.cancel = function cancel() { this.child.kill(); }; }
|
||||
this._search = r;
|
||||
r.socket = this;
|
||||
r.socket.reqid = cmd.reqid; // Search request id. This is used to send responses and cancel the request.
|
||||
r.socket.path = cmd.path; // Search path
|
||||
r.on('result', function (str) { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: str.substring(this.socket.path.length), reqid: this.socket.reqid }))); } catch (ex) { } });
|
||||
r.then(function () { try { this.socket.write(Buffer.from(JSON.stringify({ action: 'findfile', r: null, reqid: this.socket.reqid }))); } catch (ex) { } });
|
||||
break;
|
||||
}
|
||||
case 'cancelfindfile':
|
||||
{
|
||||
if (this._search) { this._search.cancel(); this._search = null; }
|
||||
break;
|
||||
}
|
||||
case 'download':
|
||||
{
|
||||
// Download a file
|
||||
var sendNextBlock = 0;
|
||||
if (cmd.sub == 'start')
|
||||
{ // Setup the download
|
||||
if ((cmd.path == null) && (cmd.ask == 'coredump'))
|
||||
{ // If we are asking for the coredump file, set the right path.
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
|
||||
} else
|
||||
{
|
||||
if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
|
||||
}
|
||||
}
|
||||
MeshServerLogEx((cmd.ask == 'coredump') ? 104 : 49, [cmd.path], 'Download: \"' + cmd.path + '\"', this.httprequest);
|
||||
if ((cmd.path == null) || (this.filedownload != null)) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
|
||||
this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
|
||||
try { this.filedownload.f = fs.openSync(this.filedownload.path, 'rbN'); } catch (e) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
|
||||
if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
|
||||
} else if ((this.filedownload != null) && (cmd.id == this.filedownload.id))
|
||||
{ // Download commands
|
||||
if (cmd.sub == 'startack') { sendNextBlock = ((typeof cmd.ack == 'number') ? cmd.ack : 8); } else if (cmd.sub == 'stop') { delete this.filedownload; } else if (cmd.sub == 'ack') { sendNextBlock = 1; }
|
||||
}
|
||||
// Send the next download block(s)
|
||||
while (sendNextBlock > 0)
|
||||
{
|
||||
sendNextBlock--;
|
||||
var buf = Buffer.alloc(16384);
|
||||
var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
|
||||
this.filedownload.ptr += len;
|
||||
if (len < 16380) { buf.writeInt32BE(0x01000001, 0); fs.closeSync(this.filedownload.f); delete this.filedownload; sendNextBlock = 0; } else { buf.writeInt32BE(0x01000000, 0); }
|
||||
this.write(buf.slice(0, len + 4)); // Write as binary
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'upload':
|
||||
{
|
||||
// Upload a file, browser to agent
|
||||
if (this.httprequest.uploadFile != null) { fs.closeSync(this.httprequest.uploadFile); delete this.httprequest.uploadFile; }
|
||||
if (cmd.path == undefined) break;
|
||||
var filepath = cmd.name ? pathjoin(cmd.path, cmd.name) : cmd.path;
|
||||
this.httprequest.uploadFilePath = filepath;
|
||||
MeshServerLogEx(50, [filepath], 'Upload: \"' + filepath + '\"', this.httprequest);
|
||||
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
|
||||
this.httprequest.uploadFileid = cmd.reqid;
|
||||
if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
|
||||
break;
|
||||
}
|
||||
case 'uploaddone':
|
||||
{
|
||||
// Indicates that an upload is done
|
||||
if (this.httprequest.uploadFile)
|
||||
{
|
||||
fs.closeSync(this.httprequest.uploadFile);
|
||||
this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
|
||||
delete this.httprequest.uploadFile;
|
||||
delete this.httprequest.uploadFileid;
|
||||
delete this.httprequest.uploadFilePath;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'uploadcancel':
|
||||
{
|
||||
// Indicates that an upload is canceled
|
||||
if (this.httprequest.uploadFile)
|
||||
{
|
||||
fs.closeSync(this.httprequest.uploadFile);
|
||||
fs.unlinkSync(this.httprequest.uploadFilePath);
|
||||
this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
|
||||
delete this.httprequest.uploadFile;
|
||||
delete this.httprequest.uploadFileid;
|
||||
delete this.httprequest.uploadFilePath;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'rename': {
|
||||
// Rename a file or folder
|
||||
var oldfullpath = path.join(cmd.path, cmd.oldname);
|
||||
var newfullpath = path.join(cmd.path, cmd.newname);
|
||||
try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
|
||||
break;
|
||||
}
|
||||
case 'upload': {
|
||||
// Upload a file, browser to agent
|
||||
if (this.httprequest.uploadFile != undefined) { fs.closeSync(this.httprequest.uploadFile); this.httprequest.uploadFile = undefined; }
|
||||
if (cmd.path == undefined) break;
|
||||
var filepath = cmd.name ? path.join(cmd.path, cmd.name) : cmd.path;
|
||||
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(Buffer.from(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
|
||||
this.httprequest.uploadFileid = cmd.reqid;
|
||||
if (this.httprequest.uploadFile) { this.write(Buffer.from(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
|
||||
break;
|
||||
}
|
||||
case 'copy': {
|
||||
// Copy a bunch of files from scpath to dspath
|
||||
for (var i in cmd.names)
|
||||
|
Loading…
Reference in New Issue
Block a user