Added loginToken support and improved way to embed page into other sites.
Ylian Saint-Hilaire committed
Dec 13, 2017 at 14:52 UTC
9501ffd60983231b754bbbc0e0e41ad77ea0d15a
12 files changed
+315
-211
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
db.js
+1
-1
@@ -80,7 +80,7 @@ module.exports.CreateDB = function (args, datapath) {
80
*/
81
}
82
83
- obj.Set = function (data) { obj.file.update({ _id: data._id }, data, { upsert: true }); }
83
+ obj.Set = function (data, func) { obj.file.update({ _id: data._id }, data, { upsert: true }, func); }
84
obj.Get = function (id, func) { obj.file.find({ _id: id }, func); }
85
obj.GetAll = function (func) { obj.file.find({}, func); }
86
obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }, { type : 0 }, func); }
meshagent.js
+2
-1
@@ -38,6 +38,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
38
obj.close = function (arg) {
39
if ((arg == 1) || (arg == null)) { try { obj.ws.close(); obj.parent.parent.debug(1, 'Soft disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Soft close, close the websocket
40
if (arg == 2) { try { obj.ws._socket._parent.end(); obj.parent.parent.debug(1, 'Hard disconnect ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); } catch (e) { console.log(e); } } // Hard close, close the TCP socket
41
+ if (arg == 3) { obj.authenticated = -1; } // Don't communicate with this agent anymore, but don't disconnect (Duplicate agent).
42
if (obj.parent.wsagents[obj.dbNodeKey] == obj) {
43
delete obj.parent.wsagents[obj.dbNodeKey];
44
obj.parent.parent.ClearConnectivityState(obj.dbMeshKey, obj.dbNodeKey, 1);
@@ -293,7 +294,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
294
if (dupAgent) {
295
// Close the duplicate agent
296
obj.parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddr + ')');
296
- dupAgent.close();
297
+ dupAgent.close(3);
298
} else {
299
// Indicate the agent is connected
300
obj.parent.parent.SetConnectivityState(obj.dbMeshKey, obj.dbNodeKey, obj.connectTime, 1, 1);
meshcentral.js
+89
-7
@@ -40,6 +40,8 @@ function CreateMeshCentralServer() {
40
obj.maintenanceTimer = null;
41
obj.serverId = null;
42
obj.currentVer = null;
43
+ obj.serverKey = new Buffer(obj.crypto.randomBytes(32), 'binary');
44
+ obj.loginCookieEncryptionKey = null;
45
try { obj.currentVer = JSON.parse(require('fs').readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { } // Fetch server version
46
47
// Setup the default configuration and files paths
@@ -70,7 +72,7 @@ function CreateMeshCentralServer() {
72
try { require('./pass').hash('test', function () { }); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
73
74
// Check for invalid arguments
73
- var validArguments = ['_', 'notls', 'user', 'port', 'mpsport', 'redirport', 'cert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug'];
75
+ var validArguments = ['_', 'notls', 'user', 'port', 'mpsport', 'redirport', 'cert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey'];
76
for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
77
if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
78
@@ -234,6 +236,8 @@ function CreateMeshCentralServer() {
236
if (obj.args.showevents) { obj.db.GetAllType('event', function (err, docs) { console.log(docs); process.exit(); }); return; }
237
if (obj.args.showpower) { obj.db.GetAllType('power', function (err, docs) { console.log(docs); process.exit(); }); return; }
238
if (obj.args.showiplocations) { obj.db.GetAllType('iploc', function (err, docs) { console.log(docs); process.exit(); }); return; }
239
+ if (obj.args.logintoken) { obj.getLoginToken(obj.args.logintoken, function (r) { console.log(r); process.exit(); }); return; }
240
+ if (obj.args.logintokenkey) { obj.showLoginTokenKey(function (r) { console.log(r); process.exit(); }); return; }
241
if (obj.args.dbexport) {
242
// Export the entire database to a JSON file
243
if (obj.args.dbexport == true) { obj.args.dbexport = obj.path.join(obj.datapath, 'meshcentral.db.json'); }
@@ -365,13 +369,18 @@ function CreateMeshCentralServer() {
369
// Dispatch an event that the server is now running
370
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' })
371
368
- obj.debug(1, 'Server started');
372
+ // Load the login cookie encryption key from the database if allowed
373
+ if ((obj.config) && (obj.config.settings) && (obj.config.settings.loginTokenOk == true)) {
374
+ obj.db.Get('LoginCookieEncryptionKey', function (err, docs) {
375
+ if ((docs.length > 0) && (docs[0].key != null)) {
376
+ obj.loginCookieEncryptionKey = Buffer.from(docs[0].key, 'hex');
377
+ } else {
378
+ obj.loginCookieEncryptionKey = obj.generateCookieKey(); obj.db.Set({ _id: 'LoginCookieEncryptionKey', key: obj.loginCookieEncryptionKey.toString('hex'), time: Date.now() });
379
+ }
380
+ });
381
+ }
382
370
- /*
371
- obj.db.GetUserWithVerifiedEmail('', 'ylian.saint-hilaire@intel.com', function (err, docs) {
372
- console.log(JSON.stringify(docs));
373
- });
374
- */
383
+ obj.debug(1, 'Server started');
384
});
385
});
386
});
@@ -823,6 +832,79 @@ function CreateMeshCentralServer() {
832
}
833
}
834
835
+ // Generate a time limited user login token
836
+ obj.getLoginToken = function (userid, func) {
837
+ var x = userid.split('/');
838
+ if (x == null || x.length != 3 || x[0] != 'user') { func('Invalid userid.'); return; }
839
+ obj.db.Get(userid, function (err, docs) {
840
+ if (err != null || docs == null || docs.length == 0) {
841
+ func('User ' + userid + ' not found.'); return;
842
+ } else {
843
+ // Load the login cookie encryption key from the database
844
+ obj.db.Get('LoginCookieEncryptionKey', function (err, docs) {
845
+ if ((docs.length > 0) && (docs[0].key != null)) {
846
+ // Key is present, use it.
847
+ obj.loginCookieEncryptionKey = Buffer.from(docs[0].key, 'hex');
848
+ func(obj.encodeCookie({ u: userid, a: 3 }, obj.loginCookieEncryptionKey));
849
+ } else {
850
+ // Key is not present, generate one.
851
+ obj.loginCookieEncryptionKey = obj.generateCookieKey();
852
+ obj.db.Set({ _id: 'LoginCookieEncryptionKey', key: obj.loginCookieEncryptionKey.toString('hex'), time: Date.now() }, function () { func(obj.encodeCookie({ u: userid, a: 3 }, obj.loginCookieEncryptionKey)); });
853
+ }
854
+ });
855
+ }
856
+ });
857
+ }
858
+
859
+ // Show the yser login token generation key
860
+ obj.showLoginTokenKey = function (func) {
861
+ // Load the login cookie encryption key from the database
862
+ obj.db.Get('LoginCookieEncryptionKey', function (err, docs) {
863
+ if ((docs.length > 0) && (docs[0].key != null)) {
864
+ // Key is present, use it.
865
+ func(docs[0].key);
866
+ } else {
867
+ // Key is not present, generate one.
868
+ obj.loginCookieEncryptionKey = obj.generateCookieKey();
869
+ obj.db.Set({ _id: 'LoginCookieEncryptionKey', key: obj.loginCookieEncryptionKey.toString('hex'), time: Date.now() }, function () { func(obj.loginCookieEncryptionKey.toString('hex')); });
870
+ }
871
+ });
872
+ }
873
+
874
+ // Generate a cryptographic key used to encode and decode cookies
875
+ obj.generateCookieKey = function () {
876
+ return new Buffer(obj.crypto.randomBytes(32), 'binary');
877
+ //return Buffer.alloc(32, 0); // Sets the key to zeros, debug only.
878
+ }
879
+
880
+ // Encode an object as a cookie using a key. (key must be 32 bytes long)
881
+ obj.encodeCookie = function (o, key) {
882
+ try {
883
+ if (key == null) { key = obj.serverKey; }
884
+ o.time = Math.floor(Date.now() / 1000); // Add the cookie creation time
885
+ var iv = new Buffer(obj.crypto.randomBytes(12), 'binary'), cipher = obj.crypto.createCipheriv('aes-256-gcm', key, iv);
886
+ var crypted = Buffer.concat([cipher.update(JSON.stringify(o), 'utf8'), cipher.final()]);
887
+ return Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
888
+ } catch (e) { return null; }
889
+ }
890
+
891
+ // Decode a cookie back into an object using a key. Return null if it's not a valid cookie. (key must be 32 bytes long)
892
+ obj.decodeCookie = function (cookie, key, timeout) {
893
+ try {
894
+ if (key == null) { key = obj.serverKey; }
895
+ cookie = new Buffer(cookie.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64');
896
+ var decipher = obj.crypto.createDecipheriv('aes-256-gcm', key, cookie.slice(0, 12));
897
+ decipher.setAuthTag(cookie.slice(12, 16));
898
+ var o = JSON.parse(decipher.update(cookie.slice(28), 'binary', 'utf8') + decipher.final('utf8'));
899
+ if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { return null; }
900
+ o.time = o.time * 1000; // Decode the cookie creation time
901
+ o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
902
+ if (timeout == null) { timeout = 2; }
903
+ if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) return null; // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
904
+ return o;
905
+ } catch (e) { return null; }
906
+ }
907
+
908
// Debug
909
obj.debug = function (lvl) {
910
if (lvl > obj.debugLevel) return;
meshmail.js
+17
-4
@@ -11,6 +11,7 @@ module.exports.CreateMeshMain = function (parent) {
11
obj.parent = parent;
12
obj.retry = 0;
13
obj.sendingMail = false;
14
+ obj.mailCookieEncryptionKey = null;
15
const nodemailer = require('nodemailer');
16
17
// Default account email validation mail
@@ -45,7 +46,7 @@ module.exports.CreateMeshMain = function (parent) {
46
// Send account check mail
47
obj.sendAccountCheckMail = function (domain, username, email) {
48
if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, no reset possible.
48
- var cookie = obj.parent.webserver.encodeCookie({ u: domain.id + '/' + username, e: email, a: 1 });
49
+ var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 1 }, obj.mailCookieEncryptionKey);
50
obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountCheckSubject, domain, username, email), text: mailReplacements(accountCheckMailText, domain, username, email, cookie), html: mailReplacements(accountCheckMailHtml, domain, username, email, cookie) });
51
sendNextMail();
52
}
@@ -53,7 +54,7 @@ module.exports.CreateMeshMain = function (parent) {
54
// Send account reset mail
55
obj.sendAccountResetMail = function (domain, username, email) {
56
if ((parent.certificates == null) || (parent.certificates.CommonName == null)) return; // If the server name is not set, don't validate the email address.
56
- var cookie = obj.parent.webserver.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 });
57
+ var cookie = obj.parent.encodeCookie({ u: domain.id + '/' + username, e: email, a: 2 }, obj.mailCookieEncryptionKey);
58
obj.pendingMails.push({ to: email, from: parent.config.smtp.from, subject: mailReplacements(accountResetSubject, domain, username, email), text: mailReplacements(accountResetMailText, domain, username, email, cookie), html: mailReplacements(accountResetMailHtml, domain, username, email, cookie) });
59
sendNextMail();
60
}
@@ -74,7 +75,7 @@ module.exports.CreateMeshMain = function (parent) {
75
sendNextMail(); // Send the next mail
76
} else {
77
obj.retry++;
77
- console.log('SMTP server failed: ' + err.response);
78
+ console.log('SMTP server failed: ' + JSON.stringify(err));
79
if (obj.retry < 6) { setTimeout(sendNextMail, 60000); } // Wait and try again
80
}
81
});
@@ -86,10 +87,22 @@ module.exports.CreateMeshMain = function (parent) {
87
if (err == null) {
88
console.log('SMTP mail server ' + parent.config.smtp.host + ' working as expected.');
89
} else {
89
- console.log('SMTP mail server ' + parent.config.smtp.host + ' failed: ' + err.response);
90
+ console.log('SMTP mail server ' + parent.config.smtp.host + ' failed: ' + JSON.stringify(err));
91
}
92
});
93
}
94
95
+ // Load the cookie encryption key from the database
96
+ obj.parent.db.Get('MailCookieEncryptionKey', function (err, docs) {
97
+ if ((docs.length > 0) && (docs[0].key != null)) {
98
+ // Key is present, use it.
99
+ obj.mailCookieEncryptionKey = Buffer.from(docs[0].key, 'hex');
100
+ } else {
101
+ // Key is not present, generate one.
102
+ obj.mailCookieEncryptionKey = obj.parent.generateCookieKey();
103
+ obj.parent.db.Set({ _id: 'MailCookieEncryptionKey', key: obj.mailCookieEncryptionKey.toString('hex'), time: Date.now() });
104
+ }
105
+ });
106
+
107
return obj;
108
}
\ No newline at end of file
meshrelay.js
+1
-1
@@ -84,7 +84,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
84
}
85
} else {
86
// Get the session from the cookie
87
- var cookie = obj.parent.parent.webserver.decodeCookie(req.query.auth);
87
+ var cookie = obj.parent.parent.decodeCookie(req.query.auth);
88
if (cookie != null) {
89
obj.authenticated = true;
90
if (cookie.tcpport != null) {
meshuser.js
+2
-2
@@ -833,7 +833,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
833
case 'agentdisconnect':
834
{
835
// Force mesh agent disconnection
836
- forceMeshAgentDisconnect(user, domain, command.nodeid, command.disconnectMode);
836
+ obj.parent.forceMeshAgentDisconnect(user, domain, command.nodeid, command.disconnectMode);
837
break;
838
}
839
case 'close':
@@ -855,7 +855,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain) {
855
if (command.nodeid) { cookieContent.nodeid = command.nodeid; }
856
if (command.tcpaddr) { cookieContent.tcpaddr = command.tcpaddr; } // Indicates the browser want to agent to TCP connect to a remote address
857
if (command.tcpport) { cookieContent.tcpport = command.tcpport; } // Indicates the browser want to agent to TCP connect to a remote port
858
- command.cookie = obj.parent.encodeCookie(cookieContent);
858
+ command.cookie = obj.parent.parent.encodeCookie(cookieContent);
859
ws.send(JSON.stringify(command));
860
}
861
}
multiserver.js
+1
-1
@@ -561,7 +561,7 @@ module.exports.CreateMultiServer = function (parent, args) {
561
if (path.substring(path.length - 11) == '/.websocket') { path = path.substring(0, path.length - 11); }
562
var queryStr = ''
563
for (var i in req.query) { queryStr += ((queryStr == '') ? '?' : '&') + i + '=' + req.query[i]; }
564
- if (user != null) { queryStr += ((queryStr == '') ? '?' : '&') + 'auth=' + obj.encodeCookie({ userid: user._id, domainid: user.domain }, cookieKey); }
564
+ if (user != null) { queryStr += ((queryStr == '') ? '?' : '&') + 'auth=' + obj.parent.encodeCookie({ userid: user._id, domainid: user.domain }, cookieKey); }
565
var url = obj.peerConfig.servers[serverid].url + path + queryStr;
566
567
// Setup an connect the web socket
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.1.0-o",
3
+ "version": "0.1.0-x",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
views/default.handlebars
+178
-151
@@ -56,41 +56,43 @@
56
<div style="float:right">
57
<div id=notificationCount onclick="clickNotificationIcon()" class="unselectable" style="display:none;min-width:28px;font-size:20px;border-radius:5px;background-color:lightblue;text-align:center;margin:8px;cursor:pointer;padding:4px" title="Click to view current notifications">0</div>
58
</div>
59
- <p>{{{logoutControl}}}</p>
59
+ <p id="logoutControl">{{{logoutControl}}}</p>
60
</div>
61
- <div id=topbar class=noselect style=display:none>
62
- <div>
61
+ <div id=topbarmaster>
62
+ <div id=topbar class=noselect style=display:none>
63
<div>
64
- <table style=width:100%;height:22px cellpadding=0 cellspacing=0 class=style1>
65
- <tr>
66
- <td id=MainMenuMyDevices style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(1)>My Devices</td>
67
- <td id=MainMenuMyAccount style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(2)>My Account</td>
68
- <td id=MainMenuMyEvents style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(3)>My Events</td>
69
- <td id=MainMenuMyFiles style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(5)>My Files</td>
70
- <td id=MainMenuMyUsers style=width:100px;height:24px;cursor:pointer;display:none class=style3 onclick=go(4)>My Users</td>
71
- <td class=style3 style=height:24px> </td>
72
- </tr>
73
- </table>
74
- <div id="MainSubMenuSpan" style=display:none>
75
- <table id="MainSubMenu" style="width: 100%; height: 22px;" cellpadding=0 cellspacing=0 class=style1>
76
- <tr>
77
- <td id=MainDev style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(10)>General</td>
78
- <td id=MainDevDesktop style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(11)>Desktop</td>
79
- <td id=MainDevTerminal style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(12)>Terminal</td>
80
- <td id=MainDevFiles style=width:100px;height:24px;cursor:pointer;display:none class=style3 onclick=go(13)>Files</td>
81
- <td id=MainDevAmt style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(14)>Intel® AMT</td>
82
- <td id=MainDevConsole style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(15)>Console</td>
83
- <td class=style3 style=height:24px> </td>
84
- </tr>
85
- </table>
86
- </div>
87
- <div id="MeshSubMenuSpan" style=display:none>
88
- <table id="MeshSubMenu" style="width: 100%; height: 22px;" cellpadding=0 cellspacing=0 class=style1>
64
+ <div>
65
+ <table style=width:100%;height:22px cellpadding=0 cellspacing=0 class=style1>
66
<tr>
90
- <td id=MeshGeneral style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(20)>General</td>
67
+ <td id=MainMenuMyDevices style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(1)>My Devices</td>
68
+ <td id=MainMenuMyAccount style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(2)>My Account</td>
69
+ <td id=MainMenuMyEvents style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(3)>My Events</td>
70
+ <td id=MainMenuMyFiles style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(5)>My Files</td>
71
+ <td id=MainMenuMyUsers style=width:100px;height:24px;cursor:pointer;display:none class=style3 onclick=go(4)>My Users</td>
72
<td class=style3 style=height:24px> </td>
73
</tr>
74
</table>
75
+ <div id="MainSubMenuSpan" style=display:none>
76
+ <table id="MainSubMenu" style="width: 100%; height: 22px;" cellpadding=0 cellspacing=0 class=style1>
77
+ <tr>
78
+ <td id=MainDev style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(10)>General</td>
79
+ <td id=MainDevDesktop style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(11)>Desktop</td>
80
+ <td id=MainDevTerminal style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(12)>Terminal</td>
81
+ <td id=MainDevFiles style=width:100px;height:24px;cursor:pointer;display:none class=style3 onclick=go(13)>Files</td>
82
+ <td id=MainDevAmt style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(14)>Intel® AMT</td>
83
+ <td id=MainDevConsole style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(15)>Console</td>
84
+ <td class=style3 style=height:24px> </td>
85
+ </tr>
86
+ </table>
87
+ </div>
88
+ <div id="MeshSubMenuSpan" style=display:none>
89
+ <table id="MeshSubMenu" style="width: 100%; height: 22px;" cellpadding=0 cellspacing=0 class=style1>
90
+ <tr>
91
+ <td id=MeshGeneral style=width:100px;height:24px;cursor:pointer class=style3 onclick=go(20)>General</td>
92
+ <td class=style3 style=height:24px> </td>
93
+ </tr>
94
+ </table>
95
+ </div>
96
</div>
97
</div>
98
</div>
@@ -265,7 +267,9 @@
267
<table style="width:100%" cellpadding="0" cellspacing="0">
268
<tr>
269
<td style=width:auto valign=top>
268
- <h1><span id=p10deviceName></span> - General</h1>
270
+ <div id="p10title">
271
+ <h1><span id=p10deviceName></span> - General</h1>
272
+ </div>
273
<div id=p10html></div>
274
</td>
275
<td style=width:20px></td>
@@ -279,7 +283,9 @@
283
<div id=p10html3></div>
284
</div>
285
<div id=p11 style=display:none>
282
- <h1 id=p11deviceNameHeader><span id=p11deviceName></span> - Desktop</h1>
286
+ <div id="p11title">
287
+ <h1 id=p11deviceNameHeader><span id=p11deviceName></span> - Desktop</h1>
288
+ </div>
289
<div id="p14warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick="showFeaturesDlg()">
290
<div class=icon2 style="float:left;margin:7px"></div>
291
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
@@ -334,7 +340,7 @@
340
</table>
341
</div>
342
<div id=p12 style=display:none>
337
- <h1><span id=p12deviceName></span> - Terminal</h1>
343
+ <div id="p12title"><h1><span id=p12deviceName></span> - Terminal</h1></div>
344
<div id="p12warning" style='max-width:100%;display:none;cursor:pointer;margin-bottom:5px' onclick=showFeaturesDlg()>
345
<div class="icon2" style="float:left;margin:7px"></div>
346
<div style='width:auto;border-radius:8px;padding:8px;background-color:lightsalmon'>Intel® AMT Redirection port or KVM feature is disabled<span id="p14warninga">, click here to enable it.</span></div>
@@ -389,7 +395,7 @@
395
</table>
396
</div>
397
<div id=p13 style=display:none>
392
- <h1><span id=p13deviceName></span> - Files</h1>
398
+ <div id="p13title"><h1><span id=p13deviceName></span> - Files</h1></div>
399
<table id="p13toolbar" style="width: 100%" cellpadding="0" cellspacing="0">
400
<tr>
401
<td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px">
@@ -443,11 +449,11 @@
449
</table>
450
</div>
451
<div id=p14 style=display:none>
446
- <h1><span id=p14deviceName></span> - Intel® AMT</h1>
452
+ <div id="p14title"><h1><span id=p14deviceName></span> - Intel® AMT</h1></div>
453
<iframe id=p14iframe style="width:100%;height:650px;border:0;overflow:hidden" src="/commander.htm"></iframe>
454
</div>
455
<div id=p15 style=display:none>
450
- <h1><span id=p15deviceName></span> - Console</h1>
456
+ <div id="p15title"><h1><span id=p15deviceName></span> - Console</h1></div>
457
<table cellpadding=0 cellspacing=0 style="width:100%;padding:0px;padding:0px;margin-top:0px">
458
<tr>
459
<td style=background:#C0C0C0>
@@ -494,7 +500,7 @@
500
<tr>
501
<td style="text-align:left"></td>
502
<td style="text-align:right">
497
- <a id="verifyEmailId2" style="color:yellow;margin-left:3px;cursor:pointer" onclick="account_showVerifyEmail()">Verify Email</a>
503
+ <a id="verifyEmailId2" style="color:yellow;margin-left:3px;cursor:pointer;display:none" onclick="account_showVerifyEmail()">Verify Email</a>
504
<a style="margin-left:3px" href="terms">Terms & Privacy</a>
505
</td>
506
</tr>
@@ -599,6 +605,7 @@
605
</div>
606
</div>
607
<script type="text/javascript">
608
+ var args;
609
var powerStatetable = ['', 'Powered', 'Sleep', 'Sleep', 'Sleep', 'Hibernating', 'Power off', 'Present'];
610
var StatusStrs = ['Disconnected', 'Connecting...', 'Setup...', 'Connected', 'Intel® AMT Connected'];
611
var sort = 0;
@@ -635,13 +642,25 @@
642
if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
643
644
// Check if we are in debug mode
638
- var args = parseUriArgs();
645
+ args = parseUriArgs();
646
debugmode = (args.debug == 1);
647
QV('p13AutoConnect', debugmode); // Files
648
QV('autoconnectbutton2', debugmode); // Terminal
649
QV('autoconnectbutton1', debugmode); // Desktop
650
651
// Setup page visuals
652
+ if (args.hide) {
653
+ var hide = parseInt(args.hide);
654
+ QV('masthead', !(hide & 1));
655
+ QV('topbarmaster', !(hide & 2));
656
+ QV('footer', !(hide & 4));
657
+ QV('p10title', !(hide & 8));
658
+ QV('p11title', !(hide & 8));
659
+ QV('p12title', !(hide & 8));
660
+ QV('p13title', !(hide & 8));
661
+ QV('p14title', !(hide & 8));
662
+ QV('p15title', !(hide & 8));
663
+ }
664
p1updateInfo();
665
666
// Setup the context menu
@@ -733,6 +752,8 @@
752
powerTimelineUpdate = null;
753
deleteAllNotifications(); // Close and clear notifications if present
754
hideContextMenu(); // Hide the context menu if present
755
+ QV('verifyEmailId2', false);
756
+ QV('logoutControl', false);
757
} else if (state == 2) {
758
// Fetch list of meshes, nodes, files
759
meshserver.Send({ action: 'meshes' });
@@ -850,7 +871,7 @@
871
}
872
case 'msg': {
873
// Check if this is a message from a node
853
- if (message.nodeid != undefined) {
874
+ if (message.nodeid != null) {
875
var index = -1;
876
for (var i in nodes) { if (nodes[i]._id == message.nodeid) { index = i; break; } }
877
if (index != -1) {
@@ -858,15 +879,15 @@
879
if (message.type == 'console') { p15consoleReceive(nodes[index], message.value); } // This is a console message.
880
if (message.type == 'notify') { // This is a notification message.
881
var n = { text:message.value };
861
- if (message.nodeid != undefined) { n.nodeid = message.nodeid; }
862
- if (message.tag != undefined) { n.tag = message.tag; }
882
+ if (message.nodeid != null) { n.nodeid = message.nodeid; }
883
+ if (message.tag != null) { n.tag = message.tag; }
884
addNotification(n);
885
}
886
}
887
} else {
888
if (message.type == 'notify') { // This is a notification message.
889
var n = { text:message.value };
869
- if (message.tag != undefined) { n.tag = message.tag; }
890
+ if (message.tag != null) { n.tag = message.tag; }
891
addNotification(n);
892
}
893
}
@@ -956,7 +977,7 @@
977
}
978
case 'createmesh': {
979
// A new mesh was created
959
- if (message.event.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()] != undefined) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
980
+ if (message.event.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()] != null) { // Check if this is a mesh create for a mesh we own. If site administrator, we get all messages so need to ignore some.
981
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
982
updateMeshes();
983
updateDevices();
@@ -966,7 +987,7 @@
987
}
988
case 'meshchange': {
989
// Update mesh information
969
- if (meshes[message.event.meshid] == undefined) {
990
+ if (meshes[message.event.meshid] == null) {
991
// This is a new mesh for us
992
meshes[message.event.meshid] = { _id: message.event.meshid, name: message.event.name, mtype: message.event.mtype, desc: message.event.desc, links: message.event.links };
993
meshserver.Send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh).
@@ -977,7 +998,7 @@
998
meshes[message.event.meshid].links = message.event.links;
999
1000
// Check if we lost rights to this mesh in this change.
980
- if (meshes[message.event.meshid].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()] == undefined) {
1001
+ if (meshes[message.event.meshid].links['user/{{{domain}}}/' + userinfo.name.toLowerCase()] == null) {
1002
if ((xxcurrentView == 20) && (currentMesh == meshes[message.event.meshid])) go(2);
1003
delete meshes[message.event.meshid];
1004
@@ -1065,21 +1086,21 @@
1086
node.wifiloc = message.event.node.wifiloc;
1087
node.gpsloc = message.event.node.gpsloc;
1088
node.userloc = message.event.node.userloc;
1068
- if (message.event.node.agent != undefined) {
1069
- if (node.agent == undefined) node.agent = {};
1070
- if (message.event.node.agent.ver != undefined) { node.agent.ver = message.event.node.agent.ver; }
1071
- if (message.event.node.agent.id != undefined) { node.agent.id = message.event.node.agent.id; }
1072
- if (message.event.node.agent.caps != undefined) { node.agent.caps = message.event.node.agent.caps; }
1073
- if (message.event.node.agent.core != undefined) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
1089
+ if (message.event.node.agent != null) {
1090
+ if (node.agent == null) node.agent = {};
1091
+ if (message.event.node.agent.ver != null) { node.agent.ver = message.event.node.agent.ver; }
1092
+ if (message.event.node.agent.id != null) { node.agent.id = message.event.node.agent.id; }
1093
+ if (message.event.node.agent.caps != null) { node.agent.caps = message.event.node.agent.caps; }
1094
+ if (message.event.node.agent.core != null) { node.agent.core = message.event.node.agent.core; } else { if (node.agent.core) { delete node.agent.core; } }
1095
node.agent.tag = message.event.node.agent.tag;
1096
}
1076
- if (message.event.node.intelamt != undefined) {
1077
- if (node.intelamt == undefined) node.intelamt = {};
1078
- if (message.event.node.intelamt.host != undefined) { node.intelamt.user = message.event.node.intelamt.host; }
1079
- if (message.event.node.intelamt.user != undefined) { node.intelamt.user = message.event.node.intelamt.user; }
1080
- if (message.event.node.intelamt.tls != undefined) { node.intelamt.tls = message.event.node.intelamt.tls; }
1081
- if (message.event.node.intelamt.ver != undefined) { node.intelamt.ver = message.event.node.intelamt.ver; }
1082
- if (message.event.node.intelamt.state != undefined) { node.intelamt.state = message.event.node.intelamt.state; }
1097
+ if (message.event.node.intelamt != null) {
1098
+ if (node.intelamt == null) node.intelamt = {};
1099
+ if (message.event.node.intelamt.host != null) { node.intelamt.user = message.event.node.intelamt.host; }
1100
+ if (message.event.node.intelamt.user != null) { node.intelamt.user = message.event.node.intelamt.user; }
1101
+ if (message.event.node.intelamt.tls != null) { node.intelamt.tls = message.event.node.intelamt.tls; }
1102
+ if (message.event.node.intelamt.ver != null) { node.intelamt.ver = message.event.node.intelamt.ver; }
1103
+ if (message.event.node.intelamt.state != null) { node.intelamt.state = message.event.node.intelamt.state; }
1104
}
1105
node.namel = node.name.toLowerCase();
1106
if (node.host) { node.hostl = node.host.toLowerCase(); } else { node.hostl = node.namel; }
@@ -1134,7 +1155,7 @@
1155
}
1156
case 'scanamtdevice': {
1157
// Populate the Intel AMT scan dialog box with the result of the RMCP scan
1137
- if ((xxdialogMode == undefined) || (!Q('dp1range')) || (Q('dp1range').value != message.event.range)) return;
1158
+ if ((xxdialogMode == null) || (!Q('dp1range')) || (Q('dp1range').value != message.event.range)) return;
1159
var x = '';
1160
if (message.event.results == null) {
1161
// The scan could not occur because of an error. Likely the user range was invalid.
@@ -1158,6 +1179,12 @@
1179
QE('dp1rangebutton', true);
1180
break;
1181
}
1182
+ case 'notify': {
1183
+ var n = { text: message.event.value };
1184
+ if (message.event.tag != null) { n.tag = message.event.tag; }
1185
+ addNotification(n);
1186
+ break;
1187
+ }
1188
}
1189
break;
1190
}
@@ -1275,7 +1302,7 @@
1302
for (var i in nodes) {
1303
if (nodes[i].v == false) continue;
1304
var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
1278
- if (meshlinks == undefined) continue;
1305
+ if (meshlinks == null) continue;
1306
if (sort == 0) {
1307
// Mesh header
1308
if (nodes[i].meshid != current) {
@@ -1312,9 +1339,9 @@
1339
1340
var title = EscapeHtml(nodes[i].name);
1341
if (title.length == 0) { title = '<i>None</i>'; }
1315
- if ((nodes[i].host != undefined) && (nodes[i].host.length > 0)) { title += " / " + EscapeHtml(nodes[i].host); }
1342
+ if ((nodes[i].host != null) && (nodes[i].host.length > 0)) { title += " / " + EscapeHtml(nodes[i].host); }
1343
var name = EscapeHtml(nodes[i].name);
1317
- if (showHostnames == true && nodes[i].host != undefined) name = EscapeHtml(nodes[i].host);
1344
+ if (showHostnames == true && nodes[i].host != null) name = EscapeHtml(nodes[i].host);
1345
if (name.length == 0) { name = '<i>None</i>'; }
1346
1347
// Node
@@ -1336,9 +1363,9 @@
1363
if (sort == 0 && Q('SearchInput').value == '') {
1364
for (var i in meshes) {
1365
var mesh = meshes[i], meshlink = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
1339
- if (meshlink != undefined) {
1366
+ if (meshlink != null) {
1367
var meshrights = meshlink.rights;
1341
- if (displayedMeshes[mesh._id] == undefined) {
1368
+ if (displayedMeshes[mesh._id] == null) {
1369
if (current != '') { r += '</tr></table>'; }
1370
r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
1371
r += getMeshActions(mesh, meshrights);
@@ -1575,7 +1602,7 @@
1602
if ((node.conn & 4) != 0) states.push('<span title="Intel® AMT is routable.">Intel® AMT</span>');
1603
if ((node.conn & 8) != 0) states.push('<span title="Mesh agent is reachable using another agent as relay.">Relay</span>');
1604
}
1578
- if ((node.pwr != undefined) && (node.pwr != 0)) { states.push(powerStateStrings[node.pwr]); }
1605
+ if ((node.pwr != null) && (node.pwr != 0)) { states.push(powerStateStrings[node.pwr]); }
1606
return states.join(', ');
1607
}
1608
@@ -1660,7 +1687,7 @@
1687
function powerSort(a, b) { var ap = a.pwr?a.pwr:0; var bp = b.pwr?b.pwr:0; if (ap == bp) { if (showHostnames == true) { if (a.hostl > b.hostl) return 1; if (a.hostl < b.hostl) 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; }
1688
function deviceSort(a, b) { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; }
1689
function deviceHostSort(a, b) { if (a.hostl > b.hostl) return 1; if (a.hostl < b.hostl) return -1; return 0; }
1663
- function onSearchInputChanged() { var x = Q('SearchInput').value.toLowerCase(); putstore("search", x); if (x == '') { for (var d in nodes) { nodes[d].v = true; } } else { for (var d in nodes) { nodes[d].v = (nodes[d].name.toLowerCase().indexOf(x) >= 0) || (nodes[d].hostl != undefined && nodes[d].hostl.toLowerCase().indexOf(x) >= 0); } } updateDevices(); }
1690
+ function onSearchInputChanged() { var x = Q('SearchInput').value.toLowerCase(); putstore("search", x); if (x == '') { for (var d in nodes) { nodes[d].v = true; } } else { for (var d in nodes) { nodes[d].v = (nodes[d].name.toLowerCase().indexOf(x) >= 0) || (nodes[d].hostl != null && nodes[d].hostl.toLowerCase().indexOf(x) >= 0); } } updateDevices(); }
1691
function onSearchFocus(x) { searchFocus = x; }
1692
function onMapSearchFocus(x) { mapSearchFocus = x; }
1693
function onConsoleFocus(x) { consoleFocus = x; }
@@ -1668,8 +1695,8 @@
1695
var contextelement = null;
1696
function handleContextMenu(event) {
1697
hideContextMenu();
1671
- var scrollLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
1672
- var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
1698
+ var scrollLeft = (window.pageXOffset !== null) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
1699
+ var scrollTop = (window.pageYOffset !== null) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
1700
var elem = document.elementFromPoint(event.pageX - scrollLeft, event.pageY - scrollTop);
1701
if (elem && elem != null && elem.id == "MxMESH") {
1702
contextelement = elem;
@@ -1743,7 +1770,7 @@
1770
for (var i in nodes) {
1771
var loc = map_parseNodeLoc(nodes[i]);
1772
var feature = xxmap.markersSource.getFeatureById(nodes[i]._id);
1746
- if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == undefined))) { // Draw markers for devices with locations
1773
+ if ((loc != null) && ((nodes[i].meshid == selectedMesh) || (selectedMesh == null))) { // Draw markers for devices with locations
1774
lat = loc[0];
1775
lon = loc[1];
1776
var type = loc[2];
@@ -1848,7 +1875,7 @@
1875
var feature = xxmap.map.forEachFeatureAtPixel(evt.pixel, function(feat, layer) { return feat; });
1876
if (feature) {
1877
var nodeid = feature.getId();
1851
- if (nodeid != undefined) { gotoDevice(nodeid, 10); } // Goto general info tab
1878
+ if (nodeid != null) { gotoDevice(nodeid, 10); } // Goto general info tab
1879
else { // For pointer
1880
var nodeFeatgoto = getCorrespondingFeature(feature); gotoDevice(nodeFeatgoto.getId(), 10);
1881
}
@@ -2149,7 +2176,7 @@
2176
function updatePlaceNodeTable(inputSearch) {
2177
var elements = document.getElementsByName("PlaceMapDeviceCheckbox"), count = 0;
2178
for (var i in nodes) {
2152
- var visible = ((nodes[i].namel.indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].hostl != undefined && nodes[i].hostl.indexOf(inputSearch) >= 0));
2179
+ var visible = ((nodes[i].namel.indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].hostl != null && nodes[i].hostl.indexOf(inputSearch) >= 0));
2180
if (visible) { count++; }
2181
QV(nodes[i]._id + '-rowid', visible);
2182
}
@@ -2157,7 +2184,7 @@
2184
/*
2185
console.log(selected);
2186
for (var i in nodes) {
2160
- if ((nodes[i].name.toLowerCase().indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].hostl != undefined && nodes[i].hostl.toLowerCase().indexOf(inputSearch) >= 0)) {
2187
+ if ((nodes[i].name.toLowerCase().indexOf(inputSearch) >= 0 || inputSearch == '') || (nodes[i].hostl != null && nodes[i].hostl.toLowerCase().indexOf(inputSearch) >= 0)) {
2188
console.log(selected.indexOf(nodes[i]._id));
2189
x += '<div class=noselect id=' + nodes[i]._id + '-rowid onclick=selectNodeToPlace(event,\''+ nodes[i]._id +'\') style=background-color:lightgray;margin-bottom:4px;border-radius:2px><input name=PlaceMapDeviceCheckbox id=' + nodes[i]._id + '-checkid type=checkbox style=width:16px;display:inline ' + ((selected.indexOf(nodes[i]._id) >= 0)?'checked':'') + ' />';
2190
x += '<div class=j' + nodes[i].icon + ' style=width:16px;height:16px;margin-top:2px;margin-right:4px;display:inline-block></div><div style=width:16px;display:inline>' + nodes[i].name + '</div></div>';
@@ -2384,7 +2411,7 @@
2411
2412
// Attribute: Mesh Agent
2413
var agentsStr = ['Unknown', 'Windows 32bit console', 'Windows 64bit console', 'Windows 32bit service', 'Windows 64bit service', 'Linux 32bit', 'Linux 64bit', 'MIPS', 'XENx86', 'Android ARM', 'Linux ARM', 'OSX 32bit', 'Android x86', 'PogoPlug ARM', 'Android APK', 'Linux Poky x86-32bit', 'OSX 64bit', 'ChromeOS', 'Linux Poky x86-64bit', 'Linux NoKVM x86-32bit', 'Linux NoKVM x86-64bit', 'Windows MinCore console', 'Windows MinCore service', 'NodeJS', 'ARM-Linaro', 'ARMv6l / ARMv7l' ];
2387
- if ((node.agent != undefined) && (node.agent.id != undefined) && (node.agent.ver != undefined)) {
2414
+ if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) {
2415
var str = '';
2416
if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; }
2417
if (node.agent.ver != 0) { str += ' v' + node.agent.ver; }
@@ -2392,12 +2419,12 @@
2419
}
2420
2421
// Attribute: Intel AMT
2395
- if (node.intelamt != undefined) {
2422
+ if (node.intelamt != null) {
2423
var str = '';
2424
var provisioningStates = { 0: 'Not Activated (Pre)', 1: 'Not Activated (In)', 2: 'Activated' };
2398
- if (node.intelamt.ver == undefined || node.intelamt.state == undefined) { str += '<i>Unknown Version & State</i>'; } else { str += (provisioningStates[node.intelamt.state] + ', v' + node.intelamt.ver); }
2425
+ if (node.intelamt.ver == null || node.intelamt.state == null) { str += '<i>Unknown Version & State</i>'; } else { str += (provisioningStates[node.intelamt.state] + ', v' + node.intelamt.ver); }
2426
if (node.intelamt.tls == 1) { str += ', TLS'; }
2400
- if (node.intelamt.user == undefined || node.intelamt.user == '') {
2427
+ if (node.intelamt.user == null || node.intelamt.user == '') {
2428
if ((meshrights & 4) != 0) {
2429
str += ', <i style=color:#FF0000;cursor:pointer title="Edit Intel® AMT credentials" onclick=editDeviceAmtSettings("' + node._id + '")>No Credentials</i>';
2430
} else {
@@ -2412,7 +2439,7 @@
2439
}
2440
2441
// Attribute: Mesh Agent Tag
2415
- if ((node.agent != undefined) && (node.agent.tag != undefined)) {
2442
+ if ((node.agent != null) && (node.agent.tag != null)) {
2443
x += addDeviceAttribute('Agent Tag', node.agent.tag);
2444
}
2445
@@ -2481,13 +2508,13 @@
2508
// Show or hide the tabs
2509
// mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
2510
// node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
2484
- QV('MainDevDesktop', (mesh.mtype == 1) || (node.agent == undefined) || (node.agent.caps == undefined) || ((node.agent.caps & 1) != 0));
2485
- QV('MainDevTerminal', (mesh.mtype == 1) || (node.agent == undefined) || (node.agent.caps == undefined) || ((node.agent.caps & 2) != 0));
2486
- QV('MainDevFiles', (mesh.mtype == 2) && ((node.agent == undefined) || (node.agent.caps == undefined) || ((node.agent.caps & 4) != 0)));
2487
- QV('MainDevAmt', node.intelamt != undefined);
2488
- QV('MainDevConsole', consoleRights && (mesh.mtype == 2) && ((node.agent == undefined) || (node.agent.caps == undefined) || ((node.agent.caps & 8) != 0)));
2489
- QV('p15uploadCore', (node.agent != undefined) && (node.agent.caps != undefined) && ((node.agent.caps & 16) != 0));
2490
- QH('p15coreName', ((node.agent != undefined) && (node.agent.core != undefined))?node.agent.core:'');
2511
+ QV('MainDevDesktop', (mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0));
2512
+ QV('MainDevTerminal', (mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0));
2513
+ QV('MainDevFiles', (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0)));
2514
+ QV('MainDevAmt', node.intelamt != null);
2515
+ QV('MainDevConsole', consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0)));
2516
+ QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0));
2517
+ QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
2518
2519
// Setup/Refresh Intel AMT tab
2520
var amtFrameNode = Q('p14iframe').contentWindow.getCurrentMeshNode();
@@ -2534,7 +2561,7 @@
2561
// Called when MeshCommander needs new credentials or updated credentials.
2562
function updateAmtCredentials(forceDialog) {
2563
var node = getNodeFromId(desktopNode._id);
2537
- if ((forceDialog == true) || (node.intelamt.user == undefined) || (node.intelamt.user == '')) {
2564
+ if ((forceDialog == true) || (node.intelamt.user == null) || (node.intelamt.user == '')) {
2565
editDeviceAmtSettings(desktopNode._id, updateAmtCredentialsEx);
2566
} else {
2567
Q('p14iframe').contentWindow.connectButtonfunctionEx();
@@ -2619,9 +2646,9 @@
2646
x += addHtmlValue('Username', '<input id=dp10username style=width:230px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
2647
x += addHtmlValue('Password', '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
2648
x += addHtmlValue('Security', '<select id=dp10tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
2622
- if ((node.intelamt.user != undefined) && (node.intelamt.user != '')) { buttons = 7; }
2649
+ if ((node.intelamt.user != null) && (node.intelamt.user != '')) { buttons = 7; }
2650
setDialogMode(2, "Edit Intel® AMT credentials", buttons, editDeviceAmtSettingsEx, x, { node: node, func: func });
2624
- if ((node.intelamt.user != undefined) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
2651
+ if ((node.intelamt.user != null) && (node.intelamt.user != '')) { Q('dp10username').value = node.intelamt.user; } else { Q('dp10username').value = 'admin'; }
2652
Q('dp10tls').value = node.intelamt.tls;
2653
validateDeviceAmtSettings();
2654
}
@@ -2783,7 +2810,7 @@
2810
var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=32 onchange=p10editdevicevalueValidate(' + mode + ') onkeyup=p10editdevicevalueValidate(' + mode + ') />');
2811
setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
2812
var v = currentNode[showEditNodeValueDialog_modes2[mode]];
2786
- if (v == undefined) v = '';
2813
+ if (v == null) v = '';
2814
Q('dp10devicevalue').value = v;
2815
p10editdevicevalueValidate();
2816
}
@@ -2805,7 +2832,7 @@
2832
var desktopNode;
2833
function setupDesktop() {
2834
// Setup the remote desktop
2808
- if ((desktopNode != currentNode) && (desktop != undefined)) { desktop.Stop(); delete desktop; desktop = undefined; }
2835
+ if ((desktopNode != currentNode) && (desktop != null)) { desktop.Stop(); delete desktop; desktop = null; }
2836
desktopNode = currentNode;
2837
updateDesktopButtons();
2838
@@ -2816,15 +2843,15 @@
2843
// Show and enable the right buttons
2844
function updateDesktopButtons() {
2845
var mesh = meshes[desktopNode.meshid];
2819
- var deskState = ((desktop != undefined) && (desktop.state != 0));
2846
+ var deskState = ((desktop != null) && (desktop.state != 0));
2847
2848
// Show the right buttons
2849
QV('disconnectbutton1span', (deskState == true));
2850
QV('connectbutton1span', (deskState == false) && (mesh.mtype == 2));
2824
- QV('connectbutton1hspan', (deskState == false) && (desktopNode.intelamt != undefined && ((desktopNode.intelamt.ver != undefined) || (mesh.mtype == 1))));
2851
+ QV('connectbutton1hspan', (deskState == false) && (desktopNode.intelamt != null && ((desktopNode.intelamt.ver != null) || (mesh.mtype == 1))));
2852
2853
// Show the right settings
2827
- QV('d7amtkvm', (desktopNode.intelamt != undefined && ((desktopNode.intelamt.ver != undefined) || (mesh.mtype == 1))) && ((deskState == false) || (desktop.contype == 2)));
2854
+ QV('d7amtkvm', (desktopNode.intelamt != null && ((desktopNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == false) || (desktop.contype == 2)));
2855
QV('d7meshkvm', (mesh.mtype == 2) && ((deskState == false) || (desktop.contype == 1)));
2856
2857
// Enable buttons
@@ -2839,10 +2866,10 @@
2866
function autoConnectDesktop(e) { if (autoConnectDesktopTimer == null) { autoConnectDesktopTimer = setInterval(connectDesktop, 100); } else { clearInterval(autoConnectDesktopTimer); autoConnectDesktopTimer = null; } }
2867
2868
function connectDesktop(e, contype) {
2842
- if (desktop == undefined) {
2869
+ if (desktop == null) {
2870
if (contype == 2) {
2871
// Setup the Intel AMT remote desktop
2845
- if ((desktopNode.intelamt.user == undefined) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
2872
+ if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; }
2873
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'));
2874
desktop.onStateChanged = onDesktopStateChange;
2875
desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
@@ -2865,7 +2892,7 @@
2892
// Disconnect and clean up the remote desktop
2893
desktop.Stop();
2894
delete desktop;
2868
- desktop = undefined;
2895
+ desktop = null;
2896
}
2897
}
2898
@@ -2874,14 +2901,14 @@
2901
if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
2902
QH('deskstatus', StatusStrs[xstate]);
2903
QE('deskSaveBtn', state == 3);
2877
- QV('deskFocusBtn', (desktop != undefined) && (desktop.contype == 2) && (state != 0) && (desktopsettings.showfocus));
2904
+ QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (state != 0) && (desktopsettings.showfocus));
2905
QE('DeskCAD', state == 3);
2906
switch (state) {
2907
case 0:
2908
// Disconnect and clean up the remote desktop
2909
desktop.Stop();
2910
delete desktop;
2884
- desktop = undefined;
2911
+ desktop = null;
2912
QV('DeskFocus', false);
2913
deskFocusBtn.value = 'All Focus';
2914
if (fullscreen == true) { deskToggleFull(); }
@@ -2923,7 +2950,7 @@
2950
d7showcursor.checked = desktopsettings.showmouse;
2951
d7bitmapquality.value = desktopsettings.quality;
2952
d7bitmapscaling.value = desktopsettings.scaling;
2926
- QV('deskFocusBtn', (desktop != undefined) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
2953
+ QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
2954
}
2955
2956
var fullscreen = false;
@@ -2988,22 +3015,22 @@
3015
3016
// Send CTRL-ALT-DEL
3017
function sendCAD() {
2991
- if (xxdialogMode || desktop == undefined || desktop.State != 3) return;
3018
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
3019
desktop.m.sendcad();
3020
}
3021
3022
// Save the desktop image to file
3023
function deskSaveImage() {
2997
- if (xxdialogMode || desktop == undefined || desktop.State != 3) return;
3024
+ if (xxdialogMode || desktop == null || desktop.State != 3) return;
3025
var d = new Date(), n = 'Desktop-' + currentNode.name + '-' + d.getFullYear() + "-" + ("0" + (d.getMonth() + 1)).slice(-2) + "-" + ("0" + d.getDate()).slice(-2) + "-" + ("0" + d.getHours()).slice(-2) + "-" + ("0" + d.getMinutes()).slice(-2);
3026
Q("Desk")['toBlob'](function (blob) { saveAs(blob, n + ".jpg"); });
3027
}
3028
3002
- function dmousedown(e) { if (!xxdialogMode && desktop != undefined) desktop.m.mousedown(e) }
3003
- function dmouseup(e) { if (!xxdialogMode && desktop != undefined) desktop.m.mouseup(e) }
3004
- function dmousemove(e) { if (!xxdialogMode && desktop != undefined) desktop.m.mousemove(e) }
3005
- function dmousewheel(e) { if (!xxdialogMode && desktop != undefined) { desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
3006
- function drotate(x) { if (!xxdialogMode && desktop != undefined) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } }
3029
+ function dmousedown(e) { if (!xxdialogMode && desktop != null) desktop.m.mousedown(e) }
3030
+ function dmouseup(e) { if (!xxdialogMode && desktop != null) desktop.m.mouseup(e) }
3031
+ function dmousemove(e) { if (!xxdialogMode && desktop != null) desktop.m.mousemove(e) }
3032
+ function dmousewheel(e) { if (!xxdialogMode && desktop != null) { desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
3033
+ function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } }
3034
3035
//
3036
// TERMINAL
@@ -3012,7 +3039,7 @@
3039
var terminalNode;
3040
function setupTerminal() {
3041
// Setup the terminal
3015
- if ((terminalNode != currentNode) && (terminal != undefined)) { terminal.Stop(); delete terminal; terminal = undefined; }
3042
+ if ((terminalNode != currentNode) && (terminal != null)) { terminal.Stop(); delete terminal; terminal = null; }
3043
terminalNode = currentNode;
3044
updateTerminalButtons();
3045
}
@@ -3020,12 +3047,12 @@
3047
// Show and enable the right buttons
3048
function updateTerminalButtons() {
3049
var mesh = meshes[terminalNode.meshid];
3023
- var termState = ((terminal != undefined) && (terminal.state != 0));
3050
+ var termState = ((terminal != null) && (terminal.state != 0));
3051
3052
// Show the right buttons
3053
QV('disconnectbutton2span', (termState == true));
3054
QV('connectbutton2span', (termState == false) && (mesh.mtype == 2));
3028
- QV('connectbutton2hspan', (termState == false) && (terminalNode.intelamt != undefined && ((terminalNode.intelamt.ver != undefined) || (mesh.mtype == 1))));
3055
+ QV('connectbutton2hspan', (termState == false) && (terminalNode.intelamt != null && ((terminalNode.intelamt.ver != null) || (mesh.mtype == 1))));
3056
3057
// Enable buttons
3058
var online = ((terminalNode.conn & 1) != 0); // If Agent (1) connected, enable Terminal
@@ -3052,10 +3079,10 @@
3079
// Disconnected, clear the terminal
3080
xterminal.m.TermResetScreen();
3081
xterminal.m.TermDraw();
3055
- if (terminal != undefined) {
3082
+ if (terminal != null) {
3083
terminal.Stop();
3084
delete terminal;
3058
- terminal = undefined;
3085
+ terminal = null;
3086
}
3087
break;
3088
case 3:
@@ -3072,7 +3099,7 @@
3099
if (!terminal) {
3100
if (contype == 2) {
3101
// Setup the Intel AMT terminal
3075
- if ((terminalNode.intelamt.user == undefined) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; }
3102
+ if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; }
3103
terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term'));
3104
terminal.onStateChanged = onTerminalStateChange;
3105
terminal.Start(terminalNode._id, 16994, '*', '*', 0);
@@ -3089,7 +3116,7 @@
3116
//QH('Term', '');
3117
terminal.Stop();
3118
delete terminal;
3092
- terminal = undefined;
3119
+ terminal = null;
3120
}
3121
Q('connectbutton2').blur(); // Deselect the connect button so the button does not get key presses.
3122
}
@@ -3146,7 +3173,7 @@
3173
filesNode = currentNode;
3174
var online = ((filesNode.conn & 1) != 0)?true:false; // If Agent (1) connected, enable Terminal
3175
QE('p13Connect', online);
3149
- if (((samenode == false) || (online == false)) && files) { files.Stop(); delete files; files = undefined; }
3176
+ if (((samenode == false) || (online == false)) && files) { files.Stop(); delete files; files = null; }
3177
}
3178
3179
function onFilesStateChange(xfiles, state) {
@@ -3161,7 +3188,7 @@
3188
QH('p13currentpath', '');
3189
QE('p13FolderUp', false);
3190
p13setActions();
3164
- if (files != undefined) { files.Stop(); delete files; files = undefined; }
3191
+ if (files != null) { files.Stop(); delete files; files = null; }
3192
break;
3193
case 3:
3194
files.Send(JSON.stringify({ action: 'ls', reqid: 1, path: '' }));
@@ -3192,7 +3219,7 @@
3219
//QH('Term', '');
3220
files.Stop();
3221
delete files;
3195
- files = undefined;
3222
+ files = null;
3223
}
3224
}
3225
@@ -3249,11 +3276,11 @@
3276
3277
// Figure out the date
3278
var fdatestr = '';
3252
- if (f.d != undefined) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + fdate.toLocaleTimeString() + " "; }
3279
+ if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + fdate.toLocaleTimeString() + " "; }
3280
3281
// Figure out the size
3282
var fsize = '';
3256
- if (f.s != undefined) { fsize = getFileSizeStr(f.s); }
3283
+ if (f.s != null) { fsize = getFileSizeStr(f.s); }
3284
3285
var h = '';
3286
if (f.t < 3) {
@@ -3274,7 +3301,7 @@
3301
QE('p13FolderUp', p13filetreelocation.length != 0);
3302
3303
// Re-check all boxes if needed using names
3277
- if (checkedNames != undefined) {
3304
+ if (checkedNames != null) {
3305
checkedBoxes = [];
3306
checkboxes = document.getElementsByName('fd');
3307
for (var i in filetreexx) { if (checkedNames.indexOf(filetreexx[i].n) >= 0) { checkedBoxes.push(filetreexx[i].nx); } }
@@ -3295,7 +3322,7 @@
3322
}
3323
3324
function p13folderup(x) {
3298
- if (x == undefined) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } }
3325
+ if (x == null) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } }
3326
files.Send(JSON.stringify({ action: 'ls', reqid: 1, path: p13filetreelocation.join('/') }));
3327
}
3328
@@ -3306,7 +3333,7 @@
3333
3334
function p13sort_files(files) {
3335
var r = [], sortselection = Q('p13sortdropdown').value;
3309
- for (var i in files) { files[i].nx = i; if (files[i].s == undefined) { files[i].s = 0; } if (files[i].n == undefined) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
3336
+ for (var i in files) { files[i].nx = i; if (files[i].s == null) { files[i].s = 0; } if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
3337
p13sortorder = 1;
3338
if (sortselection > 3) { p13sortorder = -1; sortselection -= 3; }
3339
if (sortselection == 1) { r.sort(p13sort_filename); }
@@ -3402,7 +3429,7 @@
3429
//console.log('p13downloadFileCancel');
3430
downloadFile.Stop();
3431
delete downloadFile;
3405
- downloadFile = undefined;
3432
+ downloadFile = null;
3433
}
3434
3435
// Called by the file transport to indicate when the transport connection state has changed
@@ -3410,7 +3437,7 @@
3437
switch (state) {
3438
case 0: // Transport as disconnected. If this is not part of an abort, we need to save the file
3439
setDialogMode(0); // Close any dialog boxes if present
3413
- if ((downloadFile != undefined) && (downloadFile.xstate == 1)) { saveAs(data2blob(downloadFile.xdata), downloadFile.xfile); } // Save the file
3440
+ if ((downloadFile != null) && (downloadFile.xstate == 1)) { saveAs(data2blob(downloadFile.xdata), downloadFile.xfile); } // Save the file
3441
break;
3442
case 3: // Transport as connected, send a command to indicate we want to start a file download
3443
downloadFile.Send(JSON.stringify({ action: 'download', reqid: 1, path: downloadFile.xpath }));
@@ -3492,12 +3519,12 @@
3519
3520
// Used to cancel the entire transfer.
3521
function p13uploadFileCancel(button, tag) {
3495
- if (uploadFile != undefined) {
3496
- if (uploadFile.ws != undefined) {
3522
+ if (uploadFile != null) {
3523
+ if (uploadFile.ws != null) {
3524
uploadFile.ws.Stop();
3498
- uploadFile.ws = undefined;
3525
+ uploadFile.ws = null;
3526
}
3500
- uploadFile = undefined;
3527
+ uploadFile = null;
3528
}
3529
setDialogMode(0); // Close any dialog boxes if present
3530
}
@@ -3505,7 +3532,7 @@
3532
// Receive upload ack from the mesh agent, use this to keep sending more data
3533
function p13gotUploadData(data) {
3534
var cmd = JSON.parse(data);
3508
- if ((uploadFile == undefined) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
3535
+ if ((uploadFile == null) || (parseInt(uploadFile.xfilePtr) != parseInt(cmd.reqid))) { return; }
3536
3537
if (cmd.action == 'uploadstart') {
3538
p13uploadNextPart(false);
@@ -3524,7 +3551,7 @@
3551
var end = uploadFile.xptr + 4096;
3552
if (end > data.byteLength) { if (dataPriming == true) { return; } end = data.byteLength; }
3553
if (start == data.byteLength) {
3527
- if (uploadFile.ws != undefined) { uploadFile.ws.Stop(); uploadFile.ws = undefined; }
3554
+ if (uploadFile.ws != null) { uploadFile.ws.Stop(); uploadFile.ws = null; }
3555
if (uploadFile.xfiles.length > uploadFile.xfilePtr + 1) { p13uploadReconnect(); } else { p13uploadFileCancel(); }
3556
} else {
3557
var datapart = data.slice(start, end);
@@ -3567,7 +3594,7 @@
3594
var mesh = meshes[consoleNode.meshid];
3595
var meshrights = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()].rights;
3596
if ((meshrights & 16) != 0) {
3570
- if (consoleNode.consoleText == undefined) { consoleNode.consoleText = ''; }
3597
+ if (consoleNode.consoleText == null) { consoleNode.consoleText = ''; }
3598
if (samenode == false) {
3599
QH('p15agentConsole', consoleNode.consoleText);
3600
Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight;
@@ -3618,7 +3645,7 @@
3645
// Handle Mesh Agent console data
3646
function p15consoleReceive(node, data) {
3647
data = '<div>' + EscapeHtmlBreaks(data) + '</div>'
3621
- if (node.consoleText == undefined) { node.consoleText = data; } else { node.consoleText += data; }
3648
+ if (node.consoleText == null) { node.consoleText = data; } else { node.consoleText += data; }
3649
if (consoleNode == node) {
3650
Q('p15agentConsole').innerHTML += data;
3651
Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight;
@@ -4032,7 +4059,7 @@
4059
4060
filetreelinkpath = '';
4061
for (var i in filetreelocation) {
4035
- if ((filetreex.f != undefined) && (filetreex.f[filetreelocation[i]] != undefined)) {
4062
+ if ((filetreex.f != null) && (filetreex.f[filetreelocation[i]] != null)) {
4063
filetreelocation2.push(filetreelocation[i]);
4064
fullPath += ' / ' + filetreelocation[i];
4065
if ((folderdepth == 1)) {
@@ -4044,7 +4071,7 @@
4071
if (filetreelinkpath != '') { filetreelinkpath += '/' + filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + filetreelocation[i]; } }
4072
}
4073
filetreex = filetreex.f[filetreelocation[i]];
4047
- displayPath += ' / <a style=cursor:pointer onclick=p5folderup(' + folderdepth + ')>' + (filetreex.n != undefined?filetreex.n:filetreelocation[i]) + '</a>';
4074
+ displayPath += ' / <a style=cursor:pointer onclick=p5folderup(' + folderdepth + ')>' + (filetreex.n != null?filetreex.n:filetreelocation[i]) + '</a>';
4075
folderdepth++;
4076
} else {
4077
break;
@@ -4066,11 +4093,11 @@
4093
4094
// Figure out the date
4095
var fdatestr = '';
4069
- if (f.d != undefined) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + fdate.toLocaleTimeString() + " "; }
4096
+ if (f.d != null) { var fdate = new Date(f.d), fdatestr = (fdate.getMonth() + 1) + "/" + (fdate.getDate()) + "/" + fdate.getFullYear() + " " + fdate.toLocaleTimeString() + " "; }
4097
4098
// Figure out the size
4099
var fsize = '';
4073
- if (f.s != undefined) { fsize = getFileSizeStr(f.s); }
4100
+ if (f.s != null) { fsize = getFileSizeStr(f.s); }
4101
4102
var h = '';
4103
if (f.t < 3) {
@@ -4087,7 +4114,7 @@
4114
if (f.t < 3) { html1 += h; } else { html2 += h; }
4115
}
4116
4090
- //if (f.parent == undefined) { }
4117
+ //if (f.parent == null) { }
4118
QH('p5rightOfButtons', p5getQuotabar(filetreex));
4119
4120
QH('p5files', html1 + html2);
@@ -4108,7 +4135,7 @@
4135
4136
function p5getQuotabar(f) {
4137
while (f.t > 1) { f = f.parent; }
4111
- if ((f.t != 1) || (f.maxbytes == undefined)) return '';
4138
+ if ((f.t != 1) || (f.maxbytes == null)) return '';
4139
var tf = Math.floor(f.s / 1024), tq = Math.floor((f.maxbytes - f.s) / 1024);
4140
return '<span title="' + tf + "k in " + f.c + " file" + (f.c > 1?'s':'') + ". " + (Math.floor(f.maxbytes / 1024)) + 'k maxinum">' + ((tq < 0)?('Storage limit exceed'):(tq + 'k remaining')) + ' <progress style=height:10px;width:200px value=' + f.s + ' max=' + f.maxbytes + ' /></span>';
4141
}
@@ -4122,7 +4149,7 @@
4149
4150
function p5sort_files(files) {
4151
var r = [], sortselection = Q('p5sortdropdown').value;
4125
- for (var i in files) { files[i].nx = i; if (files[i].n == undefined) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
4152
+ for (var i in files) { files[i].nx = i; if (files[i].n == null) { files[i].n = i; } files[i].ln = files[i].n.toLowerCase(); r.push(files[i]); }
4153
sortorder = 1;
4154
if (sortselection > 3) { sortorder = -1; sortselection -= 3; }
4155
if (sortselection == 1) { r.sort(p5sort_filename); }
@@ -4144,9 +4171,9 @@
4171
function getFileSelCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) cc++; } return cc; }
4172
function getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); return checkboxes.length; }
4173
function p5selectallfile() { var nv = (getFileSelCount() == 0), checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p5setActions(); }
4147
- function setupBackPointers(x) { if (x.f != undefined) { var fs = 0, fc = 0; for (var i in x.f) { setupBackPointers(x.f[i]); x.f[i].parent = x; if (x.f[i].s) { fs += x.f[i].s; } if (x.f[i].c) { fc += x.f[i].c; } if (x.f[i].t == 3) { fc++; } } x.s = fs; x.c = fc; } return x; }
4174
+ function setupBackPointers(x) { if (x.f != null) { var fs = 0, fc = 0; for (var i in x.f) { setupBackPointers(x.f[i]); x.f[i].parent = x; if (x.f[i].s) { fs += x.f[i].s; } if (x.f[i].c) { fc += x.f[i].c; } if (x.f[i].t == 3) { fc++; } } x.s = fs; x.c = fc; } return x; }
4175
function getFileSizeStr(size) { if (size == 1) return "1 byte"; return "" + size + " bytes"; }
4149
- function p5folderup(x) { if (x == undefined) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); }
4176
+ function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); }
4177
function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); }
4178
function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck() style=width:100% />'); Q('p5renameinput').focus(); }
4179
function p5createfolderEx() { meshserver.Send({ action: 'fileoperation', fileop: 'createfolder', path: filetreelocation, newfolder: Q('p5renameinput').value}); }
@@ -4277,7 +4304,7 @@
4304
}
4305
if (msg != '') msg += ', ';
4306
if (user.name != userinfo.name) { msg += "<a onclick=showUserAdminDialog(event,\"" + user._id + "\")>"; }
4280
- if ((user.siteadmin == undefined) || (user.siteadmin == 0)) {
4307
+ if ((user.siteadmin == null) || (user.siteadmin == 0)) {
4308
msg += "User";
4309
} else if (user.siteadmin == 8) {
4310
msg += "User with server files";
@@ -4286,7 +4313,7 @@
4313
} else {
4314
msg += "Partial Admin";
4315
}
4289
- if ((user.quota != undefined) && ((user.siteadmin & 8) != 0)) { msg += ", " + (user.quota / 1024) + " k"; }
4316
+ if ((user.quota != null) && ((user.siteadmin & 8) != 0)) { msg += ", " + (user.quota / 1024) + " k"; }
4317
if (user.name != userinfo.name) { msg += "</a>"; }
4318
if (user.email != null) {
4319
msg = '<table style=width:100%><tr><td>' + EscapeHtml(user.name) + ', <a onclick=doemail(event,\"' + user.email + '\")>' + user.email + '</a>' + (((serverinfo.emailcheck == true) && (user.emailVerified != true))?' (unverified)':'') + '<td align=right>' + msg + '</table>';
@@ -4370,7 +4397,7 @@
4397
QE('ua_serverrestore', userinfo.siteadmin == 0xFFFFFFFF);
4398
QE('ua_fileaccess', userinfo.siteadmin == 0xFFFFFFFF);
4399
QE('ua_serverupdate', userinfo.siteadmin == 0xFFFFFFFF);
4373
- Q('ua_fileaccessquota').value = (user.quota != undefined)?(user.quota / 1024):'';
4400
+ Q('ua_fileaccessquota').value = (user.quota != null)?(user.quota / 1024):'';
4401
showUserAdminDialogValidate();
4402
return false;
4403
}
@@ -4429,7 +4456,7 @@
4456
4457
d3filetreelinkpath = '';
4458
for (var i in d3filetreelocation) {
4432
- if ((filetreex.f != undefined) && (filetreex.f[d3filetreelocation[i]] != undefined)) {
4459
+ if ((filetreex.f != null) && (filetreex.f[d3filetreelocation[i]] != null)) {
4460
d3filetreelocation2.push(d3filetreelocation[i]);
4461
if ((folderdepth == 1)) {
4462
var sp = d3filetreelocation[i].split('/');
@@ -4459,7 +4486,7 @@
4486
4487
// Figure out the size
4488
var fsize = '';
4462
- if (f.s != undefined) { fsize = getFileSizeStr(f.s); }
4489
+ if (f.s != null) { fsize = getFileSizeStr(f.s); }
4490
4491
var h = '';
4492
if (f.t < 3) {
@@ -4480,7 +4507,7 @@
4507
}
4508
4509
function d3folderset(x) { d3filetreelocation.push(decodeURIComponent(x)); d3updatefiles(); }
4483
- function d3folderup(x) { if (x == undefined) { d3filetreelocation.pop(); } else { while (d3filetreelocation.length > x) { d3filetreelocation.pop(); } } d3updatefiles(); }
4510
+ function d3folderup(x) { if (x == null) { d3filetreelocation.pop(); } else { while (d3filetreelocation.length > x) { d3filetreelocation.pop(); } } d3updatefiles(); }
4511
function d3getFileSel() { var cc = []; var checkboxes = document.getElementsByName('fcx'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { cc.push(checkboxes[i].value) } } return cc; }
4512
function d3setActions() {
4513
var mode = Q('d3uploadMode').value;
@@ -4523,7 +4550,7 @@
4550
var t = '';
4551
var d = new Date(n.time);
4552
var icon = 0;
4526
- if (n.nodeid != undefined) {
4553
+ if (n.nodeid != null) {
4554
var node = getNodeFromId(n.nodeid);
4555
if (node != null) {
4556
//console.log(node);
@@ -4546,7 +4573,7 @@
4573
for (var i in notifications) { if (notifications[i].id == id) { j = i; } }
4574
if (j != -1) {
4575
var n = notifications[j];
4549
- if (n.nodeid != undefined) {
4576
+ if (n.nodeid != null) {
4577
if (n.tag == 'desktop') gotoDevice(n.nodeid, 12); // Desktop
4578
else if (n.tag == 'terminal') gotoDevice(n.nodeid, 11); // Terminal
4579
else if (n.tag == 'files') gotoDevice(n.nodeid, 13); // Files
@@ -4578,8 +4605,8 @@
4605
4606
// Add a new notification and play the notification sound
4607
function addNotification(n) {
4581
- if (n.time == undefined) { n.time = Date.now(); }
4582
- if (n.id == undefined) { n.id = Math.random(); }
4608
+ if (n.time == null) { n.time = Date.now(); }
4609
+ if (n.id == null) { n.id = Math.random(); }
4610
notifications.unshift(n);
4611
setNotificationCount(notifications.length);
4612
Q('chimes').play();
@@ -4598,7 +4625,7 @@
4625
// POPUP DIALOG
4626
//
4627
4601
- // undefined = Hidden, 1 = Generic Message
4628
+ // null = Hidden, 1 = Generic Message
4629
var xxdialogMode;
4630
var xxdialogFunc;
4631
var xxdialogButtons;
@@ -4662,8 +4689,8 @@
4689
4690
// Generic methods
4691
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
4665
- function putstore(name, val) { try { if (typeof (localStorage) === "undefined") return; localStorage.setItem(name, val); } catch (e) { } }
4666
- function getstore(name, val) { try { if (typeof (localStorage) === "undefined") return val; var v = localStorage.getItem(name); if ((v == undefined) || (v == null)) return val; return v; } catch (e) { return val; } }
4692
+ function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
4693
+ 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; } }
4694
function addLink(x, f) { return "<a style=cursor:pointer;color:darkblue;text-decoration:none onclick='" + f + "'>♦ " + x + "</a>"; }
4695
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
4696
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
webserver.js
+23
-42
@@ -271,11 +271,11 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
271
obj.authenticate(req.body.username, req.body.password, domain, function (err, userid, passhint) {
272
if (userid) {
273
var user = obj.users[userid];
274
-
274
+
275
// Save login time
276
user.login = Date.now();
277
obj.db.SetUser(user);
278
-
278
+
279
// Regenerate session when signing in to prevent fixation
280
req.session.regenerate(function () {
281
// Store the user's primary key in the session store to be retrieved, or in this case the entire user object
@@ -302,7 +302,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
302
res.redirect(domain.url);
303
}
304
});
305
-
305
+
306
obj.parent.DispatchEvent(['*'], obj, { etype: 'user', username: user.name, action: 'login', msg: 'Account login', domain: domain.id })
307
} else {
308
delete req.session.loginmode;
@@ -407,7 +407,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
407
var domain = checkUserIpAddress(req, res);
408
if (domain == null) return;
409
if (req.query.c != null) {
410
- var cookie = obj.decodeCookie(req.query.c, null, 30);
410
+ var cookie = obj.parent.decodeCookie(req.query.c, obj.parent.mailserver.mailCookieEncryptionKey, 30);
411
if ((cookie != null) && (cookie.u != null) && (cookie.e != null)) {
412
var idsplit = cookie.u.split('/');
413
if ((idsplit.length != 2) || (idsplit[0] != domain.id)) {
@@ -444,10 +444,13 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
444
delete userinfo.domain;
445
delete userinfo.subscriptions;
446
delete userinfo.passtype;
447
- obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + userinfo.email + ')', domain: domain.id })
447
+ obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + EscapeHtml(userinfo.email) + ')', domain: domain.id })
448
449
// Send the confirmation page
450
res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Verified e-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
451
+
452
+ // Send a notification
453
+ obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified: <b>' + EscapeHtml(userinfo.email) + '</b>.' , nolog: 1 })
454
}
455
});
456
}
@@ -571,6 +574,15 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
574
req.session.userid = 'user/' + domain.id + '/' + obj.args.user.toLowerCase();
575
req.session.domainid = domain.id;
576
req.session.currentNode = '';
577
+ } else if (req.query.login && (obj.parent.loginCookieEncryptionKey != null)) {
578
+ var loginCookie = obj.parent.decodeCookie(req.query.login, obj.parent.loginCookieEncryptionKey, 60); // 60 minute timeout
579
+ if ((loginCookie != null) && (loginCookie.a == 3) && (loginCookie.u != null) && (loginCookie.u.split('/')[1] == domain.id)) {
580
+ // If a login cookie was provided, setup the session here.
581
+ if (req.session && req.session.loginmode) { delete req.session.loginmode; }
582
+ req.session.userid = loginCookie.u;
583
+ req.session.domainid = domain.id;
584
+ req.session.currentNode = '';
585
+ }
586
}
587
// If a user is logged in, serve the default app, otherwise server the login app.
588
if (req.session && req.session.userid) {
@@ -579,11 +591,15 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
591
if (req.session.viewmode) {
592
viewmode = req.session.viewmode;
593
delete req.session.viewmode;
594
+ } else if (req.query.viewmode) {
595
+ viewmode = req.query.viewmode;
596
}
597
var currentNode = '';
598
if (req.session.currentNode) {
599
currentNode = req.session.currentNode;
600
delete req.session.currentNode;
601
+ } else if (req.query.node) {
602
+ currentNode = 'node/' + domain.id + '/' + req.query.node;
603
}
604
var user;
605
var logoutcontrol;
@@ -894,7 +910,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
910
} else {
911
// Get the session from the cookie
912
if (obj.parent.multiServer == null) { return; }
897
- var session = obj.decodeCookie(req.query.auth);
913
+ var session = obj.parent.decodeCookie(req.query.auth);
914
if (session == null) { console.log('ERR: Invalid cookie'); return; }
915
if (session.domainid != domain.id) { console.log('ERR: Invalid domain'); return; }
916
user = obj.users[session.userid];
@@ -1484,7 +1500,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1500
}
1501
1502
// Force mesh agent disconnection
1487
- function forceMeshAgentDisconnect(user, domain, nodeid, disconnectMode) {
1503
+ obj.forceMeshAgentDisconnect = function(user, domain, nodeid, disconnectMode) {
1504
if (nodeid == null) return;
1505
var splitnode = nodeid.split('/');
1506
if ((splitnode.length != 3) || (splitnode[1] != domain.id)) return; // Check that nodeid is valid and part of our domain
@@ -1642,40 +1658,5 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1658
}
1659
}
1660
1645
- // Generate a cryptographic key used to encode and decode cookies
1646
- obj.generateCookieKey = function () {
1647
- return new Buffer(obj.crypto.randomBytes(32), 'binary');
1648
- //return Buffer.alloc(32, 0); // Sets the key to zeros, debug only.
1649
- }
1650
-
1651
- // Encode an object as a cookie using a key. (key must be 32 bytes long)
1652
- obj.encodeCookie = function (o, key) {
1653
- try {
1654
- if (key == null) { key = obj.serverKey; }
1655
- o.time = Math.floor(Date.now() / 1000); // Add the cookie creation time
1656
- var iv = new Buffer(obj.crypto.randomBytes(12), 'binary'), cipher = obj.crypto.createCipheriv('aes-256-gcm', key, iv);
1657
- var crypted = Buffer.concat([cipher.update(JSON.stringify(o), 'utf8'), cipher.final()]);
1658
- return Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
1659
- } catch (e) { return null; }
1660
- }
1661
-
1662
- // Decode a cookie back into an object using a key. Return null if it's not a valid cookie. (key must be 32 bytes long)
1663
- obj.decodeCookie = function (cookie, key, timeout) {
1664
- try {
1665
- if (key == null) { key = obj.serverKey; }
1666
- cookie = new Buffer(cookie.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64');
1667
- var decipher = obj.crypto.createDecipheriv('aes-256-gcm', key, cookie.slice(0, 12));
1668
- decipher.setAuthTag(cookie.slice(12, 16));
1669
- var o = JSON.parse(decipher.update(cookie.slice(28), 'binary', 'utf8') + decipher.final('utf8'));
1670
- if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { return null; }
1671
- o.time = o.time * 1000; // Decode the cookie creation time
1672
- o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
1673
- if (timeout == null) { timeout = 2; }
1674
- if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) return null; // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
1675
- return o;
1676
- } catch (e) { return null; }
1677
- }
1678
-
1679
- obj.serverKey = obj.generateCookieKey();
1661
return obj;
1662
}