Allow complete removal of My Server tab for a specific domain.

Ylian Saint-Hilaire committed Oct 5, 2020 at 16:47 UTC 4f8aca10481737c97b031084eb91eb77b1a74b81
5 files changed +39 -19
meshcentral-config-schema.json
+1 -1
@@ -176,7 +176,7 @@
176 "description": "https url when to get the TLS certificate that MeshAgent's will see when connecting to this server. This setting is used when a reverse proxy like NGINX is used in front of MeshCentral."
177 },
178 "myServer": {
179 - "type": "object",
179 + "type": [ "object", "boolean" ],
180 "additionalProperties": false,
181 "properties": {
182 "Backup": { "type": "boolean", "default": true, "description": "Allows administrators to backup the server from the My Server tab." },
meshctrl.js
+16 -3
@@ -338,6 +338,7 @@ if (args['_'].length == 0) {
338 console.log(" --group [groupname] - Filter by group name (or --id).");
339 console.log(" --count - Only return the device count.");
340 console.log(" --json - Show result as JSON.");
341 + console.log(" --csv - Show result as comma seperated values.");
342 break;
343 }
344 case 'listusersofdevicegroup': {
@@ -1442,7 +1443,19 @@ function serverConnect() {
1443 if ((data.result != null) && (data.result != 'ok')) {
1444 console.log(data.result);
1445 } else {
1445 - if (args.count) {
1446 + if (args.csv) {
1447 + // Return a flat list
1448 + var nodecount = 0;
1449 + for (var i in data.nodes) {
1450 + var devicesInMesh = data.nodes[i];
1451 + for (var j in devicesInMesh) {
1452 + var n = devicesInMesh[j];
1453 + nodecount++;
1454 + console.log('\"' + settings.xmeshes[i]._id.split('/')[2] + '\",\"' + settings.xmeshes[i].name.split('\"').join('') + '\",\"' + n._id.split('/')[2] + '\",\"' + n.name.split('\"').join('') + '\",' + (n.icon ? n.icon : 0) + ',' + (n.conn ? n.conn : 0) + ',' + (n.pwr ? n.pwr : 0));
1455 + }
1456 + }
1457 + if (nodecount == 0) { console.log('None'); }
1458 + } else if (args.count) {
1459 // Return how many devices are in this group
1460 var nodes = [];
1461 for (var i in data.nodes) { var devicesInMesh = data.nodes[i]; for (var j in devicesInMesh) { nodes.push(devicesInMesh[j]); } }
@@ -1457,12 +1470,12 @@ function serverConnect() {
1470 var nodecount = 0;
1471 for (var i in data.nodes) {
1472 var devicesInMesh = data.nodes[i];
1460 - if (settings.xmeshes) { console.log('\r\nDevice group: \"' + settings.xmeshes[i].name + '\"'); }
1473 + if (settings.xmeshes) { console.log('\r\nDevice group: \"' + settings.xmeshes[i].name.split('\"').join('') + '\"'); }
1474 console.log('id, name, icon, conn, pwr, ip\r\n-----------------------------');
1475 for (var j in devicesInMesh) {
1476 var n = devicesInMesh[j];
1477 nodecount++;
1465 - console.log(n._id.split('/')[2] + ', \"' + n.name + '\", ' + (n.icon ? n.icon : 0) + ', ' + (n.conn ? n.conn : 0) + ', ' + (n.pwr ? n.pwr : 0));
1478 + console.log('\"' + n._id.split('/')[2] + '\", \"' + n.name.split('\"', '') + '\", ' + (n.icon ? n.icon : 0) + ', ' + (n.conn ? n.conn : 0) + ', ' + (n.pwr ? n.pwr : 0));
1479 }
1480 }
1481 if (nodecount == 0) { console.log('None'); }
meshuser.js
+14 -8
@@ -472,7 +472,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
472
473 if (user.siteadmin === SITERIGHT_ADMIN) {
474 // Check if tracing is allowed for this domain
475 - if ((domain.myserver == null) || (domain.myserver.trace === true)) {
475 + if ((domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.trace === true))) {
476 // Send server tracing information
477 try { ws.send(JSON.stringify({ action: 'traceinfo', traceSources: parent.parent.debugRemoteSources })); } catch (ex) { }
478 }
@@ -550,6 +550,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
550 }
551 case 'servertimelinestats':
552 {
553 + // Only accept if the "My Server" tab is allowed for this domain
554 + if (domain.myserver === false) break;
555 +
556 if ((user.siteadmin & 21) == 0) return; // Only site administrators with "site backup" or "site restore" or "site update" permissions can use this.
557 if (common.validateInt(command.hours, 0, 24 * 30) == false) return;
558 db.GetServerStats(command.hours, function (err, docs) {
@@ -561,6 +564,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
564 }
565 case 'serverstats':
566 {
567 + // Only accept if the "My Server" tab is allowed for this domain
568 + if (domain.myserver === false) break;
569 +
570 if ((user.siteadmin & 21) == 0) return; // Only site administrators with "site backup" or "site restore" or "site update" permissions can use this.
571 if (common.validateInt(command.interval, 1000, 1000000) == false) {
572 // Clear the timer
@@ -839,8 +845,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
845 // This is a server console message, only process this if full administrator
846 if (user.siteadmin != SITERIGHT_ADMIN) break;
847
842 - // Only accept is the console is allowed for this domain
843 - if ((domain.myserver != null) && (domain.myserver.console !== true)) break;
848 + // Only accept if the console is allowed for this domain
849 + if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver.console !== true))) break;
850
851 var r = '';
852 var cmdargs = splitArgs(command.value);
@@ -2639,7 +2645,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2645 {
2646 // Check the server version
2647 if ((user.siteadmin & 16) == 0) break;
2642 - if ((domain.myserver != null) && (domain.myserver.upgrade !== true)) break;
2648 + if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver.upgrade !== true))) break;
2649 //parent.parent.getLatestServerVersion(function (currentVersion, latestVersion) { try { ws.send(JSON.stringify({ action: 'serverversion', current: currentVersion, latest: latestVersion })); } catch (ex) { } });
2650 parent.parent.getServerTags(function (tags, err) { try { ws.send(JSON.stringify({ action: 'serverversion', tags: tags })); } catch (ex) { } });
2651 break;
@@ -2648,7 +2654,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2654 {
2655 // Perform server update
2656 if ((user.siteadmin & 16) == 0) break;
2651 - if ((domain.myserver != null) && (domain.myserver.upgrade !== true)) break;
2657 + if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver.upgrade !== true))) break;
2658 if ((command.version != null) && (typeof command.version != 'string')) break;
2659 parent.parent.performServerUpdate(command.version);
2660 break;
@@ -2657,7 +2663,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2663 {
2664 // Load the server error log
2665 if ((user.siteadmin & 16) == 0) break;
2660 - if ((domain.myserver != null) && (domain.myserver.errorlog !== true)) break;
2666 + if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver.errorlog !== true))) break;
2667 fs.readFile(parent.parent.getConfigFilePath('mesherrors.txt'), 'utf8', function (err, data) { try { ws.send(JSON.stringify({ action: 'servererrors', data: data })); } catch (ex) { } });
2668 break;
2669 }
@@ -4555,8 +4561,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4561 break;
4562 }
4563 case 'traceinfo': {
4558 - // Only accept is the tracing is allowed for this domain
4559 - if ((domain.myserver != null) && (domain.myserver.trace !== true)) break;
4564 + // Only accept if the tracing tab is allowed for this domain
4565 + if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver.trace !== true))) break;
4566
4567 if ((user.siteadmin === SITERIGHT_ADMIN) && (typeof command.traceSources == 'object')) {
4568 parent.parent.debugRemoteSources = command.traceSources;
views/default.handlebars
+1 -1
@@ -1833,7 +1833,7 @@
1833 //QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
1834 QV('p2AccountImage', !accountSettingsLocked)
1835 QV('p2ServerActions', (siteRights & 21) && ((serverFeatures & 15) != 0));
1836 - QV('LeftMenuMyServer', siteRights & 21); // 16 + 4 + 1
1836 + QV('LeftMenuMyServer', (siteRights & 21) && ((serverFeatures & 64) != 0)); // 16 + 4 + 1
1837 QV('MainMenuMyServer', siteRights & 21);
1838 QV('p2ServerActionsBackup', (siteRights & 1) && ((serverFeatures & 1) != 0));
1839 QV('p2ServerActionsRestore', (siteRights & 4) && ((serverFeatures & 2) != 0));
webserver.js
+7 -6
@@ -2371,8 +2371,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2371 if (domain.customui != null) { customui = encodeURIComponent(JSON.stringify(domain.customui)); }
2372
2373 // Server features
2374 - var serverFeatures = 63;
2375 - if (domain.myserver) {
2374 + var serverFeatures = 127;
2375 + if (domain.myserver === false) { serverFeatures = 0; } // 64 = Show "My Server" tab
2376 + else if (typeof domain.myserver == 'object') {
2377 if (domain.myserver.backup !== true) { serverFeatures -= 1; } // Disallow simple server backups
2378 if (domain.myserver.restore !== true) { serverFeatures -= 2; } // Disallow simple server restore
2379 if (domain.myserver.upgrade !== true) { serverFeatures -= 4; } // Disallow server upgrade
@@ -4063,7 +4064,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4064 if (domain == null) { return; }
4065 if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
4066 if ((!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
4066 - if ((domain.myserver != null) && (domain.myserver.backup !== true)) { res.sendStatus(401); return; }
4067 + if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver.backup !== true))) { res.sendStatus(401); return; }
4068
4069 var user = obj.users[req.session.userid];
4070 if ((user == null) || ((user.siteadmin & 1) == 0)) { res.sendStatus(401); return; } // Check if we have server backup rights
@@ -4092,7 +4093,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4093 const domain = checkUserIpAddress(req, res);
4094 if (domain == null) { return; }
4095 if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
4095 - if ((domain.myserver != null) && (domain.myserver.restore !== true)) { res.sendStatus(401); return; }
4096 + if ((domain.myserver === false) || ((domain.myserver != null) && (domain.myserver.restore !== true))) { res.sendStatus(401); return; }
4097
4098 var authUserid = null;
4099 if ((req.session != null) && (typeof req.session.userid == 'string')) { authUserid = req.session.userid; }
@@ -4818,8 +4819,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4819 obj.app.get(url, handleRootRequest);
4820 obj.app.post(url, handleRootPostRequest);
4821 obj.app.get(url + 'refresh.ashx', function (req, res) { res.sendStatus(200); });
4821 - if ((domain.myserver == null) || (domain.myserver.backup === true)) { obj.app.get(url + 'backup.zip', handleBackupRequest); }
4822 - if ((domain.myserver == null) || (domain.myserver.restore === true)) { obj.app.post(url + 'restoreserver.ashx', handleRestoreRequest); }
4822 + if ((domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.backup === true))) { obj.app.get(url + 'backup.zip', handleBackupRequest); }
4823 + if ((domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.restore === true))) { obj.app.post(url + 'restoreserver.ashx', handleRestoreRequest); }
4824 obj.app.get(url + 'terms', handleTermsRequest);
4825 obj.app.get(url + 'xterm', handleXTermRequest);
4826 obj.app.post(url + 'login', handleLoginRequest);