Added support fo domain MaxDevices limit

Ylian Saint-Hilaire committed Jun 5, 2019 at 15:24 UTC 0a62aa8ae395b37ace74f12d1dbedd4fbe64281c
8 files changed +219 -124
db.js
+2 -2
@@ -549,7 +549,7 @@ module.exports.CreateDB = function (parent, func) {
549 // TODO: Starting in MongoDB 4.0.3, you should use countDocuments() instead of count() that is deprecated. We should detect MongoDB version and switch.
550 // https://docs.mongodb.com/manual/reference/method/db.collection.countDocuments/
551 //obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.countDocuments({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } }
552 - obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } }
552 + obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max), count); }); } }
553
554 // Database actions on the events collection
555 obj.GetAllEvents = function (func) { obj.eventsfile.find({}).toArray(func); };
@@ -638,7 +638,7 @@ module.exports.CreateDB = function (parent, func) {
638 obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
639 obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); };
640 obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); };
641 - obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max)); }); } }
641 + obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { obj.file.count({ type: type, domain: domainid }, function (err, count) { func((err != null) || (count > max), count); }); } }
642
643 // Database actions on the events collection
644 obj.GetAllEvents = function (func) { obj.eventsfile.find({}, func); };
meshagent.js
+113 -89
@@ -616,40 +616,21 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
616 if ((nodes == null) || (nodes.length == 0)) {
617 // This device does not exist, use the meshid given by the device
618
619 - // See if this mesh exists, if it does not we may want to create it.
620 - mesh = getMeshAutoCreate();
621 -
622 - // Check if the mesh exists
623 - if (mesh == null) {
624 - // If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
625 - parent.agentStats.invalidDomainMeshCount++;
626 - console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddrport + ', ' + obj.dbMeshKey + ').');
627 - return;
628 - }
629 -
630 - // Check if the mesh is the right type
631 - if (mesh.mtype != 2) {
632 - // If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
633 - parent.agentStats.invalidMeshTypeCount++;
634 - console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddrport + ').');
635 - return;
636 - }
637 -
638 - // Mark when this device connected
639 - obj.connectTime = Date.now();
640 - db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime, addr: obj.remoteaddrport });
641 -
642 - // This node does not exist, create it.
643 - device = { type: 'node', mtype: mesh.mtype, _id: obj.dbNodeKey, icon: obj.agentInfo.platformType, meshid: obj.dbMeshKey, name: obj.agentInfo.computerName, rname: obj.agentInfo.computerName, domain: domain.id, agent: { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }, host: null };
644 - db.Set(device);
645 -
646 - // Event the new node
647 - if (obj.agentInfo.capabilities & 0x20) {
648 - // This is a temporary agent, don't log.
649 - parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 });
619 + // Check if we already have too many devices for this domain
620 + if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
621 + db.isMaxType(domain.limits.maxdevices, 'node', domain.id, function (ismax, count) {
622 + if (ismax == true) {
623 + // Too many devices in this domain.
624 + parent.agentStats.maxDomainDevicesReached++;
625 + } else {
626 + // We are under the limit, create the new device.
627 + completeAgentConnection2();
628 + }
629 + });
630 } else {
651 - parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: ('Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name), domain: domain.id });
631 + completeAgentConnection2();
632 }
633 + return;
634 } else {
635 device = nodes[0];
636
@@ -715,76 +696,119 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
696 }
697 }
698
718 - // Check if this agent is already connected
719 - const dupAgent = parent.wsagents[obj.dbNodeKey];
720 - parent.wsagents[obj.dbNodeKey] = obj;
721 - if (dupAgent) {
722 - // Record duplicate agents
723 - if (parent.duplicateAgentsLog[obj.dbNodeKey] == null) {
724 - if (dupAgent.remoteaddr == obj.remoteaddr) {
725 - parent.duplicateAgentsLog[obj.dbNodeKey] = { name: device.name, group: mesh.name, ip: [obj.remoteaddr], count: 1 };
726 - } else {
727 - parent.duplicateAgentsLog[obj.dbNodeKey] = { name: device.name, group: mesh.name, ip: [obj.remoteaddr, dupAgent.remoteaddr], count: 1 };
728 - }
699 + completeAgentConnection3();
700 + });
701 + }
702 +
703 + function completeAgentConnection2(device) {
704 + // See if this mesh exists, if it does not we may want to create it.
705 + var mesh = getMeshAutoCreate();
706 +
707 + // Check if the mesh exists
708 + if (mesh == null) {
709 + // If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
710 + parent.agentStats.invalidDomainMeshCount++;
711 + console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddrport + ', ' + obj.dbMeshKey + ').');
712 + return;
713 + }
714 +
715 + // Check if the mesh is the right type
716 + if (mesh.mtype != 2) {
717 + // If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
718 + parent.agentStats.invalidMeshTypeCount++;
719 + console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddrport + ').');
720 + return;
721 + }
722 +
723 + // Mark when this device connected
724 + obj.connectTime = Date.now();
725 + db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime, addr: obj.remoteaddrport });
726 +
727 + // This node does not exist, create it.
728 + var device = { type: 'node', mtype: mesh.mtype, _id: obj.dbNodeKey, icon: obj.agentInfo.platformType, meshid: obj.dbMeshKey, name: obj.agentInfo.computerName, rname: obj.agentInfo.computerName, domain: domain.id, agent: { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }, host: null };
729 + db.Set(device);
730 +
731 + // Event the new node
732 + if (obj.agentInfo.capabilities & 0x20) {
733 + // This is a temporary agent, don't log.
734 + parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 });
735 + } else {
736 + parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: ('Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name), domain: domain.id });
737 + }
738 +
739 + completeAgentConnection3();
740 + }
741 +
742 + function completeAgentConnection3() {
743 + // Check if this agent is already connected
744 + const dupAgent = parent.wsagents[obj.dbNodeKey];
745 + parent.wsagents[obj.dbNodeKey] = obj;
746 + if (dupAgent) {
747 + // Record duplicate agents
748 + if (parent.duplicateAgentsLog[obj.dbNodeKey] == null) {
749 + if (dupAgent.remoteaddr == obj.remoteaddr) {
750 + parent.duplicateAgentsLog[obj.dbNodeKey] = { name: device.name, group: mesh.name, ip: [obj.remoteaddr], count: 1 };
751 } else {
730 - parent.duplicateAgentsLog[obj.dbNodeKey].name = device.name;
731 - parent.duplicateAgentsLog[obj.dbNodeKey].group = mesh.name;
732 - parent.duplicateAgentsLog[obj.dbNodeKey].count++;
733 - if (parent.duplicateAgentsLog[obj.dbNodeKey].ip.indexOf(obj.remoteaddr) == -1) { parent.duplicateAgentsLog[obj.dbNodeKey].ip.push(obj.remoteaddr); }
752 + parent.duplicateAgentsLog[obj.dbNodeKey] = { name: device.name, group: mesh.name, ip: [obj.remoteaddr, dupAgent.remoteaddr], count: 1 };
753 }
735 -
736 - // Close the duplicate agent
737 - parent.agentStats.duplicateAgentCount++;
738 - if (obj.nodeid != null) { parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); }
739 - dupAgent.close(3);
754 } else {
741 - // Indicate the agent is connected
742 - parent.parent.SetConnectivityState(obj.dbMeshKey, obj.dbNodeKey, obj.connectTime, 1, 1);
755 + parent.duplicateAgentsLog[obj.dbNodeKey].name = device.name;
756 + parent.duplicateAgentsLog[obj.dbNodeKey].group = mesh.name;
757 + parent.duplicateAgentsLog[obj.dbNodeKey].count++;
758 + if (parent.duplicateAgentsLog[obj.dbNodeKey].ip.indexOf(obj.remoteaddr) == -1) { parent.duplicateAgentsLog[obj.dbNodeKey].ip.push(obj.remoteaddr); }
759 }
760
745 - // We are done, ready to communicate with this agent
746 - delete obj.pendingCompleteAgentConnection;
747 - obj.authenticated = 2;
761 + // Close the duplicate agent
762 + parent.agentStats.duplicateAgentCount++;
763 + if (obj.nodeid != null) { parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); }
764 + dupAgent.close(3);
765 + } else {
766 + // Indicate the agent is connected
767 + parent.parent.SetConnectivityState(obj.dbMeshKey, obj.dbNodeKey, obj.connectTime, 1, 1);
768 + }
769
749 - // Check how many times this agent disconnected in the last few minutes.
750 - const disconnectCount = parent.wsagentsDisconnections[obj.nodeid];
751 - if (disconnectCount > 6) {
752 - console.log('Agent in big trouble: NodeId=' + obj.nodeid + ', IP=' + obj.remoteaddrport + ', Agent=' + obj.agentInfo.agentId + '.');
753 - // TODO: Log or do something to recover?
754 - return;
755 - }
770 + // We are done, ready to communicate with this agent
771 + delete obj.pendingCompleteAgentConnection;
772 + obj.authenticated = 2;
773
757 - // Command 4, inform mesh agent that it's authenticated.
758 - obj.send(common.ShortToStr(4));
774 + // Check how many times this agent disconnected in the last few minutes.
775 + const disconnectCount = parent.wsagentsDisconnections[obj.nodeid];
776 + if (disconnectCount > 6) {
777 + console.log('Agent in big trouble: NodeId=' + obj.nodeid + ', IP=' + obj.remoteaddrport + ', Agent=' + obj.agentInfo.agentId + '.');
778 + // TODO: Log or do something to recover?
779 + return;
780 + }
781
760 - if (disconnectCount > 4) {
761 - // Too many disconnections, this agent has issues. Just clear the core.
762 - obj.send(common.ShortToStr(10) + common.ShortToStr(0));
763 - //console.log('Agent in trouble: NodeId=' + obj.nodeid + ', IP=' + obj.remoteaddrport + ', Agent=' + obj.agentInfo.agentId + '.');
764 - // TODO: Log or do something to recover?
765 - return;
766 - }
782 + // Command 4, inform mesh agent that it's authenticated.
783 + obj.send(common.ShortToStr(4));
784
768 - // Not sure why, but in rare cases, obj.agentInfo is undefined here.
769 - if ((obj.agentInfo == null) || (typeof obj.agentInfo.capabilities != 'number')) { return; } // This is an odd case.
785 + if (disconnectCount > 4) {
786 + // Too many disconnections, this agent has issues. Just clear the core.
787 + obj.send(common.ShortToStr(10) + common.ShortToStr(0));
788 + //console.log('Agent in trouble: NodeId=' + obj.nodeid + ', IP=' + obj.remoteaddrport + ', Agent=' + obj.agentInfo.agentId + '.');
789 + // TODO: Log or do something to recover?
790 + return;
791 + }
792
771 - // Check if we need to make an native update check
772 - obj.agentExeInfo = parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
773 - const corename = parent.parent.meshAgentsArchitectureNumbers[obj.agentInfo.agentId].core;
774 - if (corename == null) { obj.send(common.ShortToStr(10) + common.ShortToStr(0)); } // MeshCommand_CoreModule, ask mesh agent to clear the core
793 + // Not sure why, but in rare cases, obj.agentInfo is undefined here.
794 + if ((obj.agentInfo == null) || (typeof obj.agentInfo.capabilities != 'number')) { return; } // This is an odd case.
795
776 - if ((obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) {
777 - // Ask the agent for it's executable binary hash
778 - obj.send(common.ShortToStr(12) + common.ShortToStr(0));
796 + // Check if we need to make an native update check
797 + obj.agentExeInfo = parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
798 + const corename = parent.parent.meshAgentsArchitectureNumbers[obj.agentInfo.agentId].core;
799 + if (corename == null) { obj.send(common.ShortToStr(10) + common.ShortToStr(0)); } // MeshCommand_CoreModule, ask mesh agent to clear the core
800 +
801 + if ((obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) {
802 + // Ask the agent for it's executable binary hash
803 + obj.send(common.ShortToStr(12) + common.ShortToStr(0));
804 + } else {
805 + // Check the mesh core, if the agent is capable of running one
806 + if (((obj.agentInfo.capabilities & 16) != 0) && (corename != null)) {
807 + obj.send(common.ShortToStr(11) + common.ShortToStr(0)); // Command 11, ask for mesh core hash.
808 } else {
780 - // Check the mesh core, if the agent is capable of running one
781 - if (((obj.agentInfo.capabilities & 16) != 0) && (corename != null)) {
782 - obj.send(common.ShortToStr(11) + common.ShortToStr(0)); // Command 11, ask for mesh core hash.
783 - } else {
784 - agentCoreIsStable(); // No updates needed, agent is ready to go.
785 - }
809 + agentCoreIsStable(); // No updates needed, agent is ready to go.
810 }
787 - });
811 + }
812 }
813
814 // Take a basic Intel AMT policy and add all server information to it, making it ready to send to this agent.
mpsserver.js
+90 -21
@@ -128,6 +128,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
128 var disconnectCommandCount = 0;
129 var socketClosedCount = 0;
130 var socketErrorCount = 0;
131 + var maxDomainDevicesReached = 0;
132
133 // Return statistics about this MPS server
134 obj.getStats = function () {
@@ -153,7 +154,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
154 channelCloseCount: channelCloseCount,
155 disconnectCommandCount: disconnectCommandCount,
156 socketClosedCount: socketClosedCount,
156 - socketErrorCount: socketErrorCount
157 + socketErrorCount: socketErrorCount,
158 + maxDomainDevicesReached : maxDomainDevicesReached
159 };
160 }
161
@@ -189,6 +191,11 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
191 var xx = socket.tag.clientCert.subject.O.split('/');
192 if (xx.length == 1) { meshid = xx[0]; } else { domainid = xx[0].toLowerCase(); meshid = xx[1]; }
193
194 + // Check the incoming domain
195 + var domain = obj.parent.config.domains[domainid];
196 + if (domain == null) { console.log('CIRA connection for invalid domain. meshid: ' + meshid); socket.end(); return; }
197 +
198 + socket.tag.domain = domain;
199 socket.tag.domainid = domainid;
200 socket.tag.meshid = 'mesh/' + domainid + '/' + meshid;
201 socket.tag.nodeid = 'node/' + domainid + '/' + require('crypto').createHash('sha384').update(common.hex2rstr(socket.tag.clientCert.modulus, 'binary')).digest('base64').replace(/\+/g, '@').replace(/\//g, '$');
@@ -203,16 +210,45 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
210 obj.db.Get(socket.tag.nodeid, function (err, nodes) {
211 if ((nodes == null) || (nodes.length !== 1)) {
212 if (mesh.mtype == 1) {
206 - // Node is not in the database, add it. Credentials will be empty until added by the user.
207 - var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: domainid, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
208 - obj.db.Set(device);
209 -
210 - // Event the new node
211 - addedTlsDeviceCount++;
212 - var device2 = common.Clone(device);
213 - if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
214 - var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
215 - obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
213 + // Check if we already have too many devices for this domain
214 + if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
215 + db.isMaxType(domain.limits.maxdevices, 'node', domain.id, function (ismax, count) {
216 + if (ismax == true) {
217 + // Too many devices in this domain.
218 + maxDomainDevicesReached++;
219 + console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
220 + socket.end();
221 + } else {
222 + // We are under the limit, create the new device.
223 + // Node is not in the database, add it. Credentials will be empty until added by the user.
224 + var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: domainid, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
225 + obj.db.Set(device);
226 +
227 + // Event the new node
228 + addedTlsDeviceCount++;
229 + var device2 = common.Clone(device);
230 + if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
231 + var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
232 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
233 +
234 + // Add the connection to the MPS connection list
235 + obj.ciraConnections[socket.tag.nodeid] = socket;
236 + obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
237 + }
238 + });
239 + return;
240 + } else {
241 + // Node is not in the database, add it. Credentials will be empty until added by the user.
242 + var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: domainid, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
243 + obj.db.Set(device);
244 +
245 + // Event the new node
246 + addedTlsDeviceCount++;
247 + var device2 = common.Clone(device);
248 + if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
249 + var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
250 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
251 + }
252 } else {
253 // New CIRA connection for unknown node, disconnect.
254 unknownTlsNodeCount++;
@@ -312,6 +348,9 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
348 // Intel AMT GUID (socket.tag.SystemId) will be used as NodeID
349 var systemid = socket.tag.SystemId.split('-').join('');
350 var nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
351 + var domain = obj.parent.config.domains[mesh.domain];
352 + socket.tag.domain = domain;
353 + socket.tag.domainid = mesh.domain;
354 socket.tag.name = '';
355 socket.tag.nodeid = 'node/' + mesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
356 socket.tag.meshid = mesh._id;
@@ -319,16 +358,46 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
358
359 obj.db.Get(socket.tag.nodeid, function (err, nodes) {
360 if ((nodes == null) || (nodes.length !== 1)) {
322 - // Node is not in the database, add it. Credentials will be empty until added by the user.
323 - var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
324 - obj.db.Set(device);
325 -
326 - // Event the new node
327 - addedDeviceCount++;
328 - var device2 = common.Clone(device);
329 - if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
330 - var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
331 - obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain });
361 + // Check if we already have too many devices for this domain
362 + if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
363 + db.isMaxType(domain.limits.maxdevices, 'node', mesh.domain, function (ismax, count) {
364 + if (ismax == true) {
365 + // Too many devices in this domain.
366 + maxDomainDevicesReached++;
367 + console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
368 + socket.end();
369 + } else {
370 + // We are under the limit, create the new device.
371 + // Node is not in the database, add it. Credentials will be empty until added by the user.
372 + var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
373 + obj.db.Set(device);
374 +
375 + // Event the new node
376 + addedDeviceCount++;
377 + var device2 = common.Clone(device);
378 + if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
379 + var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
380 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain });
381 +
382 + // Add the connection to the MPS connection list
383 + obj.ciraConnections[socket.tag.nodeid] = socket;
384 + obj.parent.SetConnectivityState(socket.tag.meshid, socket.tag.nodeid, socket.tag.connectTime, 2, 7); // TODO: Right now report power state as "present" (7) until we can poll.
385 + SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
386 + }
387 + });
388 + return;
389 + } else {
390 + // Node is not in the database, add it. Credentials will be empty until added by the user.
391 + var device = { type: 'node', mtype: 1, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: socket.tag.name, host: null, domain: mesh.domain, intelamt: { user: '', pass: '', tls: 0, state: 2 } };
392 + obj.db.Set(device);
393 +
394 + // Event the new node
395 + addedDeviceCount++;
396 + var device2 = common.Clone(device);
397 + if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
398 + var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
399 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain });
400 + }
401 } else {
402 // Node is already present
403 var node = nodes[0];
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.3.5-z",
3 + "version": "0.3.6-a",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
sample-config.json
+1
@@ -72,6 +72,7 @@
72 "__UserConsentFlags__" : "Set to: 1 for desktop, 2 for terminal, 3 for files, 7 for all",
73 "_UserConsentFlags" : 7,
74 "_Limits": {
75 + "_MaxDevices": 100,
76 "_MaxUserAccounts": 100,
77 "_MaxUserSessions": 100,
78 "_MaxAgentSessions": 100,
views/default-min.handlebars
+5 -5
@@ -10189,7 +10189,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
10189
10190 function addDeviceAttribute(name, value) { return '<tr><td class=style7>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
10191
10192 - function editDeviceAmtSettings(nodeid, func) {
10192 + function editDeviceAmtSettings(nodeid, func, arg) {
10193 if (xxdialogMode) return;
10194 var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
10195 if ((meshrights & 4) == 0) return;
@@ -10197,7 +10197,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
10197 x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
10198 x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
10199 if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
10200 - setDialogMode(2, "Edit Intel&reg; AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
10200 + setDialogMode(2, "Edit Intel&reg; AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func, arg: arg });
10201 if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
10202 Q('dp10tls').value = node.intelamt.tls;
10203 validateDeviceAmtSettings();
@@ -10220,7 +10220,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
10220 meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
10221 tag.node.intelamt.user = amtuser;
10222 tag.node.intelamt.tls = Q('dp10tls').value;
10223 - if (tag.func) { setTimeout(tag.func, 300); }
10223 + if (tag.func) { setTimeout(function () { tag.func(null, tag.arg); }, 300); }
10224 }
10225 }
10226
@@ -10519,7 +10519,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
10519 desktopNode = currentNode;
10520 if (contype == 2) {
10521 // Setup the Intel AMT remote desktop
10522 - if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
10522 + if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop, 2); return; }
10523 desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
10524 desktop.debugmode = debugmode;
10525 desktop.onStateChanged = onDesktopStateChange;
@@ -11111,7 +11111,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
11111 if (!terminal) {
11112 if (contype == 2) {
11113 // Setup the Intel AMT terminal
11114 - if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; }
11114 + if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal, 2); return; }
11115 var termoptions = {};
11116 if (Q('termSizeList').value == 2) { termoptions.width = 100; termoptions.height = 30; }
11117 terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term', termoptions), authCookie);
views/default.handlebars
+5 -5
@@ -4141,7 +4141,7 @@
4141
4142 function addDeviceAttribute(name, value) { return '<tr><td class=style7>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
4143
4144 - function editDeviceAmtSettings(nodeid, func) {
4144 + function editDeviceAmtSettings(nodeid, func, arg) {
4145 if (xxdialogMode) return;
4146 var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
4147 if ((meshrights & 4) == 0) return;
@@ -4149,7 +4149,7 @@
4149 x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
4150 x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
4151 if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
4152 - setDialogMode(2, "Edit Intel&reg; AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
4152 + setDialogMode(2, "Edit Intel&reg; AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func, arg: arg });
4153 if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
4154 Q('dp10tls').value = node.intelamt.tls;
4155 validateDeviceAmtSettings();
@@ -4172,7 +4172,7 @@
4172 meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
4173 tag.node.intelamt.user = amtuser;
4174 tag.node.intelamt.tls = Q('dp10tls').value;
4175 - if (tag.func) { setTimeout(tag.func, 300); }
4175 + if (tag.func) { setTimeout(function () { tag.func(null, tag.arg); }, 300); }
4176 }
4177 }
4178
@@ -4471,7 +4471,7 @@
4471 desktopNode = currentNode;
4472 if (contype == 2) {
4473 // Setup the Intel AMT remote desktop
4474 - if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
4474 + if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop, 2); return; }
4475 desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
4476 desktop.debugmode = debugmode;
4477 desktop.onStateChanged = onDesktopStateChange;
@@ -5063,7 +5063,7 @@
5063 if (!terminal) {
5064 if (contype == 2) {
5065 // Setup the Intel AMT terminal
5066 - if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; }
5066 + if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal, 2); return; }
5067 var termoptions = {};
5068 if (Q('termSizeList').value == 2) { termoptions.width = 100; termoptions.height = 30; }
5069 terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term', termoptions), authCookie);
webserver.js
+2 -1
@@ -261,7 +261,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
261 invalidMeshTypeCount: 0,
262 invalidDomainMesh2Count: 0,
263 invalidMeshType2Count: 0,
264 - duplicateAgentCount: 0
264 + duplicateAgentCount: 0,
265 + maxDomainDevicesReached: 0
266 }
267 obj.getAgentStats = function () { return obj.agentStats; }
268