Added support for IP-KVM device groups.
Ylian Saint-Hilaire committed
Dec 2, 2021 at 18:34 UTC
3c6ccc91396d14413fb7c97508c6c9342889c795
5 files changed
+71
-12
meshcentral-config-schema.json
+1
@@ -292,6 +292,7 @@
292
"userQuota": { "type": "integer" },
293
"meshQuota": { "type": "integer" },
294
"loginKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." },
295
+ "ipkvm": { "type": "boolean", "default": false, "description": "Set to true to enable IP KVM device support in this domain." },
296
"minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sided web pages." },
297
"newAccounts": { "type": "boolean", "default": false, "description": "When set to true, allow new user accounts to be created from the login page." },
298
"newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } },
meshuser.js
+12
-2
@@ -2457,10 +2457,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2457
else if ((domain.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != SITERIGHT_ADMIN)) { err = 'Email verification required'; } // User must verify it's email first.
2458
2459
// Create mesh
2460
- else if (common.validateString(command.meshname, 1, 128) == false) { err = 'Invalid group name'; } // Meshname is between 1 and 64 characters
2460
+ else if (common.validateString(command.meshname, 1, 128) == false) { err = 'Invalid group name'; } // Meshname is between 1 and 128 characters
2461
else if ((command.desc != null) && (common.validateString(command.desc, 0, 1024) == false)) { err = 'Invalid group description'; } // Mesh description is between 0 and 1024 characters
2462
- else if ((command.meshtype < 1) && (command.meshtype > 3)) { err = 'Invalid group type'; } // Device group types are 1 = AMT, 2 = Agent, 3 = Local
2462
+ else if ((command.meshtype < 1) || (command.meshtype > 4)) { err = 'Invalid group type'; } // Device group types are 1 = AMT, 2 = Agent, 3 = Local
2463
else if ((parent.args.wanonly == true) && (command.meshtype == 3)) { err = 'Invalid group type'; } // Local device group type is not allowed in WAN mode
2464
+ else if ((domain.ipkvm == null) && (command.meshtype == 4)) { err = 'Invalid group type'; } // IP KVM device group type is not allowed unless enabled
2465
+ if ((err == null) && (command.meshtype == 4)) {
2466
+ if (command.kvmmodel !== 1) { err = 'Invalid KVM model'; }
2467
+ else if (common.validateString(command.kvmhost, 1, 128) == false) { err = 'Invalid KVM hostname'; }
2468
+ else if (common.validateString(command.kvmuser, 1, 128) == false) { err = 'Invalid KVM username'; }
2469
+ else if (common.validateString(command.kvmpass, 1, 128) == false) { err = 'Invalid KVM password'; }
2470
+ }
2471
} catch (ex) { err = 'Validation exception: ' + ex; }
2472
2473
// Handle any errors
@@ -2483,6 +2490,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2490
if (typeof command.flags == 'number') { mesh.flags = command.flags; }
2491
if (typeof command.consent == 'number') { mesh.consent = command.consent; }
2492
2493
+ // Add KVM information if needed
2494
+ if (command.meshtype == 4) { mesh.kvm = { model: command.kvmmodel, host: command.kvmhost, user: command.kvmuser, pass: command.kvmpass }; }
2495
+
2496
// Save the new device group
2497
db.Set(mesh);
2498
parent.meshes[meshid] = mesh;
views/default-mobile.handlebars
+9
-1
@@ -2995,7 +2995,7 @@
2995
//r += getMeshActions(mesh, meshrights);
2996
r += '</span><span id=MxMESH style=cursor:pointer onclick=goForward("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></div>';
2997
if (mesh.mtype == 1) { r += '<div style=padding:10px><i>' + "No Intel® AMT devices in this group"; }
2998
- if (mesh.mtype == 2) { r += '<div style=padding:10px><i>' + "No devices in this group"; }
2998
+ if (mesh.mtype > 1) { r += '<div style=padding:10px><i>' + "No devices in this group"; }
2999
r += '.</i></div></div>';
3000
current = mesh._id;
3001
count++;
@@ -5931,6 +5931,8 @@
5931
var meshrights = GetMeshRights(currentMesh);
5932
if (currentMesh.mtype == 1) meshtype = "Intel® AMT only, no agent";
5933
if (currentMesh.mtype == 2) meshtype = "Managed using a software agent";
5934
+ if (currentMesh.mtype == 3) meshtype = "Local devices, no agent";
5935
+ if (currentMesh.mtype == 4) { meshtype = "IP KVM device"; if (currentMesh.kvm.model == 1) { meshtype += ', ' + 'Raritan KX III'; } }
5936
5937
var x = '';
5938
x += addHtmlValue("Name", addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
@@ -5938,6 +5940,12 @@
5940
x += addHtmlValue("Type", meshtype);
5941
//x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
5942
5943
+ // Display IP KVM information if needed
5944
+ if (currentMesh.mtype == 4) {
5945
+ x += addHtmlValue("Hostname", currentMesh.kvm.host);
5946
+ x += addHtmlValue("Username", currentMesh.kvm.user);
5947
+ }
5948
+
5949
x += '<br><input type=button value=Notes onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
5950
5951
x += '<br style=clear:both><br>';
views/default.handlebars
+39
-6
@@ -4102,6 +4102,9 @@
4102
r += '<td><div id=DevxCol' + deviceHeaderId2 + ((collapsed === true)?' style=display:none':'') + '>'; // Open collapse div
4103
r += '<div style=padding:10px><i>' + "No local devices in this device group";
4104
if (((meshrights & 4) != 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 4096) == 0))) { r += ', <a href=# style=cursor:pointer onclick=\'return addLocalDeviceToMesh("' + mesh._id + '")\'>' + "add one" + '</a>'; }
4105
+ } else if (mesh.mtype == 4) {
4106
+ r += '<td><div id=DevxCol' + deviceHeaderId2 + ((collapsed === true)?' style=display:none':'') + '>'; // Open collapse div
4107
+ r += '<div style=padding:10px><i>' + "No devices in this device group";
4108
}
4109
r += '.</i></div></td>';
4110
r += '</div>'; // End collapsing area
@@ -11315,8 +11318,15 @@
11318
var x = "Create a new device group using the options below." + '<br /><br />', localGroupType = '';
11319
x += addHtmlValue("Name", '<input id=dp2meshname style=width:230px maxlength=128 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate(event,1) />');
11320
if ((features & 1) == 0) { localGroupType += '<option value=3>' + "Local devices, no agent" + '</option>'; }
11321
+ if (features2 & 0x10000) { localGroupType += '<option value=4>' + "IP KVM device" + '</option>'; }
11322
x += addHtmlValue("Type", '<div style=width:230px;margin:0;padding:0><select id=dp2meshtype style=width:100% onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate(event,2) ><option value=2>' + "Manage using a software agent" + '</option><option value=1>' + "Intel® AMT only, no agent" + '</option>' + localGroupType + '</select></div>');
11323
x += addHtmlValue("Description", '<div style=width:230px;margin:0;padding:0><textarea id=dp2meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
11324
+ x += '<div id=d2ipkvm style=display:none><hr />';
11325
+ x += addHtmlValue("Model", '<div style=width:230px;margin:0;padding:0><select id=dp2ipkvmmodel style=width:100% onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate(event,2) ><option value=1>' + "Raritan Dominion KX III" + '</option></select></div>');
11326
+ x += addHtmlValue("Hostname", '<input id=dp2ipkvmhost style=width:230px maxlength=128 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate(event,1) />');
11327
+ x += addHtmlValue("Username", '<input id=dp2ipkvmuser style=width:230px maxlength=128 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate(event,1) />');
11328
+ x += addHtmlValue("Password", '<input id=dp2ipkvmpass type=password style=width:230px maxlength=128 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate(event,1) />');
11329
+ x += '</div>';
11330
setDialogMode(2, "New Device Group", 3, account_createMeshEx, x);
11331
account_validateMeshCreate();
11332
Q('dp2meshname').focus();
@@ -11324,13 +11334,27 @@
11334
}
11335
11336
function account_validateMeshCreate(e, x) {
11337
+ var meshtype = parseInt(Q('dp2meshtype').value);
11338
if ((x == 1) && (e != null) && (e.key == "Enter") && (Q('dp2meshname').value.length > 0)) { Q('dp2meshtype').focus(); }
11339
if ((x == 2) && (e != null) && (e.key == "Enter")) { Q('dp2meshdesc').focus(); }
11329
- QE('idx_dlgOkButton', Q('dp2meshname').value.length > 0);
11340
+ var ok = (Q('dp2meshname').value.length > 0);
11341
+ QV('d2ipkvm', meshtype == 4);
11342
+ if (meshtype == 4) {
11343
+ if ((Q('dp2ipkvmhost').value.length == 0) && (Q('dp2ipkvmuser').value.length == 0) && (Q('dp2ipkvmpass').value.length == 0)) { ok = false; }
11344
+ }
11345
+ QE('idx_dlgOkButton', ok);
11346
}
11347
11348
function account_createMeshEx(button, tag) {
11333
- meshserver.send({ action: 'createmesh', meshname: Q('dp2meshname').value, meshtype: parseInt(Q('dp2meshtype').value), desc: Q('dp2meshdesc').value });
11349
+ var meshtype = parseInt(Q('dp2meshtype').value);
11350
+ var cmd = { action: 'createmesh', meshname: Q('dp2meshname').value, meshtype: meshtype, desc: Q('dp2meshdesc').value };
11351
+ if (meshtype == 4) {
11352
+ cmd.kvmmodel = parseInt(Q('dp2ipkvmmodel').value);
11353
+ cmd.kvmhost = Q('dp2ipkvmhost').value;
11354
+ cmd.kvmuser = Q('dp2ipkvmuser').value;
11355
+ cmd.kvmpass = Q('dp2ipkvmpass').value;
11356
+ }
11357
+ meshserver.send(cmd);
11358
}
11359
11360
function account_validateDeleteAccount() {
@@ -11545,6 +11569,7 @@
11569
if (currentMesh.mtype == 1) meshtype = "Intel® AMT only, no agent";
11570
if (currentMesh.mtype == 2) meshtype = "Managed using a software agent";
11571
if (currentMesh.mtype == 3) meshtype = "Local devices, no agent";
11572
+ if (currentMesh.mtype == 4) { meshtype = "IP KVM device"; if (currentMesh.kvm.model == 1) { meshtype += ', ' + 'Raritan KX III'; } }
11573
11574
var x = '';
11575
if ((args.hide & 8) != 0) { x += addHtmlValue("Name", mname); } // If title bar is hidden, display the mesh name here
@@ -11554,6 +11579,12 @@
11579
x += addHtmlValue("Type", meshtype);
11580
//x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
11581
11582
+ // Display IP KVM information if needed
11583
+ if (currentMesh.mtype == 4) {
11584
+ x += addHtmlValue("Hostname", currentMesh.kvm.host);
11585
+ x += addHtmlValue("Username", currentMesh.kvm.user);
11586
+ }
11587
+
11588
// Display device group creator
11589
if ((currentMesh.creatorid != null) && (users != null) && (users[currentMesh.creatorid] != null)) {
11590
var meshcreator = users[currentMesh.creatorid];
@@ -11622,7 +11653,7 @@
11653
}
11654
11655
// If the Intel AMT manager is active on the server, show the Intel AMT policy edit box.
11625
- if ((currentMesh.mtype != 3) && ((features2 & 1) != 0)) {
11656
+ if ((currentMesh.mtype < 3) && ((features2 & 1) != 0)) {
11657
// Intel AMT setup
11658
var intelAmtPolicy = "No Policy";
11659
if (currentMesh.amt) {
@@ -12566,7 +12597,9 @@
12597
var x = '<div style="border-bottom: 1px solid #888;margin-bottom:3px">' + "Web Page Notifications" + '</div>';
12598
x += '<div><label><input id=p20notifyIntelDeviceConnect type=checkbox />' + "Device connections" + '</label></div>';
12599
x += '<div><label><input id=p20notifyIntelDeviceDisconnect type=checkbox />' + "Device disconnections" + '</label></div>';
12569
- x += '<div><label><input id=p20notifyIntelAmtKvmActions type=checkbox />' + "Intel® AMT desktop and serial events" + '</label></div>';
12600
+ if (currentMesh.mtype < 3) {
12601
+ x += '<div><label><input id=p20notifyIntelAmtKvmActions type=checkbox />' + "Intel® AMT desktop and serial events" + '</label></div>';
12602
+ }
12603
if (emailNotify) {
12604
x += '<br /><div style="border-bottom: 1px solid #888;margin-bottom:3px">' + "Email Notifications" + '</div>';
12605
x += '<div><label><input id=p20enotifyIntelDeviceConnect type=checkbox />' + "Device connections" + '</label></div>';
@@ -12575,7 +12608,7 @@
12608
setDialogMode(2, "Notification Settings", 3, p20editMeshNotifyEx, x, emailNotify);
12609
Q('p20notifyIntelDeviceConnect').checked = (meshNotify & 2);
12610
Q('p20notifyIntelDeviceDisconnect').checked = (meshNotify & 4);
12578
- Q('p20notifyIntelAmtKvmActions').checked = (meshNotify & 8);
12611
+ if (currentMesh.mtype < 3) { Q('p20notifyIntelAmtKvmActions').checked = (meshNotify & 8); }
12612
if (emailNotify) {
12613
Q('p20enotifyIntelDeviceConnect').checked = (meshNotify & 16);
12614
Q('p20enotifyIntelDeviceDisconnect').checked = (meshNotify & 32);
@@ -12587,7 +12620,7 @@
12620
var meshNotify = 0;
12621
meshNotify += Q('p20notifyIntelDeviceConnect').checked ? 2 : 0;
12622
meshNotify += Q('p20notifyIntelDeviceDisconnect').checked ? 4 : 0;
12590
- meshNotify += Q('p20notifyIntelAmtKvmActions').checked ? 8 : 0;
12623
+ if (currentMesh.mtype < 3) { meshNotify += Q('p20notifyIntelAmtKvmActions').checked ? 8 : 0; }
12624
if (emailNotify) {
12625
meshNotify += Q('p20enotifyIntelDeviceConnect').checked ? 16 : 0;
12626
meshNotify += Q('p20enotifyIntelDeviceDisconnect').checked ? 32 : 0;
webserver.js
+10
-3
@@ -2847,6 +2847,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2847
if ((typeof domain.desktop == 'object') && (domain.desktop.viewonly == true)) { features2 += 0x00002000; } // Indicates remote desktop is viewonly
2848
if (domain.mailserver != null) { features2 += 0x00004000; } // Indicates email server is active
2849
if (domain.devicesearchbarserverandclientname) { features2 += 0x00008000; } // Search bar will find both server name and client name
2850
+ if (domain.ipkvm) { features2 += 0x00010000; } // Indicates support for IP KVM device groups
2851
return { features: features, features2: features2 };
2852
}
2853
@@ -7271,10 +7272,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
7272
obj.CloneSafeMesh = function (mesh) {
7273
if (typeof mesh != 'object') { return mesh; }
7274
var r = mesh;
7274
- if ((r.amt != null) && (r.amt.password != null)) {
7275
+ if (((r.amt != null) && (r.amt.password != null)) || ((r.kvm != null) && (r.kvm.pass != null))) {
7276
r = Object.assign({}, r); // Shallow clone
7276
- r.amt = Object.assign({}, r.amt); // Shallow clone
7277
- if ((r.amt.password != null) && (r.amt.password != '')) { r.amt.password = 1; } // Remove the Intel AMT password from the policy
7277
+ if ((r.amt != null) && (r.amt.password != null)) {
7278
+ r.amt = Object.assign({}, r.amt); // Shallow clone
7279
+ if ((r.amt.password != null) && (r.amt.password != '')) { r.amt.password = 1; } // Remove the Intel AMT password from the policy
7280
+ }
7281
+ if ((r.kvm != null) && (r.kvm.pass != null)) {
7282
+ r.kvm = Object.assign({}, r.kvm); // Shallow clone
7283
+ if ((r.kvm.pass != null) && (r.kvm.pass != '')) { r.kvm.pass = 1; } // Remove the IP KVM device password
7284
+ }
7285
}
7286
return r;
7287
}