diff --git a/meshuser.js b/meshuser.js index fa44000f..9d9a5908 100644 --- a/meshuser.js +++ b/meshuser.js @@ -49,6 +49,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use const MESHRIGHT_CHATNOTIFY = 16384; const MESHRIGHT_UNINSTALL = 32768; const MESHRIGHT_NODESKTOP = 65536; + const MESHRIGHT_ADMIN = 0xFFFFFFFF; // Site rights const SITERIGHT_SERVERBACKUP = 1; // 0x00000001 @@ -61,6 +62,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use const SITERIGHT_NOMESHCMD = 128; // 0x00000080 const SITERIGHT_USERGROUPS = 256; // 0x00000100 const SITERIGHT_RECORDINGS = 512; // 0x00000200 + const SITERIGHT_ADMIN = 0xFFFFFFFF; // 0xFFFFFFFF var obj = {}; obj.user = user; @@ -299,7 +301,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (id.startsWith('mesh/')) { // 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. var meshrights = parent.GetMeshRights(user, id); - if ((meshrights == 0xFFFFFFFF) || ((meshrights & MESHRIGHT_LIMITEVENTS) == 0) || (ids.indexOf(user._id) >= 0)) { + if ((meshrights === MESHRIGHT_ADMIN) || ((meshrights & MESHRIGHT_LIMITEVENTS) == 0) || (ids.indexOf(user._id) >= 0)) { // We have the device group rights to see this event or we are directly targetted by the event ws.send(JSON.stringify({ action: 'event', event: event })); } else { @@ -401,7 +403,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use if (args.notls == true) { serverinfo.https = false; } else { serverinfo.https = true; serverinfo.redirport = args.redirport; } if (typeof domain.userconsentflags == 'number') { serverinfo.consent = domain.userconsentflags; } if ((typeof domain.usersessionidletimeout == 'number') && (domain.usersessionidletimeout > 0)) { serverinfo.timeout = (domain.usersessionidletimeout * 60 * 1000); } - if (user.siteadmin == 0xFFFFFFFF) { + if (user.siteadmin === SITERIGHT_ADMIN) { if (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) { serverinfo.manageAllDeviceGroups = true; } if (obj.crossDomain === true) { serverinfo.crossDomain = []; for (var i in parent.parent.config.domains) { serverinfo.crossDomain.push(i); } } } @@ -412,7 +414,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Send user information to web socket, this is the first thing we send try { ws.send(JSON.stringify({ action: 'userinfo', userinfo: parent.CloneSafeUser(parent.users[user._id]) })); } catch (ex) { } - if (user.siteadmin == 0xFFFFFFFF) { + if (user.siteadmin === SITERIGHT_ADMIN) { // Send server tracing information try { ws.send(JSON.stringify({ action: 'traceinfo', traceSources: parent.parent.debugRemoteSources })); } catch (ex) { } @@ -765,7 +767,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use case 'serverconsole': { // This is a server console message, only process this if full administrator - if (user.siteadmin != 0xFFFFFFFF) break; + if (user.siteadmin != SITERIGHT_ADMIN) break; var r = ''; var cmdargs = splitArgs(command.value); @@ -1235,7 +1237,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var limit = 10000; if (common.validateInt(command.limit, 1, 60000) == true) { limit = command.limit; } - if (((rights & MESHRIGHT_LIMITEVENTS) != 0) && (rights != 0xFFFFFFFF)) { + if (((rights & MESHRIGHT_LIMITEVENTS) != 0) && (rights != MESHRIGHT_ADMIN)) { // Send the list of most recent events for this nodeid that only apply to us, up to 'limit' count db.GetNodeEventsSelfWithLimit(node._id, domain.id, user._id, limit, function (err, docs) { if (err != null) return; @@ -1260,7 +1262,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // TODO (UserGroups) // Remove MeshID's that we do not have rights to see events for - 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); } } + 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); } } for (var i in filter2) { if (exGroupFilter2.indexOf(filter2[i]) == -1) { filter.push(filter2[i]); } } if ((command.limit == null) || (typeof command.limit != 'number')) { @@ -1467,7 +1469,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use deluser = parent.users[deluserid]; if (deluser == null) { err = 'User does not exists'; } else if ((obj.crossDomain !== true) && ((delusersplit.length != 3) || (delusersplit[1] != domain.id))) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain - else if ((deluser.siteadmin == 0xFFFFFFFF) && (user.siteadmin != 0xFFFFFFFF)) { err = 'Permission denied'; } // Need full admin to remote another administrator + else if ((deluser.siteadmin === SITERIGHT_ADMIN) && (user.siteadmin != SITERIGHT_ADMIN)) { err = 'Permission denied'; } // Need full admin to remote another administrator 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. } } catch (ex) { err = 'Validation exception: ' + ex; } @@ -1702,7 +1704,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use newuserid = 'user/' + newuserdomain.id + '/' + command.username.toLowerCase(); if (command.siteadmin != null) { if ((typeof command.siteadmin != 'number') || (Number.isInteger(command.siteadmin) == false)) { err = 'Invalid site permissions'; } // Check permissions - else if ((user.siteadmin != 0xFFFFFFFF) && ((command.siteadmin & (0xFFFFFFFF - 224)) != 0)) { err = 'Invalid site permissions'; } + else if ((user.siteadmin != SITERIGHT_ADMIN) && ((command.siteadmin & (SITERIGHT_ADMIN - 224)) != 0)) { err = 'Invalid site permissions'; } } if (parent.users[newuserid]) { err = 'User already exists'; } // Account already exists 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 change = 0; if (chguser) { // If the target user is admin and we are not admin, no changes can be made. - if ((chguser.siteadmin == 0xFFFFFFFF) && (user.siteadmin != 0xFFFFFFFF)) return; + if ((chguser.siteadmin === SITERIGHT_ADMIN) && (user.siteadmin != SITERIGHT_ADMIN)) return; // Can only perform this operation on other users of our group. - if (user.siteadmin != 0xFFFFFFFF) { + if (user.siteadmin != SITERIGHT_ADMIN) { if ((user.groups != null) && (user.groups.length > 0) && ((chguser.groups == null) || (findOne(chguser.groups, user.groups) == false))) return; } @@ -1845,7 +1847,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Site admins can change any server rights, user managers can only change AccountLock, NoMeshCmd and NoNewGroups if (common.validateInt(command.siteadmin) && (chguser._id !== user._id) && (chguser.siteadmin != command.siteadmin)) { // We can't change our own siteadmin permissions. var chgusersiteadmin = chguser.siteadmin ? chguser.siteadmin : 0; - if (user.siteadmin == 0xFFFFFFFF) { chguser.siteadmin = command.siteadmin; change = 1; } + if (user.siteadmin === SITERIGHT_ADMIN) { chguser.siteadmin = command.siteadmin; change = 1; } else if (user.siteadmin & 2) { var mask = 0xFFFFFF1D; // Mask: 2 (User Mangement) + 32 (Account locked) + 64 (No New Groups) + 128 (No Tools) 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 // When sending a notification about a group change, we need to send to all the previous and new groups. var allTargetGroups = chguser.groups; - if ((Array.isArray(command.groups)) && ((user._id != command.id) || (user.siteadmin == 0xFFFFFFFF))) { + if ((Array.isArray(command.groups)) && ((user._id != command.id) || (user.siteadmin === SITERIGHT_ADMIN))) { if (command.groups.length == 0) { // Remove the user groups if (chguser.groups != null) { delete chguser.groups; change = 1; } @@ -1891,7 +1893,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use 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. parent.parent.DispatchEvent(targets, obj, event); } - if ((chguser.siteadmin) && (chguser.siteadmin != 0xFFFFFFFF) && (chguser.siteadmin & 32)) { + if ((chguser.siteadmin) && (chguser.siteadmin !== SITERIGHT_ADMIN) && (chguser.siteadmin & 32)) { // If the user is locked out of this account, disconnect now parent.parent.DispatchEvent([chguser._id], obj, 'close'); // Disconnect all this user's sessions } @@ -1934,9 +1936,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use else if (parent.userGroups[command.clone] == null) { err = "Invalid clone groupid"; } } - // Get new user group domain - ugrpdomain = parent.parent.config.domains[clonesplit[1]]; - if (ugrpdomain == null) { err = "Invalid domain"; } + if (err == null) { + // Get new user group domain + ugrpdomain = parent.parent.config.domains[clonesplit[1]]; + if (ugrpdomain == null) { err = "Invalid domain"; } + } } else { // Get new user group domain ugrpdomain = domain; @@ -1945,7 +1949,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } // In some situations, we need a verified email address to create a device group. - 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. + 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. } catch (ex) { err = "Validation exception: " + ex; } // Handle any errors @@ -2355,7 +2359,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var chguser = parent.users[command.userid]; if (chguser) { // If we are not full administrator, we can't change anything on a different full administrator - if ((user.siteadmin != 0xFFFFFFFF) & (chguser.siteadmin == 0xFFFFFFFF)) break; + if ((user.siteadmin != SITERIGHT_ADMIN) & (chguser.siteadmin === SITERIGHT_ADMIN)) break; // Can only perform this operation on other users of our group. 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 var err = null; try { // Check if we have new group restriction - if ((user.siteadmin != 0xFFFFFFFF) && ((user.siteadmin & 64) != 0)) { err = 'Permission denied'; } + if ((user.siteadmin != SITERIGHT_ADMIN) && ((user.siteadmin & 64) != 0)) { err = 'Permission denied'; } // In some situations, we need a verified email address to create a device group. - 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. + 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. // Create mesh 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 // Check if this user has rights to do this var err = null; - if (parent.GetMeshRights(user, mesh) != 0xFFFFFFFF) { err = 'Access denied'; } + if (parent.GetMeshRights(user, mesh) != MESHRIGHT_ADMIN) { err = 'Access denied'; } if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = 'Invalid group'; } // Invalid domain, operation only valid for current domain // Handle any errors @@ -2760,14 +2764,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use var targetMeshRights = 0; if ((newuser.links != null) && (newuser.links[command.meshid] != null) && (newuser.links[command.meshid].rights != null)) { targetMeshRights = newuser.links[command.meshid].rights; } - 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 + 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 if (command.remove === true) { // Remove mesh from user or user group delete newuser.links[command.meshid]; } else { // Adjust rights since we can't add more rights that we have outself for MESHRIGHT_MANAGEUSERS - if ((selfMeshRights != 0xFFFFFFFF) && (command.meshadmin == 0xFFFFFFFF)) { msgs.push("Can't set device group administrator, if not administrator"); continue; } + if ((selfMeshRights != MESHRIGHT_ADMIN) && (command.meshadmin == MESHRIGHT_ADMIN)) { msgs.push("Can't set device group administrator, if not administrator"); continue; } if (((selfMeshRights & 2) == 0) && ((command.meshadmin & 2) != 0) && ((targetMeshRights & 2) == 0)) { command.meshadmin -= 2; } // Add mesh to user or user group @@ -3008,7 +3012,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Remove mesh from user if (deluser.links != null && deluser.links[command.meshid] != null) { var delmeshrights = deluser.links[command.meshid].rights; - if ((delmeshrights == 0xFFFFFFFF) && (parent.GetMeshRights(user, mesh) != 0xFFFFFFFF)) return; // A non-admin can't kick out an admin + if ((delmeshrights == MESHRIGHT_ADMIN) && (parent.GetMeshRights(user, mesh) != MESHRIGHT_ADMIN)) return; // A non-admin can't kick out an admin delete deluser.links[command.meshid]; if (deluserid.startsWith('user/')) { db.SetUser(deluser); } else if (deluserid.startsWith('ugrp/')) { db.Set(deluser); } @@ -3523,7 +3527,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Get the node and the rights for this node parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { - if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != 0xFFFFFFFF))) return; + if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != SITERIGHT_ADMIN))) return; if (command.type == 'default') { // Send the default core to the agent @@ -3555,7 +3559,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Get the node and the rights for this node parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { - if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != 0xFFFFFFFF))) return; + if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != SITERIGHT_ADMIN))) return; // Force mesh agent disconnection parent.forceMeshAgentDisconnect(user, domain, node._id, command.disconnectMode); @@ -4188,7 +4192,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use break; } case 'traceinfo': { - if ((user.siteadmin == 0xFFFFFFFF) && (typeof command.traceSources == 'object')) { + if ((user.siteadmin === SITERIGHT_ADMIN) && (typeof command.traceSources == 'object')) { parent.parent.debugRemoteSources = command.traceSources; parent.parent.DispatchEvent(['*'], obj, { action: 'traceinfo', userid: user._id, username: user.name, traceSources: command.traceSources, nolog: 1, domain: domain.id }); } @@ -4228,7 +4232,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use // Get the node and the rights for this node parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) { // Check if this user has rights to do this - if (rights == 0xFFFFFFFF) { + if (rights == MESHRIGHT_ADMIN) { var token = parent.parent.mqttbroker.generateLogin(node.meshid, node._id); var r = { action: 'getmqttlogin', responseid: command.responseid, nodeid: node._id, user: token.user, pass: token.pass }; const serverName = parent.getWebServerName(domain); @@ -4278,7 +4282,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'distributeCore': { // This is only available when plugins are enabled since it could cause stress on the server - if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled + if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled for (var i in command.nodes) { parent.sendMeshAgentCore(user, domain, command.nodes[i]._id, 'default'); } @@ -4286,14 +4290,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } case 'plugins': { // Since plugin actions generally require a server restart, use the Full admin permission - if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled + if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled parent.db.getPlugins(function(err, docs) { try { ws.send(JSON.stringify({ action: 'updatePluginList', list: docs, result: err })); } catch (ex) { } }); break; } case 'pluginLatestCheck': { - if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled + if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled parent.parent.pluginHandler.getPluginLatest() .then(function(latest) { 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 break; } case 'addplugin': { - if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled + if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled try { parent.parent.pluginHandler.getPluginConfig(command.url) .then(parent.parent.pluginHandler.addPlugin) @@ -4318,7 +4322,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use break; } case 'installplugin': { - if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled + if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled parent.parent.pluginHandler.installPlugin(command.id, command.version_only, null, function(){ parent.db.getPlugins(function(err, docs) { 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 break; } case 'disableplugin': { - if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled + if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled parent.parent.pluginHandler.disablePlugin(command.id, function(){ parent.db.getPlugins(function(err, docs) { 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 break; } case 'removeplugin': { - if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled + if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled parent.parent.pluginHandler.removePlugin(command.id, function(){ parent.db.getPlugins(function(err, docs) { 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 break; } case 'getpluginversions': { - if ((user.siteadmin != 0xFFFFFFFF) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled + if ((user.siteadmin != SITERIGHT_ADMIN) || (parent.parent.pluginHandler == null)) break; // Must be full admin with plugins enabled parent.parent.pluginHandler.getPluginVersions(command.id) .then(function (versionInfo) { try { ws.send(JSON.stringify({ action: 'downgradePluginVersions', info: versionInfo, error: null })); } catch (ex) { } diff --git a/pluginHandler.js b/pluginHandler.js index 8f62e0c4..89245d15 100644 --- a/pluginHandler.js +++ b/pluginHandler.js @@ -27,6 +27,7 @@ module.exports.pluginHandler = function (parent) { obj.fs = require('fs'); obj.path = require('path'); + obj.common = require('./common.js'); obj.parent = parent; obj.pluginPath = obj.parent.path.join(obj.parent.datapath, 'plugins'); obj.plugins = {}; @@ -471,7 +472,7 @@ module.exports.pluginHandler = function (parent) { versStr += chunk; }); res.on('end', function () { - if (versStr[0] == '{' || versStr[0] == '[') { // let's be sure we're JSON + if ((versStr[0] == '{') || (versStr[0] == '[')) { // let's be sure we're JSON try { var vers = JSON.parse(versStr); var vList = []; @@ -515,9 +516,11 @@ module.exports.pluginHandler = function (parent) { }; obj.handleAdminReq = function (req, res, user, serv) { + if (obj.common.isAlphaNumeric(req.query.pin) !== true) { res.sendStatus(401); return; } var path = obj.path.join(obj.pluginPath, req.query.pin, 'views'); + if (obj.common.IsFilenameValid(path) !== true) { res.sendStatus(401); return; } serv.app.set('views', path); - if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminReq == 'function') { + if ((obj.plugins[req.query.pin] != null) && (typeof obj.plugins[req.query.pin].handleAdminReq == 'function')) { obj.plugins[req.query.pin].handleAdminReq(req, res, user); } else { res.sendStatus(401); @@ -525,9 +528,11 @@ module.exports.pluginHandler = function (parent) { } obj.handleAdminPostReq = function (req, res, user, serv) { + if (obj.common.isAlphaNumeric(req.query.pin) !== true) { res.sendStatus(401); return; } var path = obj.path.join(obj.pluginPath, req.query.pin, 'views'); + if (obj.common.IsFilenameValid(path) !== true) { res.sendStatus(401); return; } serv.app.set('views', path); - if (obj.plugins[req.query.pin] != null && typeof obj.plugins[req.query.pin].handleAdminPostReq == 'function') { + if ((obj.plugins[req.query.pin] != null) && (typeof obj.plugins[req.query.pin].handleAdminPostReq == 'function')) { obj.plugins[req.query.pin].handleAdminPostReq(req, res, user); } else { res.sendStatus(401); diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index ec8673bc..284ccde6 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -1751,7 +1751,7 @@ var publiclink = ''; if (publicfolder) { publiclink = ' (' + "Link" + ')'; } if (f.s > 0) { link = '' + shortname + '' + publiclink; } - h = '
 ' + fsize + '
