If needed, auto-create missing device in agent group type when CIRA connects.

Ylian Saint-Hilaire committed Dec 1, 2021 at 01:46 UTC 2d3b1fe68abc5cca9bb539356061104e576abe90
3 files changed +104 -9
mpsserver.js
+87 -7
@@ -658,9 +658,10 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
658 // If this is a agent-less mesh, use the device guid 3 times as ID.
659 if (initialMesh.mtype == 1) {
660 // Intel AMT GUID (socket.tag.SystemId) will be used as NodeID
661 - var systemid = socket.tag.SystemId.split('-').join('');
662 - var nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
663 - var domain = obj.parent.config.domains[initialMesh.domain];
661 + const systemid = socket.tag.SystemId.split('-').join('');
662 + const nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
663 + const domain = obj.parent.config.domains[initialMesh.domain];
664 + if (domain == null) return;
665 socket.tag.domain = domain;
666 socket.tag.domainid = initialMesh.domain;
667 if (socket.tag.name == null) { socket.tag.name = ''; }
@@ -694,7 +695,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
695
696 // Event the new node
697 addedDeviceCount++;
697 - var change = 'CIRA added device ' + socket.tag.name + ' to group ' + initialMesh.name;
698 + var change = 'Added CIRA device ' + socket.tag.name + ' to group ' + initialMesh.name;
699 obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: initialMesh.domain });
700
701 // Add the connection to the MPS connection list
@@ -720,7 +721,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
721
722 // Event the new node
723 addedDeviceCount++;
723 - var change = 'CIRA added device ' + socket.tag.name + ' to group ' + initialMesh.name;
724 + var change = 'Added CIRA device ' + socket.tag.name + ' to group ' + initialMesh.name;
725 obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: initialMesh.domain });
726 });
727 }
@@ -740,10 +741,89 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
741 // Intel AMT GUID (socket.tag.SystemId) will be used to search the node
742 obj.db.getAmtUuidMeshNode(initialMesh.domain, initialMesh.mtype, socket.tag.SystemId, function (err, nodes) { // TODO: Need to optimize this request with indexes
743 if ((nodes == null) || (nodes.length === 0) || (obj.parent.webserver.meshes == null)) {
743 - // New CIRA connection for unknown node, disconnect.
744 + // New CIRA connection for unknown node, create a new device.
745 unknownNodeCount++;
746 console.log('CIRA connection for unknown node. groupid: ' + initialMesh._id + ', uuid: ' + socket.tag.SystemId);
746 - obj.close(socket);
747 + //obj.close(socket);
748 + //return;
749 + var domain = obj.parent.config.domains[initialMesh.domain];
750 + if (domain == null) return;
751 +
752 + // Check if we already have too many devices for this domain
753 + if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
754 + db.isMaxType(domain.limits.maxdevices, 'node', initialMesh.domain, function (ismax, count) {
755 + if (ismax == true) {
756 + // Too many devices in this domain.
757 + maxDomainDevicesReached++;
758 + console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
759 + obj.close(socket);
760 + } else {
761 + // Attempts reverse DNS loopup on the device IP address
762 + require('dns').reverse(socket.remoteAddr, function (err, hostnames) {
763 + var hostname = socket.remoteAddr;
764 + if ((err == null) && (hostnames != null) && (hostnames.length > 0)) { hostname = hostnames[0]; }
765 +
766 + // Set the device group
767 + socket.tag.meshid = initialMesh._id;
768 +
769 + const systemid = socket.tag.SystemId.split('-').join('');
770 + const nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
771 + socket.tag.domain = domain;
772 + socket.tag.domainid = initialMesh.domain;
773 + socket.tag.name = hostname;
774 + socket.tag.nodeid = 'node/' + initialMesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
775 + socket.tag.connectTime = Date.now();
776 +
777 + // Node is not in the database, add it. Credentials will be empty until added by the user.
778 + var device = { type: 'node', mtype: 2, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: hostname, icon: (socket.tag.meiState && socket.tag.meiState.isBatteryPowered) ? 2 : 1, host: hostname, domain: initialMesh.domain, intelamt: { user: ((socket.tag.meiState) && (typeof socket.tag.meiState.amtuser == 'string')) ? socket.tag.meiState.amtuser : '', pass: ((socket.tag.meiState) && (typeof socket.tag.meiState.amtpass == 'string')) ? socket.tag.meiState.amtpass : '', tls: 0, state: 2, agent: { id: 0, caps: 0 } } };
779 + if ((socket.tag.meiState != null) && (typeof socket.tag.meiState.desc == 'string') && (socket.tag.meiState.desc.length > 0) && (socket.tag.meiState.desc.length < 1024)) { device.desc = socket.tag.meiState.desc; }
780 + obj.db.Set(device);
781 +
782 + // Event the new node
783 + addedDeviceCount++;
784 + var change = 'Added CIRA device ' + socket.tag.name + ' to group ' + initialMesh.name;
785 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: initialMesh.domain });
786 +
787 + // Add the connection to the MPS connection list
788 + addCiraConnection(socket);
789 + SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
790 + });
791 + }
792 + });
793 + return;
794 + } else {
795 + // Attempts reverse DNS loopup on the device IP address
796 + require('dns').reverse(socket.remoteAddr, function (err, hostnames) {
797 + var hostname = socket.remoteAddr;
798 + if ((err == null) && (hostnames != null) && (hostnames.length > 0)) { hostname = hostnames[0]; }
799 +
800 + // Set the device group
801 + socket.tag.meshid = initialMesh._id;
802 +
803 + const systemid = socket.tag.SystemId.split('-').join('');
804 + const nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
805 + socket.tag.domain = domain;
806 + socket.tag.domainid = initialMesh.domain;
807 + socket.tag.name = hostname;
808 + socket.tag.nodeid = 'node/' + initialMesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
809 + socket.tag.connectTime = Date.now();
810 +
811 + // Node is not in the database, add it. Credentials will be empty until added by the user.
812 + var device = { type: 'node', mtype: 2, _id: socket.tag.nodeid, meshid: socket.tag.meshid, name: hostname, icon: (socket.tag.meiState && socket.tag.meiState.isBatteryPowered) ? 2 : 1, host: hostname, domain: initialMesh.domain, agent: { ver: 0, id: 0, caps: 0 }, intelamt: { uuid: socket.tag.SystemId, user: ((socket.tag.meiState) && (typeof socket.tag.meiState.amtuser == 'string')) ? socket.tag.meiState.amtuser : '', pass: ((socket.tag.meiState) && (typeof socket.tag.meiState.amtpass == 'string')) ? socket.tag.meiState.amtpass : '', tls: 0, state: 2 } };
813 + if ((socket.tag.meiState != null) && (typeof socket.tag.meiState.desc == 'string') && (socket.tag.meiState.desc.length > 0) && (socket.tag.meiState.desc.length < 1024)) { device.desc = socket.tag.meiState.desc; }
814 + obj.db.Set(device);
815 + console.log('ADDED', device);
816 +
817 + // Event the new node
818 + addedDeviceCount++;
819 + var change = 'Added CIRA device ' + socket.tag.name + ' to group ' + initialMesh.name;
820 + obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: parent.webserver.CloneSafeNode(device), msg: change, domain: initialMesh.domain });
821 +
822 + // Add the connection to the MPS connection list
823 + addCiraConnection(socket);
824 + SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
825 + });
826 + }
827 return;
828 }
829
package.json
+16 -2
@@ -36,6 +36,8 @@
36 "sample-config-advanced.json"
37 ],
38 "dependencies": {
39 + "@yetzt/nedb": "^1.8.0",
40 + "archiver": "^4.0.2",
41 "body-parser": "^1.19.0",
42 "cbor": "~5.2.0",
43 "compression": "^1.7.4",
@@ -43,13 +45,25 @@
45 "express": "^4.17.0",
46 "express-handlebars": "^3.1.0",
47 "express-ws": "^4.0.0",
48 + "image-size": "^1.0.0",
49 "ipcheck": "^0.1.0",
50 + "loadavg-windows": "^1.1.1",
51 "minimist": "^1.2.5",
52 + "mongodb": "^4.1.0",
53 "multiparty": "^4.2.1",
49 - "@yetzt/nedb": "^1.8.0",
54 "node-forge": "^0.10.0",
55 + "node-rdpjs-2": "^0.3.5",
56 + "node-windows": "^0.1.4",
57 + "nodemailer": "^6.7.2",
58 + "otplib": "^10.2.3",
59 + "pg": "^8.7.1",
60 + "pgtools": "^0.3.2",
61 + "saslprep": "^1.0.3",
62 + "ssh2": "^1.5.0",
63 + "web-push": "^3.4.5",
64 "ws": "^5.2.3",
52 - "yauzl": "^2.10.0"
65 + "yauzl": "^2.10.0",
66 + "yubikeyotp": "^0.2.0"
67 },
68 "engines": {
69 "node": ">=10.0.0"
views/default.handlebars
+1
@@ -2322,6 +2322,7 @@
2322 for (var m in message.nodes) {
2323 for (var n in message.nodes[m]) {
2324 if (message.nodes[m][n]._id == null) { console.log('Invalid node (' + n + '): ' + JSON.stringify(message.nodes)); continue; }
2325 + if (message.nodes[m][n].name == null) { message.nodes[m][n].name = '???'; }
2326 message.nodes[m][n].namel = message.nodes[m][n].name.toLowerCase();
2327 if (message.nodes[m][n].rname) { message.nodes[m][n].rnamel = message.nodes[m][n].rname.toLowerCase(); } else { message.nodes[m][n].rnamel = message.nodes[m][n].namel; }
2328 message.nodes[m][n].meshnamel = meshes[m]?meshes[m].name.toLowerCase():'*';