diff --git a/db.js b/db.js
index c0168354..50e3a0d3 100644
--- a/db.js
+++ b/db.js
@@ -31,6 +31,7 @@ module.exports.CreateDB = function (parent, func) {
var expireEventsSeconds = (60 * 60 * 24 * 20); // By default, expire events after 20 days. (Seconds * Minutes * Hours * Days)
var expirePowerEventsSeconds = (60 * 60 * 24 * 10); // By default, expire power events after 10 days. (Seconds * Minutes * Hours * Days)
var expireServerStatsSeconds = (60 * 60 * 24 * 30); // By default, expire power events after 30 days. (Seconds * Minutes * Hours * Days)
+ const common = require('./common.js');
obj.identifier = null;
obj.dbKey = null;
obj.changeStream = false;
@@ -851,6 +852,7 @@ module.exports.CreateDB = function (parent, func) {
// Called when a device group has changed
function dbMeshChange(meshChange, added) {
+ common.unEscapeLinksFieldName(meshChange.fullDocument);
const mesh = meshChange.fullDocument;
// Update the mesh object in memory
@@ -865,7 +867,7 @@ module.exports.CreateDB = function (parent, func) {
delete mesh.type;
delete mesh._id;
if (mesh.amt) { delete mesh.amt.password; } // Remove the Intel AMT password if present
- parent.DispatchEvent(['*', mesh._id], obj, mesh);
+ parent.DispatchEvent(['*', mesh.meshid], obj, mesh);
}
// Called when a user account has changed
diff --git a/meshuser.js b/meshuser.js
index 607c5548..7b16b027 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -566,7 +566,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
case 'help': {
r = 'Available commands: help, info, versions, args, resetserver, showconfig, usersessions, tasklimiter, setmaxtasks, cores,\r\n'
r += 'migrationagents, agentstats, webstats, mpsstats, swarmstats, acceleratorsstats, updatecheck, serverupdate, nodeconfig,\r\n';
- r += 'heapdump, relays, autobackup, backupconfig, dupagents.';
+ r += 'heapdump, relays, autobackup, backupconfig, dupagents, dispatchtable.';
+ break;
+ }
+ case 'dispatchtable': {
+ r = '';
+ for (var i in parent.parent.eventsDispatch) {
+ r += (i + ', ' + parent.parent.eventsDispatch[i].length + '\r\n');
+ }
break;
}
case 'dupagents': {
@@ -972,7 +979,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
mesh = parent.meshes[meshid];
if (mesh) {
// Remove user from the mesh
- if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; parent.db.Set(mesh); }
+ 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 };
@@ -1522,65 +1529,50 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
} catch (ex) { err = 'Validation exception: ' + ex; }
// Handle any errors
- if (err != null) {
- if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deletemesh', responseid: command.responseid, result: err })); } catch (ex) { } }
- break;
+ if (err != null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deletemesh', responseid: command.responseid, result: err })); } catch (ex) { } } break; }
+
+ // Get the device group reference we are going to delete
+ var mesh = parent.meshes[command.meshid];
+ if (mesh == null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deletemesh', responseid: command.responseid, result: 'Unknown device group' })); } catch (ex) { } } return; }
+
+ // Check if this user has rights to do this
+ var err = null;
+ if (mesh.links[user._id] == null || mesh.links[user._id].rights != 0xFFFFFFFF) { err = 'Access denied'; }
+ if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = 'Invalid group'; } // Invalid domain, operation only valid for current domain
+
+ // Handle any errors
+ 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 };
+ 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
+ for (var j in mesh.links) {
+ var xuser = parent.users[j];
+ if (xuser && xuser.links) {
+ delete xuser.links[mesh._id];
+ db.SetUser(xuser);
+ parent.parent.DispatchEvent([xuser._id], obj, 'resubscribe');
+ }
}
- db.Get(command.meshid, function (err, meshes) {
- if (meshes.length != 1) {
- if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deletemesh', responseid: command.responseid, result: 'Unknown device group' })); } catch (ex) { } }
- return;
- }
- var mesh = common.unEscapeLinksFieldName(meshes[0]);
+ // Delete all files on the server for this mesh
+ try {
+ var meshpath = parent.getServerRootFilePath(mesh);
+ if (meshpath != null) { parent.deleteFolderRec(meshpath); }
+ } catch (e) { }
- // Check if this user has rights to do this
- var err = null;
- if (mesh.links[user._id] == null || mesh.links[user._id].rights != 0xFFFFFFFF) { err = 'Access denied'; }
- if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = 'Invalid group'; } // Invalid domain, operation only valid for current domain
+ parent.parent.RemoveEventDispatchId(command.meshid); // Remove all subscriptions to this mesh
- // Handle any errors
- if (err != null) {
- if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deletemesh', responseid: command.responseid, result: err })); } catch (ex) { } }
- return;
- }
+ // Mark the mesh as deleted
+ mesh.deleted = new Date(); // Mark the time this mesh was deleted, we can expire it at some point.
+ db.Set(common.escapeLinksFieldName(mesh)); // We don't really delete meshes because if a device connects to is again, we will un-delete it.
- // 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 };
- parent.parent.DispatchEvent(['*', command.meshid], obj, event); // Even if DB change stream is active, this event need to be acted on.
+ // Delete all devices attached to this mesh in the database
+ db.RemoveMeshDocuments(command.meshid);
- // Remove all user links to this mesh
- for (i in meshes) {
- var links = meshes[i].links;
- for (var j in links) {
- var xuser = parent.users[j];
- if (xuser && xuser.links) {
- delete xuser.links[meshes[i]._id];
- db.SetUser(xuser);
- parent.parent.DispatchEvent([xuser._id], obj, 'resubscribe');
- }
- }
- }
-
- // Delete all files on the server for this mesh
- try {
- var meshpath = parent.getServerRootFilePath(mesh);
- if (meshpath != null) { parent.deleteFolderRec(meshpath); }
- } catch (e) { }
-
- parent.parent.RemoveEventDispatchId(command.meshid); // Remove all subscriptions to this mesh
-
- // Mark the mesh as deleted
- var dbmesh = meshes[0];
- dbmesh.deleted = new Date(); // Mark the time this mesh was deleted, we can expire it at some point.
- db.Set(common.escapeLinksFieldName(mesh)); // We don't really delete meshes because if a device connects to is again, we will up-delete it.
- parent.meshes[command.meshid] = mesh; // Update the mesh in memory;
-
- // Delete all devices attached to this mesh in the database
- db.RemoveMeshDocuments(command.meshid);
-
- if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deletemesh', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
- });
+ if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'deletemesh', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
break;
}
case 'editmesh':
@@ -1712,7 +1704,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
} else {
event = { etype: 'mesh', username: user.name, userid: (deluserid.split('/')[2]), meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Removed user ' + (deluserid.split('/')[2]) + ' from group ' + mesh.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(['*', mesh._id, user._id, command.userid], obj, event);
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'removemeshuser', responseid: command.responseid, result: 'ok' })); } catch (ex) { } }
} else {
diff --git a/public/commander.htm b/public/commander.htm
index 391547f0..f84132c9 100644
--- a/public/commander.htm
+++ b/public/commander.htm
@@ -1,4 +1,4 @@
-
Disconnected
Loading...
System Status
Hardware Information
Event Log
Network Settings
User Accounts
Serial-over-LAN Terminal
Intel® AMT Redirection port or Serial-over-LAN feature is disabled, click here to enable it.
Remote computer is not powered on, click here to issue a power command.
Remote Desktop
Intel® AMT Redirection port or KVM feature is disabled, click here to enable it.
Remote computer is not powered on, click here to issue a power command.
Audit Log
Security Settings
Internet Settings
System Defense
Agent Presence
Script Editor
Script
Compiled Script
Variables
Console
Storage
Event Subscriptions
Wake Alarms
Permission
Granted Permissions
*Minimum 8 characters with upper, lowercase, 0-9, and one of !@#$%^&*()+-
Warning:Some power actions may result in data loss and may disconnect the desktop, terminal or disk redirection sessions.
Consent Display
Image Encoding
Software KVM
Quality
Scaling
Not Required
Required for KVM only
Always Required
Authentication
Encryption
This will save the entire state of Intel® AMT for this machine into file. Passwords will not be saved, but some sensitive data may be included.
Disabled
ICMP response
RMCP response
ICMP & RMCP response
Dynamic DNS client
Defaut Interval is 1440 minutes, Default TTL is 900 seconds.
Remote Command
Boot Source
Boot Media Index
IDER Boot Device
Verbocity
After wake