' + link + '
'; + h = '
 ' + EscapeHtml(fsize) + '
' + link + '
'; } if (f.t < 3) { html1 += h; } else { html2 += h; } @@ -2378,14 +2378,14 @@ if (node.intelamt != null) { var str = ''; var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") }; - if (node.intelamt.ver != null && node.intelamt.state == null) { str += '' + nobreak("Unknown State") + ', v' + node.intelamt.ver; } else + if (node.intelamt.ver != null && node.intelamt.state == null) { str += '' + nobreak("Unknown State") + ', v' + EscapeHtml(node.intelamt.ver); } else if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '' + "Activated" + ''; } else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '' + "Unknown Version & State" + ''; } else { str += provisioningStates[node.intelamt.state]; if (node.intelamt.flags) { if (node.intelamt.flags & 2) { str = ' ' + "CCM" + ''; } else if (node.intelamt.flags & 4) { str = ' ' + "ACM" + ''; } } - str += (', v' + node.intelamt.ver); + str += (', v' + EscapeHtml(node.intelamt.ver)); } if (node.intelamt.tls == 1) { str += ', ' + "TLS" + ''; } @@ -3669,7 +3669,7 @@ if (m[0].gatewaymac) { x += addDetailItem("MAC Layer", format("MAC: {0}, Gateway: {1}", EscapeHtml(m[0].mac), EscapeHtml(m[0].gatewaymac))); } else { - x += addDetailItem("MAC Layer", format("MAC: {0}", m[0].mac)); + x += addDetailItem("MAC Layer", format("MAC: {0}", EscapeHtml(m[0].mac))); } } for (var j = 0; j < m.length; j++) { @@ -3698,7 +3698,7 @@ // Attribute: Intel AMT if (node.intelamt != null) { var x = ''; - x += addDetailItem("Version", (node.intelamt.ver) ? ('v' + node.intelamt.ver) : ('' + "Unknown" + ''), s); + x += addDetailItem("Version", (node.intelamt.ver) ? ('v' + EscapeHtml(node.intelamt.ver)) : ('' + "Unknown" + ''), s); var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") }; var provisioningMode = ''; 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 @@ function addLink(x, f) { return '♦ ' + x + ''; } function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; } function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); } - function getFileSizeStr(size) { if (size == 1) return "1 byte"; return format('{0} bytes', size); } + function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format('{0} bytes', size); } 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('/'); } function focusTextBox(x) { setTimeout(function () { Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); } 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] != '.'); } })(); diff --git a/views/default.handlebars b/views/default.handlebars index d063e85b..ce2cc9e9 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -5316,14 +5316,14 @@ if (node.intelamt != null) { var str = ''; var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") }; - if (node.intelamt.ver != null && node.intelamt.state == null) { str += '' + "Unknown State" + ', v' + node.intelamt.ver; } else + if (node.intelamt.ver != null && node.intelamt.state == null) { str += '' + "Unknown State" + ', v' + EscapeHtml(node.intelamt.ver); } else if ((node.intelamt.ver == null) && (node.intelamt.state == 2)) { str += '' + "Activated" + ''; } else if ((node.intelamt.ver == null) || (node.intelamt.state == null)) { str += '' + "Unknown Version & State" + ''; } else { str += provisioningStates[node.intelamt.state]; if ((node.intelamt.state == 2) && node.intelamt.flags) { if (node.intelamt.flags & 2) { str += ' ' + "CCM" + ''; } else if (node.intelamt.flags & 4) { str += ' ' + "ACM" + ''; } } - str += (', v' + node.intelamt.ver); + str += (', v' + EscapeHtml(node.intelamt.ver)); } if (node.intelamt.tls == 1) { str += ', ' + "TLS" + ''; } @@ -6959,8 +6959,8 @@ for (var i in p) { if (p[i].p != 0) { var c = p[i].c; - if (c.length > 30) { c = '' + c.substring(0,30) + '...' } - x += '
' + p[i].p + '
' + (p[i].u ? p[i].u : '') + '
' + c + '
'; + if (c.length > 30) { c = '' + EscapeHTML(c.substring(0,30)) + '...' } else { c = EscapeHtml(c); } + x += '
' + EscapeHtml(p[i].p) + '
' + (p[i].u ? EscapeHtml(p[i].u) : '') + '
' + c + '
'; } } QH('DeskToolsProcesses', x); @@ -6989,8 +6989,8 @@ for (var i in s) { if (s[i].p != 0) { var c = s[i].d; - if (c.length > 30) { c = '' + c.substring(0, 30) + '...' } - x += '
' + s[i].p + '
' + c + '
'; + if (c.length > 30) { c = '' + c.substring(0, 30) + '...' } else { c = EscapeHtml(c); } + x += '
' + EscapeHtml(s[i].p) + '
' + c + '
'; } } QH('DeskToolsServices', x); @@ -7555,7 +7555,7 @@ } else { var link = shortname; if (f.s > 0) { link = '' + shortname + ''; } - h = '
 ' + fdatestr + '' + fsize + '
