diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index f36a46f2..cb9e6397 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -292,6 +292,7 @@ "userQuota": { "type": "integer" }, "meshQuota": { "type": "integer" }, "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." }, + "ipkvm": { "type": "boolean", "default": false, "description": "Set to true to enable IP KVM device support in this domain." }, "minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sided web pages." }, "newAccounts": { "type": "boolean", "default": false, "description": "When set to true, allow new user accounts to be created from the login page." }, "newAccountsUserGroups": { "type": "array", "uniqueItems": true, "items": { "type": "string" } }, diff --git a/meshuser.js b/meshuser.js index d94b8349..79e1201d 100644 --- a/meshuser.js +++ b/meshuser.js @@ -2457,10 +2457,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use 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. // Create mesh - else if (common.validateString(command.meshname, 1, 128) == false) { err = 'Invalid group name'; } // Meshname is between 1 and 64 characters + else if (common.validateString(command.meshname, 1, 128) == false) { err = 'Invalid group name'; } // Meshname is between 1 and 128 characters else if ((command.desc != null) && (common.validateString(command.desc, 0, 1024) == false)) { err = 'Invalid group description'; } // Mesh description is between 0 and 1024 characters - else if ((command.meshtype < 1) && (command.meshtype > 3)) { err = 'Invalid group type'; } // Device group types are 1 = AMT, 2 = Agent, 3 = Local + else if ((command.meshtype < 1) || (command.meshtype > 4)) { err = 'Invalid group type'; } // Device group types are 1 = AMT, 2 = Agent, 3 = Local else if ((parent.args.wanonly == true) && (command.meshtype == 3)) { err = 'Invalid group type'; } // Local device group type is not allowed in WAN mode + else if ((domain.ipkvm == null) && (command.meshtype == 4)) { err = 'Invalid group type'; } // IP KVM device group type is not allowed unless enabled + if ((err == null) && (command.meshtype == 4)) { + if (command.kvmmodel !== 1) { err = 'Invalid KVM model'; } + else if (common.validateString(command.kvmhost, 1, 128) == false) { err = 'Invalid KVM hostname'; } + else if (common.validateString(command.kvmuser, 1, 128) == false) { err = 'Invalid KVM username'; } + else if (common.validateString(command.kvmpass, 1, 128) == false) { err = 'Invalid KVM password'; } + } } catch (ex) { err = 'Validation exception: ' + ex; } // Handle any errors @@ -2483,6 +2490,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (typeof command.flags == 'number') { mesh.flags = command.flags; } if (typeof command.consent == 'number') { mesh.consent = command.consent; } + // Add KVM information if needed + if (command.meshtype == 4) { mesh.kvm = { model: command.kvmmodel, host: command.kvmhost, user: command.kvmuser, pass: command.kvmpass }; } + // Save the new device group db.Set(mesh); parent.meshes[meshid] = mesh; diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index 515ef72f..33b5dbeb 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -2995,7 +2995,7 @@ //r += getMeshActions(mesh, meshrights); r += '' + EscapeHtml(mesh.name) + ''; if (mesh.mtype == 1) { r += '
' + "No Intel® AMT devices in this group"; } - if (mesh.mtype == 2) { r += '
' + "No devices in this group"; } + if (mesh.mtype > 1) { r += '
' + "No devices in this group"; } r += '.
'; current = mesh._id; count++; @@ -5931,6 +5931,8 @@ var meshrights = GetMeshRights(currentMesh); if (currentMesh.mtype == 1) meshtype = "Intel® AMT only, no agent"; if (currentMesh.mtype == 2) meshtype = "Managed using a software agent"; + if (currentMesh.mtype == 3) meshtype = "Local devices, no agent"; + if (currentMesh.mtype == 4) { meshtype = "IP KVM device"; if (currentMesh.kvm.model == 1) { meshtype += ', ' + 'Raritan KX III'; } } var x = ''; x += addHtmlValue("Name", addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0)); @@ -5938,6 +5940,12 @@ x += addHtmlValue("Type", meshtype); //x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]); + // Display IP KVM information if needed + if (currentMesh.mtype == 4) { + x += addHtmlValue("Hostname", currentMesh.kvm.host); + x += addHtmlValue("Username", currentMesh.kvm.user); + } + x += '
'; x += '

'; diff --git a/views/default.handlebars b/views/default.handlebars index cc6ec576..75e2703c 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -4102,6 +4102,9 @@ r += '
'; // Open collapse div r += '
' + "No local devices in this device group"; if (((meshrights & 4) != 0) && ((userinfo.siteadmin == 0xFFFFFFFF) || ((userinfo.siteadmin & 4096) == 0))) { r += ', ' + "add one" + ''; } + } else if (mesh.mtype == 4) { + r += '
'; // Open collapse div + r += '
' + "No devices in this device group"; } r += '.
'; r += '
'; // End collapsing area @@ -11315,8 +11318,15 @@ var x = "Create a new device group using the options below." + '

', localGroupType = ''; x += addHtmlValue("Name", ''); if ((features & 1) == 0) { localGroupType += ''; } + if (features2 & 0x10000) { localGroupType += ''; } x += addHtmlValue("Type", '
'); x += addHtmlValue("Description", '
'); + x += ''; setDialogMode(2, "New Device Group", 3, account_createMeshEx, x); account_validateMeshCreate(); Q('dp2meshname').focus(); @@ -11324,13 +11334,27 @@ } function account_validateMeshCreate(e, x) { + var meshtype = parseInt(Q('dp2meshtype').value); if ((x == 1) && (e != null) && (e.key == "Enter") && (Q('dp2meshname').value.length > 0)) { Q('dp2meshtype').focus(); } if ((x == 2) && (e != null) && (e.key == "Enter")) { Q('dp2meshdesc').focus(); } - QE('idx_dlgOkButton', Q('dp2meshname').value.length > 0); + var ok = (Q('dp2meshname').value.length > 0); + QV('d2ipkvm', meshtype == 4); + if (meshtype == 4) { + if ((Q('dp2ipkvmhost').value.length == 0) && (Q('dp2ipkvmuser').value.length == 0) && (Q('dp2ipkvmpass').value.length == 0)) { ok = false; } + } + QE('idx_dlgOkButton', ok); } function account_createMeshEx(button, tag) { - meshserver.send({ action: 'createmesh', meshname: Q('dp2meshname').value, meshtype: parseInt(Q('dp2meshtype').value), desc: Q('dp2meshdesc').value }); + var meshtype = parseInt(Q('dp2meshtype').value); + var cmd = { action: 'createmesh', meshname: Q('dp2meshname').value, meshtype: meshtype, desc: Q('dp2meshdesc').value }; + if (meshtype == 4) { + cmd.kvmmodel = parseInt(Q('dp2ipkvmmodel').value); + cmd.kvmhost = Q('dp2ipkvmhost').value; + cmd.kvmuser = Q('dp2ipkvmuser').value; + cmd.kvmpass = Q('dp2ipkvmpass').value; + } + meshserver.send(cmd); } function account_validateDeleteAccount() { @@ -11545,6 +11569,7 @@ if (currentMesh.mtype == 1) meshtype = "Intel® AMT only, no agent"; if (currentMesh.mtype == 2) meshtype = "Managed using a software agent"; if (currentMesh.mtype == 3) meshtype = "Local devices, no agent"; + if (currentMesh.mtype == 4) { meshtype = "IP KVM device"; if (currentMesh.kvm.model == 1) { meshtype += ', ' + 'Raritan KX III'; } } var x = ''; if ((args.hide & 8) != 0) { x += addHtmlValue("Name", mname); } // If title bar is hidden, display the mesh name here @@ -11554,6 +11579,12 @@ x += addHtmlValue("Type", meshtype); //x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]); + // Display IP KVM information if needed + if (currentMesh.mtype == 4) { + x += addHtmlValue("Hostname", currentMesh.kvm.host); + x += addHtmlValue("Username", currentMesh.kvm.user); + } + // Display device group creator if ((currentMesh.creatorid != null) && (users != null) && (users[currentMesh.creatorid] != null)) { var meshcreator = users[currentMesh.creatorid]; @@ -11622,7 +11653,7 @@ } // If the Intel AMT manager is active on the server, show the Intel AMT policy edit box. - if ((currentMesh.mtype != 3) && ((features2 & 1) != 0)) { + if ((currentMesh.mtype < 3) && ((features2 & 1) != 0)) { // Intel AMT setup var intelAmtPolicy = "No Policy"; if (currentMesh.amt) { @@ -12566,7 +12597,9 @@ var x = '
' + "Web Page Notifications" + '
'; x += '
'; x += '
'; - x += '
'; + if (currentMesh.mtype < 3) { + x += '
'; + } if (emailNotify) { x += '
' + "Email Notifications" + '
'; x += '
'; @@ -12575,7 +12608,7 @@ setDialogMode(2, "Notification Settings", 3, p20editMeshNotifyEx, x, emailNotify); Q('p20notifyIntelDeviceConnect').checked = (meshNotify & 2); Q('p20notifyIntelDeviceDisconnect').checked = (meshNotify & 4); - Q('p20notifyIntelAmtKvmActions').checked = (meshNotify & 8); + if (currentMesh.mtype < 3) { Q('p20notifyIntelAmtKvmActions').checked = (meshNotify & 8); } if (emailNotify) { Q('p20enotifyIntelDeviceConnect').checked = (meshNotify & 16); Q('p20enotifyIntelDeviceDisconnect').checked = (meshNotify & 32); @@ -12587,7 +12620,7 @@ var meshNotify = 0; meshNotify += Q('p20notifyIntelDeviceConnect').checked ? 2 : 0; meshNotify += Q('p20notifyIntelDeviceDisconnect').checked ? 4 : 0; - meshNotify += Q('p20notifyIntelAmtKvmActions').checked ? 8 : 0; + if (currentMesh.mtype < 3) { meshNotify += Q('p20notifyIntelAmtKvmActions').checked ? 8 : 0; } if (emailNotify) { meshNotify += Q('p20enotifyIntelDeviceConnect').checked ? 16 : 0; meshNotify += Q('p20enotifyIntelDeviceDisconnect').checked ? 32 : 0; diff --git a/webserver.js b/webserver.js index 2f9128e8..5e4ed82b 100644 --- a/webserver.js +++ b/webserver.js @@ -2847,6 +2847,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if ((typeof domain.desktop == 'object') && (domain.desktop.viewonly == true)) { features2 += 0x00002000; } // Indicates remote desktop is viewonly if (domain.mailserver != null) { features2 += 0x00004000; } // Indicates email server is active if (domain.devicesearchbarserverandclientname) { features2 += 0x00008000; } // Search bar will find both server name and client name + if (domain.ipkvm) { features2 += 0x00010000; } // Indicates support for IP KVM device groups return { features: features, features2: features2 }; } @@ -7271,10 +7272,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { obj.CloneSafeMesh = function (mesh) { if (typeof mesh != 'object') { return mesh; } var r = mesh; - if ((r.amt != null) && (r.amt.password != null)) { + if (((r.amt != null) && (r.amt.password != null)) || ((r.kvm != null) && (r.kvm.pass != null))) { r = Object.assign({}, r); // Shallow clone - r.amt = Object.assign({}, r.amt); // Shallow clone - if ((r.amt.password != null) && (r.amt.password != '')) { r.amt.password = 1; } // Remove the Intel AMT password from the policy + if ((r.amt != null) && (r.amt.password != null)) { + r.amt = Object.assign({}, r.amt); // Shallow clone + if ((r.amt.password != null) && (r.amt.password != '')) { r.amt.password = 1; } // Remove the Intel AMT password from the policy + } + if ((r.kvm != null) && (r.kvm.pass != null)) { + r.kvm = Object.assign({}, r.kvm); // Shallow clone + if ((r.kvm.pass != null) && (r.kvm.pass != '')) { r.kvm.pass = 1; } // Remove the IP KVM device password + } } return r; }