Windows MeshAgent fixes, small UI improvements

Ylian Saint-Hilaire committed Sep 24, 2018 at 17:47 UTC 5bba0a0924bdbf8579b8d1a643f9ac83f96961dd
13 files changed +101 -54
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/MeshService-signed.exe
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64-signed.exe
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshcore.js
+4 -3
@@ -1477,13 +1477,15 @@ function createMeshCore(agent) {
1477 } catch (e) { amtLmsState = -1; amtLms = null; }
1478
1479 // Setup logged in user monitoring
1480 - /*
1480 try {
1481 var userSession = require('user-sessions');
1482 userSession.on('changed', function onUserSessionChanged() {
1483 userSession.enumerateUsers().then(function (users) {
1484 var u = [], a = users.Active;
1486 - for (var i in a) { if (a[i].Domain) { u.push(a[i].Domain + '\\' + a[i].Username); } else { u.push(a[i].Username); } }
1485 + for (var i = 0; i < a.length; i++) {
1486 + var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
1487 + if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
1488 + }
1489 obj.loggedInUsers = u;
1490 if (mesh.isControlChannelConnected) { mesh.SendCommand({ "action": "coreinfo", "users": u }); }
1491 });
@@ -1492,7 +1494,6 @@ function createMeshCore(agent) {
1494 //userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); });
1495 //userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
1496 } catch (ex) { }
1495 - */
1497 }
1498
1499 obj.stop = function () {
meshagent.js
+8 -5
@@ -164,7 +164,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
164 // Send the next block to the agent
165 obj.agentUpdate.ptr += len;
166 //console.log("Agent update send next block", obj.agentUpdate.ptr, len);
167 - if (len == agentUpdateBlockSize) { obj.ws.send(obj.agentUpdate.buf); } else { obj.ws.send(obj.agentUpdate.buf.slice(0, len + 4)); } // Command 14, mesh agent next data block
167 + if (len == agentUpdateBlockSize) { obj.send(obj.agentUpdate.buf); } else { obj.send(obj.agentUpdate.buf.slice(0, len + 4)); } // Command 14, mesh agent next data block
168
169 if (len < agentUpdateBlockSize) {
170 //console.log("Agent update sent");
@@ -294,6 +294,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
294
295 // Mark when we connected to this agent
296 obj.connectTime = Date.now();
297 + obj.db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime });
298 +
299 + // See if this node exists in the database
300 if (nodes.length == 0) {
301 // This node does not exist, create it.
302 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 };
@@ -324,7 +327,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
327
328 // Event the node change
329 var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id };
327 - if (log == 0) { event.nolog = 1; } else { event.msg = 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', '); }
330 + if (log == 0) { event.nolog = 1; } else { event.msg = 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', '); }
331 var device2 = obj.common.Clone(device);
332 if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
333 event.node = device;
@@ -450,7 +453,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
453 if (ws != null) {
454 command.nodeid = obj.dbNodeKey; // Set the nodeid, required for responses.
455 delete command.sessionid; // Remove the sessionid, since we are sending to that sessionid, so it's implyed.
453 - ws.send(JSON.stringify(command));
456 + try { ws.send(JSON.stringify(command)); } catch (ex) { }
457 } else if (obj.parent.parent.multiServer != null) {
458 // See if we can send this to a peer server
459 var serverid = obj.parent.wsPeerSessions2[command.sessionid];
@@ -617,7 +620,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
620
621 // Event the node change
622 var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id };
620 - if (changes.length > 0) { event.msg = 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', '); }
623 + if (changes.length > 0) { event.msg = 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', '); }
624 if ((obj.agentInfo.capabilities & 0x20) || (changes.length == 0)) { event.nolog = 1; } // If this is a temporary device, don't log changes
625 var device2 = obj.common.Clone(device);
626 if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
@@ -652,7 +655,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
655 obj.db.Set(device);
656
657 // Event the node change
655 - var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ') };
658 + var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from group ' + mesh.name + ': ' + changes.join(', ') };
659 if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes
660 var device2 = obj.common.Clone(device);
661 if (device2.intelamt && device2.intelamt.pass) { delete device2.intelamt.pass; } // Remove the Intel AMT password before eventing this.
meshcentral.js
+4 -2
@@ -57,6 +57,7 @@ function CreateMeshCentralServer(config, args) {
57 obj.currentVer = null;
58 obj.serverKey = new Buffer(obj.crypto.randomBytes(32), 'binary');
59 obj.loginCookieEncryptionKey = null;
60 + obj.serverSelfWriteAllowed = false;
61 try { obj.currentVer = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { } // Fetch server version
62
63 // Setup the default configuration and files paths
@@ -491,7 +492,7 @@ function CreateMeshCentralServer(config, args) {
492 // Perform maintenance operations (called every hour)
493 obj.maintenanceActions = function () {
494 // Check if we need to perform server self-update
494 - if (obj.args.selfupdate == true) {
495 + if ((obj.args.selfupdate == true) && (obj.serverSelfWriteAllowed == true)) {
496 obj.db.getValueOfTheDay('performSelfUpdate', 1, function (performSelfUpdate) {
497 if (performSelfUpdate.value > 0) {
498 performSelfUpdate.value--;
@@ -1096,7 +1097,8 @@ function CreateMeshCentralServer(config, args) {
1097 var r = 'time=' + Date.now() + '\r\n';
1098 for (var i in meshServerState) { r += (i + '=' + meshServerState[i] + '\r\n'); }
1099 obj.fs.writeFileSync(obj.getConfigFilePath('serverstate.txt'), r); // Try to write the server state, this may fail if we don't have permission.
1099 - } catch (ex) { } // Do nothing since this is not a critical feature.
1100 + obj.serverSelfWriteAllowed = true;
1101 + } catch (ex) { obj.serverSelfWriteAllowed = false; } // Do nothing since this is not a critical feature.
1102 };
1103
1104 // Logging funtions
meshuser.js
+26 -5
@@ -76,7 +76,18 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
76
77 try {
78 // Check if the user is logged in
79 - if ((!req.session) || (!req.session.userid) || (req.session.domainid != domain.id)) { try { obj.ws.close(); } catch (e) { } return; }
79 + if ((!req.session) || (!req.session.userid) || (req.session.domainid != domain.id)) {
80 + // If a default user is active, setup the session here.
81 + if (obj.args.user && obj.parent.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]) {
82 + if (req.session && req.session.loginmode) { delete req.session.loginmode; }
83 + req.session.userid = 'user/' + domain.id + '/' + obj.args.user.toLowerCase();
84 + req.session.domainid = domain.id;
85 + req.session.currentNode = '';
86 + } else {
87 + // Close the websocket connection
88 + try { obj.ws.close(); } catch (e) { } return;
89 + }
90 + }
91 req.session.ws = obj.ws; // Associate this websocket session with the web session
92 req.session.ws.userid = req.session.userid;
93 req.session.ws.domainid = domain.id;
@@ -217,6 +228,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
228 });
229 break;
230 }
231 + case 'lastconnect':
232 + {
233 + if (obj.common.validateString(command.nodeid, 0, 128) == false) return;
234 +
235 + // Query the database for the last time this node connected
236 + obj.db.Get('lc' + command.nodeid, function (err, docs) {
237 + if ((docs != null) && (docs.length > 0)) { try { ws.send(JSON.stringify({ action: 'lastconnect', nodeid: command.nodeid, time: docs[0].time })); } catch (ex) { } }
238 + });
239 + break;
240 + }
241 case 'files':
242 {
243 // Send the full list of server files to the browser app
@@ -434,7 +455,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
455 // Remove user from the mesh
456 if (mesh.links[deluser._id] != null) { delete mesh.links[deluser._id]; obj.parent.db.Set(mesh); }
457 // Notify mesh change
437 - change = 'Removed user ' + deluser.name + ' from mesh ' + mesh.name;
458 + change = 'Removed user ' + deluser.name + ' from group ' + mesh.name;
459 obj.parent.parent.DispatchEvent(['*', mesh._id, deluser._id, user._id], obj, { etype: 'mesh', username: user.name, userid: user._id, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id });
460 }
461 }
@@ -722,7 +743,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
743 obj.db.Set(obj.common.escapeLinksFieldName(mesh));
744
745 // Notify mesh change
725 - obj.parent.parent.DispatchEvent(['*', mesh._id, user._id, command.userid], obj, { etype: 'mesh', username: user.name, userid: deluser.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Removed user ' + deluser.name + ' from mesh ' + mesh.name, domain: domain.id });
746 + obj.parent.parent.DispatchEvent(['*', mesh._id, user._id, command.userid], obj, { etype: 'mesh', username: user.name, userid: deluser.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: 'Removed user ' + deluser.name + ' from group ' + mesh.name, domain: domain.id });
747 }
748 }
749 break;
@@ -805,7 +826,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
826 obj.db.RemoveNode(node._id); // Remove all entries with node:id
827
828 // Event node deletion
808 - obj.parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from mesh ' + mesh.name, domain: domain.id });
829 + obj.parent.parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from group ' + mesh.name, domain: domain.id });
830
831 // Disconnect all connections if needed
832 var state = obj.parent.parent.GetConnectivityState(nodeid);
@@ -1034,7 +1055,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
1055 obj.db.Set(node);
1056
1057 // Event the node change
1037 - event.msg = 'Changed device ' + node.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ');
1058 + event.msg = 'Changed device ' + node.name + ' from group ' + mesh.name + ': ' + changes.join(', ');
1059 var node2 = obj.common.Clone(node);
1060 if (node2.intelamt && node2.intelamt.pass) delete node2.intelamt.pass; // Remove the Intel AMT password before eventing this.
1061 event.node = node2;
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.2.0-y",
3 + "version": "0.2.1-a",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
views/default.handlebars
+54 -35
@@ -82,7 +82,7 @@
82 </div>
83 <div id="page_content" style="max-height:calc(100vh - 130px)">
84 <div id=topbarmaster>
85 - <div id=topbar class=noselect style=display:none>
85 + <div id=topbar class=noselect>
86 <div>
87 <div style="position:relative">
88 <div style="position:absolute;top:3px;right:6px">
@@ -129,7 +129,7 @@
129 </tr>
130 </table>
131 </div>
132 - <div id=UserDummyMenuSpan style=display:none>
132 + <div id=UserDummyMenuSpan>
133 <table id=UserDummyMenu style=width:100%;height:22px cellpadding=0 cellspacing=0 class=style1>
134 <tr><td class=style3 style="text-align:right;height:24px">&nbsp;</td></tr>
135 </table>
@@ -183,10 +183,10 @@
183 <div style=float:right id=devListToolbarSort>
184 Sort
185 <select id=sortselect onchange=onSortSelectChange()>
186 - <option>Mesh</option>
186 + <option>Group</option>
187 <option>Power</option>
188 <option>Device</option>
189 - <option>Group</option>
189 + <option>Tags</option>
190 </select>
191 &nbsp;
192 </div>
@@ -208,7 +208,7 @@
208 <img src="images/info.png" height="48" width="47" />
209 </td>
210 <td>
211 - To get started managing devices, <a onclick=account_createMesh() style=cursor:pointer><strong>click here to create a new group of devices called a Mesh</strong></a>.
211 + To get started, <a onclick=account_createMesh() style=cursor:pointer><strong>click here to create a device group</strong></a>.
212 </td>
213 </tr>
214 </table>
@@ -245,11 +245,11 @@
245 <a id="p2ServerActionsErrors" onclick="server_showErrorsDlg()" style="cursor:pointer">Show server error log</a><br />
246 </p>
247 <br style=clear:both />
248 - <strong>Administrative Meshes</strong>
248 + <strong>Device Groups</strong>
249 ( <a onclick=account_createMesh() style=cursor:pointer><img height=12 src="images/icon-addnew.png" width=12 border=0 /> New</a> )
250 <br /><br />
251 <div id=p2meshes></div>
252 - <div id=p2noMeshFound style=margin-left:40px;display:none>No meshes. <a onclick=account_createMesh() style=cursor:pointer><strong>Get started here!</strong></a></div>
252 + <div id=p2noMeshFound style=margin-left:40px;display:none>No device groups. <a onclick=account_createMesh() style=cursor:pointer><strong>Get started here!</strong></a></div>
253 <br style=clear:both />
254 </div>
255 <div id=p3 style=display:none>
@@ -721,7 +721,7 @@
721 </div>
722 <div id=dialog7 style="margin:auto;margin:3px">
723 <div id="d7meshkvm">
724 - <h4 style="width:100%;border-bottom:1px solid gray">Mesh Agent Remote Desktop</h4>
724 + <h4 style="width:100%;border-bottom:1px solid gray">Agent Remote Desktop</h4>
725 <div style="margin:3px 0 3px 0">
726 <select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl"></select>
727 <div style="height:20px">Quality</div>
@@ -1111,6 +1111,16 @@
1111 if (currentNode._id == message.nodeid) { drawDeviceTimeline(); }
1112 break;
1113 }
1114 + case 'lastconnect': {
1115 + var node = getNodeFromId(message.nodeid);
1116 + if (node != null) {
1117 + node.lastconnect = message.time;
1118 + if ((currentNode._id == node._id) && (Q('MainComputerState').innerHTML == '')) {
1119 + QH('MainComputerState', '<span style=font-size:12px>Last connected:<br />' + new Date(node.lastconnect).toLocaleDateString() + ', ' + new Date(node.lastconnect).toLocaleTimeString() + '</span>');
1120 + }
1121 + }
1122 + break;
1123 + }
1124 case 'msg': {
1125 // Check if this is a message from a node
1126 if (message.nodeid != null) {
@@ -1171,7 +1181,7 @@
1181 x += addHtmlValue2('Current Version', '<b>' + EscapeHtml(message.current) + '</b>');
1182 x += addHtmlValue2('Latest Version', '<b>' + EscapeHtml(message.latest) + '</b>');
1183 x += '</div>';
1174 - if (message.current == message.latest) {
1184 + if ((message.current == message.latest) || ((features & 2048) == 0)) {
1185 setDialogMode(2, "MeshCentral Version", 1, null, x);
1186 } else {
1187 setDialogMode(2, "MeshCentral Version", 3, server_showVersionDlgEx, x + '<br /><input id=d2updateCheck type=checkbox onclick=server_showVersionDlgUpdate() /> Check and click OK to start server self-update.');
@@ -1361,7 +1371,6 @@
1371 for (var i in nodes) { if (nodes[i]._id == message.event.nodeid) { index = i; break; } }
1372 if (index != -1) {
1373 var node = nodes[index];
1364 - console.log(node);
1374
1375 // Change the node
1376 node.name = message.event.node.name;
@@ -1765,9 +1774,9 @@
1774 }
1775 r += '</tr></table><div style=height:1px></div>'; // This height of 1 div fixes a problem in Linux firefox browsers
1776
1768 - // Add a "Add Mesh" option
1777 + // Add a "Add Device Group" option
1778 r += '<div style=border-top-style:solid;border-top-width:1px;border-top-color:#DDDDDD;cursor:pointer;font-size:10px>';
1770 - if ((view < 3) && (sort == 0) && (meshcount > 0)) { r += '<a onclick=account_createMesh() title="Create a new group of computers." style=cursor:pointer>Add Mesh</a>&nbsp'; }
1779 + if ((view < 3) && (sort == 0) && (meshcount > 0)) { r += '<a onclick=account_createMesh() title="Create a new group of devices." style=cursor:pointer>Add Device Group</a>&nbsp'; }
1780 r += '<a onclick=p10showMeshCmdDialog(0) style=cursor:pointer title="Download MeshCmd, a command line tool that performs many functions.">MeshCmd</a></div>';
1781 r += '</div><br/>';
1782
@@ -1946,7 +1955,7 @@
1955 function addDeviceToMesh(meshid) {
1956 if (xxdialogMode) return;
1957 var mesh = meshes[meshid];
1949 - var x = "Add a new Intel&reg; AMT device to mesh " + EscapeHtml(mesh.name) + ".<br /><br />";
1958 + var x = "Add a new Intel&reg; AMT device to device group \"" + EscapeHtml(mesh.name) + "\".<br /><br />";
1959 x += addHtmlValue('Device Name', '<input id=dp1devicename style=width:230px maxlength=32 autocomplete=off onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
1960 x += addHtmlValue('Hostname', '<input id=dp1hostname style=width:230px maxlength=32 autocomplete=off placeholder="Same as device name" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
1961 x += addHtmlValue('Username', '<input id=dp1username style=width:230px maxlength=32 autocomplete=off placeholder="admin" onchange=validateDeviceToMesh() onkeyup=validateDeviceToMesh() />');
@@ -2015,13 +2024,13 @@
2024 x += '<hr>';
2025
2026 // Setup CIRA using a MeshCommander script (Pretty Simple)
2018 - x += "<div id=dlgAddCira0>To add a new Intel&reg; AMT device to mesh " + EscapeHtml(mesh.name) + " with CIRA, download the following script files and use <a href='http://meshcommander.com' target='_blank'>MeshCommander</a> to run the script to configure computers.<br /><br />";
2027 + x += "<div id=dlgAddCira0>To add a new Intel&reg; AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, download the following script files and use <a href='http://meshcommander.com' target='_blank'>MeshCommander</a> to run the script to configure computers.<br /><br />";
2028 x += addHtmlValue('Setup CIRA', '<a href="mescript.ashx?type=1&meshid=' + meshidx.substring(0, 16) + '" target="_blank">cira_setup.mescript</a>');
2029 x += addHtmlValue('Cleanup CIRA', '<a href="mescript.ashx?type=2" target="_blank">cira_clean.mescript</a>');
2030 x += "</div>";
2031
2032 // Setup CIRA with user/pass authentication (Somewhat difficult)
2024 - x += "<div id=dlgAddCira1 style=display:none>To add a new Intel&reg; AMT device to mesh " + EscapeHtml(mesh.name) + " with CIRA, load the following certificate as trusted root within Intel AMT";
2033 + x += "<div id=dlgAddCira1 style=display:none>To add a new Intel&reg; AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, load the following certificate as trusted root within Intel AMT";
2034 if (serverinfo.mpspass) { x += " and authenticate to the server using this username and password.<br /><br />"; } else { x += " and authenticate to the server using this username and any password.<br /><br />"; }
2035 x += addHtmlValue('Root Certificate', '<a href="MeshServerRootCert.cer" target="_blank">Root Certificate File</a>');
2036 x += addHtmlValue('Username', '<input style=width:230px readonly value="' + meshidx.substring(0, 16) + '" />');
@@ -2031,7 +2040,7 @@
2040
2041 // Setup CIRA with certificate authentication (Really difficult, only is allowed)
2042 if ((features & 16) == 0) {
2034 - x += "<div id=dlgAddCira2 style=display:none>To add a new Intel&reg; AMT device to mesh " + EscapeHtml(mesh.name) + " with CIRA, load the following certificate as trusted root within Intel AMT, authenticate using a client certificate with the following common name and connect to the following server.<br /><br />";
2043 + x += "<div id=dlgAddCira2 style=display:none>To add a new Intel&reg; AMT device to device group \"" + EscapeHtml(mesh.name) + "\" with CIRA, load the following certificate as trusted root within Intel AMT, authenticate using a client certificate with the following common name and connect to the following server.<br /><br />";
2044 x += addHtmlValue('Root Certificate', '<a href="MeshServerRootCert.cer" target="_blank">Root Certificate File</a>');
2045 x += addHtmlValue('Organization', '<input style=width:230px readonly value="' + meshidx + '" />');
2046 if (serverinfo != null) { x += addHtmlValue('MPS Server', '<input style=width:230px readonly value="' + EscapeHtml(serverinfo.mpsname) + ':' + serverinfo.mpsport + '" />'); }
@@ -2083,8 +2092,8 @@
2092 //x += addHtmlValue('Operating System', '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux</option><option value=3>Windows (UnInstall)</option><option value=4>Linux (UnInstall)</option></select>') + '<hr>';
2093
2094 // Windows agent install
2086 - //x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
2087 - x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and install it the computer to manage. This agent has server and mesh information embedded within it.<br /><br />";
2095 + //x += "<div id=agins_windows>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
2096 + x += "<div id=agins_windows>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and install it the computer to manage. This agent has server and mesh information embedded within it.<br /><br />";
2097 x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '" target="_blank" title="32bit version of the MeshAgent">Windows (.exe)</a>');
2098 x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=4&meshid=' + meshid.split('/')[2] + '" target="_blank" title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
2099 if (debugmode > 0) { x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>'); }
@@ -2096,7 +2105,7 @@
2105 x += "</div>";
2106
2107 // OSX agent install
2099 - x += "<div id=agins_osx style=display:none>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and install it the computer to manage. This agent installer has server and mesh information embedded within it.<br /><br />";
2108 + x += "<div id=agins_osx style=display:none>To add a new computer to device group \"" + EscapeHtml(mesh.name) + "\", download the mesh agent and install it the computer to manage. This agent installer has server and mesh information embedded within it.<br /><br />";
2109 x += addHtmlValue('Mesh Agent', '<a href="meshosxagent?id=16&meshid=' + meshid.split('/')[2] + '" target="_blank" title="64bit version of OSX Mesh Agent">OSX Agent (64bit) - TEST BUILD</a>');
2110 x += "</div>";
2111
@@ -2995,7 +3004,7 @@
3004 var x = '<table style=width:100%>';
3005
3006 // Attribute: Mesh
2998 - x += addDeviceAttribute('<span title="The name of the administrative group this computer belong to">Mesh</span>', '<a title="The name of the group this computer belong to" onclick=gotoMesh("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
3007 + x += addDeviceAttribute('<span title="The name of the device group this computer belong to.">Group</span>', '<a title="The name of the device group this computer belong to" onclick=gotoMesh("' + node.meshid + '") style=cursor:pointer>' + EscapeHtml(meshes[node.meshid].name) + '</a>');
3008
3009 // Attribute: Name
3010 if ((node.rname != null) && (node.name != node.rname)) { x += addDeviceAttribute('<span title="The name of this computer as set in the operating system">Name</span>', '<span title="The name of this computer as set in the operating system">' + EscapeHtml(node.rname) + '</span>'); }
@@ -3091,7 +3100,7 @@
3100 // Node grouping tags
3101 var groupingTags = '<i>None</i>';
3102 if (node.tags != null) { groupingTags = ''; for (var i in node.tags) { groupingTags += '<span style="background-color:lightgray;padding:3px;margin-right:4px;border-radius:5px">' + node.tags[i] + '</span>'; } }
3094 - x += addDeviceAttribute('Groups', '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + ' <img class=hoverButton src="images/link5.png" /></span>');
3103 + x += addDeviceAttribute('Tags', '<span onclick=showEditNodeValueDialog(3) style=cursor:pointer>' + groupingTags + ' <img class=hoverButton src="images/link5.png" /></span>');
3104
3105 x += '</table><br />';
3106 // Show action button, only show if we have permissions 4, 8, 64
@@ -3130,6 +3139,7 @@
3139 if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Agent connected">Agent connected</span>'; }
3140 if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Intel&reg; AMT connected">Intel&reg; AMT connected</span>'; }
3141 if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="Intel&reg; AMT detected">Intel&reg; AMT detected</span>'; }
3142 + if ((powerstate == '') && node.lastconnect) { powerstate = '<span style=font-size:12px>Last connected:<br />' + new Date(node.lastconnect).toLocaleDateString() + ', ' + new Date(node.lastconnect).toLocaleTimeString() + '</span>'; }
3143 QH('MainComputerState', powerstate);
3144
3145 // Set the node icon
@@ -3167,7 +3177,12 @@
3177 QV('filesActionsBtn', (meshrights & 72) != 0);
3178
3179 // Request the power timeline
3170 - if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { QH('p10html2', ''); powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
3180 + if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) {
3181 + QH('p10html2', '');
3182 + powerTimelineReq = currentNode._id;
3183 + meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
3184 + meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
3185 + }
3186
3187 // Reset the desktop tools
3188 QV('DeskTools', false);
@@ -3238,7 +3253,11 @@
3253 // Look to see if we need to update the device timeline
3254 function updateDeviceTimeline() {
3255 if ((meshserver.State != 2) || (powerTimelineNode == null) || (powerTimelineUpdate == null) || (currentNode == null)) return;
3241 - if ((powerTimelineNode == powerTimelineReq) && (currentNode._id == powerTimelineNode) && (powerTimelineUpdate < Date.now())) { powerTimelineUpdate = null; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
3256 + if ((powerTimelineNode == powerTimelineReq) && (currentNode._id == powerTimelineNode) && (powerTimelineUpdate < Date.now())) {
3257 + powerTimelineUpdate = null;
3258 + meshserver.send({ action: 'powertimeline', nodeid: currentNode._id });
3259 + meshserver.send({ action: 'lastconnect', nodeid: currentNode._id });
3260 + }
3261 }
3262
3263 // Draw device power bars. The bars are 766px wide.
@@ -4762,11 +4781,11 @@
4781
4782 function account_createMesh() {
4783 if (xxdialogMode) return;
4765 - var x = "Create a new mesh computer group using the options below.<br /><br />";
4766 - x += addHtmlValue('Mesh Name', '<input id=dp2meshname style=width:230px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate() />');
4767 - x += addHtmlValue('Mesh Type', '<div style=width:230px;margin:0;padding:0><select id=dp2meshtype style=width:100% onchange=account_validateMeshCreate() ><option value=2>Mesh Agent Policy</option><option value=1>Intel&reg; AMT Agent-less Policy</option></select></div>');
4784 + var x = "Create a new device group using the options below.<br /><br />";
4785 + x += addHtmlValue('Name', '<input id=dp2meshname style=width:230px maxlength=64 onchange=account_validateMeshCreate() onkeyup=account_validateMeshCreate() />');
4786 + x += addHtmlValue('Type', '<div style=width:230px;margin:0;padding:0><select id=dp2meshtype style=width:100% onchange=account_validateMeshCreate() ><option value=2>Manage using a software agent</option><option value=1>Intel&reg; AMT only, no agent</option></select></div>');
4787 x += addHtmlValue('Description', '<div style=width:230px;margin:0;padding:0><textarea id=dp2meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
4769 - setDialogMode(2, "Create Mesh", 3, account_createMeshEx, x);
4788 + setDialogMode(2, "New Device Group", 3, account_createMeshEx, x);
4789 account_validateMeshCreate();
4790 Q('dp2meshname').focus();
4791 }
@@ -4874,8 +4893,8 @@
4893 QH('p20meshName', EscapeHtml(currentMesh.name));
4894 var meshtype = 'Unknown #' + currentMesh.mtype;
4895 var meshrights = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
4877 - if (currentMesh.mtype == 1) meshtype = 'Intel&reg; AMT computer group (No Agent)';
4878 - if (currentMesh.mtype == 2) meshtype = 'Mesh agent computer group';
4896 + if (currentMesh.mtype == 1) meshtype = 'Intel&reg; AMT only, no agent';
4897 + if (currentMesh.mtype == 2) meshtype = 'Managed using a software agent';
4898
4899 var x = '';
4900 x += addHtmlValue('Name', addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
@@ -4883,7 +4902,7 @@
4902 x += addHtmlValue('Type', meshtype);
4903 x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
4904
4886 - x += '<br><input type=button value=Notes title="View notes about this mesh" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
4905 + x += '<br><input type=button value=Notes title="View notes about this device group" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
4906
4907 x += '<br style=clear:both><br>';
4908 var currentMeshLinks = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
@@ -4959,9 +4978,9 @@
4978
4979 function p20editmesh(focus) {
4980 if (xxdialogMode) return;
4962 - var x = addHtmlValue('Mesh Name', '<input id=dp20meshname style=width:230px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate() />');
4981 + var x = addHtmlValue('Name', '<input id=dp20meshname style=width:230px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate() />');
4982 x += addHtmlValue('Description', '<div style=width:230px;margin:0;padding:0><textarea id=dp20meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
4964 - setDialogMode(2, "Edit Mesh", 3, p20editmeshEx, x);
4983 + setDialogMode(2, "Edit Device Group", 3, p20editmeshEx, x);
4984 Q('dp20meshname').value = currentMesh.name;
4985 if (currentMesh.desc) Q('dp20meshdesc').value = currentMesh.desc;
4986 p20editmeshValidate();
@@ -4978,7 +4997,7 @@
4997
4998 function p20showAddMeshUserDialog() {
4999 if (xxdialogMode) return;
4981 - var x = "Allow a user to manage the mesh and computers on this mesh<br /><br />";
5000 + var x = "Allow a user to manage this device group and devices in this group<br /><br />";
5001 x += addHtmlValue('User Name', '<input id=dp20username style=width:230px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() />');
5002 x += '<br><div>';
5003 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20fulladmin>Full Administrator<br>';
@@ -4991,7 +5010,7 @@
5010 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>Wake Devices<br>';
5011 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>Edit Device Notes<br>';
5012 x += '</div>';
4994 - setDialogMode(2, "Add User to Mesh", 3, p20showAddMeshUserDialogEx, x);
5013 + setDialogMode(2, "Add User to Device Group", 3, p20showAddMeshUserDialogEx, x);
5014 p20validateAddMeshUserDialog();
5015 Q('dp20username').focus();
5016 }
@@ -5044,7 +5063,7 @@
5063 var buttons = 1, x = addHtmlValue('User Name', userid.split('/')[2]);
5064 x += addHtmlValue('Permissions', r);
5065 if ((('user/' + domain + '/' + userinfo.name.toLowerCase()) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
5047 - setDialogMode(2, "Mesh User", buttons, p20viewuserEx, x, userid);
5066 + setDialogMode(2, "Device Group User", buttons, p20viewuserEx, x, userid);
5067 }
5068
5069 function p20viewuserEx(button, userid) { if (button != 2) return; setDialogMode(2, "Remote Mesh User", 3, p20viewuserEx2, "Confirm removal of user " + userid.split('/')[2] + "?", userid); }
webserver.js
+4 -3
@@ -575,7 +575,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
575 var escUserId = obj.common.escapeFieldName(userid);
576 if (mesh.links[escUserId] != null) { delete mesh.links[escUserId]; obj.db.Set(mesh); }
577 // Notify mesh change
578 - var change = 'Removed user ' + user.name + ' from mesh ' + mesh.name;
578 + var change = 'Removed user ' + user.name + ' from group ' + mesh.name;
579 obj.parent.DispatchEvent(['*', mesh._id, user._id, userid], obj, { etype: 'mesh', username: user.name, userid: userid, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id });
580 }
581 }
@@ -728,7 +728,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
728 if (obj.args.clickonce !== false) { features += 256; } // Enable ClickOnce (Default true)
729 if (obj.args.allowhighqualitydesktop == true) { features += 512; } // Enable AllowHighQualityDesktop (Default false)
730 if (obj.args.lanonly == true || obj.args.mpsport == 0) { features += 1024; } // No CIRA
731 -
731 + if ((obj.serverSelfWriteAllowed == true) && (user.siteadmin == 0xFFFFFFFF)) { features += 2048; } // Server can self-write (Allows self-update)
732 +
733 // Send the master web application
734 if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
735 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
@@ -1410,7 +1411,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1411 obj.db.Set(node);
1412
1413 // Event the node change
1413 - var event = { etype: 'node', action: 'changenode', nodeid: node._id, domain: domain.id, msg: 'Intel(R) AMT host change ' + node.name + ' from mesh ' + mesh.name + ': ' + oldname + ' to ' + amthost };
1414 + var event = { etype: 'node', action: 'changenode', nodeid: node._id, domain: domain.id, msg: 'Intel(R) AMT host change ' + node.name + ' from group ' + mesh.name + ': ' + oldname + ' to ' + amthost };
1415 var node2 = obj.common.Clone(node);
1416 if (node2.intelamt && node2.intelamt.pass) delete node2.intelamt.pass; // Remove the Intel AMT password before eventing this.
1417 event.node = node2;