diff --git a/agents/MeshCmd-signed.exe b/agents/MeshCmd-signed.exe
index 9890996f..ac26da21 100644
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
diff --git a/agents/MeshCmd64-signed.exe b/agents/MeshCmd64-signed.exe
index 76c0cf80..3377a38f 100644
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
diff --git a/agents/MeshService-signed.exe b/agents/MeshService-signed.exe
index 60b35c31..13ca8580 100644
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
diff --git a/agents/MeshService.exe b/agents/MeshService.exe
index 81ac047d..3af133b0 100644
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
diff --git a/agents/MeshService64-signed.exe b/agents/MeshService64-signed.exe
index d4f6f895..b8552db8 100644
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
diff --git a/agents/MeshService64.exe b/agents/MeshService64.exe
index 3d87e0a5..b53f5cb1 100644
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
diff --git a/meshcentral.js b/meshcentral.js
index a1d7f2ac..11ca7e13 100644
--- a/meshcentral.js
+++ b/meshcentral.js
@@ -99,7 +99,7 @@ function CreateMeshCentralServer(config, args) {
console.log(' --redirport [number] Creates an additional HTTP server to redirect users to the HTTPS server.');
console.log(' --exactports Server must run with correct ports or exit.');
console.log(' --noagentupdate Server will not update mesh agent native binaries.');
- console.log(' --cert [name], (country), (org) Create a web server certificate with [name]server name.');
+ console.log(' --cert [name], (country), (org) Create a web server certificate with [name] server name.');
console.log(' country and organization can optionaly be set.');
return;
}
@@ -1148,9 +1148,13 @@ function mainStart(args) {
var config = getConfig();
if (config == null) { process.exit(); }
+ // Check is Windows SSPI will be used
+ var sspi = false;
+ if (require('os').platform() == 'win32') { for (var i in config.domains) { if (config.domains[i].auth == 'sspi') { sspi = true; } } }
+
// Build the list of required modules
var modules = ['ws', 'nedb', 'https', 'yauzl', 'xmldom', 'express', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-session', 'express-handlebars'];
- if (require('os').platform() == 'win32') { modules.push('node-sspi'); modules.push('node-windows'); } // Add Windows modules
+ if (require('os').platform() == 'win32') { modules.push('node-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
if (config.letsencrypt != null) { modules.push('greenlock'); modules.push('le-store-certbot'); modules.push('le-challenge-fs'); modules.push('le-acme-core'); } // Add Greenlock Modules
if (config.settings.mongodb != null) { modules.push('mongojs'); } // Add MongoDB
if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
diff --git a/meshuser.js b/meshuser.js
index 9c99be5e..7c3d4d27 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -624,7 +624,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
if ((obj.common.validateString(command.meshname, 1, 64) == true) && (command.meshname != mesh.name)) { change = 'Mesh name changed from "' + mesh.name + '" to "' + command.meshname + '"'; mesh.name = command.meshname; }
- if ((obj.common.validateString(command.desc, 1, 1024) == true) && (command.desc != mesh.desc)) { if (change != '') change += ' and description changed'; else change += 'Mesh "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
+ if ((obj.common.validateString(command.desc, 0, 1024) == true) && (command.desc != mesh.desc)) { if (change != '') change += ' and description changed'; else change += 'Mesh "' + mesh.name + '" description changed'; mesh.desc = command.desc; }
if (change != '') { obj.db.Set(mesh); obj.parent.parent.DispatchEvent(['*', mesh._id, user._id], obj, { etype: 'mesh', username: user.name, meshid: mesh._id, name: mesh.name, mtype: mesh.mtype, desc: mesh.desc, action: 'meshchange', links: mesh.links, msg: change, domain: domain.id }) }
}
break;
diff --git a/package.json b/package.json
index d801fefc..22d130f8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "meshcentral",
- "version": "0.1.7-s",
+ "version": "0.1.7-x",
"keywords": [
"Remote Management",
"Intel AMT",
diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars
index 8db6b8ac..a2679a39 100644
--- a/views/default-mobile.handlebars
+++ b/views/default-mobile.handlebars
@@ -20,58 +20,34 @@
text-decoration: underline;
}
- #footer a:hover {
- color: #fff;
- text-decoration: none;
- }
-
- .i1 {
- background: url(../images/icons50.png) 0px 0px;
- height: 50px;
- width: 50px;
- border: none;
+ #footer a:hover {
+ color: #fff;
+ text-decoration: none;
}
- .i2 {
- background: url(../images/icons50.png) -50px 0px;
- height: 50px;
- width: 50px;
- border: none;
- }
-
- .i3 {
- background: url(../images/icons50.png) -100px 0px;
- height: 50px;
- width: 50px;
- border: none;
- }
-
- .i4 {
- background: url(../images/icons50.png) -150px 0px;
- height: 50px;
- width: 50px;
- border: none;
- }
-
- .i5 {
- background: url(../images/icons50.png) -200px 0px;
- height: 50px;
- width: 50px;
- border: none;
- }
-
- .i6 {
- background: url(../images/icons50.png) -250px 0px;
- height: 50px;
- width: 50px;
- border: none;
- }
+ .i1 {background:url(../images/icons50.png) 0px 0px;height:50px;width:50px;border:none;}
+ .i2 {background:url(../images/icons50.png) -50px 0px;height:50px;width:50px;border:none;}
+ .i3 {background:url(../images/icons50.png) -100px 0px;height:50px;width:50px;border:none;}
+ .i4 {background:url(../images/icons50.png) -150px 0px;height:50px;width:50px;border:none;}
+ .i5 {background:url(../images/icons50.png) -200px 0px;height:50px;width:50px;border:none;}
+ .i6 {background:url(../images/icons50.png) -250px 0px; height:50px;width:50px; border:none; }
+ .m0 {background:url(../images/images16.png) -32px 0px; height:16px;width:16px; border:none;float:left }
+ .m1 {background:url(../images/images16.png) -16px 0px; height:16px;width:16px; border:none;float:left }
+ .m2 {background:url(../images/images16.png) -96px 0px; height:16px;width:16px; border:none;float:left }
+ .m3 {background:url(../images/images16.png) -112px 0px; height:16px;width:16px; border:none;float:left }
.gray {
/*filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0\'/></filter></svg>#grayscale");*/ /* Firefox 10+, Firefox on Android */
filter: gray; /* IE6-9 */
-webkit-filter: grayscale(100%) opacity(60%); /* Chrome 19+, Safari 6+, Safari 6+ iOS */
}
+
+ .DevSt {
+ padding-left:5px;
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ border-bottom-color: #DDDDDD;
+ }
@@ -86,7 +62,7 @@
-
+
Server disconnected, click to reconnect.
@@ -100,6 +76,51 @@
+
+
+
+
+
+
+
+
◀
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
◀
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
X
@@ -225,9 +246,9 @@
break;
}
case 'files': {
- filetree = setupBackPointers(message.filetree);
- updateFiles();
- d3updatefiles();
+ //filetree = setupBackPointers(message.filetree);
+ //updateFiles();
+ //d3updatefiles();
break;
}
case 'nodes': {
@@ -401,12 +422,12 @@
if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
}
node.namel = node.name.toLowerCase();
- if (node.host) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
+ if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
if (message.event.node.icon) { node.icon = message.event.node.icon; }
//onSortSelectChange(true);
//drawNotifications();
- //refreshDevice(node._id);
+ refreshDevice(node._id);
//updateMapMarkers();
updateDevices();
@@ -422,8 +443,8 @@
var node = nodes[index];
// Change the node connection state
- //node.conn = message.event.conn;
- //node.pwr = message.event.pwr;
+ node.conn = message.event.conn;
+ node.pwr = message.event.pwr;
updateDevices();
//updateMapMarkers();
//refreshDevice(node._id);
@@ -462,19 +483,27 @@
// MY DEVICES
//
+ var backStack = [];
+ function goBack() { if (backStack.length == 0) { goMyDevices(); } else { gotoDevice(backStack.pop()); } }
+ function goMyDevices() { go(2); }
+
var sort = 0;
var deviceHeaderId = 0;
var deviceHeaderCount;
var deviceHeaders = {};
+ var showRealNames = false;
+ var deviceHeaderTotal = 0;
+ var deviceHeaders = {};
+ var deviceHeadersTitles = {};
function updateDevices() {
var r = '', c = 0, current = null, count = 0, displayedMeshes = {}, groups = {}, groupCount = {};
// 3 wide, list view or desktop view
deviceHeaderId = 0;
deviceHeaderCount = {};
- var deviceHeaderTotal = 0;
- var deviceHeaders = {};
- var deviceHeadersTitles = {};
+ deviceHeaderTotal = 0;
+ deviceHeaders = {};
+ deviceHeadersTitles = {};
var current;
// Go thru the list of nodes and display them
@@ -484,17 +513,17 @@
if (meshlinks == null) continue;
var meshrights = meshlinks.rights;
- /*
if (sort == 0) {
// Mesh header
+ nodes.sort(meshSort);
if (nodes[i].meshid != current) {
- //deviceHeaderSet();
+ deviceHeaderSet();
var extra = '';
- if (meshes[nodes[i].meshid].mtype == 1) { extra = ', Intel® AMT only'; }
+ if (meshes[nodes[i].meshid].mtype == 1) { extra = ', Intel® AMT only'; }
if (current != null) { if (c == 2) { r += '
'; } if (r != '') { r += ''; } }
- r += '
';
+ r += '
';
//r += getMeshActions(mesh2, meshrights);
- r += '' + EscapeHtml(meshes[nodes[i].meshid].name) + '' + extra + '
';
+ r += '' + EscapeHtml(meshes[nodes[i].meshid].name) + '' + extra + '
';
current = nodes[i].meshid;
displayedMeshes[current] = 1;
c = 0;
@@ -502,9 +531,9 @@
} else if (sort == 1) {
// Power header
if (nodes[i].pwr !== current) {
- //deviceHeaderSet();
+ deviceHeaderSet();
if (current !== null) { if (c == 2) { r += '
'; } if (r != '') { r += ''; } }
- r += '
' + PowerStateStr2(nodes[i].pwr) + '
';
+ r += '
' + PowerStateStr2(nodes[i].pwr) + '
';
current = nodes[i].pwr;
c = 0;
}
@@ -512,29 +541,23 @@
// Device header
if (current == null) { current = '1'; }
}
- */
-
count++;
var title = EscapeHtml(nodes[i].name);
if (title.length == 0) { title = 'None'; }
if ((nodes[i].rname != null) && (nodes[i].rname.length > 0)) { title += " / " + EscapeHtml(nodes[i].rname); }
var name = EscapeHtml(nodes[i].name);
- //if (showRealNames == true && nodes[i].rname != null) name = EscapeHtml(nodes[i].rname);
+ if (showRealNames == true && nodes[i].rname != null) name = EscapeHtml(nodes[i].rname);
if (name.length == 0) { name = 'None'; }
// Node
- var icon = nodes[i].icon;
- var nodestate = NodeStateStr(nodes[i]);
+ var icon = nodes[i].icon, nodestate = NodeStateStr(nodes[i]);
if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
- //var title = '';
- //r += '
' + name + '
' + nodestate + '
';
- r += '
';
+ r += '
';
r += '';
- r += '
';
+ r += '
';
r += '
' + name + '
' + nodestate + '
';
- r += '
';
- r += '
';
+ r += '
';
// If we are displaying devices by group, put the device in the right group.
/*
@@ -554,9 +577,39 @@
if (typeof deviceHeaderCount[nodes[i].state] == 'undefined') { deviceHeaderCount[nodes[i].state] = 1; } else { deviceHeaderCount[nodes[i].state]++; }
}
+ // Display all empty meshes, we need to do this because users can add devices to these at any time.
+ if (sort == 0) {
+ for (var i in meshes) {
+ var mesh = meshes[i], meshlink = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
+ if (meshlink != null) {
+ var meshrights = meshlink.rights;
+ if (displayedMeshes[mesh._id] == null) {
+ if ((current != '') && (r != '')) { r += ''; }
+ r += '
No Intel® AMT devices in this mesh'; }
+ if (mesh.mtype == 2) { r += '
No devices in this mesh'; }
+ r += '.
';
+ current = mesh._id;
+ count++;
+ }
+ }
+ }
+ }
+
QH('xdevices', r);
+ deviceHeaderSet();
+ for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
+ for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
}
+ function gotoMeshStack(meshid) {
+ backStack.push(currentNode._id);
+ gotoMesh(meshid);
+ }
+
+ var powerStatetable = ['', 'Powered', 'Sleep', 'Sleep', 'Sleep', 'Hibernating', 'Power off', 'Present'];
var powerStateStrings = ['', 'Powered', 'Sleeping', 'Sleeping', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present'];
var powerStateStrings2 = ['', 'Device is powered', 'Device is in sleep state (S1)', 'Device is in sleep state (S2)', 'Device is in deep sleep state (S3)', 'Device is hibernating (S4)', 'Device is in soft-off state (S5)', 'Device is present, but power state cannot be determined'];
var powerColorTable = ['#00000000', 'black', 'blue', 'blue', 'lightblue', 'blueviolet', 'darkgreen', 'lightseagreen', 'lightseagreen'];
@@ -583,6 +636,31 @@
return 'Unknown';
}
+ function onSortSelectChange(skipsave) {
+ sort = document.getElementById("sortselect").selectedIndex;
+ if (!skipsave) { putstore("sort", sort); }
+ if (sort == 0) { nodes.sort(meshSort); }
+ if (sort == 1) { nodes.sort(powerSort); }
+ if (sort == 2) { if (showRealNames == true) { nodes.sort(deviceHostSort); } else { nodes.sort(deviceSort); } }
+ updateDevices();
+ }
+
+ function deviceHeaderSet() {
+ if (deviceHeaderId == 0) { deviceHeaderId = 1; return; }
+ deviceHeaders["DevxHeader" + deviceHeaderId] = ', ' + deviceHeaderTotal + ((deviceHeaderTotal == 1) ? ' node' : ' nodes');
+ var title = '';
+ for (x in deviceHeaderCount) { if (title.length > 0) title += ', '; title += deviceHeaderCount[x] + ' ' + PowerStateStr2(x); }
+ deviceHeadersTitles["DevxHeader" + deviceHeaderId] = title;
+ deviceHeaderId++;
+ deviceHeaderCount = {};
+ deviceHeaderTotal = 0;
+ }
+
+ function meshSort(a, b) { if (a.meshnamel > b.meshnamel) return 1; if (a.meshnamel < b.meshnamel) return -1; if (a.meshid == b.meshid) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
+ function powerSort(a, b) { var ap = a.pwr?a.pwr:0; var bp = b.pwr?b.pwr:0; if (ap == bp) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } if (ap > bp) return 1; if (ap < bp) return -1; return 0; }
+ function deviceSort(a, b) { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; }
+ function deviceHostSort(a, b) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; }
+
//
// MY DEVICE
//
@@ -604,9 +682,7 @@
var powerTimeline = null;
function getCurrentNode() { return currentNode; };
function gotoDevice(nodeid, panel, refresh) {
- //disconnectAllKvmFunction();
- var node = getNodeFromId(nodeid);
- var mesh = meshes[node.meshid];
+ var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
if (!currentNode || currentNode._id != node._id || refresh == true) {
currentNode = node;
@@ -616,18 +692,20 @@
if (nname.length == 0) { nname = 'None'; }
if ((meshrights & 4) != 0) { nname = '' + nname + ''; }
QH('p10deviceName', nname);
+ /*
QH('p11deviceName', nname);
QH('p12deviceName', nname);
QH('p13deviceName', nname);
QH('p14deviceName', nname);
QH('p15deviceName', nname);
QH('p16deviceName', nname);
+ */
// Node attributes
var x = '
';
// Attribute: Mesh
- x += addDeviceAttribute('Mesh', '' + EscapeHtml(meshes[node.meshid].name) + '');
+ x += addDeviceAttribute('Mesh', '' + EscapeHtml(meshes[node.meshid].name) + '');
// Attribute: Name
if (node.rname != null) { x += addDeviceAttribute('Name', '' + EscapeHtml(node.rname) + ''); }
@@ -676,12 +754,12 @@
if (node.intelamt.state == 2) {
if (node.intelamt.user == null || node.intelamt.user == '') {
if ((meshrights & 4) != 0) {
- str += ', No Credentials';
+ str += ', No Credentials';
} else {
- str += ', No Credentials';
+ str += ', No Credentials';
}
}
- str += ' ';
+ str += ' ';
if ((meshrights & 4) != 0) {
str += '';
}
@@ -717,31 +795,20 @@
x += '
';
// Show action button, only show if we have permissions 4, 8, 64
- if ((meshrights & 76) != 0) { x += ''; }
- x += '';
+ //if ((meshrights & 76) != 0) { x += ''; }
+ //x += '';
//if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += ''; }
QH('p10html', x);
// Show node last 7 days timeline
- drawDeviceTimeline();
+ //drawDeviceTimeline();
// Show bottom buttons
x = '
';
- if ((meshrights & 4) != 0) x += 'Delete Device';
+ //if ((meshrights & 4) != 0) x += 'Delete Device';
x += '
';
- if (mesh.mtype == 2) x += 'Interfaces ';
- if (xxmap != null) x += 'Location ';
-
- if (((meshrights & 8) != 0) && (mesh.mtype == 2)) x += 'Router ';
-
- // RDP link, show this link only of the remote machine is Windows.
- if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) {
- if ((node.agent.id > 0) && (node.agent.id < 5)) { x += 'RDP '; }
- if (node.agent.id > 4) {
- x += 'Putty ';
- x += 'WinSCP ';
- }
- }
+ //if (mesh.mtype == 2) x += 'Interfaces ';
+ //if (xxmap != null) x += 'Location ';
x += '
'
QH('p10html3', x);
@@ -749,60 +816,269 @@
// Set the node power state
powerstate = PowerStateStr(node.state);
//if (node.state == 0) { powerstate = 'Unknown State'; }
- if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ' '; } powerstate += 'Agent connected'; }
- if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += ' '; } powerstate += 'Intel® AMT connected'; }
- if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ' '; } powerstate += 'Intel® AMT detected'; }
+ if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += 'Mesh Agent'; }
+ if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += 'Intel® AMT connected'; } else
+ if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += 'Intel® AMT detected'; }
QH('MainComputerState', powerstate);
// Set the node icon
- Q('MainComputerImage').setAttribute("src", "images/icons200-" + node.icon + "-1.png");
- Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
-
- // Setup/Refresh the desktop tab
- setupTerminal();
- setupFiles();
- var consoleRights = ((meshrights & 16) != 0);
- if (consoleRights) { setupConsole(); } else { if (panel == 15) { panel = 10; } }
-
- // Show or hide the tabs
- // mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
- // node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
- QV('MainDevDesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0)) && (meshrights & 8));
- QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0)) && (meshrights & 8));
- QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8));
- QV('MainDevAmt', (node.intelamt != null) && (node.intelamt.state == 2) && (meshrights & 8));
- QV('MainDevConsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
- QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0) && (userinfo.siteadmin == 0xFFFFFFFF));
- QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
-
- // Setup/Refresh Intel AMT tab
- var amtFrameNode = Q('p14iframe').contentWindow.getCurrentMeshNode();
- if ((amtFrameNode != null) && (amtFrameNode._id != currentNode._id)) { Q('p14iframe').contentWindow.disconnect(); }
- var online = ((node.conn & 6) != 0)?true:false; // If CIRA (2) or AMT (4) connected, enable Commander
- Q('p14iframe').contentWindow.setConnectionState(online);
- Q('p14iframe').contentWindow.setFrameHeight('650px');
- Q('p14iframe').contentWindow.setAuthCallback(updateAmtCredentials);
-
- // Display "action" button on desktop/terminal/files
- QV('deskActionsBtn', (meshrights & 72) != 0); // 72 = Wake-up + Remote Control permissions
- QV('termActionsBtn', (meshrights & 72) != 0);
- QV('filesActionsBtn', (meshrights & 72) != 0);
-
- // Request the power timeline
- if ((powerTimelineNode != currentNode._id) && (powerTimelineReq != currentNode._id)) { powerTimelineReq = currentNode._id; meshserver.send({ action: 'powertimeline', nodeid: currentNode._id }); }
-
- // Reset the desktop tools
- QV('DeskTools', false);
- showDeskToolsProcesses();
-
- // Ask for device events
- //refreshDeviceEvents();
+ QH('MainComputerImage', '');
}
- setupDesktop(); // Always refresh the desktop, even if we are on the same device, we need to do some canvas switching.
if (!panel) panel = 10;
go(panel);
}
+ function addDeviceAttribute(name, value) {
+ return '
' + name + '
' + value + '
';
+ }
+
+ function p10showiconselector() {
+ if (xxdialogMode) return;
+ var mesh = meshes[currentNode.meshid];
+ var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
+ if ((meshrights & 4) == 0) return;
+
+ var x = '
';
+ x += '';
+ x += '';
+ x += ' ';
+ x += '';
+ x += '';
+ x += '
';
+ setDialogMode(2, "Icon Selection", 0, null, x);
+ QV('id_dialogclose', true);
+ }
+
+ function p10setIcon(icon) {
+ setDialogMode(0);
+ meshserver.send({ action: 'changedevice', nodeid: currentNode._id, icon: icon });
+ }
+
+ var showEditNodeValueDialog_modes = ['Device Name', 'Hostname', 'Description', 'Groups'];
+ var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc', 'tags'];
+ var showEditNodeValueDialog_modes3 = ['', '', '', 'Group1, Group2, Group3'];
+ function showEditNodeValueDialog(mode) {
+ if (xxdialogMode) return;
+ var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '');
+ setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
+ var v = currentNode[showEditNodeValueDialog_modes2[mode]];
+ if (v == null) v = '';
+ if (Array.isArray(v)) { v = v.join(', '); }
+ Q('dp10devicevalue').value = v;
+ p10editdevicevalueValidate();
+ Q('dp10devicevalue').focus();
+ }
+
+ function showEditNodeValueDialogEx(button, mode) {
+ var x = { action: 'changedevice', nodeid: currentNode._id };
+ x[showEditNodeValueDialog_modes2[mode]] = Q('dp10devicevalue').value;
+ meshserver.send(x);
+ }
+
+ function p10editdevicevalueValidate(mode, e) {
+ var x = ((mode > 1) || (Q('dp10devicevalue').value.length > 0));
+ QE('idx_dlgOkButton', x);
+ if ((e != null) && (x == true) && (e.keyCode == 13)) { dialogclose(1); }
+ }
+
+ //
+ // MY ACCOUNT
+ //
+
+ function gotoMesh(meshid) {
+ currentMesh = meshes[meshid];
+ p20updateMesh();
+ go(20);
+ }
+
+
+ //
+ // MY MESHS
+ //
+
+ var currentMesh;
+ function p20updateMesh() {
+ QH('p20meshName', EscapeHtml(currentMesh.name));
+ var meshtype = 'Unknown #' + currentMesh.mtype;
+ var meshrights = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
+ if (currentMesh.mtype == 1) meshtype = 'Intel® AMT group';
+ if (currentMesh.mtype == 2) meshtype = 'Mesh agent group';
+
+ var x = '';
+ x += addHtmlValue('Name', addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
+ x += addHtmlValue('Description', addLinkConditional(((currentMesh.desc && currentMesh.desc != '')?EscapeHtml(currentMesh.desc):'None'), 'p20editmesh(2)', (meshrights & 1) != 0));
+ x += addHtmlValue('Type', meshtype);
+ //x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
+
+ //x += ' ';
+
+ x += '
';
+ var currentMeshLinks = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
+ if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += ' Add User'; }
+
+ /*
+ if ((meshrights & 4) != 0) {
+ if (currentMesh.mtype == 1) {
+ x += ' Install CIRA';
+ x += ' Install local';
+ }
+ if (currentMesh.mtype == 2) {
+ x += ' Install';
+ }
+ }
+ */
+
+ /*
+ function getMeshActions(mesh, meshrights) {
+ if ((meshrights & 4) == 0) return '';
+ var r = '';
+ if (mesh.mtype == 1) {
+ r += ' Add CIRA';
+ r += ' Add Local';
+ }
+ if (mesh.mtype == 2) {
+ r += ' Add Agent';
+ }
+ return r;
+ }
+ */
+
+ x += '
User Authorizations
';
+
+ // Sort the users for this mesh
+ var count = 1, sortedusers = [];
+ for (var i in currentMesh.links) { sortedusers.push({ id: i, name: i.split('/')[2], rights: currentMesh.links[i].rights }); }
+ sortedusers.sort(function(a, b) { if (a.name > b.name) return 1; if (a.name < b.name) return -1; return 0; });
+
+ // Display all users for this mesh
+ for (var i in sortedusers) {
+ var trash = '', rights = 'Partial Rights', r = sortedusers[i].rights;
+ if (r == 0xFFFFFFFF) rights = 'Full Administrator'; else if (r == 0) rights = 'No Rights';
+ if ((i != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = ''; }
+ x += '
';
+ x += '
' + trash + '
' + rights + '
' + sortedusers[i].name + '
';
+ x += '
';
+ ++count;
+ }
+
+ x += '
';
+
+ // If we are full administrator on this mesh, allow deletion of the mesh
+ if (meshrights == 0xFFFFFFFF) { x += '
'; }
+
+ QH('p20info', x);
+ }
+
+
+ function p20showDeleteMeshDialog() {
+ if (xxdialogMode) return;
+ var x = "Are you sure you want to delete mesh \"" + EscapeHtml(currentMesh.name) + "\"? Deleting the mesh will also delete all information about computers within this mesh.
";
+ x += "Confirm";
+ setDialogMode(2, "Delete Mesh", 3, p20showDeleteMeshDialogEx, x);
+ p20validateDeleteMeshDialog();
+ }
+
+ function p20validateDeleteMeshDialog() {
+ QE('idx_dlgOkButton', Q('p20check').checked);
+ }
+
+ function p20showDeleteMeshDialogEx(buttons, tag) {
+ meshserver.send({ action: 'deletemesh', meshid: currentMesh._id, meshname: currentMesh.name });
+ }
+
+ function p20editmesh(focus) {
+ if (xxdialogMode) return;
+ var x = addHtmlValue('Name', '');
+ x += addHtmlValue('Description', '');
+ setDialogMode(2, "Edit Mesh", 3, p20editmeshEx, x);
+ Q('dp20meshname').value = currentMesh.name;
+ if (currentMesh.desc) Q('dp20meshdesc').value = currentMesh.desc;
+ p20editmeshValidate();
+ if (focus == 2) { Q('dp20meshdesc').focus(); } else { Q('dp20meshname').focus(); }
+ }
+
+ function p20editmeshEx() {
+ meshserver.send({ action: 'editmesh', meshid: currentMesh._id, meshname: Q('dp20meshname').value, desc: Q('dp20meshdesc').value });
+ }
+
+ function p20editmeshValidate() {
+ QE('idx_dlgOkButton', Q('dp20meshname').value.length > 0);
+ }
+
+ function p20showAddMeshUserDialog() {
+ if (xxdialogMode) return;
+ var x = addHtmlValue('User', '');
+ x += '
';
+ x += 'Full Administrator ';
+ x += 'Edit Mesh ';
+ x += 'Manage Mesh Users ';
+ x += 'Manage Mesh Computers ';
+ x += 'Remote Control ';
+ x += 'Mesh Agent Console ';
+ x += 'Server Files ';
+ x += 'Wake Devices ';
+ x += 'Edit Device Notes ';
+ x += '
';
+ setDialogMode(2, "Add User to Mesh", 3, p20showAddMeshUserDialogEx, x);
+ p20validateAddMeshUserDialog();
+ Q('dp20username').focus();
+ }
+
+ function p20validateAddMeshUserDialog() {
+ var meshrights = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
+ QE('idx_dlgOkButton', (Q('dp20username').value.length > 0));
+ QE('p20fulladmin', meshrights == 0xFFFFFFFF);
+ QE('p20editmesh', (!Q('p20fulladmin').checked) && (meshrights == 0xFFFFFFFF));
+ QE('p20manageusers', !Q('p20fulladmin').checked);
+ QE('p20managecomputers', !Q('p20fulladmin').checked);
+ QE('p20remotecontrol', !Q('p20fulladmin').checked);
+ QE('p20meshagentconsole', !Q('p20fulladmin').checked);
+ QE('p20meshserverfiles', !Q('p20fulladmin').checked);
+ QE('p20wakedevices', !Q('p20fulladmin').checked);
+ QE('p20editnotes', !Q('p20fulladmin').checked);
+ }
+
+ function p20showAddMeshUserDialogEx() {
+ var meshadmin = 0;
+ if (Q('p20fulladmin').checked == true) { meshadmin = 0xFFFFFFFF; } else {
+ if (Q('p20editmesh').checked == true) meshadmin += 1;
+ if (Q('p20manageusers').checked == true) meshadmin += 2;
+ if (Q('p20managecomputers').checked == true) meshadmin += 4;
+ if (Q('p20remotecontrol').checked == true) meshadmin += 8;
+ if (Q('p20meshagentconsole').checked == true) meshadmin += 16;
+ if (Q('p20meshserverfiles').checked == true) meshadmin += 32;
+ if (Q('p20wakedevices').checked == true) meshadmin += 64;
+ if (Q('p20editnotes').checked == true) meshadmin += 128;
+ }
+ meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value , meshadmin: meshadmin});
+ }
+
+ function p20viewuser(userid) {
+ if (xxdialogMode) return;
+ userid = decodeURIComponent(userid);
+ var r = '', cmeshrights = currentMesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights, meshrights = currentMesh.links[userid].rights;
+ if (meshrights == 0xFFFFFFFF) r = ', Full Administrator'; else {
+ if ((meshrights & 1) != 0) r += ', Edit Mesh';
+ if ((meshrights & 2) != 0) r += ', Manage Mesh Users';
+ if ((meshrights & 4) != 0) r += ', Manage Mesh Computers';
+ if ((meshrights & 8) != 0) r += ', Remote Control';
+ if ((meshrights & 16) != 0) r += ', Agent Console';
+ if ((meshrights & 32) != 0) r += ', Server Files';
+ if ((meshrights & 64) != 0) r += ', Wake Devices';
+ if ((meshrights & 128) != 0) r += ', Edit Notes';
+ }
+ r = r.substring(2);
+ if (r == '') { r = 'No Rights'; }
+ var buttons = 1, x = addHtmlValue('User', userid.split('/')[2]);
+ x += addHtmlValue('Permissions', r);
+ if ((('user/{{{domain}}}/' + userinfo.name.toLowerCase()) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
+ setDialogMode(2, "Mesh User", buttons, p20viewuserEx, x, userid);
+ }
+
+ function p20viewuserEx(button, userid) { if (button != 2) return; setDialogMode(2, "Remote Mesh User", 3, p20viewuserEx2, "Confirm removal of user " + userid.split('/')[2] + "?", userid); }
+ function p20deleteUser(e, userid) { haltEvent(e); p20viewuserEx(2, decodeURIComponent(userid)); }
+ function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid}); }
+
//
// PANELS
//
@@ -852,7 +1128,7 @@
if (((b & 8) || x) && f) f(x, t);
}
- function center() { QS('dialog').left = ((((getDocWidth() - 400) / 2)) + "px"); }
+ function center() { QS('dialog').left = ((((getDocWidth() - 300) / 2)) + "px"); }
function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
@@ -861,6 +1137,10 @@
function validateEmail(v) { var emailReg = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; return emailReg.test(v); }
function reload() { window.location.href = window.location.href; }
function getNodeFromId(id) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } return null; }
+ function addHtmlValue(t, v) { return '
' + t + '
' + v + '
'; }
+ function addHtmlValue2(t, v) { return '
' + v + '
' + t + '
'; }
+ function addLink(x, f) { return "♦ " + x + ""; }
+ function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
diff --git a/views/default.handlebars b/views/default.handlebars
index 1b7b9bac..48a2e92a 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -1304,7 +1304,7 @@
if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
}
node.namel = node.name.toLowerCase();
- if (node.host) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
+ if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
if (message.event.node.icon) { node.icon = message.event.node.icon; }
onSortSelectChange(true);
@@ -4742,8 +4742,7 @@
function p20editmesh(focus) {
if (xxdialogMode) return;
- x = "Create a new mesh computer group using the options below.
";
- x += addHtmlValue('Mesh Name', '');
+ var x = addHtmlValue('Mesh Name', '');
x += addHtmlValue('Description', '');
setDialogMode(2, "Edit Mesh", 3, p20editmeshEx, x);
Q('dp20meshname').value = currentMesh.name;
@@ -4762,7 +4761,7 @@
function p20showAddMeshUserDialog() {
if (xxdialogMode) return;
- x = "Allow a user to manage the mesh and computers on this mesh
";
+ var x = "Allow a user to manage the mesh and computers on this mesh
";
x += addHtmlValue('User Name', '');
x += '
';
x += 'Full Administrator ';
diff --git a/webserver.js b/webserver.js
index 37913fa2..a0b1005c 100644
--- a/webserver.js
+++ b/webserver.js
@@ -712,14 +712,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
// Send the master web application
if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' Logout'; } // If a default user is in use or no user mode, don't display the logout button
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
- res.render(obj.path.join(__dirname, isModuleBrowser(req) ? 'views/default-mobile' : 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass, webcerthash: obj.webCertificateHashBase64, footer: (domain.footer == null) ? '' : domain.footer });
+ res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass, webcerthash: obj.webCertificateHashBase64, footer: (domain.footer == null) ? '' : domain.footer });
} else {
// Send back the login application
var loginmode = req.session.loginmode, features = 0;
delete req.session.loginmode; // Clear this state, if the user hits refresh, we want to go back to the login page.
if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
- res.render(obj.path.join(__dirname, isModuleBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, footer: (domain.footer == null) ? '' : domain.footer });
+ res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, footer: (domain.footer == null) ? '' : domain.footer });
}
}
@@ -738,9 +738,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
if (req.session && req.session.userid) {
if (req.session.domainid != domain.id) { req.session.destroy(function () { res.redirect(domain.url); }); return; } // Check is the session is for the correct domain
var user = obj.users[req.session.userid];
- res.render(obj.path.join(__dirname, isModuleBrowser(req) ? 'views/terms-mobile' : 'views/terms'), { title: domain.title, title2: domain.title2, logoutControl: 'Welcome ' + user.name + '. Logout' });
+ res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/terms-mobile' : 'views/terms'), { title: domain.title, title2: domain.title2, logoutControl: 'Welcome ' + user.name + '. Logout' });
} else {
- res.render(obj.path.join(__dirname, isModuleBrowser(req) ? 'views/terms-mobile' : 'views/terms'), { title: domain.title, title2: domain.title2 });
+ res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/terms-mobile' : 'views/terms'), { title: domain.title, title2: domain.title2 });
}
}
@@ -1873,9 +1873,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
// Return true if a mobile browser is detected.
// This code comes from "http://detectmobilebrowsers.com/" and was modified, This is free and unencumbered software released into the public domain. For more information, please refer to the http://unlicense.org/
- function isModuleBrowser(req) {
- var ua = req.headers['user-agent'].toLowerCase();
- return (/(android|bb\d+|meego).+mobile|mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(ua) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0, 4)));
+ function isMobileBrowser(req) {
+ //var ua = req.headers['user-agent'].toLowerCase();
+ //return (/(android|bb\d+|meego).+mobile|mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(ua) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0, 4)));
+ return (req.headers['user-agent'].toLowerCase().indexOf('mobile') >= 0);
}
return obj;