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 + '\'>&nbsp;<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 + '\'>&nbsp;<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 + '\'>&diams; ' + 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 + '\'>&nbsp;<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 + '\'>&nbsp;<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 + '">&nbsp;<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 + '">&nbsp;<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>&nbsp;</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>&nbsp;</td>';
12694 + var tpl = '<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1>&nbsp;</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>&nbsp;</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'; } }