Added support fo domain MaxDevices limit
This commit is contained in:
parent
184a95b3ce
commit
0a62aa8ae3
4
db.js
4
db.js
|
@ -549,7 +549,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
// TODO: Starting in MongoDB 4.0.3, you should use countDocuments() instead of count() that is deprecated. We should detect MongoDB version and switch.
|
// TODO: Starting in MongoDB 4.0.3, you should use countDocuments() instead of count() that is deprecated. We should detect MongoDB version and switch.
|
||||||
// https://docs.mongodb.com/manual/reference/method/db.collection.countDocuments/
|
// https://docs.mongodb.com/manual/reference/method/db.collection.countDocuments/
|
||||||
//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)); }); } }
|
//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)); }); } }
|
||||||
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)); }); } }
|
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); }); } }
|
||||||
|
|
||||||
// Database actions on the events collection
|
// Database actions on the events collection
|
||||||
obj.GetAllEvents = function (func) { obj.eventsfile.find({}).toArray(func); };
|
obj.GetAllEvents = function (func) { obj.eventsfile.find({}).toArray(func); };
|
||||||
|
@ -638,7 +638,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
|
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
|
||||||
obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); };
|
obj.getLocalAmtNodes = function (func) { obj.file.find({ type: 'node', host: { $exists: true, $ne: null }, intelamt: { $exists: true } }, func); };
|
||||||
obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); };
|
obj.getAmtUuidNode = function (meshid, uuid, func) { obj.file.find({ type: 'node', meshid: meshid, 'intelamt.uuid': uuid }, func); };
|
||||||
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)); }); } }
|
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); }); } }
|
||||||
|
|
||||||
// Database actions on the events collection
|
// Database actions on the events collection
|
||||||
obj.GetAllEvents = function (func) { obj.eventsfile.find({}, func); };
|
obj.GetAllEvents = function (func) { obj.eventsfile.find({}, func); };
|
||||||
|
|
226
meshagent.js
226
meshagent.js
|
@ -616,40 +616,21 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
if ((nodes == null) || (nodes.length == 0)) {
|
if ((nodes == null) || (nodes.length == 0)) {
|
||||||
// This device does not exist, use the meshid given by the device
|
// This device does not exist, use the meshid given by the device
|
||||||
|
|
||||||
// See if this mesh exists, if it does not we may want to create it.
|
// Check if we already have too many devices for this domain
|
||||||
mesh = getMeshAutoCreate();
|
if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
|
||||||
|
db.isMaxType(domain.limits.maxdevices, 'node', domain.id, function (ismax, count) {
|
||||||
// Check if the mesh exists
|
if (ismax == true) {
|
||||||
if (mesh == null) {
|
// Too many devices in this domain.
|
||||||
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
parent.agentStats.maxDomainDevicesReached++;
|
||||||
parent.agentStats.invalidDomainMeshCount++;
|
} else {
|
||||||
console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddrport + ', ' + obj.dbMeshKey + ').');
|
// We are under the limit, create the new device.
|
||||||
return;
|
completeAgentConnection2();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
// Check if the mesh is the right type
|
|
||||||
if (mesh.mtype != 2) {
|
|
||||||
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
|
||||||
parent.agentStats.invalidMeshTypeCount++;
|
|
||||||
console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddrport + ').');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark when this device connected
|
|
||||||
obj.connectTime = Date.now();
|
|
||||||
db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime, addr: obj.remoteaddrport });
|
|
||||||
|
|
||||||
// This node does not exist, create it.
|
|
||||||
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 };
|
|
||||||
db.Set(device);
|
|
||||||
|
|
||||||
// Event the new node
|
|
||||||
if (obj.agentInfo.capabilities & 0x20) {
|
|
||||||
// This is a temporary agent, don't log.
|
|
||||||
parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 });
|
|
||||||
} else {
|
} else {
|
||||||
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 });
|
completeAgentConnection2();
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
device = nodes[0];
|
device = nodes[0];
|
||||||
|
|
||||||
|
@ -715,78 +696,121 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this agent is already connected
|
completeAgentConnection3();
|
||||||
const dupAgent = parent.wsagents[obj.dbNodeKey];
|
|
||||||
parent.wsagents[obj.dbNodeKey] = obj;
|
|
||||||
if (dupAgent) {
|
|
||||||
// Record duplicate agents
|
|
||||||
if (parent.duplicateAgentsLog[obj.dbNodeKey] == null) {
|
|
||||||
if (dupAgent.remoteaddr == obj.remoteaddr) {
|
|
||||||
parent.duplicateAgentsLog[obj.dbNodeKey] = { name: device.name, group: mesh.name, ip: [obj.remoteaddr], count: 1 };
|
|
||||||
} else {
|
|
||||||
parent.duplicateAgentsLog[obj.dbNodeKey] = { name: device.name, group: mesh.name, ip: [obj.remoteaddr, dupAgent.remoteaddr], count: 1 };
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parent.duplicateAgentsLog[obj.dbNodeKey].name = device.name;
|
|
||||||
parent.duplicateAgentsLog[obj.dbNodeKey].group = mesh.name;
|
|
||||||
parent.duplicateAgentsLog[obj.dbNodeKey].count++;
|
|
||||||
if (parent.duplicateAgentsLog[obj.dbNodeKey].ip.indexOf(obj.remoteaddr) == -1) { parent.duplicateAgentsLog[obj.dbNodeKey].ip.push(obj.remoteaddr); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the duplicate agent
|
|
||||||
parent.agentStats.duplicateAgentCount++;
|
|
||||||
if (obj.nodeid != null) { parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); }
|
|
||||||
dupAgent.close(3);
|
|
||||||
} else {
|
|
||||||
// Indicate the agent is connected
|
|
||||||
parent.parent.SetConnectivityState(obj.dbMeshKey, obj.dbNodeKey, obj.connectTime, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are done, ready to communicate with this agent
|
|
||||||
delete obj.pendingCompleteAgentConnection;
|
|
||||||
obj.authenticated = 2;
|
|
||||||
|
|
||||||
// Check how many times this agent disconnected in the last few minutes.
|
|
||||||
const disconnectCount = parent.wsagentsDisconnections[obj.nodeid];
|
|
||||||
if (disconnectCount > 6) {
|
|
||||||
console.log('Agent in big trouble: NodeId=' + obj.nodeid + ', IP=' + obj.remoteaddrport + ', Agent=' + obj.agentInfo.agentId + '.');
|
|
||||||
// TODO: Log or do something to recover?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command 4, inform mesh agent that it's authenticated.
|
|
||||||
obj.send(common.ShortToStr(4));
|
|
||||||
|
|
||||||
if (disconnectCount > 4) {
|
|
||||||
// Too many disconnections, this agent has issues. Just clear the core.
|
|
||||||
obj.send(common.ShortToStr(10) + common.ShortToStr(0));
|
|
||||||
//console.log('Agent in trouble: NodeId=' + obj.nodeid + ', IP=' + obj.remoteaddrport + ', Agent=' + obj.agentInfo.agentId + '.');
|
|
||||||
// TODO: Log or do something to recover?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not sure why, but in rare cases, obj.agentInfo is undefined here.
|
|
||||||
if ((obj.agentInfo == null) || (typeof obj.agentInfo.capabilities != 'number')) { return; } // This is an odd case.
|
|
||||||
|
|
||||||
// Check if we need to make an native update check
|
|
||||||
obj.agentExeInfo = parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
|
|
||||||
const corename = parent.parent.meshAgentsArchitectureNumbers[obj.agentInfo.agentId].core;
|
|
||||||
if (corename == null) { obj.send(common.ShortToStr(10) + common.ShortToStr(0)); } // MeshCommand_CoreModule, ask mesh agent to clear the core
|
|
||||||
|
|
||||||
if ((obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) {
|
|
||||||
// Ask the agent for it's executable binary hash
|
|
||||||
obj.send(common.ShortToStr(12) + common.ShortToStr(0));
|
|
||||||
} else {
|
|
||||||
// Check the mesh core, if the agent is capable of running one
|
|
||||||
if (((obj.agentInfo.capabilities & 16) != 0) && (corename != null)) {
|
|
||||||
obj.send(common.ShortToStr(11) + common.ShortToStr(0)); // Command 11, ask for mesh core hash.
|
|
||||||
} else {
|
|
||||||
agentCoreIsStable(); // No updates needed, agent is ready to go.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function completeAgentConnection2(device) {
|
||||||
|
// See if this mesh exists, if it does not we may want to create it.
|
||||||
|
var mesh = getMeshAutoCreate();
|
||||||
|
|
||||||
|
// Check if the mesh exists
|
||||||
|
if (mesh == null) {
|
||||||
|
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
parent.agentStats.invalidDomainMeshCount++;
|
||||||
|
console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddrport + ', ' + obj.dbMeshKey + ').');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the mesh is the right type
|
||||||
|
if (mesh.mtype != 2) {
|
||||||
|
// If we disconnect, the agent will just reconnect. We need to log this or tell agent to connect in a few hours.
|
||||||
|
parent.agentStats.invalidMeshTypeCount++;
|
||||||
|
console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddrport + ').');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark when this device connected
|
||||||
|
obj.connectTime = Date.now();
|
||||||
|
db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime, addr: obj.remoteaddrport });
|
||||||
|
|
||||||
|
// This node does not exist, create it.
|
||||||
|
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 };
|
||||||
|
db.Set(device);
|
||||||
|
|
||||||
|
// Event the new node
|
||||||
|
if (obj.agentInfo.capabilities & 0x20) {
|
||||||
|
// This is a temporary agent, don't log.
|
||||||
|
parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 });
|
||||||
|
} else {
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
completeAgentConnection3();
|
||||||
|
}
|
||||||
|
|
||||||
|
function completeAgentConnection3() {
|
||||||
|
// Check if this agent is already connected
|
||||||
|
const dupAgent = parent.wsagents[obj.dbNodeKey];
|
||||||
|
parent.wsagents[obj.dbNodeKey] = obj;
|
||||||
|
if (dupAgent) {
|
||||||
|
// Record duplicate agents
|
||||||
|
if (parent.duplicateAgentsLog[obj.dbNodeKey] == null) {
|
||||||
|
if (dupAgent.remoteaddr == obj.remoteaddr) {
|
||||||
|
parent.duplicateAgentsLog[obj.dbNodeKey] = { name: device.name, group: mesh.name, ip: [obj.remoteaddr], count: 1 };
|
||||||
|
} else {
|
||||||
|
parent.duplicateAgentsLog[obj.dbNodeKey] = { name: device.name, group: mesh.name, ip: [obj.remoteaddr, dupAgent.remoteaddr], count: 1 };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parent.duplicateAgentsLog[obj.dbNodeKey].name = device.name;
|
||||||
|
parent.duplicateAgentsLog[obj.dbNodeKey].group = mesh.name;
|
||||||
|
parent.duplicateAgentsLog[obj.dbNodeKey].count++;
|
||||||
|
if (parent.duplicateAgentsLog[obj.dbNodeKey].ip.indexOf(obj.remoteaddr) == -1) { parent.duplicateAgentsLog[obj.dbNodeKey].ip.push(obj.remoteaddr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the duplicate agent
|
||||||
|
parent.agentStats.duplicateAgentCount++;
|
||||||
|
if (obj.nodeid != null) { parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); }
|
||||||
|
dupAgent.close(3);
|
||||||
|
} else {
|
||||||
|
// Indicate the agent is connected
|
||||||
|
parent.parent.SetConnectivityState(obj.dbMeshKey, obj.dbNodeKey, obj.connectTime, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are done, ready to communicate with this agent
|
||||||
|
delete obj.pendingCompleteAgentConnection;
|
||||||
|
obj.authenticated = 2;
|
||||||
|
|
||||||
|
// Check how many times this agent disconnected in the last few minutes.
|
||||||
|
const disconnectCount = parent.wsagentsDisconnections[obj.nodeid];
|
||||||
|
if (disconnectCount > 6) {
|
||||||
|
console.log('Agent in big trouble: NodeId=' + obj.nodeid + ', IP=' + obj.remoteaddrport + ', Agent=' + obj.agentInfo.agentId + '.');
|
||||||
|
// TODO: Log or do something to recover?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command 4, inform mesh agent that it's authenticated.
|
||||||
|
obj.send(common.ShortToStr(4));
|
||||||
|
|
||||||
|
if (disconnectCount > 4) {
|
||||||
|
// Too many disconnections, this agent has issues. Just clear the core.
|
||||||
|
obj.send(common.ShortToStr(10) + common.ShortToStr(0));
|
||||||
|
//console.log('Agent in trouble: NodeId=' + obj.nodeid + ', IP=' + obj.remoteaddrport + ', Agent=' + obj.agentInfo.agentId + '.');
|
||||||
|
// TODO: Log or do something to recover?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not sure why, but in rare cases, obj.agentInfo is undefined here.
|
||||||
|
if ((obj.agentInfo == null) || (typeof obj.agentInfo.capabilities != 'number')) { return; } // This is an odd case.
|
||||||
|
|
||||||
|
// Check if we need to make an native update check
|
||||||
|
obj.agentExeInfo = parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
|
||||||
|
const corename = parent.parent.meshAgentsArchitectureNumbers[obj.agentInfo.agentId].core;
|
||||||
|
if (corename == null) { obj.send(common.ShortToStr(10) + common.ShortToStr(0)); } // MeshCommand_CoreModule, ask mesh agent to clear the core
|
||||||
|
|
||||||
|
if ((obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) {
|
||||||
|
// Ask the agent for it's executable binary hash
|
||||||
|
obj.send(common.ShortToStr(12) + common.ShortToStr(0));
|
||||||
|
} else {
|
||||||
|
// Check the mesh core, if the agent is capable of running one
|
||||||
|
if (((obj.agentInfo.capabilities & 16) != 0) && (corename != null)) {
|
||||||
|
obj.send(common.ShortToStr(11) + common.ShortToStr(0)); // Command 11, ask for mesh core hash.
|
||||||
|
} else {
|
||||||
|
agentCoreIsStable(); // No updates needed, agent is ready to go.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Take a basic Intel AMT policy and add all server information to it, making it ready to send to this agent.
|
// Take a basic Intel AMT policy and add all server information to it, making it ready to send to this agent.
|
||||||
function completeIntelAmtPolicy(amtPolicy) {
|
function completeIntelAmtPolicy(amtPolicy) {
|
||||||
if (amtPolicy == null) return null;
|
if (amtPolicy == null) return null;
|
||||||
|
|
107
mpsserver.js
107
mpsserver.js
|
@ -128,6 +128,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
var disconnectCommandCount = 0;
|
var disconnectCommandCount = 0;
|
||||||
var socketClosedCount = 0;
|
var socketClosedCount = 0;
|
||||||
var socketErrorCount = 0;
|
var socketErrorCount = 0;
|
||||||
|
var maxDomainDevicesReached = 0;
|
||||||
|
|
||||||
// Return statistics about this MPS server
|
// Return statistics about this MPS server
|
||||||
obj.getStats = function () {
|
obj.getStats = function () {
|
||||||
|
@ -153,7 +154,8 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
channelCloseCount: channelCloseCount,
|
channelCloseCount: channelCloseCount,
|
||||||
disconnectCommandCount: disconnectCommandCount,
|
disconnectCommandCount: disconnectCommandCount,
|
||||||
socketClosedCount: socketClosedCount,
|
socketClosedCount: socketClosedCount,
|
||||||
socketErrorCount: socketErrorCount
|
socketErrorCount: socketErrorCount,
|
||||||
|
maxDomainDevicesReached : maxDomainDevicesReached
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +191,11 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
var xx = socket.tag.clientCert.subject.O.split('/');
|
var xx = socket.tag.clientCert.subject.O.split('/');
|
||||||
if (xx.length == 1) { meshid = xx[0]; } else { domainid = xx[0].toLowerCase(); meshid = xx[1]; }
|
if (xx.length == 1) { meshid = xx[0]; } else { domainid = xx[0].toLowerCase(); meshid = xx[1]; }
|
||||||
|
|
||||||
|
// Check the incoming domain
|
||||||
|
var domain = obj.parent.config.domains[domainid];
|
||||||
|
if (domain == null) { console.log('CIRA connection for invalid domain. meshid: ' + meshid); socket.end(); return; }
|
||||||
|
|
||||||
|
socket.tag.domain = domain;
|
||||||
socket.tag.domainid = domainid;
|
socket.tag.domainid = domainid;
|
||||||
socket.tag.meshid = 'mesh/' + domainid + '/' + meshid;
|
socket.tag.meshid = 'mesh/' + domainid + '/' + meshid;
|
||||||
socket.tag.nodeid = 'node/' + domainid + '/' + require('crypto').createHash('sha384').update(common.hex2rstr(socket.tag.clientCert.modulus, 'binary')).digest('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
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) {
|
||||||
obj.db.Get(socket.tag.nodeid, function (err, nodes) {
|
obj.db.Get(socket.tag.nodeid, function (err, nodes) {
|
||||||
if ((nodes == null) || (nodes.length !== 1)) {
|
if ((nodes == null) || (nodes.length !== 1)) {
|
||||||
if (mesh.mtype == 1) {
|
if (mesh.mtype == 1) {
|
||||||
// Node is not in the database, add it. Credentials will be empty until added by the user.
|
// Check if we already have too many devices for this domain
|
||||||
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 } };
|
if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
|
||||||
obj.db.Set(device);
|
db.isMaxType(domain.limits.maxdevices, 'node', domain.id, function (ismax, count) {
|
||||||
|
if (ismax == true) {
|
||||||
|
// Too many devices in this domain.
|
||||||
|
maxDomainDevicesReached++;
|
||||||
|
console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
|
||||||
|
socket.end();
|
||||||
|
} else {
|
||||||
|
// We are under the limit, create the new device.
|
||||||
|
// Node is not in the database, add it. Credentials will be empty until added by the user.
|
||||||
|
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 } };
|
||||||
|
obj.db.Set(device);
|
||||||
|
|
||||||
// Event the new node
|
// Event the new node
|
||||||
addedTlsDeviceCount++;
|
addedTlsDeviceCount++;
|
||||||
var device2 = common.Clone(device);
|
var device2 = common.Clone(device);
|
||||||
if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
||||||
var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
|
var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
|
||||||
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
|
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
|
||||||
|
|
||||||
|
// Add the connection to the MPS connection list
|
||||||
|
obj.ciraConnections[socket.tag.nodeid] = socket;
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Node is not in the database, add it. Credentials will be empty until added by the user.
|
||||||
|
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 } };
|
||||||
|
obj.db.Set(device);
|
||||||
|
|
||||||
|
// Event the new node
|
||||||
|
addedTlsDeviceCount++;
|
||||||
|
var device2 = common.Clone(device);
|
||||||
|
if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
||||||
|
var change = 'CIRA added device ' + socket.tag.name + ' to mesh ' + mesh.name;
|
||||||
|
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: domainid });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// New CIRA connection for unknown node, disconnect.
|
// New CIRA connection for unknown node, disconnect.
|
||||||
unknownTlsNodeCount++;
|
unknownTlsNodeCount++;
|
||||||
|
@ -312,6 +348,9 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
// Intel AMT GUID (socket.tag.SystemId) will be used as NodeID
|
// Intel AMT GUID (socket.tag.SystemId) will be used as NodeID
|
||||||
var systemid = socket.tag.SystemId.split('-').join('');
|
var systemid = socket.tag.SystemId.split('-').join('');
|
||||||
var nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
var nodeid = Buffer.from(systemid + systemid + systemid, 'hex').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||||
|
var domain = obj.parent.config.domains[mesh.domain];
|
||||||
|
socket.tag.domain = domain;
|
||||||
|
socket.tag.domainid = mesh.domain;
|
||||||
socket.tag.name = '';
|
socket.tag.name = '';
|
||||||
socket.tag.nodeid = 'node/' + mesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
|
socket.tag.nodeid = 'node/' + mesh.domain + '/' + nodeid; // Turn 16bit systemid guid into 48bit nodeid that is base64 encoded
|
||||||
socket.tag.meshid = mesh._id;
|
socket.tag.meshid = mesh._id;
|
||||||
|
@ -319,16 +358,46 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
|
||||||
|
|
||||||
obj.db.Get(socket.tag.nodeid, function (err, nodes) {
|
obj.db.Get(socket.tag.nodeid, function (err, nodes) {
|
||||||
if ((nodes == null) || (nodes.length !== 1)) {
|
if ((nodes == null) || (nodes.length !== 1)) {
|
||||||
// Node is not in the database, add it. Credentials will be empty until added by the user.
|
// Check if we already have too many devices for this domain
|
||||||
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 } };
|
if (domain.limits && (typeof domain.limits.maxdevices == 'number')) {
|
||||||
obj.db.Set(device);
|
db.isMaxType(domain.limits.maxdevices, 'node', mesh.domain, function (ismax, count) {
|
||||||
|
if (ismax == true) {
|
||||||
|
// Too many devices in this domain.
|
||||||
|
maxDomainDevicesReached++;
|
||||||
|
console.log('Too many devices on this domain to accept the CIRA connection. meshid: ' + socket.tag.meshid);
|
||||||
|
socket.end();
|
||||||
|
} else {
|
||||||
|
// We are under the limit, create the new device.
|
||||||
|
// Node is not in the database, add it. Credentials will be empty until added by the user.
|
||||||
|
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 } };
|
||||||
|
obj.db.Set(device);
|
||||||
|
|
||||||
// Event the new node
|
// Event the new node
|
||||||
addedDeviceCount++;
|
addedDeviceCount++;
|
||||||
var device2 = common.Clone(device);
|
var device2 = common.Clone(device);
|
||||||
if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
||||||
var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
|
var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
|
||||||
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain });
|
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain });
|
||||||
|
|
||||||
|
// Add the connection to the MPS connection list
|
||||||
|
obj.ciraConnections[socket.tag.nodeid] = socket;
|
||||||
|
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.
|
||||||
|
SendUserAuthSuccess(socket); // Notify the auth success on the CIRA connection
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Node is not in the database, add it. Credentials will be empty until added by the user.
|
||||||
|
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 } };
|
||||||
|
obj.db.Set(device);
|
||||||
|
|
||||||
|
// Event the new node
|
||||||
|
addedDeviceCount++;
|
||||||
|
var device2 = common.Clone(device);
|
||||||
|
if (device2.intelamt.pass != null) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
|
||||||
|
var change = 'CIRA added device ' + socket.tag.name + ' to group ' + mesh.name;
|
||||||
|
obj.parent.DispatchEvent(['*', socket.tag.meshid], obj, { etype: 'node', action: 'addnode', node: device2, msg: change, domain: mesh.domain });
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Node is already present
|
// Node is already present
|
||||||
var node = nodes[0];
|
var node = nodes[0];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.3.5-z",
|
"version": "0.3.6-a",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
"__UserConsentFlags__" : "Set to: 1 for desktop, 2 for terminal, 3 for files, 7 for all",
|
"__UserConsentFlags__" : "Set to: 1 for desktop, 2 for terminal, 3 for files, 7 for all",
|
||||||
"_UserConsentFlags" : 7,
|
"_UserConsentFlags" : 7,
|
||||||
"_Limits": {
|
"_Limits": {
|
||||||
|
"_MaxDevices": 100,
|
||||||
"_MaxUserAccounts": 100,
|
"_MaxUserAccounts": 100,
|
||||||
"_MaxUserSessions": 100,
|
"_MaxUserSessions": 100,
|
||||||
"_MaxAgentSessions": 100,
|
"_MaxAgentSessions": 100,
|
||||||
|
|
|
@ -10189,7 +10189,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
|
||||||
|
|
||||||
function addDeviceAttribute(name, value) { return '<tr><td class=style7>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
|
function addDeviceAttribute(name, value) { return '<tr><td class=style7>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
|
||||||
|
|
||||||
function editDeviceAmtSettings(nodeid, func) {
|
function editDeviceAmtSettings(nodeid, func, arg) {
|
||||||
if (xxdialogMode) return;
|
if (xxdialogMode) return;
|
||||||
var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
|
var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
|
||||||
if ((meshrights & 4) == 0) return;
|
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
|
||||||
x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
|
x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
|
||||||
x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
|
x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
|
||||||
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
|
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
|
||||||
setDialogMode(2, "Edit Intel® AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
|
setDialogMode(2, "Edit Intel® AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func, arg: arg });
|
||||||
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
|
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
|
||||||
Q('dp10tls').value = node.intelamt.tls;
|
Q('dp10tls').value = node.intelamt.tls;
|
||||||
validateDeviceAmtSettings();
|
validateDeviceAmtSettings();
|
||||||
|
@ -10220,7 +10220,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
|
||||||
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
|
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
|
||||||
tag.node.intelamt.user = amtuser;
|
tag.node.intelamt.user = amtuser;
|
||||||
tag.node.intelamt.tls = Q('dp10tls').value;
|
tag.node.intelamt.tls = Q('dp10tls').value;
|
||||||
if (tag.func) { setTimeout(tag.func, 300); }
|
if (tag.func) { setTimeout(function () { tag.func(null, tag.arg); }, 300); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10519,7 +10519,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
|
||||||
desktopNode = currentNode;
|
desktopNode = currentNode;
|
||||||
if (contype == 2) {
|
if (contype == 2) {
|
||||||
// Setup the Intel AMT remote desktop
|
// Setup the Intel AMT remote desktop
|
||||||
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
|
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop, 2); return; }
|
||||||
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
|
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
|
||||||
desktop.debugmode = debugmode;
|
desktop.debugmode = debugmode;
|
||||||
desktop.onStateChanged = onDesktopStateChange;
|
desktop.onStateChanged = onDesktopStateChange;
|
||||||
|
@ -11111,7 +11111,7 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
|
||||||
if (!terminal) {
|
if (!terminal) {
|
||||||
if (contype == 2) {
|
if (contype == 2) {
|
||||||
// Setup the Intel AMT terminal
|
// Setup the Intel AMT terminal
|
||||||
if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; }
|
if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal, 2); return; }
|
||||||
var termoptions = {};
|
var termoptions = {};
|
||||||
if (Q('termSizeList').value == 2) { termoptions.width = 100; termoptions.height = 30; }
|
if (Q('termSizeList').value == 2) { termoptions.width = 100; termoptions.height = 30; }
|
||||||
terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term', termoptions), authCookie);
|
terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term', termoptions), authCookie);
|
||||||
|
|
|
@ -4141,7 +4141,7 @@
|
||||||
|
|
||||||
function addDeviceAttribute(name, value) { return '<tr><td class=style7>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
|
function addDeviceAttribute(name, value) { return '<tr><td class=style7>' + name + '</td><td class=style9>' + value + '</td></tr>'; }
|
||||||
|
|
||||||
function editDeviceAmtSettings(nodeid, func) {
|
function editDeviceAmtSettings(nodeid, func, arg) {
|
||||||
if (xxdialogMode) return;
|
if (xxdialogMode) return;
|
||||||
var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
|
var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
|
||||||
if ((meshrights & 4) == 0) return;
|
if ((meshrights & 4) == 0) return;
|
||||||
|
@ -4149,7 +4149,7 @@
|
||||||
x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
|
x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
|
||||||
x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
|
x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
|
||||||
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
|
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
|
||||||
setDialogMode(2, "Edit Intel® AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
|
setDialogMode(2, "Edit Intel® AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func, arg: arg });
|
||||||
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
|
if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
|
||||||
Q('dp10tls').value = node.intelamt.tls;
|
Q('dp10tls').value = node.intelamt.tls;
|
||||||
validateDeviceAmtSettings();
|
validateDeviceAmtSettings();
|
||||||
|
@ -4172,7 +4172,7 @@
|
||||||
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
|
meshserver.send({ action: 'changedevice', nodeid: tag.node._id, intelamt: { user: amtuser, pass: amtpass, tls: Q('dp10tls').value } });
|
||||||
tag.node.intelamt.user = amtuser;
|
tag.node.intelamt.user = amtuser;
|
||||||
tag.node.intelamt.tls = Q('dp10tls').value;
|
tag.node.intelamt.tls = Q('dp10tls').value;
|
||||||
if (tag.func) { setTimeout(tag.func, 300); }
|
if (tag.func) { setTimeout(function () { tag.func(null, tag.arg); }, 300); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4471,7 +4471,7 @@
|
||||||
desktopNode = currentNode;
|
desktopNode = currentNode;
|
||||||
if (contype == 2) {
|
if (contype == 2) {
|
||||||
// Setup the Intel AMT remote desktop
|
// Setup the Intel AMT remote desktop
|
||||||
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
|
if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop, 2); return; }
|
||||||
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
|
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
|
||||||
desktop.debugmode = debugmode;
|
desktop.debugmode = debugmode;
|
||||||
desktop.onStateChanged = onDesktopStateChange;
|
desktop.onStateChanged = onDesktopStateChange;
|
||||||
|
@ -5063,7 +5063,7 @@
|
||||||
if (!terminal) {
|
if (!terminal) {
|
||||||
if (contype == 2) {
|
if (contype == 2) {
|
||||||
// Setup the Intel AMT terminal
|
// Setup the Intel AMT terminal
|
||||||
if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; }
|
if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal, 2); return; }
|
||||||
var termoptions = {};
|
var termoptions = {};
|
||||||
if (Q('termSizeList').value == 2) { termoptions.width = 100; termoptions.height = 30; }
|
if (Q('termSizeList').value == 2) { termoptions.width = 100; termoptions.height = 30; }
|
||||||
terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term', termoptions), authCookie);
|
terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term', termoptions), authCookie);
|
||||||
|
|
|
@ -261,7 +261,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||||
invalidMeshTypeCount: 0,
|
invalidMeshTypeCount: 0,
|
||||||
invalidDomainMesh2Count: 0,
|
invalidDomainMesh2Count: 0,
|
||||||
invalidMeshType2Count: 0,
|
invalidMeshType2Count: 0,
|
||||||
duplicateAgentCount: 0
|
duplicateAgentCount: 0,
|
||||||
|
maxDomainDevicesReached: 0
|
||||||
}
|
}
|
||||||
obj.getAgentStats = function () { return obj.agentStats; }
|
obj.getAgentStats = function () { return obj.agentStats; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue