diff --git a/meshuser.js b/meshuser.js index 6657a9b3..5b7f61b2 100644 --- a/meshuser.js +++ b/meshuser.js @@ -1955,6 +1955,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Add KVM information if needed if (command.meshtype == 4) { mesh.kvm = { model: command.kvmmodel, host: command.kvmhost, user: command.kvmuser, pass: command.kvmpass }; } + // If this is device group that requires a relay device, store that now + if ((parent.args.lanonly != true) && (command.meshtype == 3) && (typeof command.relayid == 'string')) { + // Check the relay id + var relayIdSplit = command.relayid.split('/'); + if ((relayIdSplit[0] == 'node') && (relayIdSplit[1] == domain.id)) { mesh.relayid = command.relayid; } + } + // Save the new device group db.Set(mesh); parent.meshes[meshid] = mesh; @@ -2120,6 +2127,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if ((common.validateInt(command.consent) == true) && (command.consent != mesh.consent)) { if (change != '') change += ' and consent changed'; else change += 'Device group "' + mesh.name + '" consent changed'; changesids.push(4); mesh.consent = command.consent; } if ((common.validateInt(command.expireDevs, 0, 2000) == true) && (command.expireDevs != mesh.expireDevs)) { if (change != '') change += ' and auto-remove changed'; else change += 'Device group "' + mesh.name + '" auto-remove changed'; changesids.push(5); if (command.expireDevs == 0) { delete mesh.expireDevs; } else { mesh.expireDevs = command.expireDevs; } } + if ((typeof command.relayid == 'string') && (mesh.mtype == 3) && (mesh.relayid != null) && (command.relayid != mesh.relayid)) { + var relayIdSplit = command.relayid.split('/'); + if ((relayIdSplit.length == 3) && (relayIdSplit[0] = 'node') && (relayIdSplit[1] == domain.id)) { if (change != '') { change += ' and device relay changed'; } else { change = 'Device relay changed'; } changesids.push(7); mesh.relayid = command.relayid; } + } + // See if we need to change device group invitation codes if (mesh.mtype == 2) { if (command.invite === '*') { @@ -2152,7 +2164,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (change != '') { db.Set(mesh); - var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, flags: mesh.flags, consent: mesh.consent, action: 'meshchange', links: mesh.links, msgid: 142, msgArgs: [ mesh.name, changesids ], msg: change, domain: domain.id, invite: mesh.invite, expireDevs: command.expireDevs }; + var event = { etype: 'mesh', userid: user._id, username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, flags: mesh.flags, consent: mesh.consent, action: 'meshchange', links: mesh.links, msgid: 142, msgArgs: [mesh.name, changesids], msg: change, domain: domain.id, invite: mesh.invite, expireDevs: command.expireDevs, relayid: mesh.relayid }; if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the mesh. Another event will come. parent.parent.DispatchEvent(parent.CreateMeshDispatchTargets(mesh, [user._id]), obj, event); } diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index a35c321f..1a775078 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -1796,7 +1796,7 @@ // This is a new mesh for us if (add) { - meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links }; + meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links, relayid: message.event.relayid }; meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh). } } else { @@ -1807,6 +1807,7 @@ } meshes[message.event.meshid].desc = message.event.desc; meshes[message.event.meshid].links = message.event.links; + if (message.event.relayid != null) { meshes[message.event.meshid].relayid = message.event.relayid; } // Check if we lost rights to this mesh in this change. if (IsMeshViewable(message.event.meshid) == false) { @@ -6043,7 +6044,7 @@ 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 == 3) { if (currentMesh.relayid == null) { meshtype = "Local devices, no agent"; } else { meshtype = "No agent devices relayed thru agent"; } } if (currentMesh.mtype == 4) { meshtype = "IP-KVM device"; if (currentMesh.kvm.model == 1) { meshtype += ', ' + 'Raritan KX III'; } } var x = ''; @@ -6052,6 +6053,14 @@ x += addHtmlValue("Type", meshtype); //x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]); + // Display the relay device if applicable + if ((currentMesh.mtype == 3) && (currentMesh.relayid != null)) { + var relayName = '' + "Unknown" + ''; + var relayNode = getNodeFromId(currentMesh.relayid); + if (relayNode != null) { relayName = EscapeHtml(relayNode.name); } + x += addHtmlValue("Relay Device", addLinkConditional(relayName, 'p20editmeshrelay()', (meshrights & 1) != 0)); + } + // Display IP-KVM information if needed if (currentMesh.mtype == 4) { x += addHtmlValue("Hostname", currentMesh.kvm.host); @@ -6145,6 +6154,29 @@ meshserver.send({ action: 'deletemesh', meshid: currentMesh._id, meshname: currentMesh.name }); } + function p20editmeshrelay() { + if (xxdialogMode) return; + + // Look for all relay devices + var relayDevices = []; + if ((features & 2) == 0) { for (var i in nodes) { var node = nodes[i]; if ((node.mtype == 2) && (node.agent != null) && (GetNodeRights(node) == 0xFFFFFFFF)) { relayDevices.push(node); } } } + relayDevices.sort(nameSort); + + if (relayDevices.length == 0) { + // Relay relay devices available + setDialogMode(2, "Edit Device Group", 1, null, "No relay devices available."); + } else { + var relayDevices2 = []; + for (var i in relayDevices) { relayDevices2.push(''); } + var x = addHtmlValue("Relay Device", '
'); + setDialogMode(2, "Edit Device Group", 3, p20editmeshrelayEx, x); + } + } + + function p20editmeshrelayEx() { + meshserver.send({ action: 'editmesh', meshid: currentMesh._id, relayid: Q('d2devrelay').value }); + } + function p20editmesh(focus) { if (xxdialogMode) return; var x = addHtmlValue("Name", ''); @@ -6712,6 +6744,7 @@ // Generic Methods // + function nameSort(a, b) { var aa = a.name.toLowerCase(), bb = b.name.toLowerCase(); return sortCollator.compare(aa, bb); } function getNodeAmtVersion(node) { if ((node == null) || (node.intelamt == null) || (typeof node.intelamt.ver != 'string')) return 0; var verSplit = node.intelamt.ver.split('.'); if (verSplit.length < 2) return 0; return parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); } function putstore(name, val) { try { if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return; if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); } } catch (e) { } if (name[0] != '_') { var s = {}; for (var i = 0, len = localStorage.length; i < len; ++i) { var k = localStorage.key(i); if (k[0] != '_') { s[k] = localStorage.getItem(k); } } meshserver.send({ action: 'userWebState', state: JSON.stringify(s) }); } } function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } } diff --git a/views/default.handlebars b/views/default.handlebars index 2f4dd70b..b199d95c 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -3045,7 +3045,7 @@ // This is a new mesh for us if (add) { - meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links }; + meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links, amt: message.event.amt, invite: message.event.invite, expireDevs: message.event.expireDevs, relayid: message.event.relayid }; meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh). } } else { @@ -3061,6 +3061,7 @@ if (message.event.amt) { meshes[message.event.meshid].amt = message.event.amt; } if (message.event.invite != null) { meshes[message.event.meshid].invite = message.event.invite; } else { delete meshes[message.event.meshid].invite; } if (message.event.expireDevs != null) { if (message.event.expireDevs > 0) { meshes[message.event.meshid].expireDevs = message.event.expireDevs; } else { delete meshes[message.event.meshid].expireDevs; } } + if (message.event.relayid != null) { meshes[message.event.meshid].relayid = message.event.relayid; } // Check if we lost rights to this mesh in this change. if (IsMeshViewable(message.event.meshid) == false) { @@ -11574,12 +11575,25 @@ // Remind the user to add two factor authentication if ((features & 0x00040000) && (count2factoraAuths() == 0)) { setDialogMode(2, "Account Security", 1, null, "Unable to access this feature until two-factor authentication is enabled. This is required for extra security. Go to the \"My Account\" tab and look at the \"Account Security\" section."); return false; } + // Look for all relay devices + var relayDevices = []; + if ((features & 2) == 0) { for (var i in nodes) { var node = nodes[i]; if ((node.mtype == 2) && (node.agent != null) && (GetNodeRights(node) == 0xFFFFFFFF)) { relayDevices.push(node); } } } + // We are allowed, let's prompt to information var x = "Create a new device group using the options below." + '

', localGroupType = ''; x += addHtmlValue("Name", ''); if ((features & 1) == 0) { localGroupType += ''; } + if (((features & 2) == 0) && (relayDevices.length > 0)) { localGroupType += ''; } if (features2 & 0x10000) { localGroupType += ''; } x += addHtmlValue("Type", '
'); + if (relayDevices.length > 0) { + x += ''; + } x += addHtmlValue("Description", '
'); x += '