Much improved event logs

This commit is contained in:
Ylian Saint-Hilaire 2019-07-29 16:35:48 -07:00
parent 187b9ac5b1
commit fe1891346f
12 changed files with 381 additions and 266 deletions

View File

@ -171,8 +171,9 @@ function createMeshCore(agent)
}
break;
default:
this.parent._daipc = null; this.end(); return;
break;
this.parent._daipc = null;
this.end();
return;
}
}
catch(xe)
@ -306,6 +307,17 @@ function createMeshCore(agent)
var nextTunnelIndex = 1;
var amtPolicy = null;
// 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; }
}
mesh.SendCommand(msg);
}
// If we are running in Duktape, agent will be null
if (agent == null) {
// Running in native agent, Import libraries
@ -615,6 +627,7 @@ function createMeshCore(agent)
switch (data.type) {
case 'console': { // Process a console command
if (data.value && data.sessionid) {
MeshServerLog('Processing console command: ' + data.value, data);
var args = splitArgs(data.value);
processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
}
@ -636,6 +649,8 @@ function createMeshCore(agent)
tunnel.rights = data.rights;
tunnel.consent = data.consent;
tunnel.username = data.username;
tunnel.userid = data.userid;
tunnel.remoteaddr = data.remoteaddr;
tunnel.state = 0;
tunnel.url = xurl;
tunnel.protocol = 0;
@ -664,12 +679,14 @@ function createMeshCore(agent)
case 'pskill': {
// Kill a process
if (data.value) {
MeshServerLog('Killing process ' + data.value, data);
try { process.kill(data.value); } catch (e) { sendConsoleText("pskill: " + JSON.stringify(e)); }
}
break;
}
case 'openUrl': {
// Open a local web browser and return success/fail
MeshServerLog('Opening: ' + data.url, data);
sendConsoleText('OpenURL: ' + data.url);
if (data.url) { mesh.SendCommand({ "action": "msg", "type":"openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
break;
@ -677,31 +694,33 @@ function createMeshCore(agent)
case 'getclip': {
// Send the load clipboard back to the user
//sendConsoleText('getClip: ' + JSON.stringify(data));
if (require('MeshAgent').isService)
{
require('clipboard').dispatchRead().then(function (str) { mesh.SendCommand({ "action": "msg", "type": "getclip", "sessionid": data.sessionid, "data": str }); });
}
else
{
require("clipboard").read().then(function (str) { mesh.SendCommand({ "action": "msg", "type": "getclip", "sessionid": data.sessionid, "data": str }); });
if (require('MeshAgent').isService) {
require('clipboard').dispatchRead().then(function (str) {
if (str) {
MeshServerLog('Getting clipboard content, ' + str.length + ' byte(s)', data);
mesh.SendCommand({ "action": "msg", "type": "getclip", "sessionid": data.sessionid, "data": str });
}
});
} else {
require("clipboard").read().then(function (str) {
if (str) {
MeshServerLog('Getting clipboard content, ' + str.length + ' byte(s)', data);
mesh.SendCommand({ "action": "msg", "type": "getclip", "sessionid": data.sessionid, "data": str });
}
});
}
break;
}
case 'setclip': {
// Set the load clipboard to a user value
//sendConsoleText('setClip: ' + JSON.stringify(data));
if (typeof data.data == 'string')
{
if (require('MeshAgent').isService)
{
require('clipboard').dispatchWrite(data.data);
if (typeof data.data == 'string') {
MeshServerLog('Setting clipboard content, ' + data.data.length + ' byte(s)', data);
if (typeof data.data == 'string') {
if (require('MeshAgent').isService) { require('clipboard').dispatchWrite(data.data); } else { require("clipboard")(data.data); } // Set the clipboard
mesh.SendCommand({ "action": "msg", "type": "setclip", "sessionid": data.sessionid, "success": true });
}
else
{
require("clipboard")(data.data); // Set the clipboard
}
mesh.SendCommand({ "action": "msg", "type": "setclip", "sessionid": data.sessionid, "success": true });
}
}
break;
}
default:
@ -711,7 +730,10 @@ function createMeshCore(agent)
break;
}
case 'acmactivate': {
if (amt != null) { amt.setAcmResponse(data); }
if (amt != null) {
MeshServerLog('Attempting Intel AMT ACM mode activation', data);
amt.setAcmResponse(data);
}
break;
}
case 'wakeonlan': {
@ -726,6 +748,7 @@ function createMeshCore(agent)
var forced = 0;
if (data.forced == 1) { forced = 1; }
data.actiontype = parseInt(data.actiontype);
MeshServerLog('Performing power action=' + data.actiontype + ', forced=' + forced, data);
sendConsoleText('Performing power action=' + data.actiontype + ', forced=' + forced + '.');
var r = mesh.ExecPowerState(data.actiontype, forced);
sendConsoleText('ExecPowerState returned code: ' + r);
@ -740,13 +763,15 @@ function createMeshCore(agent)
case 'toast': {
// Display a toast message
if (data.title && data.msg) {
MeshServerLog('Displaying toast message, title=' + data.title + ', message=' + data.msg, data);
try { require('toaster').Toast(data.title, data.msg); } catch (ex) { }
}
break;
}
case 'openUrl': {
// Open a local web browser and return success/fail
sendConsoleText('OpenURL: ' + data.url);
//sendConsoleText('OpenURL: ' + data.url);
MeshServerLog('Opening: ' + data.url, data);
if (data.url) { mesh.SendCommand({ "action": "openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
break;
}
@ -1003,44 +1028,41 @@ function createMeshCore(agent)
// Perform notification if needed. Toast messages may not be supported on all platforms.
if (this.httprequest.consent && (this.httprequest.consent & 16)) {
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting Terminal Access. Grant access?', 10);
pr.ws = this;
this.pause();
pr.then(
function () {
// Success!
// Success
MeshServerLog('Starting remote terminal after local user accepted (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2)) {
// User Notifications is required
try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
}
this.ws.resume();
},
function (e) {
// User Consent Denied/Failed!
// User Consent Denied/Failed
MeshServerLog('Failed to start remote terminal after local user rejected (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
this.ws.end();
});
}
else {
} else {
// User Consent Prompt is not required
if (this.httprequest.consent && (this.httprequest.consent & 2)) {
// User Notifications is required
MeshServerLog('Started remote terminal with toast notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
} else {
MeshServerLog('Started remote terminal without notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
}
this.resume();
}
this.removeAllListeners('data');
this.on('data', onTunnelControlData);
//this.write('MeshCore Terminal Hello');
@ -1096,10 +1118,8 @@ function createMeshCore(agent)
if (this.httprequest.consent && (this.httprequest.consent & 8))
{
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting KVM Access. Grant access?', 10);
pr.ws = this;
this.pause();
@ -1107,37 +1127,32 @@ function createMeshCore(agent)
pr.then(
function ()
{
// Success!
// Success
MeshServerLog('Starting remote desktop after local user accepted (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1))
{
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) {
// User Notifications is required
try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote desktop session.'); } catch (ex) { }
}
this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
this.ws.resume();
},
function (e)
{
// User Consent Denied/Failed!
// User Consent Denied/Failed
MeshServerLog('Failed to start remote desktop after local user rejected (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
//var err = 'User consent: ' + e.toString();
//var b = Buffer.alloc(5 + err.length);
//b.writeUInt16BE(MNG_ERROR, 0);
//b.writeUInt16BE(err.length + 4, 2);
//Buffer.from(err).copy(b, 4);
//this.ws.end(b);
});
}
else
{
// User Consent Prompt is not required
if (this.httprequest.consent && (this.httprequest.consent & 1))
{
if (this.httprequest.consent && (this.httprequest.consent & 1)) {
// User Notifications is required
MeshServerLog('Started remote desktop with toast notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote desktop session.'); } catch (ex) { }
} else {
MeshServerLog('Started remote desktop without notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
}
this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
}
@ -1161,35 +1176,36 @@ function createMeshCore(agent)
if (this.httprequest.consent && (this.httprequest.consent & 32))
{
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting remote file access. Grant access?', 10);
pr.ws = this;
this.pause();
pr.then(
function () {
// Success!
// Success
MeshServerLog('Starting remote files after local user accepted (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4))
{
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) {
// User Notifications is required
try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote file session.'); } catch (ex) { }
}
this.ws.resume();
},
function (e) {
// User Consent Denied/Failed!
// User Consent Denied/Failed
MeshServerLog('Failed to start remote files after local user rejected (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
});
}
else {
} else {
// User Consent Prompt is not required
if (this.httprequest.consent && (this.httprequest.consent & 4)) {
// User Notifications is required
MeshServerLog('Started remote files with toast notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote file session.'); } catch (ex) { }
} else {
MeshServerLog('Started remote files without notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
}
this.resume();
}
@ -1252,12 +1268,15 @@ function createMeshCore(agent)
case 'mkdir': {
// Create a new empty folder
fs.mkdirSync(cmd.path);
MeshServerLog('Create folder: \"' + cmd.path + '\"', this.httprequest);
break;
}
case 'rm': {
// Delete, possibly recursive delete
for (var i in cmd.delfiles) {
try { deleteFolderRecursive(obj.path.join(cmd.path, cmd.delfiles[i]), cmd.rec); } catch (e) { }
var p = obj.path.join(cmd.path, cmd.delfiles[i]), delcount = 0;
try { delcount = deleteFolderRecursive(p, cmd.rec); } catch (e) { }
MeshServerLog((cmd.rec ? 'Delete recursive: \"' : 'Delete: \"') + p + '\", ' + delcount + ' element(s) removed', this.httprequest);
}
break;
}
@ -1265,6 +1284,7 @@ function createMeshCore(agent)
// Rename a file or folder
var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
var newfullpath = obj.path.join(cmd.path, cmd.newname);
MeshServerLog('Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
break;
}
@ -1272,6 +1292,7 @@ function createMeshCore(agent)
// Download a file
var sendNextBlock = 0;
if (cmd.sub == 'start') { // Setup the download
MeshServerLog('Download: \"' + cmd.path + '\"', this.httprequest);
if (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; }
@ -1317,6 +1338,7 @@ function createMeshCore(agent)
if (this.httprequest.uploadFile != undefined) { fs.closeSync(this.httprequest.uploadFile); this.httprequest.uploadFile = undefined; }
if (cmd.path == undefined) break;
var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
MeshServerLog('Upload: \"' + filepath + '\"', this.httprequest);
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(new Buffer(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
this.httprequest.uploadFileid = cmd.reqid;
if (this.httprequest.uploadFile) { this.write(new Buffer(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
@ -1326,6 +1348,7 @@ function createMeshCore(agent)
// 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]);
MeshServerLog('Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
}
break;
@ -1334,6 +1357,7 @@ function createMeshCore(agent)
// 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]);
MeshServerLog('Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
}
break;
@ -1349,19 +1373,23 @@ function createMeshCore(agent)
// Delete a directory with a files and directories within it
function deleteFolderRecursive(path, rec) {
var count = 0;
if (fs.existsSync(path)) {
if (rec == true) {
fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index) {
var curPath = obj.path.join(path, file);
if (fs.statSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath, true);
count += deleteFolderRecursive(curPath, true);
} else { // delete file
fs.unlinkSync(curPath);
count++;
}
});
}
fs.unlinkSync(path);
count++;
}
return count;
};
// Called when receiving control data on WebRTC
@ -1391,6 +1419,7 @@ function createMeshCore(agent)
// Lock the current user out of the desktop
try {
if (process.platform == 'win32') {
MeshServerLog('Locking remote user out of desktop', ws.httprequest);
var child = require('child_process');
child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
}
@ -1557,6 +1586,9 @@ function createMeshCore(agent)
}
break;
*/
case 'log':
if (args['_'].length != 1) { response = 'Proper usage: log "sample text"'; } else { MeshServerLog(args['_'][0]); response = 'ok'; }
break;
case 'getclip':
if (require('MeshAgent').isService) {
require('clipboard').dispatchRead().then(function (str) { sendConsoleText(str, sessionid); });

150
agents/meshcore.min.js vendored
View File

@ -171,8 +171,9 @@ function createMeshCore(agent)
}
break;
default:
this.parent._daipc = null; this.end(); return;
break;
this.parent._daipc = null;
this.end();
return;
}
}
catch(xe)
@ -306,6 +307,17 @@ function createMeshCore(agent)
var nextTunnelIndex = 1;
var amtPolicy = null;
// 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; }
}
mesh.SendCommand(msg);
}
// If we are running in Duktape, agent will be null
if (agent == null) {
// Running in native agent, Import libraries
@ -615,6 +627,7 @@ function createMeshCore(agent)
switch (data.type) {
case 'console': { // Process a console command
if (data.value && data.sessionid) {
MeshServerLog('Processing console command: ' + data.value, data);
var args = splitArgs(data.value);
processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
}
@ -636,6 +649,8 @@ function createMeshCore(agent)
tunnel.rights = data.rights;
tunnel.consent = data.consent;
tunnel.username = data.username;
tunnel.userid = data.userid;
tunnel.remoteaddr = data.remoteaddr;
tunnel.state = 0;
tunnel.url = xurl;
tunnel.protocol = 0;
@ -664,12 +679,14 @@ function createMeshCore(agent)
case 'pskill': {
// Kill a process
if (data.value) {
MeshServerLog('Killing process ' + data.value, data);
try { process.kill(data.value); } catch (e) { sendConsoleText("pskill: " + JSON.stringify(e)); }
}
break;
}
case 'openUrl': {
// Open a local web browser and return success/fail
MeshServerLog('Opening: ' + data.url, data);
sendConsoleText('OpenURL: ' + data.url);
if (data.url) { mesh.SendCommand({ "action": "msg", "type":"openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
break;
@ -677,31 +694,33 @@ function createMeshCore(agent)
case 'getclip': {
// Send the load clipboard back to the user
//sendConsoleText('getClip: ' + JSON.stringify(data));
if (require('MeshAgent').isService)
{
require('clipboard').dispatchRead().then(function (str) { mesh.SendCommand({ "action": "msg", "type": "getclip", "sessionid": data.sessionid, "data": str }); });
}
else
{
require("clipboard").read().then(function (str) { mesh.SendCommand({ "action": "msg", "type": "getclip", "sessionid": data.sessionid, "data": str }); });
if (require('MeshAgent').isService) {
require('clipboard').dispatchRead().then(function (str) {
if (str) {
MeshServerLog('Getting clipboard content, ' + str.length + ' byte(s)', data);
mesh.SendCommand({ "action": "msg", "type": "getclip", "sessionid": data.sessionid, "data": str });
}
});
} else {
require("clipboard").read().then(function (str) {
if (str) {
MeshServerLog('Getting clipboard content, ' + str.length + ' byte(s)', data);
mesh.SendCommand({ "action": "msg", "type": "getclip", "sessionid": data.sessionid, "data": str });
}
});
}
break;
}
case 'setclip': {
// Set the load clipboard to a user value
//sendConsoleText('setClip: ' + JSON.stringify(data));
if (typeof data.data == 'string')
{
if (require('MeshAgent').isService)
{
require('clipboard').dispatchWrite(data.data);
if (typeof data.data == 'string') {
MeshServerLog('Setting clipboard content, ' + data.data.length + ' byte(s)', data);
if (typeof data.data == 'string') {
if (require('MeshAgent').isService) { require('clipboard').dispatchWrite(data.data); } else { require("clipboard")(data.data); } // Set the clipboard
mesh.SendCommand({ "action": "msg", "type": "setclip", "sessionid": data.sessionid, "success": true });
}
else
{
require("clipboard")(data.data); // Set the clipboard
}
mesh.SendCommand({ "action": "msg", "type": "setclip", "sessionid": data.sessionid, "success": true });
}
}
break;
}
default:
@ -711,7 +730,10 @@ function createMeshCore(agent)
break;
}
case 'acmactivate': {
if (amt != null) { amt.setAcmResponse(data); }
if (amt != null) {
MeshServerLog('Attempting Intel AMT ACM mode activation', data);
amt.setAcmResponse(data);
}
break;
}
case 'wakeonlan': {
@ -726,6 +748,7 @@ function createMeshCore(agent)
var forced = 0;
if (data.forced == 1) { forced = 1; }
data.actiontype = parseInt(data.actiontype);
MeshServerLog('Performing power action=' + data.actiontype + ', forced=' + forced, data);
sendConsoleText('Performing power action=' + data.actiontype + ', forced=' + forced + '.');
var r = mesh.ExecPowerState(data.actiontype, forced);
sendConsoleText('ExecPowerState returned code: ' + r);
@ -740,13 +763,15 @@ function createMeshCore(agent)
case 'toast': {
// Display a toast message
if (data.title && data.msg) {
MeshServerLog('Displaying toast message, title=' + data.title + ', message=' + data.msg, data);
try { require('toaster').Toast(data.title, data.msg); } catch (ex) { }
}
break;
}
case 'openUrl': {
// Open a local web browser and return success/fail
sendConsoleText('OpenURL: ' + data.url);
//sendConsoleText('OpenURL: ' + data.url);
MeshServerLog('Opening: ' + data.url, data);
if (data.url) { mesh.SendCommand({ "action": "openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
break;
}
@ -1003,44 +1028,41 @@ function createMeshCore(agent)
// Perform notification if needed. Toast messages may not be supported on all platforms.
if (this.httprequest.consent && (this.httprequest.consent & 16)) {
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting Terminal Access. Grant access?', 10);
pr.ws = this;
this.pause();
pr.then(
function () {
// Success!
// Success
MeshServerLog('Starting remote terminal after local user accepted (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2)) {
// User Notifications is required
try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
}
this.ws.resume();
},
function (e) {
// User Consent Denied/Failed!
// User Consent Denied/Failed
MeshServerLog('Failed to start remote terminal after local user rejected (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
this.ws.end();
});
}
else {
} else {
// User Consent Prompt is not required
if (this.httprequest.consent && (this.httprequest.consent & 2)) {
// User Notifications is required
MeshServerLog('Started remote terminal with toast notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote terminal session.'); } catch (ex) { }
} else {
MeshServerLog('Started remote terminal without notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
}
this.resume();
}
this.removeAllListeners('data');
this.on('data', onTunnelControlData);
//this.write('MeshCore Terminal Hello');
@ -1096,10 +1118,8 @@ function createMeshCore(agent)
if (this.httprequest.consent && (this.httprequest.consent & 8))
{
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting KVM Access. Grant access?', 10);
pr.ws = this;
this.pause();
@ -1107,37 +1127,32 @@ function createMeshCore(agent)
pr.then(
function ()
{
// Success!
// Success
MeshServerLog('Starting remote desktop after local user accepted (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1))
{
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) {
// User Notifications is required
try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote desktop session.'); } catch (ex) { }
}
this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
this.ws.resume();
},
function (e)
{
// User Consent Denied/Failed!
// User Consent Denied/Failed
MeshServerLog('Failed to start remote desktop after local user rejected (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
//var err = 'User consent: ' + e.toString();
//var b = Buffer.alloc(5 + err.length);
//b.writeUInt16BE(MNG_ERROR, 0);
//b.writeUInt16BE(err.length + 4, 2);
//Buffer.from(err).copy(b, 4);
//this.ws.end(b);
});
}
else
{
// User Consent Prompt is not required
if (this.httprequest.consent && (this.httprequest.consent & 1))
{
if (this.httprequest.consent && (this.httprequest.consent & 1)) {
// User Notifications is required
MeshServerLog('Started remote desktop with toast notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote desktop session.'); } catch (ex) { }
} else {
MeshServerLog('Started remote desktop without notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
}
this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
}
@ -1161,35 +1176,36 @@ function createMeshCore(agent)
if (this.httprequest.consent && (this.httprequest.consent & 32))
{
// User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'Waiting for user to grant access...' }));
var pr = require('message-box').create('MeshCentral', this.httprequest.username + ' requesting remote file access. Grant access?', 10);
pr.ws = this;
this.pause();
pr.then(
function () {
// Success!
// Success
MeshServerLog('Starting remote files after local user accepted (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4))
{
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) {
// User Notifications is required
try { require('toaster').Toast('MeshCentral', this.ws.httprequest.username + ' started a remote file session.'); } catch (ex) { }
}
this.ws.resume();
},
function (e) {
// User Consent Denied/Failed!
// User Consent Denied/Failed
MeshServerLog('Failed to start remote files after local user rejected (' + this.httprequest.remoteaddr + ')', this.httprequest);
this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString() }));
});
}
else {
} else {
// User Consent Prompt is not required
if (this.httprequest.consent && (this.httprequest.consent & 4)) {
// User Notifications is required
MeshServerLog('Started remote files with toast notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
try { require('toaster').Toast('MeshCentral', this.httprequest.username + ' started a remote file session.'); } catch (ex) { }
} else {
MeshServerLog('Started remote files without notification (' + this.httprequest.remoteaddr + ')', this.httprequest);
}
this.resume();
}
@ -1252,12 +1268,15 @@ function createMeshCore(agent)
case 'mkdir': {
// Create a new empty folder
fs.mkdirSync(cmd.path);
MeshServerLog('Create folder: \"' + cmd.path + '\"', this.httprequest);
break;
}
case 'rm': {
// Delete, possibly recursive delete
for (var i in cmd.delfiles) {
try { deleteFolderRecursive(obj.path.join(cmd.path, cmd.delfiles[i]), cmd.rec); } catch (e) { }
var p = obj.path.join(cmd.path, cmd.delfiles[i]), delcount = 0;
try { delcount = deleteFolderRecursive(p, cmd.rec); } catch (e) { }
MeshServerLog((cmd.rec ? 'Delete recursive: \"' : 'Delete: \"') + p + '\", ' + delcount + ' element(s) removed', this.httprequest);
}
break;
}
@ -1265,6 +1284,7 @@ function createMeshCore(agent)
// Rename a file or folder
var oldfullpath = obj.path.join(cmd.path, cmd.oldname);
var newfullpath = obj.path.join(cmd.path, cmd.newname);
MeshServerLog('Rename: \"' + oldfullpath + '\" to \"' + cmd.newname + '\"', this.httprequest);
try { fs.renameSync(oldfullpath, newfullpath); } catch (e) { console.log(e); }
break;
}
@ -1272,6 +1292,7 @@ function createMeshCore(agent)
// Download a file
var sendNextBlock = 0;
if (cmd.sub == 'start') { // Setup the download
MeshServerLog('Download: \"' + cmd.path + '\"', this.httprequest);
if (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; }
@ -1317,6 +1338,7 @@ function createMeshCore(agent)
if (this.httprequest.uploadFile != undefined) { fs.closeSync(this.httprequest.uploadFile); this.httprequest.uploadFile = undefined; }
if (cmd.path == undefined) break;
var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
MeshServerLog('Upload: \"' + filepath + '\"', this.httprequest);
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(new Buffer(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
this.httprequest.uploadFileid = cmd.reqid;
if (this.httprequest.uploadFile) { this.write(new Buffer(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
@ -1326,6 +1348,7 @@ function createMeshCore(agent)
// 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]);
MeshServerLog('Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
}
break;
@ -1334,6 +1357,7 @@ function createMeshCore(agent)
// 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]);
MeshServerLog('Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
}
break;
@ -1349,19 +1373,23 @@ function createMeshCore(agent)
// Delete a directory with a files and directories within it
function deleteFolderRecursive(path, rec) {
var count = 0;
if (fs.existsSync(path)) {
if (rec == true) {
fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index) {
var curPath = obj.path.join(path, file);
if (fs.statSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath, true);
count += deleteFolderRecursive(curPath, true);
} else { // delete file
fs.unlinkSync(curPath);
count++;
}
});
}
fs.unlinkSync(path);
count++;
}
return count;
};
// Called when receiving control data on WebRTC
@ -1391,6 +1419,7 @@ function createMeshCore(agent)
// Lock the current user out of the desktop
try {
if (process.platform == 'win32') {
MeshServerLog('Locking remote user out of desktop', ws.httprequest);
var child = require('child_process');
child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
}
@ -1557,6 +1586,9 @@ function createMeshCore(agent)
}
break;
*/
case 'log':
if (args['_'].length != 1) { response = 'Proper usage: log "sample text"'; } else { MeshServerLog(args['_'][0]); response = 'ok'; }
break;
case 'getclip':
if (require('MeshAgent').isService) {
require('clipboard').dispatchRead().then(function (str) { sendConsoleText(str, sessionid); });

View File

@ -1192,6 +1192,20 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Nothing is done right now.
break;
}
case 'log':
{
// Log a value in the event log
if ((typeof command.msg == 'string') && (command.msg.length < 4096)) {
var event = { etype: 'node', action: 'agentlog', nodeid: obj.dbNodeKey, domain: domain.id, msg: command.msg };
if (typeof command.userid == 'string') {
var loguser = parent.users[command.userid];
if (loguser) { event.userid = command.userid; event.username = loguser.name; }
}
if ((typeof command.sessionid == 'string') && (command.sessionid.length < 500)) { event.sessionid = command.sessionid; }
parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, event);
}
break;
}
case 'ping': { sendPong(); break; }
case 'pong': { break; }
case 'getScript':
@ -1273,10 +1287,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
break;
}
case 'log': {
// Only the diagnostic agent can do
if (((obj.agentInfo.capabilities & 0x40) != 0) && (typeof command.value.value == 'string') && (command.value.value.length < 256))
{
// Log a value in the event log of the main again
if (((obj.agentInfo.capabilities & 0x40) != 0) && (typeof command.value.value == 'string') && (command.value.value.length < 256)) {
// If this is a diagnostic agent, log the event in the log of the main agent
var event = { etype: 'node', action: 'diagnostic', nodeid: obj.realNodeKey, domain: domain.id, msg: command.value.value };
parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, event);
}

View File

@ -70,7 +70,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (parent.parent.multiServer == null) {
var targets = ['*', 'server-users'];
if (obj.user.groups) { for (var i in obj.user.groups) { targets.push('server-users:' + i); } }
parent.parent.DispatchEvent(targets, obj, { action: 'wssessioncount', username: obj.user.name, count: parent.wssessions[obj.user._id].length, nolog: 1, domain: domain.id });
parent.parent.DispatchEvent(targets, obj, { action: 'wssessioncount', userid: user._id, username: user.name, count: parent.wssessions[obj.user._id].length, nolog: 1, domain: domain.id });
} else {
parent.recountSessions(ws.sessionId); // Recount sessions
}
@ -141,6 +141,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
command.consent = mesh.consent; // Add user consent
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
command.username = user.name; // Add user name
command.userid = user._id; // Add user id
command.remoteaddr = (req.ip.startsWith('::ffff:')) ? (req.ip.substring(7)) : req.ip; // User's IP address
delete command.nodeid; // Remove the nodeid since it's implied
try { agent.send(JSON.stringify(command)); } catch (ex) { }
}
@ -157,6 +159,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
command.consent = mesh.consent; // Add user consent
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
command.username = user.name; // Add user name
command.userid = user._id; // Add user id
command.remoteaddr = (req.ip.startsWith('::ffff:')) ? (req.ip.substring(7)) : req.ip; // User's IP address
parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
}
}
@ -214,7 +218,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (parent.parent.multiServer == null) {
var targets = ['*', 'server-users'];
if (obj.user.groups) { for (var i in obj.user.groups) { targets.push('server-users:' + i); } }
parent.parent.DispatchEvent(targets, obj, { action: 'wssessioncount', username: user.name, count: parent.wssessions[user._id].length, nolog: 1, domain: domain.id });
parent.parent.DispatchEvent(targets, obj, { action: 'wssessioncount', userid: user._id, username: user.name, count: parent.wssessions[user._id].length, nolog: 1, domain: domain.id });
} else {
parent.recountSessions(ws.sessionId); // Recount sessions
}
@ -835,14 +839,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
break;
}
case 'clearevents':
{
// Delete all events
if (user.siteadmin != 0xFFFFFFFF) break;
db.RemoveAllEvents(domain.id);
parent.parent.DispatchEvent(['*', 'server-global'], obj, { action: 'clearevents', nolog: 1, domain: domain.id });
break;
}
case 'users':
{
// Request a list of all users
@ -885,7 +881,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
parent.db.SetUser(user);
// Event the change
var message = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', domain: domain.id };
var message = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', domain: domain.id };
if (db.changeStream) { message.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
if (oldemail != null) {
message.msg = 'Changed email of user ' + user.name + ' from ' + oldemail + ' to ' + user.email;
@ -994,7 +990,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; parent.db.Set(common.escapeLinksFieldName(mesh)); }
// Notify mesh change
change = 'Removed user ' + deluser.name + ' from group ' + mesh.name;
var event = { etype: 'mesh', username: user.name, userid: user._id, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id };
var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come.
parent.parent.DispatchEvent(['*', mesh._id, deluser._id, user._id], obj, event);
}
@ -1115,9 +1111,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var event, targets = ['*', 'server-users'];
if (newuser.groups) { for (var i in newuser.groups) { targets.push('server-users:' + i); } }
if (newuser.email == null) {
event = { etype: 'user', username: newuser.name, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, username is ' + newuser.name, domain: domain.id };
event = { etype: 'user', userid: newuser._id, username: newuser.name, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, username is ' + newuser.name, domain: domain.id };
} else {
event = { etype: 'user', username: newuser.name, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, email is ' + newuser.email, domain: domain.id };
event = { etype: 'user', userid: newuser._id, username: newuser.name, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, email is ' + newuser.email, domain: domain.id };
}
if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
@ -1202,9 +1198,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var event, targets = ['*', 'server-users'];
if (newuser.groups) { for (var i in newuser.groups) { targets.push('server-users:' + i); } }
if (command.email == null) {
event = { etype: 'user', username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, username is ' + command.username, domain: domain.id };
event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, username is ' + command.username, domain: domain.id };
} else {
event = { etype: 'user', username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, email is ' + command.email.toLowerCase(), domain: domain.id };
event = { etype: 'user', userid: newuser._id, username: newusername, account: parent.CloneSafeUser(newuser), action: 'accountcreate', msg: 'Account created, email is ' + command.email.toLowerCase(), domain: domain.id };
}
if (parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
@ -1285,7 +1281,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var targets = ['*', 'server-users', user._id, chguser._id];
if (allTargetGroups) { for (var i in allTargetGroups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Account changed: ' + chguser.name, domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Account changed: ' + chguser.name, domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
}
@ -1324,7 +1320,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Notify change
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Mesh notification change.', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Mesh notification change.', domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
@ -1361,7 +1357,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var targets = ['*', 'server-users'];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Account password changed: ' + user.name, domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Account password changed: ' + user.name, domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
@ -1411,7 +1407,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var targets = ['*', 'server-users', user._id, chguser._id];
if (chguser.groups) { for (var i in chguser.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Changed account credentials.', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Changed account credentials.', domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
} else {
@ -1561,12 +1557,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Event the user change
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', domain: domain.id, nolog: 1 };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', domain: domain.id, nolog: 1 };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
// Event the device group creation
var event = { etype: 'mesh', username: user.name, meshid: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, action: 'createmesh', links: links, msg: 'Mesh created: ' + command.meshname, domain: domain.id };
var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: meshid, name: command.meshname, mtype: command.meshtype, desc: command.desc, action: 'createmesh', links: links, msg: 'Mesh created: ' + command.meshname, domain: domain.id };
parent.parent.DispatchEvent(['*', meshid, user._id], obj, event); // Even if DB change stream is active, this event must be acted upon.
try { ws.send(JSON.stringify({ action: 'createmesh', responseid: command.responseid, result: 'ok', meshid: meshid })); } catch (ex) { }
@ -1598,7 +1594,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (err != null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deletemesh', responseid: command.responseid, result: err })); } catch (ex) { } } return; }
// Fire the removal event first, because after this, the event will not route
var event = { etype: 'mesh', username: user.name, meshid: command.meshid, name: command.meshname, action: 'deletemesh', msg: 'Mesh deleted: ' + command.meshname, domain: domain.id };
var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: command.meshid, name: command.meshname, action: 'deletemesh', msg: 'Mesh deleted: ' + command.meshname, domain: domain.id };
parent.parent.DispatchEvent(['*', command.meshid], obj, event); // Even if DB change stream is active, this event need to be acted on.
// Remove all user links to this mesh
@ -1647,7 +1643,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if ((common.validateInt(command.consent) == true) && (command.consent != mesh.consent)) { if (change != '') change += ' and consent changed'; else change += 'Group "' + mesh.name + '" consent changed'; mesh.consent = command.consent; }
if (change != '') {
db.Set(common.escapeLinksFieldName(mesh));
var event = { etype: 'mesh', username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, flags: mesh.flags, consent: mesh.consent, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id };
var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, flags: mesh.flags, consent: mesh.consent, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come.
parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, event);
}
@ -1797,7 +1793,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
db.Set(common.escapeLinksFieldName(mesh));
var amtpolicy2 = common.Clone(amtpolicy);
delete amtpolicy2.password;
var event = { etype: 'mesh', username: user.name, meshid: mesh._id, amt: amtpolicy2, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id };
var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, amt: amtpolicy2, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come.
parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, event);
@ -1845,7 +1841,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Event the new node
var device2 = common.Clone(device);
delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'node', username: user.name, action: 'addnode', node: device2, msg: 'Added device ' + command.devicename + ' to mesh ' + mesh.name, domain: domain.id });
parent.parent.DispatchEvent(['*', command.meshid], obj, { etype: 'node', userid: user._id, username: user.name, action: 'addnode', node: device2, msg: 'Added device ' + command.devicename + ' to mesh ' + mesh.name, domain: domain.id });
});
}
break;
@ -1909,7 +1905,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Event the node change
var newMesh = parent.meshes[command.meshid];
var event = { etype: 'node', username: user.name, action: 'nodemeshchange', nodeid: node._id, node: node, oldMeshId: oldMeshId, newMeshId: command.meshid, msg: 'Moved device ' + node.name + ' to group ' + newMesh.name, domain: domain.id };
var event = { etype: 'node', userid: user._id, username: user.name, action: 'nodemeshchange', nodeid: node._id, node: node, oldMeshId: oldMeshId, newMeshId: command.meshid, msg: 'Moved device ' + node.name + ' to group ' + newMesh.name, domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come.
parent.parent.DispatchEvent(['*', oldMeshId, command.meshid], obj, event);
});
@ -1950,7 +1946,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
});
// Event node deletion
var event = { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from group ' + mesh.name, domain: domain.id };
var event = { etype: 'node', userid: user._id, username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from group ' + mesh.name, domain: domain.id };
// TODO: We can't use the changeStream for node delete because we will not know the meshid the device was in.
//if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to remove the node. Another event will come.
parent.parent.DispatchEvent(['*', node.meshid], obj, event);
@ -2080,7 +2076,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Get the mesh for this device
mesh = parent.meshes[node.meshid];
if (mesh) {
// Check if this user has rights to do this
if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
@ -2088,7 +2083,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
var agent = parent.wsagents[node._id];
if (agent != null) {
// Send the power command
try { agent.send(JSON.stringify({ action: 'toast', title: command.title, msg: command.msg })); } catch (ex) { }
try { agent.send(JSON.stringify({ action: 'toast', title: command.title, msg: command.msg, sessionid: ws.sessionId, username: user.name, userid: user._id })); } catch (ex) { }
}
}
}
@ -2143,7 +2138,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
// Ready the node change event
var changes = [], event = { etype: 'node', username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
var changes = [], event = { etype: 'node', userid: user._id, username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
change = 0;
event.msg = ": ";
@ -2405,7 +2400,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Notify change
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added authentication application.', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added authentication application.', domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
} else {
@ -2428,7 +2423,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Notify change
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Removed authentication application.', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Removed authentication application.', domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
} else {
@ -2467,7 +2462,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Notify change
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
break;
@ -2502,7 +2497,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Notify change
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Removed security key.', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Removed security key.', domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
break;
@ -2552,7 +2547,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Notify change TODO: Should be done on all sessions/servers for this user.
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
} else {
@ -2605,7 +2600,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Notify change
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.parent.DispatchEvent(targets, obj, event);
} else {

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.3.8-s",
"version": "0.3.8-t",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -837,7 +837,7 @@ NoMeshesPanel img {
color: gray;
}
#p3events {
#p3events, #p16events, #p31events {
height: calc(100vh - 245px);
overflow-y: scroll;
}
@ -848,12 +848,6 @@ NoMeshesPanel img {
padding: 0;
}
.p3eventsTable {
width: 100%;
border-spacing: 0;
padding: 0;
}
#p4name, #p4email, #p4pass1, #p4pass2 {
width: 230px;
}
@ -1360,6 +1354,14 @@ a {
float: left;
}
.si5 {
background: url(../images/icons16.png) -80px 0px;
height: 16px;
width: 16px;
border: none;
float: left;
}
.mi {
background: url(../images/meshicon50.png) 0px 0px;
height: 50px;
@ -1582,6 +1584,14 @@ a {
float: none;
}
#p16events .g1 {
float: none;
}
#p31events .g1 {
float: none;
}
#p3users .g1 {
height: 24px;
float: left;
@ -1617,6 +1627,14 @@ a {
float: none;
}
#p16events .g2 {
float: none;
}
#p31events .g2 {
float: none;
}
#p3users .g2 {
height: 24px;
float: right;
@ -2288,6 +2306,7 @@ a {
width: calc(100vw - 120px);
}
/*
#p16events, #p31events {
max-height: calc(100vh - 245px);
overflow-y: auto;
@ -2296,6 +2315,7 @@ a {
.room4submenu #p16events, #p31events {
max-height: calc(100vh - 269px);
}
*/
.night #p16events, #p31events {
color: #222;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1063,11 +1063,6 @@
}
break;
}
case 'clearevents': {
//events = [];
//events_update();
break;
}
case 'login': {
// Update the last login time
if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) { users['user/' + domain + '/' + message.event.username.toLowerCase()].login = message.event.time; }

View File

@ -286,7 +286,6 @@
<table class="pTable">
<tr>
<td class="h1"></td>
<td>&nbsp;<input id="p2deleteall" type=button onclick=showDeleteAllEventsDialog() style="display:none" value="Delete All..." /></td>
<td class="auto-style1">
Show
<select id=p3limitdropdown onchange=refreshEvents()>
@ -762,7 +761,7 @@
<td class="h2"></td>
</tr>
</table>
<div id=p31events></div>
<div id=p31events style=""></div>
</div>
<div id=p40 style="display:none;">
<h1>My Server Stats</h1>
@ -1263,7 +1262,6 @@
if (xxcurrentView == 4 || ((xxcurrentView >= 30) && (xxcurrentView < 40))) { setDialogMode(0); go(1); currentUser = null; }
}
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
QV('p2deleteall', userinfo.siteadmin == 0xFFFFFFFF);
QV('ServerConsole', userinfo.siteadmin === 0xFFFFFFFF);
if ((xxcurrentView == 115) && (userinfo.siteadmin != 0xFFFFFFFF)) { go(6); }
if ((xxcurrentView == 6) && ((userinfo.siteadmin & 21) == 0)) { go(1); }
@ -1689,6 +1687,23 @@
}
case 'event': {
if (!message.event.nolog) {
if (currentNode && (message.event.nodeid == currentNode._id)) {
// If this event has a nodeid and we are looking at this node, update the log in real time.
currentDeviceEvents.unshift(message.event);
var eventLimit = parseInt(p16limitdropdown.value);
while (currentDeviceEvents.length > eventLimit) { currentDeviceEvents.pop(); } // Remove element(s) at the end
masterUpdate(1024);
}
if (currentUser && (message.event.userid == currentUser._id)) {
// If this event has a userid and we are looking at this user, update the log in real time.
currentUserEvents.unshift(message.event);
var eventLimit = parseInt(p31limitdropdown.value);
while (currentUserEvents.length > eventLimit) { currentUserEvents.pop(); } // Remove element(s) at the end
masterUpdate(2048);
}
// Add this event to the master events log.
events.unshift(message.event);
var eventLimit = parseInt(p3limitdropdown.value);
while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
@ -2001,11 +2016,6 @@
}
break;
}
case 'clearevents': {
events = [];
masterUpdate(32);
break;
}
case 'login': {
// Update the last login time
if (users != null && users['user/' + domain + '/' + message.event.username.toLowerCase()]) {
@ -4147,6 +4157,7 @@
function deviceUrlFunction() {
if (xxdialogMode) return;
setDialogMode(2, "Open Page on Device", 3, deviceUrlFunctionEx, '<input id=d2devurl placeholder="http://server.com" style=width:100%;overflow-y:scroll></input>');
Q('d2devurl').focus();
}
function deviceUrlFunctionEx() {
@ -4156,6 +4167,7 @@
function deviceToastFunction() {
if (xxdialogMode) return;
setDialogMode(2, "Device Notification", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
Q('d2devToast').focus();
}
function deviceToastFunctionEx() {
@ -5830,50 +5842,56 @@
function deviceEventsUpdate() {
var x = '', dateHeader = null;
for (var i in currentDeviceEvents) {
var event = currentDeviceEvents[i];
var time = new Date(event.time);
if (printDate(time) != dateHeader) {
if (dateHeader != null) x += '</table>';
dateHeader = printDate(time);
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td class=DevSt colspan=4>' + dateHeader + '</td></tr>';
}
var icon = 'si3';
if (event.etype == 'user') icon = 'm2';
if (event.etype == 'server') icon = 'si3';
var event = currentDeviceEvents[i], time = new Date(event.time);
if (event.msg) {
if (event.h == null) { event.h = Math.random(); }
if (printDate(time) != dateHeader) {
if (dateHeader != null) x += '</table>';
dateHeader = printDate(time);
x += '<table class=p3eventsTable cellpadding=0 cellspacing=0><tr><td colspan=4 class=DevSt>' + dateHeader + '</td></tr>';
}
var icon = 'si3';
if (event.etype == 'user') icon = 'm2';
if (event.etype == 'server') icon = 'si3';
var msg = event.msg.split('(R)').join('&reg;');
//if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
x += '<tr><td style=width:18px><div class=' + icon + '></div></td><td class=g1 style=float:none>&nbsp;</td><td style=background-color:#C9C9C9>' + printTime(time) + ' - ' + msg + '</td><td class=g2 style=float:none>&nbsp;</td></tr><tr style=height:2px></tr>';
var msg = event.msg.split('(R)').join('&reg;');
if (event.username) {
if ((userinfo.siteadmin & 2) && (event.userid)) {
msg = '<a href=# onclick=\'gotoUser("' + encodeURIComponent(event.userid) + '");haltEvent(event);\'>' + event.username + '</a> &rarr; ' + msg;
} else {
msg = event.username + ' &rarr; ' + msg;
}
}
x += '<tr onclick=showEventDetails(' + event.h + ',1) onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1>&nbsp;</td><td class=style10>' + printTime(time) + ' - ' + msg + '</td><td class=g2>&nbsp;</td></tr><tr style=height:2px></tr>';
}
}
if (dateHeader != null) x += '</table>';
if (x == '') x = "<br><i>No Events Found</i><br><br>";
QH('p16events', x);
}
/*
function showDeleteAllEventsDialog() {
if (xxdialogMode) return;
var x = "Delete all events in the server event log?<br /><br />";
x += "<input id=p3check type=checkbox onchange=validateDeleteAllEventsDialog() />Confirm";
setDialogMode(2, "Delete All Events", 3, showDeleteAllEventsDialogEx, x);
validateDeleteAllEventsDialog();
}
function validateDeleteAllEventsDialog() {
QE('idx_dlgOkButton', Q('p3check').checked);
}
function showDeleteAllEventsDialogEx(buttons, tag) {
meshserver.send({ action: 'clearevents' });
}
*/
function refreshDeviceEvents() {
//currentDeviceEvents = null;
//QH('p16events', '');
meshserver.send({ action: 'events', nodeid: currentNode._id, limit: parseInt(p16limitdropdown.value) });
}
function showEventDetails(h, mode) {
var eventList, xevent;
if (mode == 1) { eventList = currentDeviceEvents; }
if (mode == 2) { eventList = events; }
if (mode == 3) { eventList = currentUserEvents; }
for (var i in eventList) { if (eventList[i].h == h) { xevent = eventList[i]; break; } }
if (xevent) {
if (xxdialogMode) return false;
var x = '<div style=overflow-y:auto>';
for (var i in xevent) {
if ((i == 'h') || (i == '_id') || (i == 'ids') || (i == 'domain') || (xevent[i] == null) || (typeof xevent[i] == 'object')) continue;
x += addHtmlValue3(EscapeHtml(i), EscapeHtml(xevent[i]));
}
x += '</div>';
setDialogMode(2, "Event Details", 9, null, x);
}
}
//
// CONSOLE
//
@ -7206,6 +7224,7 @@
for (var i in events) {
var event = events[i], time = new Date(event.time);
if (event.msg) {
if (event.h == null) { event.h = Math.random(); }
if (printDate(time) != dateHeader) {
if (dateHeader != null) x += '</table>';
dateHeader = printDate(time);
@ -7216,8 +7235,21 @@
if (event.etype == 'server') icon = 'si3';
var msg = event.msg.split('(R)').join('&reg;');
if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
x += '<tr onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1>&nbsp;</td><td class=style10>' + printTime(time) + ' - ' + msg + '</td><td class=g2>&nbsp;</td></tr><tr style=height:2px></tr>';
if (event.nodeid) {
var node = getNodeFromId(event.nodeid);
if (node != null) {
icon = 'si' + node.icon;
msg = '<a href=# onclick=\'gotoDevice("' + event.nodeid + '",10);haltEvent(event);\'>' + node.name + '</a> &rarr; ' + msg;
}
}
if (event.username) {
if ((userinfo.siteadmin & 2) && (event.userid)) {
msg = '<a href=# onclick=\'gotoUser("' + encodeURIComponent(event.userid) + '");haltEvent(event);\'>' + event.username + '</a> &rarr; ' + msg;
} else {
msg = event.username + ' &rarr; ' + msg;
}
}
x += '<tr onclick=showEventDetails(' + event.h + ',2) onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1>&nbsp;</td><td class=style10>' + printTime(time) + ' - ' + msg + '</td><td class=g2>&nbsp;</td></tr><tr style=height:2px></tr>';
}
}
if (dateHeader != null) x += '</table>';
@ -7225,22 +7257,6 @@
QH('p3events', x);
}
function showDeleteAllEventsDialog() {
if (xxdialogMode) return;
var x = "Delete all events in the server event log?<br /><br />";
x += "<label><input id=p3check type=checkbox onchange=validateDeleteAllEventsDialog() />Confirm</label>";
setDialogMode(2, "Delete All Events", 3, showDeleteAllEventsDialogEx, x);
validateDeleteAllEventsDialog();
}
function validateDeleteAllEventsDialog() {
QE('idx_dlgOkButton', Q('p3check').checked);
}
function showDeleteAllEventsDialogEx(buttons, tag) {
meshserver.send({ action: 'clearevents' });
}
function refreshEvents() {
meshserver.send({ action: 'events', limit: parseInt(p3limitdropdown.value) });
}
@ -7902,23 +7918,35 @@
function userEventsUpdate() {
var x = '', dateHeader = null;
for (var i in currentUserEvents) {
var event = currentUserEvents[i];
var time = new Date(event.time);
if (printDate(time) != dateHeader) {
if (dateHeader != null) x += '</table>';
dateHeader = printDate(time);
x += '<table style=width:100% cellpadding=0 cellspacing=0><tr><td class=DevSt>' + dateHeader + '</td></tr>';
}
var icon = 'si3';
if (event.etype == 'user') icon = 'm2';
if (event.etype == 'server') icon = 'si3';
var event = currentUserEvents[i], time = new Date(event.time);
if (event.msg) {
if (event.h == null) { event.h = Math.random(); }
if (printDate(time) != dateHeader) {
if (dateHeader != null) x += '</table>';
dateHeader = printDate(time);
x += '<table class=p3eventsTable cellpadding=0 cellspacing=0><tr><td colspan=4 class=DevSt>' + dateHeader + '</td></tr>';
}
var icon = 'si3';
if (event.etype == 'user') icon = 'm2';
if (event.etype == 'server') icon = 'si3';
var msg = event.msg.split('(R)').join('&reg;');
if (event.username && event.username != userinfo.name) { msg += ': ' + event.username; }
x += '<tr><td><div class=bar18 style=height:18px;width:100%;font-size:medium>';
x += '<div style=float:left;height:18px;width:18px;background-color:white><div class=' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
x += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
x += '<div style=font-size:14px><span style=width:300px>' + printTime(time) + ' - ' + msg + '</span></div></div></td></tr>';
var msg = event.msg.split('(R)').join('&reg;');
if (event.nodeid) {
var node = getNodeFromId(event.nodeid);
if (node != null) {
icon = 'si' + node.icon;
msg = '<a href=# onclick=\'gotoDevice("' + event.nodeid + '",10);haltEvent(event);\'>' + node.name + '</a> &rarr; ' + msg;
}
}
if (event.username && (event.username != currentUser.name)) {
if ((userinfo.siteadmin & 2) && (event.userid)) {
msg = '<a href=# onclick=\'gotoUser("' + encodeURIComponent(event.userid) + '");haltEvent(event);\'>' + event.username + '</a> &rarr; ' + msg;
} else {
msg = event.username + ' &rarr; ' + msg;
}
}
x += '<tr onclick=showEventDetails(' + event.h + ',3) onmouseover=eventMouseHover(this,1) onmouseout=eventMouseHover(this,0) style=cursor:pointer><td style=width:18px><div class=' + icon + '></div></td><td class=g1>&nbsp;</td><td class=style10>' + printTime(time) + ' - ' + msg + '</td><td class=g2>&nbsp;</td></tr><tr style=height:2px></tr>';
}
}
if (dateHeader != null) x += '</table>';
if (x == '') x = "<br><i>No Events Found</i><br><br>";
@ -8516,6 +8544,7 @@
//function addHtmlValue(t, v) { return '<div style=height:20px><div style=float:right;width:220px><b>' + v + '</b></div><div>' + t + '</div></div>'; }
function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
function addHtmlValue3(t, v) { return '<div><b>' + t + '</b></div><div style=margin-left:16px>' + v + '</div>'; }
function parseUriArgs() { var name, r = {}, parsedUri = window.document.location.href.split(/[\?&|\=]/); parsedUri.splice(0, 1); for (x in parsedUri) { switch (x % 2) { case 0: { name = decodeURIComponent(parsedUri[x]); break; } case 1: { r[name] = decodeURIComponent(parsedUri[x]); var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } default: { break; } } } return r; }
function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version

File diff suppressed because one or more lines are too long

View File

@ -319,7 +319,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (user.name != username) {
user.name = username;
obj.db.SetUser(user);
var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id };
var event = { etype: 'user', userid: userid, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id };
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
}
@ -365,7 +365,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (usercount == 0) { user.siteadmin = 4294967295; /*if (domain.newaccounts === 2) { delete domain.newaccounts; }*/ } // If this is the first user, give the account site admin.
obj.users[user._id] = user;
obj.db.SetUser(user);
var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, name is ' + name, domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, name is ' + name, domain: domain.id };
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
obj.parent.DispatchEvent(['*', 'server-users'], obj, event);
return fn(null, user._id);
@ -375,7 +375,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (user.name != username) {
user.name = username;
obj.db.SetUser(user);
var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id };
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
}
@ -495,7 +495,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Destroy the user's session to log them out will be re-created next request
if (req.session.userid) {
var user = obj.users[req.session.userid];
if (user != null) { obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id }); }
if (user != null) { obj.parent.DispatchEvent(['*'], obj, { etype: 'user', userid: user._id, username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id }); }
}
req.session = null;
res.redirect(domain.url);
@ -697,7 +697,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Notify account login
var targets = ['*', 'server-users'];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
obj.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'login', msg: 'Account login', domain: domain.id });
obj.parent.DispatchEvent(targets, obj, { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'login', msg: 'Account login', domain: domain.id });
// Regenerate session when signing in to prevent fixation
//req.session.regenerate(function () {
@ -824,7 +824,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Send the verification email
if ((obj.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (obj.common.validateEmail(user.email, 1, 256) == true)) { obj.parent.mailserver.sendAccountCheckMail(domain, user.name, user.email); }
}, 0);
var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, email is ' + req.body.email, domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountcreate', msg: 'Account created, email is ' + req.body.email, domain: domain.id };
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
obj.parent.DispatchEvent(['*', 'server-users'], obj, event);
}
@ -886,7 +886,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
user.passchange = Math.floor(Date.now() / 1000);
delete user.passtype;
obj.db.SetUser(user);
var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'User password reset', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'User password reset', domain: domain.id };
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
@ -1030,7 +1030,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.db.SetUser(user);
// Event the change
var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + EscapeHtml(user.email) + ')', domain: domain.id };
var event = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + EscapeHtml(user.email) + ')', domain: domain.id };
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
@ -1065,7 +1065,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.db.SetUser(userinfo);
// Event the change
var event = { etype: 'user', username: userinfo.name, account: obj.CloneSafeUser(userinfo), action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id };
var event = { etype: 'user', userid: user._id, username: userinfo.name, account: obj.CloneSafeUser(userinfo), action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id };
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
@ -1134,7 +1134,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (mesh.links[userid] != null) { delete mesh.links[userid]; obj.db.Set(obj.common.escapeLinksFieldName(mesh)); }
// Notify mesh change
var change = 'Removed user ' + user.name + ' from group ' + mesh.name;
obj.parent.DispatchEvent(['*', mesh._id, user._id, userid], obj, { etype: 'mesh', username: user.name, userid: userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id });
obj.parent.DispatchEvent(['*', mesh._id, user._id, userid], obj, { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id });
}
}
}
@ -1147,7 +1147,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
delete obj.users[user._id];
req.session = null;
res.redirect(domain.url + getQueryPortion(req));
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: user._id, username: user.name, action: 'accountremove', msg: 'Account removed', domain: domain.id });
} else {
res.redirect(domain.url + getQueryPortion(req));
}
@ -1206,7 +1206,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.db.SetUser(user);
req.session.viewmode = 2;
res.redirect(domain.url + getQueryPortion(req));
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', username: user.name, action: 'passchange', msg: 'Account password changed: ' + user.name, domain: domain.id });
obj.parent.DispatchEvent(['*', 'server-users'], obj, { etype: 'user', userid: user._id, username: user.name, action: 'passchange', msg: 'Account password changed: ' + user.name, domain: domain.id });
}, 0);
}
});
@ -1291,7 +1291,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (usercount == 0) { user2.siteadmin = 4294967295; } // If this is the first user, give the account site admin.
obj.users[req.session.userid] = user2;
obj.db.SetUser(user2);
var event = { etype: 'user', username: req.connection.user, account: obj.CloneSafeUser(user2), action: 'accountcreate', msg: 'Domain account created, user ' + req.connection.user, domain: domain.id };
var event = { etype: 'user', userid: req.session.userid, username: req.connection.user, account: obj.CloneSafeUser(user2), action: 'accountcreate', msg: 'Domain account created, user ' + req.connection.user, domain: domain.id };
if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to create the user. Another event will come.
obj.parent.DispatchEvent(['*', 'server-users'], obj, event);
}
@ -3311,7 +3311,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (u) {
var targets = ['*', 'server-users'];
if (u.groups) { for (var i in u.groups) { targets.push('server-users:' + i); } }
obj.parent.DispatchEvent(targets, obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 });
obj.parent.DispatchEvent(targets, obj, { action: 'wssessioncount', userid: userid, username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 });
}
}
}
@ -3325,7 +3325,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (u) {
var targets = ['*', 'server-users'];
if (u.groups) { for (var i in u.groups) { targets.push('server-users:' + i); } }
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 })
obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', userid: userid, username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 })
}
}
}
@ -3350,7 +3350,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (u) {
var targets = ['*', 'server-users'];
if (u.groups) { for (var i in u.groups) { targets.push('server-users:' + i); } }
obj.parent.DispatchEvent(targets, obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 });
obj.parent.DispatchEvent(targets, obj, { action: 'wssessioncount', userid: userid, username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 });
obj.sessionsCount[userid] = newcount;
}
}