diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json
index 59a87ccb..71ab9e89 100644
--- a/meshcentral-config-schema.json
+++ b/meshcentral-config-schema.json
@@ -1414,6 +1414,11 @@
"type": "boolean",
"default": true,
"description": "Allows administrators to access the server trace tab from from the My Server tab."
+ },
+ "Config": {
+ "type": "boolean",
+ "default": true,
+ "description": "Allows administrators remotely view server configuration on the My Server tab."
}
}
},
diff --git a/meshcentral.js b/meshcentral.js
index 221f6415..4c32a980 100644
--- a/meshcentral.js
+++ b/meshcentral.js
@@ -3787,9 +3787,7 @@ function getConfig(createSampleConfig) {
// Read configuration file if present and change arguments.
var config = {}, configFilePath = path.join(datapath, 'config.json');
- if (args.configfile) {
- configFilePath = common.joinPath(datapath, args.configfile);
- }
+ if (args.configfile) { configFilePath = common.joinPath(datapath, args.configfile); }
if (fs.existsSync(configFilePath)) {
// Load and validate the configuration file
try { config = require(configFilePath); } catch (ex) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return null; }
diff --git a/meshuser.js b/meshuser.js
index f5833428..cdbbdb97 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -6513,10 +6513,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
}
function serverCommandServerConfig(command) {
- // Load the server config
- var configFilePath = common.joinPath(parent.parent.datapath, (parent.parent.args.configfile ? parent.parent.args.configfile : 'config.json'));
- if (userHasSiteUpdate())
+ // Load the server config.json. This is a sensitive file so care must be taken to only send to trusted administrators.
+ if (userHasSiteUpdate() && (domain.myserver !== false) && ((domain.myserver == null) || (domain.myserver.config === true))) {
+ const configFilePath = common.joinPath(parent.parent.datapath, (parent.parent.args.configfile ? parent.parent.args.configfile : 'config.json'));
fs.readFile(configFilePath, 'utf8', function (err, data) { obj.send({ action: 'serverconfig', data: data }); });
+ }
}
function serverCommandServerStats(command) {
diff --git a/sample-config-advanced.json b/sample-config-advanced.json
index 9840f13a..f083d1e3 100644
--- a/sample-config-advanced.json
+++ b/sample-config-advanced.json
@@ -289,7 +289,8 @@
"Upgrade": false,
"ErrorLog": false,
"Console": false,
- "Trace": false
+ "Trace": false,
+ "Config": false
},
"_passwordRequirements": {
"min": 8,
diff --git a/views/default.handlebars b/views/default.handlebars
index 91d9a0e6..90bbd52a 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -574,7 +574,7 @@
-
+
@@ -2151,14 +2151,14 @@
//QV('p2AccountImage', ((features & 4) == 0) && (serverinfo.domainauth == false)); // If account actions are not visible, also remove the image on that panel
QV('accountCreateLoginTokenSpan', features2 & 0x00000080);
QV('p2AccountImageFrame', !accountSettingsLocked)
- QV('p2ServerActions', (siteRights & 21) && ((serverFeatures & 15) != 0));
+ QV('p2ServerActions', (siteRights & 21) && ((serverFeatures & 143) != 0));
QV('LeftMenuMyServer', (siteRights & 21) && ((serverFeatures & 64) != 0)); // 16 + 4 + 1
QV('MainMenuMyServer', siteRights & 21);
QV('p2ServerActionsBackup', (siteRights & 1) && ((serverFeatures & 1) != 0));
QV('p2ServerActionsRestore', (siteRights & 4) && ((serverFeatures & 2) != 0));
QV('p2ServerActionsVersion', (siteRights & 16) && ((serverFeatures & 4) != 0));
QV('p2ServerActionsErrors', (siteRights & 16) && ((serverFeatures & 8) != 0));
- QV('p2ServerActionsConfig', (siteRights & 16) && ((serverFeatures & 8) != 0));
+ QV('p2ServerActionsConfig', (siteRights & 16) && ((serverFeatures & 128) != 0));
QV('MainMenuMyFiles', siteRights & 8);
QV('LeftMenuMyFiles', siteRights & 8);
if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
@@ -2746,7 +2746,7 @@
case 'servererrors': {
if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerErrors')) {
if (message.data == null) {
- setDialogMode(2, "MeshCentral Server Errors", 1, null, "Server has no error log.");
+ setDialogMode(2, "Server Errors", 1, null, "Server has no error log.");
} else {
var x = '' + EscapeHtml(message.data) + '
';
x += '
';
@@ -2760,11 +2760,14 @@
case 'serverconfig': {
if ((xxdialogMode == 2) && (xxdialogTag == 'MeshCentralServerConfig')) {
if (message.data == null) {
- setDialogMode(2, "MeshCentral Server Config", 1, null, "Server has no config file.");
+ setDialogMode(2, "Server Configuration", 1, null, "Server has no config file.");
} else {
- var x = '' + EscapeHtml(message.data) + '
';
- x += '
';
- setDialogMode(2, "MeshCentral Server Config", 3, null, x);
+ setDialogMode(4, "Server Configuration", 2);
+ QV('d4EncodingButton', false);
+ QS('dialog').width = 'auto';
+ QS('dialog').bottom = '80px';
+ QS('dialog').top = QS('dialog').left = QS('dialog').right = '100px';
+ Q('d4editorarea').value = message.data;
}
}
break;
@@ -2998,6 +3001,7 @@
meshserver.send({ action: 'fileoperation', fileop: 'set', path: tag.path, file: tag.file, data: btoa(data) });
}
setDialogMode(4, EscapeHtml(message.file), 3, p5editSaveBack, null, message);
+ QV('d4EncodingButton', true);
QS('dialog').width = 'auto';
QS('dialog').bottom = '80px';
QS('dialog').top = QS('dialog').left = QS('dialog').right = '100px';
@@ -11073,6 +11077,7 @@
if (gdownloadFile.tag == 'viewer') {
// View the file in the dialog box
setDialogMode(4, EscapeHtml(gdownloadFile.file), 3, p13editSaveBack, null, gdownloadFile.file);
+ QV('d4EncodingButton', true);
QS('dialog').width = 'auto';
QS('dialog').bottom = '80px';
QS('dialog').top = QS('dialog').left = QS('dialog').right = '100px';
@@ -12640,7 +12645,7 @@
function server_showErrorsDlg() {
if (xxdialogMode) return false;
- setDialogMode(2, "MeshCentral Errors", 1, null, "Loading...", 'MeshCentralServerErrors');
+ setDialogMode(2, "Server Errors", 1, null, "Loading...", 'MeshCentralServerErrors');
meshserver.send({ action: 'servererrors' });
return false;
}
@@ -12650,7 +12655,7 @@
function server_showConfigDlg() {
if (xxdialogMode) return false;
- setDialogMode(2, "MeshCentral Server Config", 1, null, "Loading...", 'MeshCentralServerConfig');
+ setDialogMode(2, "Server Configuration", 1, null, "Loading...", 'MeshCentralServerConfig');
meshserver.send({ action: 'serverconfig' });
return false;
}
diff --git a/webserver.js b/webserver.js
index 864f6d15..3bb9e851 100644
--- a/webserver.js
+++ b/webserver.js
@@ -3063,7 +3063,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (domain.customui != null) { customui = encodeURIComponent(JSON.stringify(domain.customui)); }
// Server features
- var serverFeatures = 127;
+ var serverFeatures = 255;
if (domain.myserver === false) { serverFeatures = 0; } // 64 = Show "My Server" tab
else if (typeof domain.myserver == 'object') {
if (domain.myserver.backup !== true) { serverFeatures -= 1; } // Disallow simple server backups
@@ -3072,6 +3072,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (domain.myserver.errorlog !== true) { serverFeatures -= 8; } // Disallow show server crash log
if (domain.myserver.console !== true) { serverFeatures -= 16; } // Disallow server console
if (domain.myserver.trace !== true) { serverFeatures -= 32; } // Disallow server tracing
+ if (domain.myserver.config !== true) { serverFeatures -= 128; } // Disallow server configuration
}
if (obj.db.databaseType != 1) { // If not using NeDB, we can't backup using the simple system.
if ((serverFeatures & 1) != 0) { serverFeatures -= 1; } // Disallow server backups