Code fixes & clean up.
Ylian Saint-Hilaire committed
Jul 6, 2020 at 12:46 UTC
aa6070deb5d7f9ba5edb4b5d2671ab9d94831603
6 files changed
+96
-85
meshuser.js
+40
-36
@@ -49,6 +49,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
49
const MESHRIGHT_CHATNOTIFY = 16384;
50
const MESHRIGHT_UNINSTALL = 32768;
51
const MESHRIGHT_NODESKTOP = 65536;
52
+ const MESHRIGHT_ADMIN = 0xFFFFFFFF;
53
54
// Site rights
55
const SITERIGHT_SERVERBACKUP = 1; // 0x00000001
@@ -61,6 +62,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
62
const SITERIGHT_NOMESHCMD = 128; // 0x00000080
63
const SITERIGHT_USERGROUPS = 256; // 0x00000100
64
const SITERIGHT_RECORDINGS = 512; // 0x00000200
65
+ const SITERIGHT_ADMIN = 0xFFFFFFFF; // 0xFFFFFFFF
66
67
var obj = {};
68
obj.user = user;
@@ -299,7 +301,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
301
if (id.startsWith('mesh/')) {
302
// Check if we have rights to get this message. If we have limited events on this mesh, don't send the event to the user.
303
var meshrights = parent.GetMeshRights(user, id);
302
- if ((meshrights == 0xFFFFFFFF) || ((meshrights & MESHRIGHT_LIMITEVENTS) == 0) || (ids.indexOf(user._id) >= 0)) {
304
+ if ((meshrights === MESHRIGHT_ADMIN) || ((meshrights & MESHRIGHT_LIMITEVENTS) == 0) || (ids.indexOf(user._id) >= 0)) {
305
// We have the device group rights to see this event or we are directly targetted by the event
306
ws.send(JSON.stringify({ action: 'event', event: event }));
307
} else {
@@ -401,7 +403,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
403
if (args.notls == true) { serverinfo.https = false; } else { serverinfo.https = true; serverinfo.redirport = args.redirport; }
404
if (typeof domain.userconsentflags == 'number') { serverinfo.consent = domain.userconsentflags; }
405
if ((typeof domain.usersessionidletimeout == 'number') && (domain.usersessionidletimeout > 0)) { serverinfo.timeout = (domain.usersessionidletimeout * 60 * 1000); }
404
- if (user.siteadmin == 0xFFFFFFFF) {
406
+ if (user.siteadmin === SITERIGHT_ADMIN) {
407
if (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) { serverinfo.manageAllDeviceGroups = true; }
408
if (obj.crossDomain === true) { serverinfo.crossDomain = []; for (var i in parent.parent.config.domains) { serverinfo.crossDomain.push(i); } }
409
}
@@ -412,7 +414,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
414
// Send user information to web socket, this is the first thing we send
415
try { ws.send(JSON.stringify({ action: 'userinfo', userinfo: parent.CloneSafeUser(parent.users[user._id]) })); } catch (ex) { }
416
415
- if (user.siteadmin == 0xFFFFFFFF) {
417
+ if (user.siteadmin === SITERIGHT_ADMIN) {
418
// Send server tracing information
419
try { ws.send(JSON.stringify({ action: 'traceinfo', traceSources: parent.parent.debugRemoteSources })); } catch (ex) { }
420
@@ -765,7 +767,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
767
case 'serverconsole':
768
{
769
// This is a server console message, only process this if full administrator
768
- if (user.siteadmin != 0xFFFFFFFF) break;
770
+ if (user.siteadmin != SITERIGHT_ADMIN) break;
771
772
var r = '';
773
var cmdargs = splitArgs(command.value);
@@ -1235,7 +1237,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1237
var limit = 10000;
1238
if (common.validateInt(command.limit, 1, 60000) == true) { limit = command.limit; }
1239
1238
- if (((rights & MESHRIGHT_LIMITEVENTS) != 0) && (rights != 0xFFFFFFFF)) {
1240
+ if (((rights & MESHRIGHT_LIMITEVENTS) != 0) && (rights != MESHRIGHT_ADMIN)) {
1241
// Send the list of most recent events for this nodeid that only apply to us, up to 'limit' count
1242
db.GetNodeEventsSelfWithLimit(node._id, domain.id, user._id, limit, function (err, docs) {
1243
if (err != null) return;
@@ -1260,7 +1262,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1262
// TODO (UserGroups)
1263
1264
// Remove MeshID's that we do not have rights to see events for
1263
- for (var link in obj.user.links) { if (((obj.user.links[link].rights & MESHRIGHT_LIMITEVENTS) != 0) && ((obj.user.links[link].rights != 0xFFFFFFFF))) { exGroupFilter2.push(link); } }
1265
+ for (var link in obj.user.links) { if (((obj.user.links[link].rights & MESHRIGHT_LIMITEVENTS) != 0) && ((obj.user.links[link].rights != MESHRIGHT_ADMIN))) { exGroupFilter2.push(link); } }
1266
for (var i in filter2) { if (exGroupFilter2.indexOf(filter2[i]) == -1) { filter.push(filter2[i]); } }
1267
1268
if ((command.limit == null) || (typeof command.limit != 'number')) {
@@ -1467,7 +1469,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1469
deluser = parent.users[deluserid];
1470
if (deluser == null) { err = 'User does not exists'; }
1471
else if ((obj.crossDomain !== true) && ((delusersplit.length != 3) || (delusersplit[1] != domain.id))) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain
1470
- else if ((deluser.siteadmin == 0xFFFFFFFF) && (user.siteadmin != 0xFFFFFFFF)) { err = 'Permission denied'; } // Need full admin to remote another administrator
1472
+ else if ((deluser.siteadmin === SITERIGHT_ADMIN) && (user.siteadmin != SITERIGHT_ADMIN)) { err = 'Permission denied'; } // Need full admin to remote another administrator
1473
else if ((obj.crossDomain !== true) && (user.groups != null) && (user.groups.length > 0) && ((deluser.groups == null) || (findOne(deluser.groups, user.groups) == false))) { err = 'Invalid user group'; } // Can only perform this operation on other users of our group.
1474
}
1475
} catch (ex) { err = 'Validation exception: ' + ex; }
@@ -1702,7 +1704,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1704
newuserid = 'user/' + newuserdomain.id + '/' + command.username.toLowerCase();
1705
if (command.siteadmin != null) {
1706
if ((typeof command.siteadmin != 'number') || (Number.isInteger(command.siteadmin) == false)) { err = 'Invalid site permissions'; } // Check permissions
1705
- else if ((user.siteadmin != 0xFFFFFFFF) && ((command.siteadmin & (0xFFFFFFFF - 224)) != 0)) { err = 'Invalid site permissions'; }
1707
+ else if ((user.siteadmin != SITERIGHT_ADMIN) && ((command.siteadmin & (SITERIGHT_ADMIN - 224)) != 0)) { err = 'Invalid site permissions'; }
1708
}
1709
if (parent.users[newuserid]) { err = 'User already exists'; } // Account already exists
1710
else if ((newuserdomain.auth == 'sspi') || (newuserdomain.auth == 'ldap')) { err = 'Unable to add user in this mode'; }
@@ -1818,10 +1820,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1820
change = 0;
1821
if (chguser) {
1822
// If the target user is admin and we are not admin, no changes can be made.
1821
- if ((chguser.siteadmin == 0xFFFFFFFF) && (user.siteadmin != 0xFFFFFFFF)) return;
1823
+ if ((chguser.siteadmin === SITERIGHT_ADMIN) && (user.siteadmin != SITERIGHT_ADMIN)) return;
1824
1825
// Can only perform this operation on other users of our group.
1824
- if (user.siteadmin != 0xFFFFFFFF) {
1826
+ if (user.siteadmin != SITERIGHT_ADMIN) {
1827
if ((user.groups != null) && (user.groups.length > 0) && ((chguser.groups == null) || (findOne(chguser.groups, user.groups) == false))) return;
1828
}
1829
@@ -1845,7 +1847,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1847
// Site admins can change any server rights, user managers can only change AccountLock, NoMeshCmd and NoNewGroups
1848
if (common.validateInt(command.siteadmin) && (chguser._id !== user._id) && (chguser.siteadmin != command.siteadmin)) { // We can't change our own siteadmin permissions.
1849
var chgusersiteadmin = chguser.siteadmin ? chguser.siteadmin : 0;
1848
- if (user.siteadmin == 0xFFFFFFFF) { chguser.siteadmin = command.siteadmin; change = 1; }
1850
+ if (user.siteadmin === SITERIGHT_ADMIN) { chguser.siteadmin = command.siteadmin; change = 1; }
1851
else if (user.siteadmin & 2) {
1852
var mask = 0xFFFFFF1D; // Mask: 2 (User Mangement) + 32 (Account locked) + 64 (No New Groups) + 128 (No Tools)
1853
if ((user.siteadmin & 256) != 0) { mask -= 256; } // Mask: Manage User Groups
@@ -1856,7 +1858,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1858
1859
// When sending a notification about a group change, we need to send to all the previous and new groups.
1860
var allTargetGroups = chguser.groups;
1859
- if ((Array.isArray(command.groups)) && ((user._id != command.id) || (user.siteadmin == 0xFFFFFFFF))) {
1861
+ if ((Array.isArray(command.groups)) && ((user._id != command.id) || (user.siteadmin === SITERIGHT_ADMIN))) {
1862
if (command.groups.length == 0) {
1863
// Remove the user groups
1864
if (chguser.groups != null) { delete chguser.groups; change = 1; }
@@ -1891,7 +1893,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1893
if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
1894
parent.parent.DispatchEvent(targets, obj, event);
1895
}
1894
- if ((chguser.siteadmin) && (chguser.siteadmin != 0xFFFFFFFF) && (chguser.siteadmin & 32)) {
1896
+ if ((chguser.siteadmin) && (chguser.siteadmin !== SITERIGHT_ADMIN) && (chguser.siteadmin & 32)) {
1897
// If the user is locked out of this account, disconnect now
1898
parent.parent.DispatchEvent([chguser._id], obj, 'close'); // Disconnect all this user's sessions
1899
}
@@ -1934,9 +1936,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1936
else if (parent.userGroups[command.clone] == null) { err = "Invalid clone groupid"; }
1937
}
1938
1937
- // Get new user group domain
1938
- ugrpdomain = parent.parent.config.domains[clonesplit[1]];
1939
- if (ugrpdomain == null) { err = "Invalid domain"; }
1939
+ if (err == null) {
1940
+ // Get new user group domain
1941
+ ugrpdomain = parent.parent.config.domains[clonesplit[1]];
1942
+ if (ugrpdomain == null) { err = "Invalid domain"; }
1943
+ }
1944
} else {
1945
// Get new user group domain
1946
ugrpdomain = domain;
@@ -1945,7 +1949,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1949
}
1950
1951
// In some situations, we need a verified email address to create a device group.
1948
- if ((err == null) && (parent.parent.mailserver != null) && (ugrpdomain.auth != 'sspi') && (ugrpdomain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != 0xFFFFFFFF)) { err = "Email verification required"; } // User must verify it's email first.
1952
+ if ((err == null) && (parent.parent.mailserver != null) && (ugrpdomain.auth != 'sspi') && (ugrpdomain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != SITERIGHT_ADMIN)) { err = "Email verification required"; } // User must verify it's email first.
1953
} catch (ex) { err = "Validation exception: " + ex; }
1954
1955
// Handle any errors
@@ -2355,7 +2359,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2359
var chguser = parent.users[command.userid];
2360
if (chguser) {
2361
// If we are not full administrator, we can't change anything on a different full administrator
2358
- if ((user.siteadmin != 0xFFFFFFFF) & (chguser.siteadmin == 0xFFFFFFFF)) break;
2362
+ if ((user.siteadmin != SITERIGHT_ADMIN) & (chguser.siteadmin === SITERIGHT_ADMIN)) break;
2363
2364
// Can only perform this operation on other users of our group.
2365
if ((user.groups != null) && (user.groups.length > 0) && ((chguser.groups == null) || (findOne(chguser.groups, user.groups) == false))) break;
@@ -2499,10 +2503,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2503
var err = null;
2504
try {
2505
// Check if we have new group restriction
2502
- if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 64) != 0)) { err = 'Permission denied'; }
2506
+ if ((user.siteadmin != SITERIGHT_ADMIN) && ((user.siteadmin & 64) != 0)) { err = 'Permission denied'; }
2507
2508
// In some situations, we need a verified email address to create a device group.
2505
- else if ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != 0xFFFFFFFF)) { err = 'Email verification required'; } // User must verify it's email first.
2509
+ else if ((parent.parent.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (user.emailVerified !== true) && (user.siteadmin != SITERIGHT_ADMIN)) { err = 'Email verification required'; } // User must verify it's email first.
2510
2511
// Create mesh
2512
else if (common.validateString(command.meshname, 1, 64) == false) { err = 'Invalid group name'; } // Meshname is between 1 and 64 characters
@@ -2582,7 +2586,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2586
2587
// Check if this user has rights to do this
2588
var err = null;
2585
- if (parent.GetMeshRights(user, mesh) != 0xFFFFFFFF) { err = 'Access denied'; }
2589
+ if (parent.GetMeshRights(user, mesh) != MESHRIGHT_ADMIN) { err = 'Access denied'; }
2590
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = 'Invalid group'; } // Invalid domain, operation only valid for current domain
2591
2592
// Handle any errors
@@ -2760,14 +2764,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2764
2765
var targetMeshRights = 0;
2766
if ((newuser.links != null) && (newuser.links[command.meshid] != null) && (newuser.links[command.meshid].rights != null)) { targetMeshRights = newuser.links[command.meshid].rights; }
2763
- if ((targetMeshRights == 0xFFFFFFFF) && (selfMeshRights != 0xFFFFFFFF)) { msgs.push("Can't change rights of device group administrator"); continue; } // A non-admin can't kick out an admin
2767
+ if ((targetMeshRights === MESHRIGHT_ADMIN) && (selfMeshRights != MESHRIGHT_ADMIN)) { msgs.push("Can't change rights of device group administrator"); continue; } // A non-admin can't kick out an admin
2768
2769
if (command.remove === true) {
2770
// Remove mesh from user or user group
2771
delete newuser.links[command.meshid];
2772
} else {
2773
// Adjust rights since we can't add more rights that we have outself for MESHRIGHT_MANAGEUSERS
2770
- if ((selfMeshRights != 0xFFFFFFFF) && (command.meshadmin == 0xFFFFFFFF)) { msgs.push("Can't set device group administrator, if not administrator"); continue; }
2774
+ if ((selfMeshRights != MESHRIGHT_ADMIN) && (command.meshadmin == MESHRIGHT_ADMIN)) { msgs.push("Can't set device group administrator, if not administrator"); continue; }
2775
if (((selfMeshRights & 2) == 0) && ((command.meshadmin & 2) != 0) && ((targetMeshRights & 2) == 0)) { command.meshadmin -= 2; }
2776
2777
// Add mesh to user or user group
@@ -3008,7 +3012,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3012
// Remove mesh from user
3013
if (deluser.links != null && deluser.links[command.meshid] != null) {
3014
var delmeshrights = deluser.links[command.meshid].rights;
3011
- if ((delmeshrights == 0xFFFFFFFF) && (parent.GetMeshRights(user, mesh) != 0xFFFFFFFF)) return; // A non-admin can't kick out an admin
3015
+ if ((delmeshrights == MESHRIGHT_ADMIN) && (parent.GetMeshRights(user, mesh) != MESHRIGHT_ADMIN)) return; // A non-admin can't kick out an admin
3016
delete deluser.links[command.meshid];
3017
if (deluserid.startsWith('user/')) { db.SetUser(deluser); }
3018
else if (deluserid.startsWith('ugrp/')) { db.Set(deluser); }
@@ -3523,7 +3527,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3527
3528
// Get the node and the rights for this node
3529
parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
3526
- if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != 0xFFFFFFFF))) return;
3530
+ if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != SITERIGHT_ADMIN))) return;
3531
3532
if (command.type == 'default') {
3533
// Send the default core to the agent
@@ -3555,7 +3559,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3559
3560
// Get the node and the rights for this node
3561
parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
3558
- if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != 0xFFFFFFFF))) return;
3562
+ if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != SITERIGHT_ADMIN))) return;
3563
3564
// Force mesh agent disconnection
3565
parent.forceMeshAgentDisconnect(user, domain, node._id, command.disconnectMode);
@@ -4188,7 +4192,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4192
break;
4193
}
4194
case 'traceinfo': {
4191
- if ((user.siteadmin == 0xFFFFFFFF) && (typeof command.traceSources == 'object')) {
4195
+ if ((user.siteadmin === SITERIGHT_ADMIN) && (typeof command.traceSources == 'object')) {
4196
parent.parent.debugRemoteSources = command.traceSources;
4197
parent.parent.DispatchEvent(['*'], obj, { action: 'traceinfo', userid: user._id, username: user.name, traceSources: command.traceSources, nolog: 1, domain: domain.id });
4198
}
@@ -4228,7 +4232,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4232
// Get the node and the rights for this node
4233
parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
4234
// Check if this user has rights to do this
4231
- if (rights == 0xFFFFFFFF) {
4235
+ if (rights == MESHRIGHT_ADMIN) {
4236
var token = parent.parent.mqttbroker.generateLogin(node.meshid, node._id);
4237
var r = { action: 'getmqttlogin', responseid: command.responseid, nodeid: node._id, user: token.user, pass: token.pass };
4238
const serverName = parent.getWebServerName(domain);
@@ -4278,7 +4282,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4282
}
4283
case 'distributeCore': {
4284
// This is only available when plugins are enabled since it could cause stress on the server
4281
- if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4285
+ if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4286
for (var i in command.nodes) {
4287
parent.sendMeshAgentCore(user, domain, command.nodes[i]._id, 'default');
4288
}
@@ -4286,14 +4290,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4290
}
4291
case 'plugins': {
4292
// Since plugin actions generally require a server restart, use the Full admin permission
4289
- if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4293
+ if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4294
parent.db.getPlugins(function(err, docs) {
4295
try { ws.send(JSON.stringify({ action: 'updatePluginList', list: docs, result: err })); } catch (ex) { }
4296
});
4297
break;
4298
}
4299
case 'pluginLatestCheck': {
4296
- if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4300
+ if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4301
parent.parent.pluginHandler.getPluginLatest()
4302
.then(function(latest) {
4303
try { ws.send(JSON.stringify({ action: 'pluginVersionsAvailable', list: latest })); } catch (ex) { }
@@ -4301,7 +4305,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4305
break;
4306
}
4307
case 'addplugin': {
4304
- if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4308
+ if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4309
try {
4310
parent.parent.pluginHandler.getPluginConfig(command.url)
4311
.then(parent.parent.pluginHandler.addPlugin)
@@ -4318,7 +4322,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4322
break;
4323
}
4324
case 'installplugin': {
4321
- if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4325
+ if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4326
parent.parent.pluginHandler.installPlugin(command.id, command.version_only, null, function(){
4327
parent.db.getPlugins(function(err, docs) {
4328
try { ws.send(JSON.stringify({ action: 'updatePluginList', list: docs, result: err })); } catch (ex) { }
@@ -4329,7 +4333,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4333
break;
4334
}
4335
case 'disableplugin': {
4332
- if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4336
+ if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4337
parent.parent.pluginHandler.disablePlugin(command.id, function(){
4338
parent.db.getPlugins(function(err, docs) {
4339
try { ws.send(JSON.stringify({ action: 'updatePluginList', list: docs, result: err })); } catch (ex) { }
@@ -4340,7 +4344,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4344
break;
4345
}
4346
case 'removeplugin': {
4343
- if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4347
+ if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4348
parent.parent.pluginHandler.removePlugin(command.id, function(){
4349
parent.db.getPlugins(function(err, docs) {
4350
try { ws.send(JSON.stringify({ action: 'updatePluginList', list: docs, result: err })); } catch (ex) { }
@@ -4349,7 +4353,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4353
break;
4354
}
4355
case 'getpluginversions': {
4352
- if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4356
+ if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled
4357
parent.parent.pluginHandler.getPluginVersions(command.id)
4358
.then(function (versionInfo) {
4359
try { ws.send(JSON.stringify({ action: 'downgradePluginVersions', info: versionInfo, error: null })); } catch (ex) { }
pluginHandler.js
+8
-3
@@ -27,6 +27,7 @@ module.exports.pluginHandler = function (parent) {
27
28
obj.fs = require('fs');
29
obj.path = require('path');
30
+ obj.common = require('./common.js');
31
obj.parent = parent;
32
obj.pluginPath = obj.parent.path.join(obj.parent.datapath, 'plugins');
33
obj.plugins = {};
@@ -471,7 +472,7 @@ module.exports.pluginHandler = function (parent) {
472
versStr += chunk;
473
});
474
res.on('end', function () {
474
- if (versStr[0] == '{' || versStr[0] == '[') { // let's be sure we're JSON
475
+ if ((versStr[0] == '{') || (versStr[0] == '[')) { // let's be sure we're JSON
476
try {
477
var vers = JSON.parse(versStr);
478
var vList = [];
@@ -515,9 +516,11 @@ module.exports.pluginHandler = function (parent) {
516
};
517
518
obj.handleAdminReq = function (req, res, user, serv) {
519
+ if (obj.common.isAlphaNumeric(req.query.pin) !== true) { res.sendStatus(401); return; }
520
var path = obj.path.join(obj.pluginPath, req.query.pin, 'views');
521
+ if (obj.common.IsFilenameValid(path) !== true) { res.sendStatus(401); return; }
522
serv.app.set('views', path);
520
- if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminReq == 'function') {
523
+ if ((obj.plugins[req.query.pin] != null) && (typeof obj.plugins[req.query.pin].handleAdminReq == 'function')) {
524
obj.plugins[req.query.pin].handleAdminReq(req, res, user);
525
} else {
526
res.sendStatus(401);
@@ -525,9 +528,11 @@ module.exports.pluginHandler = function (parent) {
528
}
529
530
obj.handleAdminPostReq = function (req, res, user, serv) {
531
+ if (obj.common.isAlphaNumeric(req.query.pin) !== true) { res.sendStatus(401); return; }
532
var path = obj.path.join(obj.pluginPath, req.query.pin, 'views');
533
+ if (obj.common.IsFilenameValid(path) !== true) { res.sendStatus(401); return; }
534
serv.app.set('views', path);
530
- if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminPostReq == 'function') {
535
+ if ((obj.plugins[req.query.pin] != null) && (typeof obj.plugins[req.query.pin].handleAdminPostReq == 'function')) {
536
obj.plugins[req.query.pin].handleAdminPostReq(req, res, user);
537
} else {
538
res.sendStatus(401);
views/default-mobile.handlebars
+6
-6
@@ -1751,7 +1751,7 @@
1751
var publiclink = '';
1752
if (publicfolder) { publiclink = ' (<a style=cursor:pointer onclick=\'p5showPublicLink("' + publicPath + '/' + f.nx + '")\'>' + "Link" + '</a>)'; }
1753
if (f.s > 0) { link = '<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"downloadfile.ashx?link=' + encodeURIComponent(filetreelinkpath + '/' + f.nx) + '\">' + shortname + '</a>' + publiclink; }
1754
- h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'> <span style=float:right;padding-right:4px>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
1754
+ h = '<div class=filelist file=3><input file=3 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value=\'' + f.nx + '\'> <span style=float:right;padding-right:4px>' + EscapeHtml(fsize) + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
1755
}
1756
1757
if (f.t < 3) { html1 += h; } else { html2 += h; }
@@ -2378,14 +2378,14 @@
2378
if (node.intelamt != null) {
2379
var str = '';
2380
var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") };
2381
- if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + nobreak("Unknown State") + '</i>, v' + node.intelamt.ver; } else
2381
+ if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + nobreak("Unknown State") + '</i>, v' + EscapeHtml(node.intelamt.ver); } else
2382
2383
if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>' + "Activated" + '</i>'; }
2384
else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '<i>' + "Unknown Version & State" + '</i>'; }
2385
else {
2386
str += provisioningStates[node.intelamt.state];
2387
if (node.intelamt.flags) { if (node.intelamt.flags & 2) { str = ' <span>' + "CCM" + '</span>'; } else if (node.intelamt.flags & 4) { str = ' <span>' + "ACM" + '</span>'; } }
2388
- str += (', v' + node.intelamt.ver);
2388
+ str += (', v' + EscapeHtml(node.intelamt.ver));
2389
}
2390
2391
if (node.intelamt.tls == 1) { str += ', <span>' + "TLS" + '</span>'; }
@@ -3669,7 +3669,7 @@
3669
if (m[0].gatewaymac) {
3670
x += addDetailItem("MAC Layer", format("MAC: {0}, Gateway: {1}", EscapeHtml(m[0].mac), EscapeHtml(m[0].gatewaymac)));
3671
} else {
3672
- x += addDetailItem("MAC Layer", format("MAC: {0}", m[0].mac));
3672
+ x += addDetailItem("MAC Layer", format("MAC: {0}", EscapeHtml(m[0].mac)));
3673
}
3674
}
3675
for (var j = 0; j < m.length; j++) {
@@ -3698,7 +3698,7 @@
3698
// Attribute: Intel AMT
3699
if (node.intelamt != null) {
3700
var x = '';
3701
- x += addDetailItem("Version", (node.intelamt.ver) ? ('v' + node.intelamt.ver) : ('<i>' + "Unknown" + '</i>'), s);
3701
+ x += addDetailItem("Version", (node.intelamt.ver) ? ('v' + EscapeHtml(node.intelamt.ver)) : ('<i>' + "Unknown" + '</i>'), s);
3702
var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") };
3703
var provisioningMode = '';
3704
if ((node.intelamt.state == 2) && node.intelamt.flags) { if (node.intelamt.flags & 2) { provisioningMode = (', ' + "Client Control Mode (CCM)"); } else if (node.intelamt.flags & 4) { provisioningMode = (', ' + "Admin Control Mode (ACM)"); } }
@@ -4220,7 +4220,7 @@
4220
function addLink(x, f) { return '<a style=cursor:pointer;color:darkblue;text-decoration:none onclick=\'' + f + '\'>♦ ' + x + '</a>'; }
4221
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
4222
function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); }
4223
- function getFileSizeStr(size) { if (size == 1) return "1 byte"; return format('{0} bytes', size); }
4223
+ function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format('{0} bytes', size); }
4224
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('/'); }
4225
function focusTextBox(x) { setTimeout(function () { Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
4226
var isFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
views/default.handlebars
+18
-18
@@ -5316,14 +5316,14 @@
5316
if (node.intelamt != null) {
5317
var str = '';
5318
var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") };
5319
- if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + "Unknown State" + '</i>, v' + node.intelamt.ver; } else
5319
+ if (node.intelamt.ver != null && node.intelamt.state == null) { str += '<i>' + "Unknown State" + '</i>, v' + EscapeHtml(node.intelamt.ver); } else
5320
5321
if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '<i>' + "Activated" + '</i>'; }
5322
else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '<i>' + "Unknown Version & State" + '</i>'; }
5323
else {
5324
str += provisioningStates[node.intelamt.state];
5325
if ((node.intelamt.state == 2) && node.intelamt.flags) { if (node.intelamt.flags & 2) { str += ' <span title="' + "Intel AMT is activated in Client Control Mode" + '">' + "CCM" + '</span>'; } else if (node.intelamt.flags & 4) { str += ' <span title="' + "Intel AMT is activated in Admin Control Mode" + '">' + "ACM" + '</span>'; } }
5326
- str += (', v' + node.intelamt.ver);
5326
+ str += (', v' + EscapeHtml(node.intelamt.ver));
5327
}
5328
5329
if (node.intelamt.tls == 1) { str += ', <span title="' + "Intel AMT is setup with TLS network security" + '">' + "TLS" + '</span>'; }
@@ -6959,8 +6959,8 @@
6959
for (var i in p) {
6960
if (p[i].p != 0) {
6961
var c = p[i].c;
6962
- if (c.length > 30) { c = '<span title="' + c + '">' + c.substring(0,30) + '...</span>' }
6963
- x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a href=# style=float:right;padding-right:5px;cursor:pointer title="' + "Stop process" + '" onclick=\'return stopProcess(' + p[i].p + ',"' + p[i].c + '")\'><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u ? p[i].u : '') + '</div><div>' + c + '</div></div>';
6962
+ if (c.length > 30) { c = '<span title="' + EscapeHtml(c) + '">' + EscapeHTML(c.substring(0,30)) + '...</span>' } else { c = EscapeHtml(c); }
6963
+ x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + EscapeHtml(p[i].p) + '</div><a href=# style=float:right;padding-right:5px;cursor:pointer title="' + "Stop process" + '" onclick=\'return stopProcess(' + EscapeHtml(p[i].p) + ',"' + EscapeHtml(p[i].c) + '")\'><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u ? EscapeHtml(p[i].u) : '') + '</div><div>' + c + '</div></div>';
6964
}
6965
}
6966
QH('DeskToolsProcesses', x);
@@ -6989,8 +6989,8 @@
6989
for (var i in s) {
6990
if (s[i].p != 0) {
6991
var c = s[i].d;
6992
- if (c.length > 30) { c = '<span title="' + c + '">' + c.substring(0, 30) + '...</span>' }
6993
- x += '<div onclick=showServiceDetailsDialog(' + s[i].i + ') class=deskToolsBar><div style=width:70px;float:left;padding-right:5px>' + s[i].p + '</div><div>' + c + '</div></div>';
6992
+ if (c.length > 30) { c = '<span title="' + c + '">' + c.substring(0, 30) + '...</span>' } else { c = EscapeHtml(c); }
6993
+ x += '<div onclick=showServiceDetailsDialog(' + s[i].i + ') class=deskToolsBar><div style=width:70px;float:left;padding-right:5px>' + EscapeHtml(s[i].p) + '</div><div>' + c + '</div></div>';
6994
}
6995
}
6996
QH('DeskToolsServices', x);
@@ -7555,7 +7555,7 @@
7555
} else {
7556
var link = shortname;
7557
if (f.s > 0) { link = '<a href=# style=cursor:pointer onclick="return p13downloadfile(\'' + encodeURIComponentEx(newlinkpath + '/' + name) + '\',\'' + encodeURIComponentEx(name) + '\',' + f.s + ')">' + shortname + '</a>'; }
7558
- h = '<div id=fileEntry cmenu=filesContextMenu fileIndex=' + i + ' class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
7558
+ h = '<div id=fileEntry cmenu=filesContextMenu fileIndex=' + i + ' class=filelist file=3><input file=3 style=float:left name=fd class=fcb type=checkbox onchange=p13setActions() value=\'' + f.nx + '\'> <span class=fsize>' + fdatestr + '</span><span style=float:right>' + EscapeHTML(fsize) + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
7559
}
7560
7561
if (f.t < 3) { html1 += h; } else { html2 += h; }
@@ -8145,7 +8145,7 @@
8145
if (m.gatewaymac) {
8146
x += addDetailItem("MAC Layer", format("MAC: {0}, Gateway: {1}", EscapeHtml(m.mac), EscapeHtml(m.gatewaymac)));
8147
} else {
8148
- x += addDetailItem("MAC Layer", format("MAC: {0}", m.mac));
8148
+ x += addDetailItem("MAC Layer", format("MAC: {0}", EscapeHtml(m.mac)));
8149
}
8150
}
8151
for (var j in m.ipv4layer) {
@@ -8178,7 +8178,7 @@
8178
if (m[0].gatewaymac) {
8179
x += addDetailItem("MAC Layer", format("MAC: {0}, Gateway: {1}", EscapeHtml(m[0].mac), EscapeHtml(m[0].gatewaymac)));
8180
} else {
8181
- x += addDetailItem("MAC Layer", format("MAC: {0}", m[0].mac));
8181
+ x += addDetailItem("MAC Layer", format("MAC: {0}", EscapeHtml(m[0].mac)));
8182
}
8183
}
8184
for (var j = 0; j < m.length; j++) {
@@ -8207,7 +8207,7 @@
8207
// Attribute: Intel AMT
8208
if (node.intelamt != null) {
8209
var x = '';
8210
- x += addDetailItem("Version", (node.intelamt.ver)?('v' + node.intelamt.ver):('<i>' + "Unknown" + '</i>'), s);
8210
+ x += addDetailItem("Version", (node.intelamt.ver)?('v' + EscapeHtml(node.intelamt.ver)):('<i>' + "Unknown" + '</i>'), s);
8211
var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") };
8212
var provisioningMode = '';
8213
if ((node.intelamt.state == 2) && node.intelamt.flags) { if (node.intelamt.flags & 2) { provisioningMode = (', ' + "Client Control Mode (CCM)"); } else if (node.intelamt.flags & 4) { provisioningMode = (', ' + "Admin Control Mode (ACM)"); } }
@@ -10069,7 +10069,7 @@
10069
function getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); return checkboxes.length; }
10070
function p5selectallfile() { var nv = (getFileSelCount() == 0), checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p5setActions(); }
10071
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; }
10072
- function getFileSizeStr(size) { if (size == 1) return "1 byte"; return format("{0} bytes", size); }
10072
+ function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format("{0} bytes", size); }
10073
function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); return false; }
10074
function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); return false; }
10075
function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% />'); focusTextBox('p5renameinput'); p5fileNameCheck(); }
@@ -11938,7 +11938,7 @@
11938
} else {
11939
var link = shortname;
11940
//if (f.s > 0) { link = "<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"downloadfile.ashx?link=" + encodeURIComponentEx(filetreelinkpath + '/' + f.nx) + "\">" + shortname + "</a>"; }
11941
- h = '<div class=filelist file=3><input style=float:left name=fcx class=fcb type=checkbox onchange=d3setActions() value="' + f.nx + '"> <span style=float:right>' + fsize + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
11941
+ h = '<div class=filelist file=3><input style=float:left name=fcx class=fcb type=checkbox onchange=d3setActions() value="' + f.nx + '"> <span style=float:right>' + EscapeHtml(fsize) + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
11942
}
11943
11944
if (f.t < 3) { html1 += h; } else { html2 += h; }
@@ -11991,18 +11991,18 @@
11991
} else {
11992
for (var i in notifications) {
11993
var n = notifications[i], t = '', d = new Date(n.time), icon = 0;
11994
- if (n.title != null) { t = '<b>' + n.title + '</b>: ' }
11994
+ if (n.title != null) { t = '<b>' + EscapeHtml(n.title) + '</b>: ' }
11995
if (n.nodeid != null) {
11996
var node = getNodeFromId(n.nodeid);
11997
if (node != null) {
11998
icon = node.icon;
11999
- if (notifySettings & 16) { t = '<b>' + meshes[node.meshid].name + ' / ' + node.name + '</b>: '; } else { t = '<b>' + node.name + '</b>: '; } // Display with or without group name
11999
+ if (notifySettings & 16) { t = '<b>' + EscapeHtml(meshes[node.meshid].name) + ' / ' + EscapeHtml(node.name) + '</b>: '; } else { t = '<b>' + EscapeHtml(node.name) + '</b>: '; } // Display with or without group name
12000
}
12001
}
12002
12003
r += '<div title="' + format("Occured at {0}", printDateTime(d)) + '" id="notifyx' + n.id + '" class=notification style="cursor:pointer;border-top:1px solid ' + ((r == '') ? 'transparent' : 'orange') + '">';
12004
if (icon) { r += '<div class=j' + icon + ' onclick="notificationSelected(' + n.id + ')" style=margin:5px;float:left></div>'; }
12005
- r += '<div onclick="notificationDelete(' + n.id + ')" class=unselectable title="' + "Clear this notification" + '" style=margin:5px;float:right;color:orange><b>X</b></div><div onclick="notificationSelected(' + n.id + ')" style=margin:5px>' + t + n.text + '</div></div>';
12005
+ r += '<div onclick="notificationDelete(' + n.id + ')" class=unselectable title="' + "Clear this notification" + '" style=margin:5px;float:right;color:orange><b>X</b></div><div onclick="notificationSelected(' + n.id + ')" style=margin:5px>' + t + EscapeHtml(n.text) + '</div></div>';
12006
}
12007
}
12008
var deleteall = '';
@@ -12656,9 +12656,9 @@
12656
installedPluginList.forEach(function(p){
12657
var cant_action = [];
12658
if (p.hasAdminPanel == true && p.status) {
12659
- p.nameHtml = '<a onclick="return goPlugin(\'' + p.shortName + '\', \'' + p.name.replace(/'/g, "\\'") + '\');">' + p.name + '</a>';
12659
+ p.nameHtml = '<a onclick="return goPlugin(\'' + p.shortName + '\', \'' + p.name.replace(/'/g, "\\'") + '\');">' + EscapeHtml(p.name) + '</a>';
12660
} else {
12661
- p.nameHtml = p.name;
12661
+ p.nameHtml = EscapeHtml(p.name);
12662
}
12663
p.statusText = statusMap[p.status].text;
12664
p.statusColor = statusMap[p.status].color;
@@ -12691,7 +12691,7 @@
12691
}
12692
p.actions += '</select>';
12693
12694
- var tpl = '<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1> </td><td class=gradTable2>' + p.nameHtml + '</td><td class=gradTable2>' + p.description + '</td><td class=gradTable2 style=text-align:center><a href="' + p.homepage + '" target="_blank">Home</a></td><td class=gradTable2 style=text-align:center>' + p.version + '</td><td style=text-align:center class="pluginUpgradeAvailable gradTable2">' + p.upgradeAvail + '</td><td class=gradTable2 style="text-align:center;color:#' + p.statusColor + '">' + p.statusText + '</td><td class="pluginAction gradTable2" style=text-align:center>' + p.actions + '</td><td class=gradTable3> </td>';
12694
+ var tpl = '<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1> </td><td class=gradTable2>' + p.nameHtml + '</td><td class=gradTable2>' + EscapeHtml(p.description) + '</td><td class=gradTable2 style=text-align:center><a href="' + EscapeHtml(p.homepage) + '" target="_blank">Home</a></td><td class=gradTable2 style=text-align:center>' + EscapeHtml(p.version) + '</td><td style=text-align:center class="pluginUpgradeAvailable gradTable2">' + p.upgradeAvail + '</td><td class=gradTable2 style="text-align:center;color:#' + p.statusColor + '">' + p.statusText + '</td><td class="pluginAction gradTable2" style=text-align:center>' + p.actions + '</td><td class=gradTable3> </td>';
12695
var tr = tbl.insertRow(-1);
12696
tr.innerHTML = tpl;
12697
tr.classList.add('p42tblRow');
views/mstsc.handlebars
+1
-1
@@ -74,7 +74,7 @@
74
if (name != '') { document.title = name + ' - ' + document.title; }
75
76
function load() {
77
- if (name != '') { QH('computerName', name); }
77
+ if (name != '') { QH('computerName', EscapeHtml(name)); }
78
client = MstscClient.create(Q('myCanvas'));
79
Q('inputDomain').focus();
80
canvas = Q('myCanvas');
webserver.js
+23
-21
@@ -1513,28 +1513,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1513
var idsplit = cookie.u.split('/');
1514
if ((idsplit.length != 2) || (idsplit[0] != domain.id)) {
1515
parent.debug('web', 'handleCheckMailRequest: Invalid domain.');
1516
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 1, domainurl: encodeURIComponent(domain.url) }, req, domain));
1516
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 1, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain));
1517
} else {
1518
obj.db.Get('user/' + cookie.u.toLowerCase(), function (err, docs) {
1519
if (docs.length == 0) {
1520
parent.debug('web', 'handleCheckMailRequest: Invalid username.');
1521
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 2, domainurl: encodeURIComponent(domain.url), arg1: encodeURIComponent(idsplit[1]) }, req, domain));
1521
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 2, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(idsplit[1]).replace(/'/g, '%27') }, req, domain));
1522
} else {
1523
var user = docs[0];
1524
if (user.email != cookie.e) {
1525
parent.debug('web', 'handleCheckMailRequest: Invalid e-mail.');
1526
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 3, domainurl: encodeURIComponent(domain.url), arg1: encodeURIComponent(user.email), arg2: encodeURIComponent(user.name) }, req, domain));
1526
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 3, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain));
1527
} else {
1528
if (cookie.a == 1) {
1529
// Account email verification
1530
if (user.emailVerified == true) {
1531
parent.debug('web', 'handleCheckMailRequest: email already verified.');
1532
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 4, domainurl: encodeURIComponent(domain.url), arg1: encodeURIComponent(user.email), arg2: encodeURIComponent(user.name) }, req, domain));
1532
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 4, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain));
1533
} else {
1534
obj.db.GetUserWithVerifiedEmail(domain.id, user.email, function (err, docs) {
1535
if (docs.length > 0) {
1536
parent.debug('web', 'handleCheckMailRequest: email already in use.');
1537
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 5, domainurl: encodeURIComponent(domain.url), arg1: encodeURIComponent(user.email) }, req, domain));
1537
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 5, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27') }, req, domain));
1538
} else {
1539
parent.debug('web', 'handleCheckMailRequest: email verification success.');
1540
@@ -1549,7 +1549,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1549
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
1550
1551
// Send the confirmation page
1552
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 6, domainurl: encodeURIComponent(domain.url), arg1: encodeURIComponent(user.email), arg2: encodeURIComponent(user.name) }, req, domain));
1552
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 6, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: encodeURIComponent(user.email).replace(/'/g, '%27'), arg2: encodeURIComponent(user.name).replace(/'/g, '%27') }, req, domain));
1553
1554
// Send a notification
1555
obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(user.email) + '</b>.', nolog: 1, id: Math.random() });
@@ -1563,7 +1563,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1563
// Account reset
1564
if (user.emailVerified != true) {
1565
parent.debug('web', 'handleCheckMailRequest: email not verified.');
1566
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 7, domainurl: encodeURIComponent(domain.url), arg1: EscapeHtml(user.email), arg2: EscapeHtml(user.name) }, req, domain));
1566
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 7, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.email), arg2: EscapeHtml(user.name) }, req, domain));
1567
} else {
1568
// Set a temporary password
1569
obj.crypto.randomBytes(16, function (err, buf) {
@@ -1588,7 +1588,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1588
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
1589
1590
// Send the new password
1591
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 8, domainurl: encodeURIComponent(domain.url), arg1: EscapeHtml(user.name), arg2: EscapeHtml(newpass) }, req, domain));
1591
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 8, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27'), arg1: EscapeHtml(user.name), arg2: EscapeHtml(newpass) }, req, domain));
1592
parent.debug('web', 'handleCheckMailRequest: send temporary password.');
1593
1594
// Send to authlog
@@ -1597,14 +1597,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1597
});
1598
}
1599
} else {
1600
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 9, domainurl: encodeURIComponent(domain.url) }, req, domain));
1600
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 9, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain));
1601
}
1602
}
1603
}
1604
});
1605
}
1606
} else {
1607
- render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 10, domainurl: encodeURIComponent(domain.url) }, req, domain));
1607
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 10, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain));
1608
}
1609
}
1610
}
@@ -1637,7 +1637,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1637
if (req.query.ws != null) {
1638
// This is a query with a websocket relay cookie, check that the cookie is valid and use it.
1639
var rcookie = parent.decodeCookie(req.query.ws, parent.loginCookieEncryptionKey, 240); // Cookie with 4 hour timeout
1640
- if ((rcookie != null) && (rcookie.domainid == domain.id) && (rcookie.nodeid != null) && (rcookie.tcpport != null)) { render(req, res, getRenderPage('mstsc', req, domain), getRenderArgs({ cookie: req.query.ws, name: encodeURIComponent(req.query.name) }, req, domain)); return; }
1640
+ if ((rcookie != null) && (rcookie.domainid == domain.id) && (rcookie.nodeid != null) && (rcookie.tcpport != null)) {
1641
+ render(req, res, getRenderPage('mstsc', req, domain), getRenderArgs({ cookie: req.query.ws, name: encodeURIComponent(req.query.name).replace(/'/g, '%27') }, req, domain)); return;
1642
+ }
1643
}
1644
1645
// Get the logged in user if present
@@ -1688,7 +1690,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1690
1691
// Generate a cookie and respond
1692
var cookie = parent.encodeCookie({ userid: user._id, domainid: user.domain, nodeid: node._id, tcpport: port }, parent.loginCookieEncryptionKey);
1691
- render(req, res, getRenderPage('mstsc', req, domain), getRenderArgs({ cookie: cookie, name: encodeURIComponent(node.name) }, req, domain));
1693
+ render(req, res, getRenderPage('mstsc', req, domain), getRenderArgs({ cookie: cookie, name: encodeURIComponent(node.name).replace(/'/g, '%27') }, req, domain));
1694
});
1695
}
1696
@@ -2260,7 +2262,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2262
if (domain.customui != null) { customui = encodeURIComponent(JSON.stringify(domain.customui)); }
2263
2264
// Refresh the session
2263
- render(req, res, getRenderPage('default', req, domain), getRenderArgs({ authCookie: authCookie, authRelayCookie: authRelayCookie, viewmode: viewmode, currentNode: currentNode, logoutControls: encodeURIComponent(JSON.stringify(logoutcontrols)).replace(/'/g, '%27'), domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, customui: customui, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate), amtscanoptions: amtscanoptions, pluginHandler: (parent.pluginHandler == null) ? 'null' : parent.pluginHandler.prepExports() }, req, domain));
2265
+ render(req, res, getRenderPage('default', req, domain), getRenderArgs({ authCookie: authCookie, authRelayCookie: authRelayCookie, viewmode: viewmode, currentNode: currentNode, logoutControls: encodeURIComponent(JSON.stringify(logoutcontrols)).replace(/'/g, '%27'), domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, customui: customui, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate).replace(/'/g, '%27'), amtscanoptions: amtscanoptions, pluginHandler: (parent.pluginHandler == null) ? 'null' : parent.pluginHandler.prepExports() }, req, domain));
2266
});
2267
} else {
2268
// Send back the login application
@@ -2354,7 +2356,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2356
if (domain.customui != null) { customui = encodeURIComponent(JSON.stringify(domain.customui)); }
2357
2358
// Render the login page
2357
- render(req, res, getRenderPage('login', req, domain), getRenderArgs({ loginmode: loginmode, rootCertLink: getRootCertLink(), newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, customui: customui, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail, otpsms: otpsms, twoFactorCookieDays: twoFactorCookieDays, authStrategies: authStrategies.join(',') }, req, domain));
2359
+ render(req, res, getRenderPage('login', req, domain), getRenderArgs({ loginmode: loginmode, rootCertLink: getRootCertLink(), newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, customui: customui, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge).replace(/'/g, '%27'), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail, otpsms: otpsms, twoFactorCookieDays: twoFactorCookieDays, authStrategies: authStrategies.join(',') }, req, domain));
2360
}
2361
2362
// Handle a post request on the root
@@ -2500,7 +2502,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2502
parent.debug('web', 'handleMessengerRequest()');
2503
2504
var webRtcConfig = null;
2503
- if (obj.parent.config.settings && obj.parent.config.settings.webrtconfig && (typeof obj.parent.config.settings.webrtconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtconfig)); }
2505
+ if (obj.parent.config.settings && obj.parent.config.settings.webrtconfig && (typeof obj.parent.config.settings.webrtconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtconfig)).replace(/'/g, '%27'); }
2506
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
2507
render(req, res, getRenderPage('messenger', req, domain), getRenderArgs({ webrtconfig: webRtcConfig }, req, domain));
2508
}
@@ -3852,8 +3854,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3854
if (xdomain != '') xdomain += '/';
3855
var meshsettings = 'MeshName=' + mesh.name + '\r\nMeshType=' + mesh.mtype + '\r\nMeshID=0x' + meshidhex + '\r\nServerID=' + serveridhex + '\r\n';
3856
if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else { meshsettings += 'MeshServer=local\r\n'; }
3855
- if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
3856
- if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; }
3857
+ if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
3858
+ if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; }
3859
if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; }
3860
if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } }
3861
if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + '\r\n'; } }
@@ -4033,8 +4035,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4035
if (obj.args.agentport != null) { httpsPort = obj.args.agentport; } // If an agent only port is enabled, use that.
4036
if (obj.args.agentaliasport != null) { httpsPort = obj.args.agentaliasport; } // If an agent alias port is specified, use that.
4037
if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else { meshsettings += 'MeshServer=local\r\n'; }
4036
- if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
4037
- if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; }
4038
+ if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
4039
+ if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; }
4040
if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; }
4041
if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } }
4042
if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + '\r\n'; } }
@@ -4130,8 +4132,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4132
if (obj.args.agentport != null) { httpsPort = obj.args.agentport; } // If an agent only port is enabled, use that.
4133
if (obj.args.agentaliasport != null) { httpsPort = obj.args.agentaliasport; } // If an agent alias port is specified, use that.
4134
if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else { meshsettings += 'MeshServer=local\r\n'; }
4133
- if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
4134
- if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; }
4135
+ if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
4136
+ if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; }
4137
if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; }
4138
if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } }
4139
if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + '\r\n'; } }