UI customization improvements.

Ylian Saint-Hilaire committed Nov 5, 2020 at 02:27 UTC 98b39000eb18bd25249336e1b6c476b4f3114775
11 files changed +72 -39
meshcentral.js
+6 -6
@@ -131,7 +131,7 @@ function CreateMeshCentralServer(config, args) {
131 try { require('./pass').hash('test', function () { }, 0); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
132
133 // Check for invalid arguments
134 - var validArguments = ['_', 'notls', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'rediraliasport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'showitem', 'listuserids', 'showusergroups', 'shownodes', 'showallmeshes', 'showmeshes', 'showevents', 'showsmbios', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'xinstall', 'xuninstall', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbfix', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'vaultpushconfigfiles', 'vaultpullconfigfiles', 'vaultdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'serverid', 'recordencryptionrecode', 'vault', 'token', 'unsealkey', 'name', 'log', 'dbstats', 'translate', 'createaccount', 'resetaccount', 'pass', 'adminaccount', 'removeaccount', 'domain', 'email'];
134 + var validArguments = ['_', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'rediraliasport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'showitem', 'listuserids', 'showusergroups', 'shownodes', 'showallmeshes', 'showmeshes', 'showevents', 'showsmbios', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'xinstall', 'xuninstall', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbfix', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'vaultpushconfigfiles', 'vaultpullconfigfiles', 'vaultdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'serverid', 'recordencryptionrecode', 'vault', 'token', 'unsealkey', 'name', 'log', 'dbstats', 'translate', 'createaccount', 'resetaccount', 'pass', 'adminaccount', 'removeaccount', 'domain', 'email'];
135 for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
136 if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
137 for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence.
@@ -1103,12 +1103,12 @@ function CreateMeshCentralServer(config, args) {
1103 if ((obj.args.ciralocalfqdn != null) && ((obj.args.lanonly == true) || (obj.args.wanonly == true))) { addServerWarning("CIRA local FQDN's ignored when server in LAN-only or WAN-only mode."); }
1104 if ((obj.args.ciralocalfqdn != null) && (obj.args.ciralocalfqdn.split(',').length > 4)) { addServerWarning("Can't have more than 4 CIRA local FQDN's. Ignoring value."); obj.args.ciralocalfqdn = null; }
1105 if (obj.args.ignoreagenthashcheck === true) { addServerWarning("Agent hash checking is being skipped, this is unsafe."); }
1106 - if (obj.args.port == null || typeof obj.args.port != 'number') { if (obj.args.notls == null) { obj.args.port = 443; } else { obj.args.port = 80; } }
1106 + if (obj.args.port == null || typeof obj.args.port != 'number') { obj.args.port = 443; }
1107 if (obj.args.aliasport != null && (typeof obj.args.aliasport != 'number')) obj.args.aliasport = null;
1108 if (obj.args.mpsport == null || typeof obj.args.mpsport != 'number') obj.args.mpsport = 4433;
1109 if (obj.args.mpsaliasport != null && (typeof obj.args.mpsaliasport != 'number')) obj.args.mpsaliasport = null;
1110 if (obj.args.rediraliasport != null && (typeof obj.args.rediraliasport != 'number')) obj.args.rediraliasport = null;
1111 - if (obj.args.notls == null && obj.args.redirport == null) obj.args.redirport = 80;
1111 + if (obj.args.redirport == null) obj.args.redirport = 80;
1112 if (obj.args.minifycore === 0) obj.args.minifycore = false;
1113 if (typeof args.agentidletimeout != 'number') { args.agentidletimeout = 150000; } else { args.agentidletimeout *= 1000 } // Default agent idle timeout is 2m, 30sec.
1114
@@ -2107,7 +2107,7 @@ function CreateMeshCentralServer(config, args) {
2107 obj.meshToolsBinaries[this.toolname].hashx = this.hashx;
2108 obj.meshToolsBinaries[this.toolname].path = this.agentpath;
2109 obj.meshToolsBinaries[this.toolname].dlname = this.dlname;
2110 - obj.meshToolsBinaries[this.toolname].url = ((obj.args.notls == true) ? 'http://' : 'https://') + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?meshaction=' + this.dlname;
2110 + obj.meshToolsBinaries[this.toolname].url = ('https://' + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?meshaction=' + this.dlname;
2111 var stats = null;
2112 try { stats = obj.fs.statSync(this.agentpath); } catch (e) { }
2113 if (stats != null) { obj.meshToolsBinaries[this.toolname].size = stats.size; }
@@ -2148,7 +2148,7 @@ function CreateMeshCentralServer(config, args) {
2148 obj.meshAgentInstallScripts[this.info.id].hash = this.hash.digest('hex');
2149 obj.meshAgentInstallScripts[this.info.id].path = this.agentpath;
2150 obj.meshAgentInstallScripts[this.info.id].data = this.xdata;
2151 - obj.meshAgentInstallScripts[this.info.id].url = ((obj.args.notls == true) ? 'http://' : 'https://') + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?script=' + this.info.id;
2151 + obj.meshAgentInstallScripts[this.info.id].url = ('https://' + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?script=' + this.info.id;
2152 var stats = null;
2153 try { stats = obj.fs.statSync(this.agentpath); } catch (e) { }
2154 if (stats != null) { obj.meshAgentInstallScripts[this.info.id].size = stats.size; }
@@ -2213,7 +2213,7 @@ function CreateMeshCentralServer(config, args) {
2213 archcount++;
2214 obj.meshAgentBinaries[archid] = Object.assign({}, obj.meshAgentsArchitectureNumbers[archid]);
2215 obj.meshAgentBinaries[archid].path = agentpath;
2216 - obj.meshAgentBinaries[archid].url = ((obj.args.notls == true) ? 'http://' : 'https://') + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?id=' + archid;
2216 + obj.meshAgentBinaries[archid].url = ('http://' + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?id=' + archid;
2217 obj.meshAgentBinaries[archid].size = stats.size;
2218
2219 // If this is a windows binary, pull binary information
meshctrl.js
+28 -2
@@ -272,6 +272,15 @@ if (args['_'].length == 0) {
272 console.log(" --hours [hours] - Validity period in hours or 0 for infinit.");
273 break;
274 }
275 + case 'showevents': {
276 + console.log("Show the server's event stream for this user account. Example usage:\r\n");
277 + console.log(" MeshCtrl ShowEvents");
278 + console.log(" MeshCtrl ShowEvents --filter nodeconnect");
279 + console.log(" MeshCtrl ShowEvents --filter uicustomevent,changenode");
280 + console.log("\r\nOptional arguments:\r\n");
281 + console.log(" --filter [actions] - Show only specified actions.");
282 + break;
283 + }
284 case 'serverinfo': {
285 console.log("Get information on the MeshCentral server, Example usages:\r\n");
286 console.log(" MeshCtrl ServerInfo --loginuser myaccountname --loginpass mypassword");
@@ -625,10 +634,12 @@ if (args['_'].length == 0) {
634 break;
635 }
636 case 'broadcast': {
628 - console.log("Display a message to all logged in users, Example usages:\r\n");
637 + console.log("Display a message to one or all logged in users, Example usages:\r\n");
638 console.log(" MeshCtrl Broadcast --msg \"This is a test\"");
639 console.log("\r\nRequired arguments:\r\n");
640 console.log(" --msg [message] - Message to display.");
641 + console.log("\r\nOptional arguments:\r\n");
642 + console.log(" --user [userid] - Send the message to the speficied user.");
643 break;
644 }
645 case 'deviceinfo': {
@@ -1216,6 +1227,7 @@ function serverConnect() {
1227 }
1228 case 'broadcast': {
1229 var op = { action: 'userbroadcast', msg: args.msg, responseid: 'meshctrl' };
1230 + if (args.user) { op.userid = args.user; }
1231 ws.send(JSON.stringify(op));
1232 break;
1233 }
@@ -1269,7 +1281,21 @@ function serverConnect() {
1281 var data = null;
1282 try { data = JSON.parse(rawdata); } catch (ex) { }
1283 if (data == null) { console.log('Unable to parse data: ' + rawdata); }
1272 - if (settings.cmd == 'showevents') { console.log(JSON.stringify(data, null, 2)); return; }
1284 + if (settings.cmd == 'showevents') {
1285 + if (args.filter == null) {
1286 + // Display all events
1287 + console.log(JSON.stringify(data, null, 2));
1288 + } else {
1289 + // Display select events
1290 + var filters = args.filter.split(',');
1291 + if (typeof data.event == 'object') {
1292 + if (filters.indexOf(data.event.action) >= 0) { console.log(JSON.stringify(data, null, 2) + '\r\n'); }
1293 + } else {
1294 + if (filters.indexOf(data.action) >= 0) { console.log(JSON.stringify(data, null, 2) + '\r\n'); }
1295 + }
1296 + }
1297 + return;
1298 + }
1299 switch (data.action) {
1300 case 'serverinfo': { // SERVERINFO
1301 settings.currentDomain = data.serverinfo.domain;
meshdesktopmultiplex.js
+1 -1
@@ -984,7 +984,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
984 /*
985 // Validate that the id is valid, we only need to do this on non-authenticated sessions.
986 // TODO: Figure out when this needs to be done.
987 - if ((user == null) && (!parent.args.notls)) {
987 + if (user == null) {
988 // Check the identifier, if running without TLS, skip this.
989 var ids = obj.id.split(':');
990 if (ids.length != 3) { ws.close(); delete obj.id; return null; } // Invalid ID, drop this.
meshmail.js
+2 -2
@@ -128,10 +128,10 @@ module.exports.CreateMeshMail = function (parent) {
128 var httpsport = (typeof obj.parent.args.aliasport == 'number') ? obj.parent.args.aliasport : obj.parent.args.port;
129 if (domain.dns == null) {
130 // Default domain or subdomain of the default.
131 - options.serverurl = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + obj.parent.certificates.CommonName + ':' + httpsport + domain.url;
131 + options.serverurl = 'https://' + obj.parent.certificates.CommonName + ':' + httpsport + domain.url;
132 } else {
133 // Domain with a DNS name.
134 - options.serverurl = 'http' + ((obj.parent.args.notls == null) ? 's' : '') + '://' + domain.dns + ':' + httpsport + domain.url;
134 + options.serverurl = 'https://' + domain.dns + ':' + httpsport + domain.url;
135 }
136 if (options.serverurl.endsWith('/')) { options.serverurl = options.serverurl.substring(0, options.serverurl.length - 1); } // Remove the ending / if present
137 for (var i in options) {
meshscanner.js
+4 -4
@@ -175,15 +175,15 @@ module.exports.CreateMeshScanner = function (parent) {
175 var port = (parent.args.aliasport)?parent.args.aliasport:parent.args.port;
176
177 // Build the IPv4 response
178 - var url = (parent.args.notls ? 'ws' : 'wss') + '://%s:' + port + '/agent.ashx';
178 + var url = 'wss://%s:' + port + '/agent.ashx';
179 obj.multicastPacket4 = Buffer.from("MeshCentral2|" + obj.agentCertificateHashHex + '|' + url, 'ascii');
180 - if (parent.certificates.CommonName.indexOf('.') != -1) { url = (parent.args.notls ? 'ws' : 'wss') + '://' + parent.certificates.CommonName + ':' + port + '/agent.ashx'; }
180 + if (parent.certificates.CommonName.indexOf('.') != -1) { url = 'wss://' + parent.certificates.CommonName + ':' + port + '/agent.ashx'; }
181 obj.multicastPacket4x = Buffer.from("MeshCentral2|" + obj.agentCertificateHashHex + '|' + url + '|' + name + '|' + info, 'ascii');
182
183 // Build the IPv6 response
184 - url = (parent.args.notls ? 'ws' : 'wss') + '://[%s]:' + port + '/agent.ashx';
184 + url = 'wss://[%s]:' + port + '/agent.ashx';
185 obj.multicastPacket6 = Buffer.from("MeshCentral2|" + obj.agentCertificateHashHex + '|' + url, 'ascii');
186 - if (parent.certificates.CommonName.indexOf('.') != -1) { url = (parent.args.notls ? 'ws' : 'wss') + '://' + parent.certificates.CommonName + ':' + port + '/agent.ashx'; }
186 + if (parent.certificates.CommonName.indexOf('.') != -1) { url = 'wss://' + parent.certificates.CommonName + ':' + port + '/agent.ashx'; }
187 obj.multicastPacket6x = Buffer.from("MeshCentral2|" + obj.agentCertificateHashHex + '|' + url + '|' + name + '|' + info, 'ascii');
188
189 setupServers();
meshuser.js
+7 -5
@@ -457,7 +457,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
457 }
458 if (matchingDomains.length > 0) { serverinfo.amtAcmFqdn = matchingDomains; }
459 }
460 - if (args.notls == true) { serverinfo.https = false; } else { serverinfo.https = true; serverinfo.redirport = args.redirport; }
460 + serverinfo.https = true;
461 + serverinfo.redirport = args.redirport;
462 if (typeof domain.userconsentflags == 'number') { serverinfo.consent = domain.userconsentflags; }
463 if ((typeof domain.usersessionidletimeout == 'number') && (domain.usersessionidletimeout > 0)) { serverinfo.timeout = (domain.usersessionidletimeout * 60 * 1000); }
464 if (user.siteadmin === SITERIGHT_ADMIN) {
@@ -1743,6 +1744,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1744 try {
1745 if (parent.wssessions2[i].domainid == domain.id) {
1746 var sessionUser = parent.users[parent.wssessions2[i].userid];
1747 + if ((command.userid != null) && (command.userid != sessionUser._id) && (command.userid != sessionUser._id.split('/')[2])) { continue; }
1748 if ((command.target == null) || ((sessionUser.links) != null && (sessionUser.links[command.target] != null))) {
1749 if ((user.groups == null) || (user.groups.length == 0)) {
1750 // We are part of no user groups, send to everyone.
@@ -2662,7 +2664,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2664 var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
2665 var xdomain = (domain.dns == null) ? domain.id : '';
2666 if (xdomain != '') xdomain += "/";
2665 - var url = "http" + (args.notls ? '' : 's') + "://" + parent.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "messenger?id=meshmessenger/" + encodeURIComponent(command.nodeid) + "/" + encodeURIComponent(user._id) + "&title=" + encodeURIComponent(user.name);
2667 + var url = "https://" + parent.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "messenger?id=meshmessenger/" + encodeURIComponent(command.nodeid) + "/" + encodeURIComponent(user._id) + "&title=" + encodeURIComponent(user.name);
2668
2669 // Create the notification message
2670 routeCommandToNode({ 'action': 'openUrl', 'nodeid': command.nodeid, 'userid': user._id, 'username': user.name, 'url': url });
@@ -4570,7 +4572,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4572 var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
4573 var xdomain = (domain.dns == null) ? domain.id : '';
4574 if (xdomain != '') xdomain += '/';
4573 - var url = 'http' + (args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'agentinvite?c=' + inviteCookie;
4575 + var url = 'https://' + serverName + ':' + httpsPort + '/' + xdomain + 'agentinvite?c=' + inviteCookie;
4576 if (serverName.split('.') == 1) { url = '/' + xdomain + 'agentinvite?c=' + inviteCookie; }
4577
4578 ws.send(JSON.stringify({ action: 'createInviteLink', meshid: command.meshid, url: url, expire: command.expire, cookie: inviteCookie, responseid: command.responseid, tag: command.tag }));
@@ -4725,7 +4727,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4727 var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
4728 var xdomain = (domain.dns == null) ? domain.id : '';
4729 if (xdomain != '') xdomain += '/';
4728 - var url = 'http' + (args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'desktop?c=' + inviteCookie;
4730 + var url = 'https://' + serverName + ':' + httpsPort + '/' + xdomain + 'desktop?c=' + inviteCookie;
4731 if (serverName.split('.') == 1) { url = '/' + xdomain + 'desktop?c=' + inviteCookie; }
4732 command.url = url;
4733 ws.send(JSON.stringify(command));
@@ -4819,7 +4821,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4821 var xdomain = (domain.dns == null) ? domain.id : '';
4822 if (xdomain != '') xdomain += '/';
4823 var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
4822 - r.wsUrl = 'ws' + (args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'mqtt.ashx';
4824 + r.wsUrl = 'wss://' + serverName + ':' + httpsPort + '/' + xdomain + 'mqtt.ashx';
4825 r.wsTrustedCert = parent.isTrustedCert(domain);
4826
4827 try { ws.send(JSON.stringify(r)); } catch (ex) { }
mstsc.js
+1 -1
@@ -64,7 +64,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
64 var options = { rejectUnauthorized: false };
65 if (domain.dns != null) { options.servername = domain.dns; }
66 var protocol = 'wss';
67 - if (args.notls || args.tlsoffload) { protocol = 'ws'; }
67 + if (args.tlsoffload) { protocol = 'ws'; }
68 var domainadd = '';
69 if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
70 var url = protocol + '://127.0.0.1:' + args.port + '/' + domainadd + 'meshrelay.ashx?auth=' + obj.infos.ip;
redirserver.js
+1 -1
@@ -75,7 +75,7 @@ module.exports.CreateRedirServer = function (parent, db, args, func) {
75 parent.letsencrypt.challenge(req.url.slice(leChallengePrefix.length), getCleanHostname(req), function (response) { if (response == null) { res.sendStatus(404); } else { res.send(response); } });
76 } else {
77 // Everything else
78 - var selfurl = ((args.notls !== true) ? (' wss://' + req.headers.host) : (' ws://' + req.headers.host));
78 + var selfurl = (' wss://' + req.headers.host);
79 res.set({
80 'strict-transport-security': 'max-age=60000; includeSubDomains',
81 'Referrer-Policy': 'no-referrer',
views/default-mobile.handlebars
+7 -1
@@ -3331,7 +3331,13 @@
3331 for (var pid in processes) { p.push({ p: parseInt(pid), c: processes[pid].cmd, d: processes[pid].cmd.toLowerCase(), u: processes[pid].user }); }
3332 if (deskTools.sort == 0) { p.sort(sortProcessPid); } else if (deskTools.sort == 1) { p.sort(sortProcessName); }
3333 var x = '';
3334 - for (var i in p) { if (p[i].p != 0) { x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a style=float:right;padding-right:5px;cursor:pointer onclick=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>' + p[i].c + '</div></div>'; } }
3334 + for (var i in p) {
3335 + if (p[i].p != 0) {
3336 + var c = p[i].c;
3337 + if (c.length > 30) { c = '<span title="' + EscapeHtml(c) + '">' + EscapeHtml(c.substring(0, 30)) + '...</span>' } else { c = EscapeHtml(c); }
3338 + x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + EscapeHtml(p[i].p) + '</div><a style=float:right;padding-right:5px;cursor:pointer onclick=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>';
3339 + }
3340 + }
3341 QH('DeskToolsProcesses', x);
3342 }
3343 }
views/default.handlebars
+4 -3
@@ -1573,8 +1573,7 @@
1573 if (typeof dialog.elements == 'object') {
1574 for (var i in dialog.elements) {
1575 var elem = dialog.elements[i];
1576 - if (elem.type == 'text') { t.values[i] = Q('cui:' + i).value; }
1577 - if (elem.type == 'droplist') { t.values[i] = Q('cui:' + i).value; }
1576 + if ((elem.type == 'droplist') || (elem.type == 'textarea') || (elem.type == 'text')) { t.values[i] = Q('cui:' + i).value; }
1577 }
1578 }
1579 meshserver.send(t);
@@ -5790,7 +5789,9 @@
5789 // Custom UI
5790 if ((customui != null) && (customui.devicebuttons != null)) {
5791 for (var i in customui.devicebuttons) {
5793 - x += '<input id="cui:' + i + '" type="button" value="' + customui.devicebuttons[i].name + '" onclick=customUIAction(event,"devicebuttons") />';
5792 + if ((customui.devicebuttons[i].showif == null) || ((mesh != null) && (customui.devicebuttons[i].showif == mesh._id)) || (customui.devicebuttons[i].showif == currentNode._id)) {
5793 + x += '<input id="cui:' + i + '" type="button" value="' + customui.devicebuttons[i].name + '" onclick=customUIAction(event,"devicebuttons") />';
5794 + }
5795 }
5796 }
5797
webserver.js
+11 -13
@@ -1729,7 +1729,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1729 if (typeof installflags != 'number') { installflags = 0; }
1730 parent.debug('web', 'handleAgentInviteRequest using cookie.');
1731 var meshcookie = parent.encodeCookie({ m: mesh._id.split('/')[2] }, parent.invitationLinkEncryptionKey);
1732 - render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: meshcookie, serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name).replace(/'/g, '%27'), installflags: installflags }, req, domain));
1732 + render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: meshcookie, serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: 1, servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name).replace(/'/g, '%27'), installflags: installflags }, req, domain));
1733 } else if (req.query.m != null) {
1734 // The MeshId is specified in the query string, use that
1735 var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.m.toLowerCase()];
@@ -1739,7 +1739,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1739 if (typeof installflags != 'number') { installflags = 0; }
1740 parent.debug('web', 'handleAgentInviteRequest using meshid.');
1741 var meshcookie = parent.encodeCookie({ m: mesh._id.split('/')[2] }, parent.invitationLinkEncryptionKey);
1742 - render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: meshcookie, serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name).replace(/'/g, '%27'), installflags: installflags }, req, domain));
1742 + render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: meshcookie, serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: 1, servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name).replace(/'/g, '%27'), installflags: installflags }, req, domain));
1743 }
1744 }
1745
@@ -2527,7 +2527,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2527
2528 // Return true if it looks like we are using a real TLS certificate.
2529 obj.isTrustedCert = function (domain) {
2530 - if (obj.args.notls == true) return false; // We are not using TLS, so not trusted cert.
2530 if ((domain != null) && (typeof domain.trustedcert == 'boolean')) return domain.trustedcert; // If the status of the cert specified, use that.
2531 if (typeof obj.args.trustedcert == 'boolean') return obj.args.trustedcert; // If the status of the cert specified, use that.
2532 if (obj.args.tlsoffload != null) return true; // We are using TLS offload, a real cert is likely used.
@@ -2540,7 +2539,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2539 // Get the link to the root certificate if needed
2540 function getRootCertLink() {
2541 // Check if the HTTPS certificate is issued from MeshCentralRoot, if so, add download link to root certificate.
2543 - if ((obj.args.notls == null) && (obj.args.tlsoffload == null) && (obj.parent.config.letsencrypt == null) && (obj.tlsSniCredentials == null) && (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) && (obj.certificates.CommonName.indexOf('.') != -1)) { return '<a href=/MeshServerRootCert.cer title="Download the root certificate for this server">Root Certificate</a>'; }
2542 + if ((obj.args.tlsoffload == null) && (obj.parent.config.letsencrypt == null) && (obj.tlsSniCredentials == null) && (obj.certificates.WebIssuer.indexOf('MeshCentralRoot-') == 0) && (obj.certificates.CommonName.indexOf('.') != -1)) { return '<a href=/MeshServerRootCert.cer title="Download the root certificate for this server">Root Certificate</a>'; }
2543 return '';
2544 }
2545
@@ -4106,7 +4105,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4105 var xdomain = (domain.dns == null) ? domain.id : '';
4106 if (xdomain != '') xdomain += '/';
4107 var meshsettings = 'MeshName=' + mesh.name + '\r\nMeshType=' + mesh.mtype + '\r\nMeshID=0x' + meshidhex + '\r\nServerID=' + serveridhex + '\r\n';
4109 - if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else {
4108 + if (obj.args.lanonly != true) { meshsettings += 'MeshServer=wss://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else {
4109 meshsettings += 'MeshServer=local\r\n';
4110 if ((obj.args.localdiscovery != null) && (typeof obj.args.localdiscovery.key == 'string') && (obj.args.localdiscovery.key.length > 0)) { meshsettings += 'DiscoveryKey=' + obj.args.localdiscovery.key + '\r\n'; }
4111 }
@@ -4227,7 +4226,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4226 if (user != null) { meshaction.username = user.name; }
4227 if (req.query.key != null) { meshaction.loginKey = req.query.key; }
4228 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
4230 - if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + obj.getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
4229 + if (obj.args.lanonly != true) { meshaction.serverUrl = 'wss://' + obj.getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
4230
4231 setContentDispositionHeader(res, 'application/octet-stream', 'meshaction.txt', null, 'meshaction.txt');
4232 res.send(JSON.stringify(meshaction, null, ' '));
@@ -4243,7 +4242,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4242 if (user != null) { meshaction.username = user.name; }
4243 if (req.query.key != null) { meshaction.loginKey = req.query.key; }
4244 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
4246 - if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + obj.getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
4245 + if (obj.args.lanonly != true) { meshaction.serverUrl = 'wss://' + obj.getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
4246 setContentDispositionHeader(res, 'application/octet-stream', 'meshaction.txt', null, 'meshaction.txt');
4247 res.send(JSON.stringify(meshaction, null, ' '));
4248 } else if (req.query.meshaction == 'winrouter') {
@@ -4407,7 +4406,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4406 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
4407 if (obj.args.agentport != null) { httpsPort = obj.args.agentport; } // If an agent only port is enabled, use that.
4408 if (obj.args.agentaliasport != null) { httpsPort = obj.args.agentaliasport; } // If an agent alias port is specified, use that.
4410 - if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else {
4409 + if (obj.args.lanonly != true) { meshsettings += 'MeshServer=wss://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else {
4410 meshsettings += 'MeshServer=local\r\n';
4411 if ((obj.args.localdiscovery != null) && (typeof obj.args.localdiscovery.key == 'string') && (obj.args.localdiscovery.key.length > 0)) { meshsettings += 'DiscoveryKey=' + obj.args.localdiscovery.key + '\r\n'; }
4412 }
@@ -4499,7 +4498,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4498 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
4499 if (obj.args.agentport != null) { httpsPort = obj.args.agentport; } // If an agent only port is enabled, use that.
4500 if (obj.args.agentaliasport != null) { httpsPort = obj.args.agentaliasport; } // If an agent alias port is specified, use that.
4502 - if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else {
4501 + if (obj.args.lanonly != true) { meshsettings += 'MeshServer=wss://' + serverName + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else {
4502 meshsettings += 'MeshServer=local\r\n';
4503 if ((obj.args.localdiscovery != null) && (typeof obj.args.localdiscovery.key == 'string') && (obj.args.localdiscovery.key.length > 0)) { meshsettings += 'DiscoveryKey=' + obj.args.localdiscovery.key + '\r\n'; }
4504 }
@@ -4599,7 +4598,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4598 // Starts the HTTPS server, this should be called after the user/mesh tables are loaded
4599 function serverStart() {
4600 // Start the server, only after users and meshes are loaded from the database.
4602 - if (obj.args.notls || obj.args.tlsoffload) {
4601 + if (obj.args.tlsoffload) {
4602 // Setup the HTTP server without TLS
4603 obj.expressWs = require('express-ws')(obj.app, null, { wsOptions: { perMessageDeflate: (args.wscompression === true) } });
4604 } else {
@@ -4619,7 +4618,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4618 // Start a second agent-only server if needed
4619 if (obj.args.agentport) {
4620 var agentPortTls = true;
4622 - if ((obj.args.notls == 1) || (obj.args.notls == true)) { agentPortTls = false; }
4621 if (obj.args.tlsoffload != null) { agentPortTls = false; }
4622 if (typeof obj.args.agentporttls == 'boolean') { agentPortTls = obj.args.agentporttls; }
4623 if (obj.certificates.webdefault == null) { agentPortTls = false; }
@@ -4651,7 +4649,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4649 name: 'xid', // Recommended security practice to not use the default cookie name
4650 httpOnly: true,
4651 keys: [obj.args.sessionkey], // If multiple instances of this server are behind a load-balancer, this secret must be the same for all instances
4654 - secure: ((obj.args.notls != true) && (obj.args.tlsoffload == null)) // Use this cookie only over TLS (Check this: https://expressjs.com/en/guide/behind-proxies.html)
4652 + secure: (obj.args.tlsoffload == null) // Use this cookie only over TLS (Check this: https://expressjs.com/en/guide/behind-proxies.html)
4653 }
4654 if (obj.args.sessionsamesite != null) { sessionOptions.sameSite = obj.args.sessionsamesite; } else { sessionOptions.sameSite = 'strict'; }
4655 if (obj.args.sessiontime != null) { sessionOptions.maxAge = (obj.args.sessiontime * 60 * 1000); }
@@ -4696,7 +4694,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4694 } else {
4695 // Use default security headers
4696 var geourl = (domain.geolocation ? ' *.openstreetmap.org' : '');
4699 - var selfurl = ((args.notls !== true) ? (' wss://' + req.headers.host) : (' ws://' + req.headers.host));
4697 + var selfurl = (' wss://' + req.headers.host);
4698 var headers = {
4699 'Referrer-Policy': 'no-referrer',
4700 'X-XSS-Protection': '1; mode=block',