Added MongoDB change stream support.

Ylian Saint-Hilaire committed May 28, 2019 at 17:25 UTC 8416b0a0aafe5356e9b86504ebacc9021530613e
9 files changed +122 -36
amtscanner.js
+1
@@ -335,6 +335,7 @@ module.exports.CreateAmtScanner = function (parent) {
335 var node2 = obj.parent.common.Clone(node);
336 if (node2.intelamt && node2.intelamt.pass) delete node2.intelamt.pass; // Remove the Intel AMT password before eventing this.
337 event.node = node2;
338 + if (obj.parent.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
339 obj.parent.DispatchEvent(['*', node.meshid], obj, event);
340 }
341 });
db.js
+37 -8
@@ -33,6 +33,7 @@ module.exports.CreateDB = function (parent, func) {
33 var expireServerStatsSeconds = (60 * 60 * 24 * 30); // By default, expire power events after 30 days. (Seconds * Minutes * Hours * Days)
34 obj.identifier = null;
35 obj.dbKey = null;
36 + obj.changeStream = false;
37
38 obj.SetupDatabase = function (func) {
39 // Check if the database unique identifier is present
@@ -228,14 +229,18 @@ module.exports.CreateDB = function (parent, func) {
229 }
230 });
231
231 - /*
232 - // Setup the changeStream on the MongoDB main collection
233 - obj.fileChangeStream = obj.file.watch({ fullDocument: 'updateLookup' });
234 - obj.fileChangeStream.on('change', function (next) {
235 - // Process next document
236 - console.log('change', next);
237 - });
238 - */
232 + // Setup the changeStream on the MongoDB main collection if possible
233 + try {
234 + obj.fileChangeStream = obj.file.watch([{ $match: { 'fullDocument.type': { $in: [ 'node', 'mesh', 'user' ] } } }], { fullDocument: 'updateLookup' });
235 + obj.fileChangeStream.on('change', function (change) {
236 + switch (change.fullDocument.type) {
237 + case 'node': { dbNodeChange(change); break; } // A node has changed
238 + case 'mesh': { dbMeshChange(change); break; } // A device group has changed
239 + case 'user': { dbUserChange(change); break; } // A user account has changed
240 + }
241 + });
242 + obj.changeStream = true;
243 + } catch (ex) { }
244
245 // Setup MongoDB events collection and indexes
246 obj.eventsfile = db.collection('events'); // Collection containing all events
@@ -767,5 +772,29 @@ module.exports.CreateDB = function (parent, func) {
772
773 function padNumber(number, digits) { return Array(Math.max(digits - String(number).length + 1, 0)).join(0) + number; }
774
775 + // Called when a node has changed
776 + function dbNodeChange(nodeChange) {
777 + const node = nodeChange.fullDocument;
778 + if (node.intelamt && node.intelamt.pass) { delete node.intelamt.pass; } // Remove the Intel AMT password before eventing this.
779 + parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', action: 'changenode', node: node, nodeid: node._id, domain: node.domain, nolog: 1 });
780 + }
781 +
782 + // Called when a device group has changed
783 + function dbMeshChange(meshChange) {
784 + const mesh = meshChange.fullDocument;
785 + mesh.action = 'meshchange';
786 + mesh.meshid = mesh._id;
787 + mesh.nolog = 1;
788 + delete mesh.type;
789 + delete mesh._id;
790 + parent.DispatchEvent(['*', mesh._id], obj, mesh);
791 + }
792 +
793 + // Called when a user account has changed
794 + function dbUserChange(userChange) {
795 + const user = userChange.fullDocument;
796 + parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: parent.webserver.CloneSafeUser(user), action: 'accountchange', domain: user.domain, nolog: 1 });
797 + }
798 +
799 return obj;
800 };
\ No newline at end of file
meshagent.js
+4
@@ -714,6 +714,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
714 const device2 = common.Clone(device);
715 if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
716 event.node = device;
717 + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
718 parent.parent.DispatchEvent(['*', device.meshid], obj, event);
719 }
720 }
@@ -1296,6 +1297,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1297 var device2 = common.Clone(device);
1298 if (device2.intelamt && device2.intelamt.pass) { delete device2.intelamt.pass; } // Remove the Intel AMT password before eventing this.
1299 event.node = device;
1300 + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1301 parent.parent.DispatchEvent(['*', device.meshid], obj, event);
1302 }
1303 }
@@ -1339,6 +1341,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1341 var device2 = common.Clone(device);
1342 if (device2.intelamt && device2.intelamt.pass) { delete device2.intelamt.pass; } // Remove the Intel AMT password before eventing this.
1343 event.node = device;
1344 + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1345 parent.parent.DispatchEvent(['*', device.meshid], obj, event);
1346 }
1347 }
@@ -1370,6 +1373,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1373 var device2 = common.Clone(device);
1374 if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
1375 event.node = device;
1376 + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1377 parent.parent.DispatchEvent(['*', device.meshid], obj, event);
1378 }
1379 }
meshuser.js
+55 -17
@@ -598,6 +598,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
598 }
599 case 'info': {
600 var info = process.memoryUsage();
601 + info.dbType = ['None','NeDB','MongoJS','MongoDB'][parent.db.databaseType];
602 + if (parent.db.databaseType == 3) { info.dbChangeStream = parent.db.changeStream; }
603 try { info.platform = process.platform; } catch (ex) { }
604 try { info.arch = process.arch; } catch (ex) { }
605 try { info.pid = process.pid; } catch (ex) { }
@@ -841,6 +843,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
843
844 // Event the change
845 var message = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', domain: domain.id };
846 + 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.
847 if (oldemail != null) {
848 message.msg = 'Changed email of user ' + user.name + ' from ' + oldemail + ' to ' + user.email;
849 } else {
@@ -930,7 +933,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
933 if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; parent.db.Set(mesh); }
934 // Notify mesh change
935 change = 'Removed user ' + deluser.name + ' from group ' + mesh.name;
933 - parent.parent.DispatchEvent(['*', mesh._id, deluser._id, user._id], obj, { 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 });
936 + 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 };
937 + 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.
938 + parent.parent.DispatchEvent(['*', mesh._id, deluser._id, user._id], obj, event);
939 }
940 }
941 }
@@ -1160,7 +1165,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1165
1166 var targets = ['*', 'server-users', user._id, chguser._id];
1167 if (allTargetGroups) { for (var i in allTargetGroups) { targets.push('server-users:' + i); } }
1163 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Account changed: ' + chguser.name, domain: domain.id });
1168 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Account changed: ' + chguser.name, domain: domain.id };
1169 + 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.
1170 + parent.parent.DispatchEvent(targets, obj, event);
1171 }
1172 if ((chguser.siteadmin) && (chguser.siteadmin != 0xFFFFFFFF) && (chguser.siteadmin & 32)) {
1173 // If the user is locked out of this account, disconnect now
@@ -1201,7 +1208,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1208
1209 var targets = ['*', 'server-users'];
1210 if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
1204 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Account password changed: ' + user.name, domain: domain.id });
1211 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Account password changed: ' + user.name, domain: domain.id };
1212 + 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.
1213 + parent.parent.DispatchEvent(targets, obj, event);
1214
1215 // Send user notification of password change
1216 displayNotificationMessage('Password changed.', 'Account Settings', 'ServerNotify');
@@ -1249,7 +1258,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1258
1259 var targets = ['*', 'server-users', user._id, chguser._id];
1260 if (chguser.groups) { for (var i in chguser.groups) { targets.push('server-users:' + i); } }
1252 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Changed account credentials.', domain: domain.id });
1261 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(chguser), action: 'accountchange', msg: 'Changed account credentials.', domain: domain.id };
1262 + 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.
1263 + parent.parent.DispatchEvent(targets, obj, event);
1264 } else {
1265 // Report that the password change failed
1266 // TODO
@@ -1447,7 +1458,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1458 if ((common.validateString(command.desc, 0, 1024) == true) && (command.desc != mesh.desc)) { if (change != '') change += ' and description changed'; else change += 'Group "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
1459 if ((common.validateInt(command.flags) == true) && (command.flags != mesh.flags)) { if (change != '') change += ' and flags changed'; else change += 'Group "' + mesh.name + '" flags changed'; mesh.flags = command.flags; }
1460 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; }
1450 - if (change != '') { db.Set(common.escapeLinksFieldName(mesh)); parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { 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 }); }
1461 + if (change != '') {
1462 + db.Set(common.escapeLinksFieldName(mesh));
1463 + 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 };
1464 + 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.
1465 + parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, event);
1466 + }
1467 }
1468 break;
1469 }
@@ -1483,7 +1499,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1499 db.Set(common.escapeLinksFieldName(mesh));
1500
1501 // Notify mesh change
1486 - parent.parent.DispatchEvent(['*', mesh._id, user._id, newuserid], obj, { etype: 'mesh', username: newuser.name, userid: command.userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Added user ' + newuser.name + ' to mesh ' + mesh.name, domain: domain.id });
1502 + var event = { etype: 'mesh', username: newuser.name, userid: command.userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Added user ' + newuser.name + ' to mesh ' + mesh.name, domain: domain.id };
1503 + 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.
1504 + parent.parent.DispatchEvent(['*', mesh._id, user._id, newuserid], obj, event);
1505 }
1506 break;
1507 }
@@ -1518,11 +1536,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1536 db.Set(common.escapeLinksFieldName(mesh));
1537
1538 // Notify mesh change
1539 + var event;
1540 if (deluser != null) {
1522 - parent.parent.DispatchEvent(['*', mesh._id, user._id, command.userid], obj, { etype: 'mesh', username: user.name, userid: deluser.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Removed user ' + deluser.name + ' from group ' + mesh.name, domain: domain.id });
1541 + event = { etype: 'mesh', username: user.name, userid: deluser.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Removed user ' + deluser.name + ' from group ' + mesh.name, domain: domain.id };
1542 } else {
1524 - parent.parent.DispatchEvent(['*', mesh._id, user._id, command.userid], obj, { 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 });
1543 + 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 };
1544 }
1545 + 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.
1546 + parent.parent.DispatchEvent(['*', mesh._id, user._id, command.userid], obj, event);
1547 }
1548 }
1549 break;
@@ -1553,7 +1574,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1574 if (command.amtpolicy.type === 2) { amtpolicy = { type: command.amtpolicy.type, password: command.amtpolicy.password, badpass: command.amtpolicy.badpass, cirasetup: command.amtpolicy.cirasetup }; }
1575 mesh.amt = amtpolicy;
1576 db.Set(common.escapeLinksFieldName(mesh));
1556 - parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { etype: 'mesh', username: user.name, meshid: mesh._id, amt: amtpolicy, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id });
1577 + var event = { etype: 'mesh', username: user.name, meshid: mesh._id, amt: amtpolicy, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id };
1578 + 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.
1579 + parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, event);
1580
1581 // Send new policy to all computers on this mesh
1582 //routeCommandToMesh(command.meshid, { action: 'amtPolicy', amtPolicy: amtpolicy });
@@ -1663,7 +1686,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1686
1687 // Event the node change
1688 var newMesh = parent.meshes[command.meshid];
1666 - parent.parent.DispatchEvent(['*', oldMeshId, command.meshid], obj, { 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 });
1689 + 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 };
1690 + 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.
1691 + parent.parent.DispatchEvent(['*', oldMeshId, command.meshid], obj, event);
1692 });
1693 }
1694 break;
@@ -1931,11 +1956,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1956 // Save the node
1957 db.Set(node);
1958
1934 - // Event the node change
1959 + // Event the node change. Only do this if the database will not do it.
1960 event.msg = 'Changed device ' + node.name + ' from group ' + mesh.name + ': ' + changes.join(', ');
1961 var node2 = common.Clone(node);
1962 if (node2.intelamt && node2.intelamt.pass) delete node2.intelamt.pass; // Remove the Intel AMT password before eventing this.
1963 event.node = node2;
1964 + if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
1965 parent.parent.DispatchEvent(['*', node.meshid], obj, event);
1966 }
1967 }
@@ -2138,7 +2164,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2164 // Notify change
2165 var targets = ['*', 'server-users', user._id];
2166 if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
2141 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added authentication application.', domain: domain.id });
2167 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added authentication application.', domain: domain.id };
2168 + 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.
2169 + parent.parent.DispatchEvent(targets, obj, event);
2170 } else {
2171 ws.send(JSON.stringify({ action: 'otpauth-setup', success: false })); // Report fail
2172 }
@@ -2159,7 +2187,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2187 // Notify change
2188 var targets = ['*', 'server-users', user._id];
2189 if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
2162 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Removed authentication application.', domain: domain.id });
2190 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Removed authentication application.', domain: domain.id };
2191 + 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.
2192 + parent.parent.DispatchEvent(targets, obj, event);
2193 } else {
2194 ws.send(JSON.stringify({ action: 'otpauth-clear', success: false })); // Report fail
2195 }
@@ -2196,7 +2226,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2226 // Notify change
2227 var targets = ['*', 'server-users', user._id];
2228 if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
2199 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id });
2229 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
2230 + 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.
2231 + parent.parent.DispatchEvent(targets, obj, event);
2232 break;
2233 }
2234 case 'otp-hkey-get':
@@ -2229,7 +2261,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2261 // Notify change
2262 var targets = ['*', 'server-users', user._id];
2263 if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
2232 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Removed security key.', domain: domain.id });
2264 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Removed security key.', domain: domain.id };
2265 + 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.
2266 + parent.parent.DispatchEvent(targets, obj, event);
2267 break;
2268 }
2269 case 'otp-hkey-yubikey-add':
@@ -2277,7 +2311,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2311 // Notify change TODO: Should be done on all sessions/servers for this user.
2312 var targets = ['*', 'server-users', user._id];
2313 if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
2280 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id });
2314 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
2315 + 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.
2316 + parent.parent.DispatchEvent(targets, obj, event);
2317 } else {
2318 ws.send(JSON.stringify({ action: 'otp-hkey-yubikey-add', result: false, name: command.name }));
2319 }
@@ -2328,7 +2364,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2364 // Notify change
2365 var targets = ['*', 'server-users', user._id];
2366 if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
2331 - parent.parent.DispatchEvent(targets, obj, { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id });
2367 + var event = { etype: 'user', username: user.name, account: parent.CloneSafeUser(user), action: 'accountchange', msg: 'Added security key.', domain: domain.id };
2368 + 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.
2369 + parent.parent.DispatchEvent(targets, obj, event);
2370 } else {
2371 //console.log('webauthn-endregister-error', regResult.error);
2372 ws.send(JSON.stringify({ action: 'otp-hkey-setup-response', result: false, error: regResult.error, name: command.name, index: keyIndex }));
mpsserver.js
+1
@@ -776,6 +776,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
776 var node2 = common.Clone(node);
777 if (node2.intelamt && node2.intelamt.pass) delete node2.intelamt.pass; // Remove the Intel AMT password before eventing this.
778 event.node = node2;
779 + if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
780 obj.parent.DispatchEvent(['*', node.meshid], obj, event);
781 });
782 });
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.3.5-i",
3 + "version": "0.3.5-j",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
views/default-mobile.handlebars
+1
@@ -799,6 +799,7 @@
799 events_update();
800 }
801 */
802 + if (message.event.noact) break; // Take no action on this event
803 switch (message.event.action) {
804 case 'accountchange': {
805 // An account was created or changed
views/default.handlebars
+4 -3
@@ -1624,6 +1624,7 @@
1624 while (events.length > eventLimit) { events.pop(); } // Remove element(s) at the end
1625 masterUpdate(32);
1626 }
1627 + if (message.event.noact) break; // Take no action on this event
1628 switch (message.event.action) {
1629 case 'userWebState': {
1630 // New user web state, update the web page as needed
@@ -1670,7 +1671,7 @@
1671 }
1672 if (users == null) break;
1673
1673 - // Check if the account if part of our user group
1674 + // Check if the account is part of our user group
1675 if ((userinfo.groups == null) || (userinfo.groups.length == 0) || (findOne(message.event.account.groups, userinfo.groups) == true)) {
1676 users[message.event.account._id] = message.event.account; // Part of our groups, update this user.
1677 } else {
@@ -1704,8 +1705,8 @@
1705 meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
1706 } else {
1707 // This is an existing mesh
1707 - if (message.event.name) { meshes[message.event.meshid].name = message.event.name; }
1708 - if (message.event.desc) { meshes[message.event.meshid].desc = message.event.desc; }
1708 + if (message.event.name != null) { meshes[message.event.meshid].name = message.event.name; }
1709 + if (message.event.desc != null) { meshes[message.event.meshid].desc = message.event.desc; }
1710 if (message.event.flags != null) { meshes[message.event.meshid].flags = message.event.flags; }
1711 if (message.event.consent != null) { meshes[message.event.meshid].consent = message.event.consent; }
1712 if (message.event.links) { meshes[message.event.meshid].links = message.event.links; }
webserver.js
+18 -7
@@ -316,8 +316,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
316 // If the display username has changes, update it.
317 if (user.name != username) {
318 user.name = username;
319 - db.SetUser(user);
320 - parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id });
319 + obj.db.SetUser(user);
320 + var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id };
321 + 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.
322 + parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
323 }
324 // If user is locker out, block here.
325 if ((user.siteadmin) && (user.siteadmin != 0xFFFFFFFF) && (user.siteadmin & 32) != 0) { fn('locked'); return; }
@@ -368,8 +370,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
370 // If the display username has changes, update it.
371 if (user.name != username) {
372 user.name = username;
371 - db.SetUser(user);
372 - parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id });
373 + obj.db.SetUser(user);
374 + var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'Changed account display name to ' + username, domain: domain.id };
375 + 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.
376 + parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
377 }
378 // If user is locker out, block here.
379 if ((user.siteadmin) && (user.siteadmin != 0xFFFFFFFF) && (user.siteadmin & 32) != 0) { fn('locked'); return; }
@@ -870,7 +874,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
874 user.passchange = Math.floor(Date.now() / 1000);
875 delete user.passtype;
876 obj.db.SetUser(user);
873 - obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'User password reset', domain: domain.id });
877 + var event = { etype: 'user', username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', msg: 'User password reset', domain: domain.id };
878 + 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.
879 + obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
880
881 // Login succesful
882 req.session.userid = userid;
@@ -995,7 +1001,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1001 obj.db.SetUser(user);
1002
1003 // Event the change
998 - obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { 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 });
1004 + 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 };
1005 + 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.
1006 + obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
1007
1008 // Send the confirmation page
1009 res.render(obj.path.join(obj.parent.webViewsPath, 'message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' });
@@ -1028,7 +1036,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1036 obj.db.SetUser(userinfo);
1037
1038 // Event the change
1031 - obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: obj.CloneSafeUser(userinfo), action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id });
1039 + var event = { etype: 'user', username: userinfo.name, account: obj.CloneSafeUser(userinfo), action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id };
1040 + 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.
1041 + obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
1042
1043 // Send the new password
1044 res.render(obj.path.join(obj.parent.webViewsPath, 'message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', domainurl: domain.url, message: '<div>Password for account <b>' + EscapeHtml(user.name) + '</b> has been reset to:</div><div style=padding:14px;font-size:18px><b>' + EscapeHtml(newpass) + '</b></div>Login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' });
@@ -2169,6 +2179,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2179 var node2 = obj.common.Clone(node);
2180 if (node2.intelamt && node2.intelamt.pass) delete node2.intelamt.pass; // Remove the Intel AMT password before eventing this.
2181 event.node = node2;
2182 + if (obj.db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
2183 obj.parent.DispatchEvent(['*', node.meshid], obj, event);
2184 }
2185 }