' + link + '
'; + h = '
 ' + fdatestr + '' + EscapeHTML(fsize) + '
' + link + '
'; } if (f.t < 3) { html1 += h; } else { html2 += h; } @@ -8145,7 +8145,7 @@ if (m.gatewaymac) { x += addDetailItem("MAC Layer", format("MAC: {0}, Gateway: {1}", EscapeHtml(m.mac), EscapeHtml(m.gatewaymac))); } else { - x += addDetailItem("MAC Layer", format("MAC: {0}", m.mac)); + x += addDetailItem("MAC Layer", format("MAC: {0}", EscapeHtml(m.mac))); } } for (var j in m.ipv4layer) { @@ -8178,7 +8178,7 @@ if (m[0].gatewaymac) { x += addDetailItem("MAC Layer", format("MAC: {0}, Gateway: {1}", EscapeHtml(m[0].mac), EscapeHtml(m[0].gatewaymac))); } else { - x += addDetailItem("MAC Layer", format("MAC: {0}", m[0].mac)); + x += addDetailItem("MAC Layer", format("MAC: {0}", EscapeHtml(m[0].mac))); } } for (var j = 0; j < m.length; j++) { @@ -8207,7 +8207,7 @@ // Attribute: Intel AMT if (node.intelamt != null) { var x = ''; - x += addDetailItem("Version", (node.intelamt.ver)?('v' + node.intelamt.ver):('' + "Unknown" + ''), s); + x += addDetailItem("Version", (node.intelamt.ver)?('v' + EscapeHtml(node.intelamt.ver)):('' + "Unknown" + ''), s); var provisioningStates = { 0: nobreak("Not Activated (Pre)"), 1: nobreak("Not Activated (In)"), 2: nobreak("Activated") }; var provisioningMode = ''; 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 @@ function getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fc'); return checkboxes.length; } function p5selectallfile() { var nv = (getFileSelCount() == 0), checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p5setActions(); } 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; } - function getFileSizeStr(size) { if (size == 1) return "1 byte"; return format("{0} bytes", size); } + function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format("{0} bytes", size); } function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); return false; } function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); return false; } function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, ''); focusTextBox('p5renameinput'); p5fileNameCheck(); } @@ -11938,7 +11938,7 @@ } else { var link = shortname; //if (f.s > 0) { link = "" + shortname + ""; } - h = '
 ' + fsize + '
' + link + '
'; + h = '
 ' + EscapeHtml(fsize) + '
' + link + '
'; } if (f.t < 3) { html1 += h; } else { html2 += h; } @@ -11991,18 +11991,18 @@ } else { for (var i in notifications) { var n = notifications[i], t = '', d = new Date(n.time), icon = 0; - if (n.title != null) { t = '' + n.title + ': ' } + if (n.title != null) { t = '' + EscapeHtml(n.title) + ': ' } if (n.nodeid != null) { var node = getNodeFromId(n.nodeid); if (node != null) { icon = node.icon; - if (notifySettings & 16) { t = '' + meshes[node.meshid].name + ' / ' + node.name + ': '; } else { t = '' + node.name + ': '; } // Display with or without group name + if (notifySettings & 16) { t = '' + EscapeHtml(meshes[node.meshid].name) + ' / ' + EscapeHtml(node.name) + ': '; } else { t = '' + EscapeHtml(node.name) + ': '; } // Display with or without group name } } r += '
'; if (icon) { r += '
'; } - r += '
X
' + t + n.text + '
'; + r += '
X
' + t + EscapeHtml(n.text) + '
'; } } var deleteall = ''; @@ -12656,9 +12656,9 @@ installedPluginList.forEach(function(p){ var cant_action = []; if (p.hasAdminPanel == true && p.status) { - p.nameHtml = '' + p.name + ''; + p.nameHtml = '' + EscapeHtml(p.name) + ''; } else { - p.nameHtml = p.name; + p.nameHtml = EscapeHtml(p.name); } p.statusText = statusMap[p.status].text; p.statusColor = statusMap[p.status].color; @@ -12691,7 +12691,7 @@ } p.actions += ''; - var tpl = ' ' + p.nameHtml + '' + p.description + 'Home' + p.version + '' + p.upgradeAvail + '' + p.statusText + '' + p.actions + ' '; + var tpl = ' ' + p.nameHtml + '' + EscapeHtml(p.description) + 'Home' + EscapeHtml(p.version) + '' + p.upgradeAvail + '' + p.statusText + '' + p.actions + ' '; var tr = tbl.insertRow(-1); tr.innerHTML = tpl; tr.classList.add('p42tblRow'); diff --git a/views/mstsc.handlebars b/views/mstsc.handlebars index dc273e5d..162323d2 100644 --- a/views/mstsc.handlebars +++ b/views/mstsc.handlebars @@ -74,7 +74,7 @@ if (name != '') { document.title = name + ' - ' + document.title; } function load() { - if (name != '') { QH('computerName', name); } + if (name != '') { QH('computerName', EscapeHtml(name)); } client = MstscClient.create(Q('myCanvas')); Q('inputDomain').focus(); canvas = Q('myCanvas'); diff --git a/webserver.js b/webserver.js index 8b796d4c..17184596 100644 --- a/webserver.js +++ b/webserver.js @@ -1513,28 +1513,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { var idsplit = cookie.u.split('/'); if ((idsplit.length != 2) || (idsplit[0] != domain.id)) { parent.debug('web', 'handleCheckMailRequest: Invalid domain.'); - render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 1, domainurl: encodeURIComponent(domain.url) }, req, domain)); + render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 1, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); } else { obj.db.Get('user/' + cookie.u.toLowerCase(), function (err, docs) { if (docs.length == 0) { parent.debug('web', 'handleCheckMailRequest: Invalid username.'); - render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 2, domainurl: encodeURIComponent(domain.url), arg1: encodeURIComponent(idsplit[1]) }, req, domain)); + 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)); } else { var user = docs[0]; if (user.email != cookie.e) { parent.debug('web', 'handleCheckMailRequest: Invalid e-mail.'); - 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)); + 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)); } else { if (cookie.a == 1) { // Account email verification if (user.emailVerified == true) { parent.debug('web', 'handleCheckMailRequest: email already verified.'); - 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)); + 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)); } else { obj.db.GetUserWithVerifiedEmail(domain.id, user.email, function (err, docs) { if (docs.length > 0) { parent.debug('web', 'handleCheckMailRequest: email already in use.'); - render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 5, domainurl: encodeURIComponent(domain.url), arg1: encodeURIComponent(user.email) }, req, domain)); + 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)); } else { parent.debug('web', 'handleCheckMailRequest: email verification success.'); @@ -1549,7 +1549,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event); // Send the confirmation page - 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)); + 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)); // Send a notification obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:
' + EscapeHtml(user.email) + '.', nolog: 1, id: Math.random() }); @@ -1563,7 +1563,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // Account reset if (user.emailVerified != true) { parent.debug('web', 'handleCheckMailRequest: email not verified.'); - 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)); + 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)); } else { // Set a temporary password obj.crypto.randomBytes(16, function (err, buf) { @@ -1588,7 +1588,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event); // Send the new password - 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)); + 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)); parent.debug('web', 'handleCheckMailRequest: send temporary password.'); // Send to authlog @@ -1597,14 +1597,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { }); } } else { - render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 9, domainurl: encodeURIComponent(domain.url) }, req, domain)); + render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 9, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); } } } }); } } else { - render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 10, domainurl: encodeURIComponent(domain.url) }, req, domain)); + render(req, res, getRenderPage('message', req, domain), getRenderArgs({ titleid: 1, msgid: 10, domainurl: encodeURIComponent(domain.url).replace(/'/g, '%27') }, req, domain)); } } } @@ -1637,7 +1637,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if (req.query.ws != null) { // This is a query with a websocket relay cookie, check that the cookie is valid and use it. var rcookie = parent.decodeCookie(req.query.ws, parent.loginCookieEncryptionKey, 240); // Cookie with 4 hour timeout - 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; } + 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).replace(/'/g, '%27') }, req, domain)); return; + } } // Get the logged in user if present @@ -1688,7 +1690,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // Generate a cookie and respond var cookie = parent.encodeCookie({ userid: user._id, domainid: user.domain, nodeid: node._id, tcpport: port }, parent.loginCookieEncryptionKey); - render(req, res, getRenderPage('mstsc', req, domain), getRenderArgs({ cookie: cookie, name: encodeURIComponent(node.name) }, req, domain)); + render(req, res, getRenderPage('mstsc', req, domain), getRenderArgs({ cookie: cookie, name: encodeURIComponent(node.name).replace(/'/g, '%27') }, req, domain)); }); } @@ -2260,7 +2262,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if (domain.customui != null) { customui = encodeURIComponent(JSON.stringify(domain.customui)); } // Refresh the session - 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)); + 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)); }); } else { // Send back the login application @@ -2354,7 +2356,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if (domain.customui != null) { customui = encodeURIComponent(JSON.stringify(domain.customui)); } // Render the login page - 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)); + 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)); } // Handle a post request on the root @@ -2500,7 +2502,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { parent.debug('web', 'handleMessengerRequest()'); var webRtcConfig = null; - 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)); } + 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'); } res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' }); render(req, res, getRenderPage('messenger', req, domain), getRenderArgs({ webrtconfig: webRtcConfig }, req, domain)); } @@ -3852,8 +3854,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { if (xdomain != '') xdomain += '/'; var meshsettings = 'MeshName=' + mesh.name + '\r\nMeshType=' + mesh.mtype + '\r\nMeshID=0x' + meshidhex + '\r\nServerID=' + serveridhex + '\r\n'; 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'; } - if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } - if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; } + if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } + if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; } if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; } if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } } 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) { if (obj.args.agentport != null) { httpsPort = obj.args.agentport; } // If an agent only port is enabled, use that. if (obj.args.agentaliasport != null) { httpsPort = obj.args.agentaliasport; } // If an agent alias port is specified, use that. 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'; } - if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } - if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; } + if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } + if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; } if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; } if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } } 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) { if (obj.args.agentport != null) { httpsPort = obj.args.agentport; } // If an agent only port is enabled, use that. if (obj.args.agentaliasport != null) { httpsPort = obj.args.agentaliasport; } // If an agent alias port is specified, use that. 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'; } - if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } - if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; } + if ((req.query.tag != null) && (typeof req.query.tag == 'string') && (obj.common.isAlphaNumeric(req.query.tag) == true)) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; } + if ((req.query.installflags != null) && (req.query.installflags != 0) && (parseInt(req.query.installflags) == req.query.installflags)) { meshsettings += 'InstallFlags=' + parseInt(req.query.installflags) + '\r\n'; } if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; } if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } } if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + '\r\n'; } }