Merge branch 'Ylianst:master' into master

This commit is contained in:
itNGO 2022-02-09 15:11:13 +01:00 committed by GitHub
commit 6cb08efde2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 837 additions and 719 deletions

View File

@ -90,7 +90,9 @@
"agentVersion": "Neue Version",
"elevation": "Zum Installieren/Deinstallieren dieser Software sind erhöhte Berechtigungen erforderlich.",
"graphicalerror": "Die grafische Version dieses Installationsprogramms kann auf diesem System nicht ausgeführt werden",
"description": "Klicken Sie auf die Schaltflächen unten, um diese Fernverwaltungssoftware zu installieren oder zu deinstallieren. Nach der Installation wird diese Software im Hintergrund ausgeführt, sodass dieser Computer von einem entfernten Administrator verwaltet und gesteuert werden kann."
"description": "Klicken Sie auf die Schaltflächen unten, um diese Fernverwaltungssoftware zu installieren oder zu deinstallieren. Nach der Installation wird diese Software im Hintergrund ausgeführt, sodass dieser Computer von einem entfernten Administrator verwaltet und gesteuert werden kann.",
"connectionDetailsButton": "Verbindungsinformationen...",
"connectionDetailsTitle": "Verbindungsinformationen"
},
"es": {
"agent": "Agente",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3177,8 +3177,20 @@ function openUserDesktopUrl(url) {
var uid = require('user-sessions').consoleUid();
var user = require('user-sessions').getUsername(uid);
var domain = require('user-sessions').getDomain(uid);
var task = { name: 'MeshChatTask', user: user, domain: domain, execPath: process.env['windir'] + '\\system32\\cmd.exe', arguments: ['/C START ' + url.split('&').join('^&')] };
try
{
require('win-tasks').addTask(task);
require('win-tasks').getTask({ name: 'MeshChatTask' }).run();
require('win-tasks').deleteTask('MeshChatTask');
return (true);
}
catch(zz)
{
var taskoptions = { env: { _target: process.env['windir'] + '\\system32\\cmd.exe', _args: '/C START ' + url.split('&').join('^&'), _user: '"' + domain + '\\' + user + '"' } };
for (var c1e in process.env) {
for (var c1e in process.env)
{
taskoptions.env[c1e] = process.env[c1e];
}
var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], taskoptions);
@ -3201,6 +3213,7 @@ function openUserDesktopUrl(url) {
child.stdin.write('SCHTASKS /RUN /TN MeshChatTask\r\n');
child.stdin.write('SCHTASKS /DELETE /F /TN MeshChatTask\r\nexit\r\n');
child.waitExit();
}
break;
case 'linux':
child = require('child_process').execFile('/usr/bin/xdg-open', ['xdg-open', url], { uid: require('user-sessions').consoleUid() });

View File

@ -299,7 +299,9 @@
"titlePicture": { "type": "string", "default": null, "description": "Web site .png logo file that is 450x66 in size placed in meshcentral-data that is used on the top of many pages." },
"loginPicture": { "type": "string", "default": null, "description": "Web site .png logo file placed in meshcentral-data that used on the login page when sitestyle is 2." },
"rootRedirect": { "type": "string", "default": null, "description": "Redirects HTTP root requests to this URL. When in use, direct users to /login to see the normal login page." },
"mobileSite": { "type": "boolean", "default": true, "description": "When set to false, this setting will disable the mobile site." },
"unknownUserRootRedirect": { "type": "string", "default": null, "description": "Redirects HTTP root requests to this URL only where user is not already logged in. When in use, direct users to /login to see the normal login page." },
"nightMode": { "type": "integer", "default": 0, "description": "0 = User selects day/night mode, 1 = Always night mode, 2 = Always day mode" },
"userQuota": { "type": "integer" },
"meshQuota": { "type": "integer" },
"loginKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." },
@ -442,6 +444,8 @@
"sms2factor": { "type": "boolean", "default": true, "description": "Set to false to disable SMS 2FA." },
"push2factor": { "type": "boolean", "default": true, "description": "Set to false to disable push notification 2FA." },
"otp2factor": { "type": "boolean", "default": true, "description": "Set to false to disable one-time-password 2FA." },
"backupcode2factor": { "type": "boolean", "default": true, "description": "Set to false to disable 2FA backup codes." },
"single2factorWarning": { "type": "boolean", "default": true, "description": "Set to false to disable single 2FA warning." },
"lock2factor": { "type": "boolean", "default": false, "description": "When set to true, prevents any changes to 2FA." },
"force2factor": { "type": "boolean", "default": false, "description": "Requires that all accounts setup 2FA." },
"skip2factor": { "type": "string", "description": "IP addresses where 2FA login is skipped, for example: 127.0.0.1,192.168.2.0/24" },
@ -450,7 +454,8 @@
"loginTokens": { "type": "boolean", "default": true, "description": "Allows users to create alternative username/passwords for their account." },
"twoFactorTimeout": { "type": "integer", "default": 300, "description": "Maximum about of time the to wait for a 2FA token on the login page in seconds." },
"autofido2fa": { "type": "boolean", "default": false, "description": "If true and user account has FIDO key setup, 2FA login screen will automatically request FIDO 2FA." },
"maxfidokeys": { "type": "integer", "default": null, "description": "Maximum number of FIDO/YubikeyOTP hardware 2FA keys that can be setup in a user account." }
"maxfidokeys": { "type": "integer", "default": null, "description": "Maximum number of FIDO/YubikeyOTP hardware 2FA keys that can be setup in a user account." },
"allowaccountreset": { "type": "boolean", "default": true, "description": "If set to false, the account reset option on the login screen will not be available to users." }
}
},
"twoFactorCookieDurationDays": { "type": "integer", "default": 30, "description": "Number of days that a user is allowed to remember this device for when completing 2FA. Set this to 0 to remove this option." },
@ -510,6 +515,7 @@
"description": { "type": "string", "default": "Mesh Agent background service", "description": "The description of the agent as displayed to the user." },
"companyName": { "type": "string", "default": "Mesh Agent", "description": "This will be used as the path to install the agent, by default this is 'Mesh Agent' in Windows and 'meshagent' in other OS's." },
"serviceName": { "type": "string", "default": "Mesh Agent", "description": "The name of the background service, by default this is 'Mesh Agent' in Windows and 'meshagent' in other OS's but should be set to an all lower case, no space string." },
"installText": { "type": "string", "default": null, "description": "Text string to show in the agent installation dialog box." },
"image": { "type": "string", "default": null, "description": "The filename of a image file in .png format located in meshcentral-data to display in the MeshCentral Agent installation dialog, image should be square and from 64x64 to 200x200." },
"fileName": { "type": "string", "default": "meshagent", "description": "The agent filename." }
}

View File

@ -17,7 +17,7 @@
const common = require('./common.js');
// If app metrics is available
if (process.argv[2] == '--launch') { try { require('appmetrics-dash').monitor({ url: '/', title: 'MeshCentral', port: 88, host: '127.0.0.1' }); } catch (e) { } }
if (process.argv[2] == '--launch') { try { require('appmetrics-dash').monitor({ url: '/', title: 'MeshCentral', port: 88, host: '127.0.0.1' }); } catch (ex) { } }
function CreateMeshCentralServer(config, args) {
var obj = {};
@ -76,7 +76,7 @@ function CreateMeshCentralServer(config, args) {
// Server version
obj.currentVer = null;
function getCurrentVersion() { try { obj.currentVer = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { } return obj.currentVer; } // Fetch server version
function getCurrentVersion() { try { obj.currentVer = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (ex) { } return obj.currentVer; } // Fetch server version
getCurrentVersion();
// Setup the default configuration and files paths
@ -118,8 +118,8 @@ function CreateMeshCentralServer(config, args) {
if (obj.config.settings && (typeof obj.config.settings.filespath == 'string')) { obj.filespath = obj.config.settings.filespath; }
// Create data and files folders if needed
try { obj.fs.mkdirSync(obj.datapath); } catch (e) { }
try { obj.fs.mkdirSync(obj.filespath); } catch (e) { }
try { obj.fs.mkdirSync(obj.datapath); } catch (ex) { }
try { obj.fs.mkdirSync(obj.filespath); } catch (ex) { }
// Windows Specific Code, setup service and event log
obj.service = null;
@ -134,10 +134,10 @@ function CreateMeshCentralServer(config, args) {
// Start the Meshcentral server
obj.Start = function () {
var i;
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.
try { require('./pass').hash('test', function () { }, 0); } catch (ex) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
// Check for invalid arguments
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', 'removesubdomain', 'adminaccount', 'domain', 'email', 'configfile', 'maintenancemode', 'nedbtodb', 'removetestagents', 'agentupdatetest', 'hashpassword', 'hashpass', 'indexmcrec', 'mpsdebug'];
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', 'removesubdomain', 'adminaccount', 'domain', 'email', 'configfile', 'maintenancemode', 'nedbtodb', 'removetestagents', 'agentupdatetest', 'hashpassword', 'hashpass', 'indexmcrec', 'mpsdebug', 'dumpcores'];
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; } }
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; }
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.
@ -173,7 +173,7 @@ function CreateMeshCentralServer(config, args) {
// Fix a NeDB database
if (obj.args.dbfix) {
var lines = null, badJsonCount = 0, feildNames = [], fixedDb = [];
try { lines = obj.fs.readFileSync(obj.getConfigFilePath(obj.args.dbfix), { encoding: 'utf8' }).split('\n'); } catch (e) { console.log('Invalid file: ' + obj.args.dbfix + ': ' + e); process.exit(); }
try { lines = obj.fs.readFileSync(obj.getConfigFilePath(obj.args.dbfix), { encoding: 'utf8' }).split('\n'); } catch (ex) { console.log('Invalid file: ' + obj.args.dbfix + ': ' + ex); process.exit(); }
for (var i = 0; i < lines.length; i++) {
var x = null;
try { x = JSON.parse(lines[i]); } catch (ex) { badJsonCount++; }
@ -190,6 +190,9 @@ function CreateMeshCentralServer(config, args) {
// Perform a password hash
if (obj.args.hashpassword) { require('./pass').hash(obj.args.hashpassword, function (err, salt, hash, tag) { console.log(salt + ',' + hash); process.exit(); }); return; }
// Dump to mesh cores
if (obj.args.dumpcores) { obj.updateMeshCore(function () { console.log('Done.'); }, true); return; }
// Perform web site translations into different languages
if (obj.args.translate) {
// Check NodeJS version
@ -381,10 +384,10 @@ function CreateMeshCentralServer(config, args) {
svc.on('alreadyinstalled', function () { console.log('MeshCentral service already installed.'); process.exit(); });
svc.on('invalidinstallation', function () { console.log('Invalid MeshCentral service installation.'); process.exit(); });
if (obj.args.xinstall == true) { try { svc.install(); } catch (e) { logException(e); } }
if (obj.args.stop == true || obj.args.restart == true) { try { svc.stop(); } catch (e) { logException(e); } }
if (obj.args.start == true) { try { svc.start(); } catch (e) { logException(e); } }
if (obj.args.xuninstall == true) { try { svc.uninstall(); } catch (e) { logException(e); } }
if (obj.args.xinstall == true) { try { svc.install(); } catch (ex) { logException(ex); } }
if (obj.args.stop == true || obj.args.restart == true) { try { svc.stop(); } catch (ex) { logException(ex); } }
if (obj.args.start == true) { try { svc.start(); } catch (ex) { logException(ex); } }
if (obj.args.xuninstall == true) { try { svc.uninstall(); } catch (ex) { logException(ex); } }
return;
}
@ -534,7 +537,7 @@ function CreateMeshCentralServer(config, args) {
xxprocess.stderr.on('data', function (data) { });
xxprocess.on('close', function (code) {
var latestVer = null;
if (code == 0) { try { latestVer = xxprocess.data.split(' ').join('').split('\r').join('').split('\n').join(''); } catch (e) { } }
if (code == 0) { try { latestVer = xxprocess.data.split(' ').join('').split('\r').join('').split('\n').join(''); } catch (ex) { } }
callback(getCurrentVersion(), latestVer);
});
} catch (ex) { callback(getCurrentVersion(), null, ex); } // If the system is running out of memory, an exception here can easily happen.
@ -560,7 +563,7 @@ function CreateMeshCentralServer(config, args) {
try {
var lines = xxprocess.data.split('\r\n').join('\n').split('\n');
for (var i in lines) { var s = lines[i].split(': '); if ((s.length == 2) && (obj.args.npmtag == null) || (obj.args.npmtag == s[0])) { tags[s[0]] = s[1]; } }
} catch (e) { }
} catch (ex) { }
}
callback(tags);
});
@ -1045,10 +1048,10 @@ function CreateMeshCentralServer(config, args) {
// Import the entire database from a JSON file
if (obj.args.dbimport == true) { obj.args.dbimport = obj.getConfigFilePath('meshcentral.db.json'); }
var json = null, json2 = '', badCharCount = 0;
try { json = obj.fs.readFileSync(obj.args.dbimport, { encoding: 'utf8' }); } catch (e) { console.log('Invalid JSON file: ' + obj.args.dbimport + ': ' + e); process.exit(); }
try { json = obj.fs.readFileSync(obj.args.dbimport, { encoding: 'utf8' }); } catch (ex) { console.log('Invalid JSON file: ' + obj.args.dbimport + ': ' + ex); process.exit(); }
for (i = 0; i < json.length; i++) { if (json.charCodeAt(i) >= 32) { json2 += json[i]; } else { var tt = json.charCodeAt(i); if (tt != 10 && tt != 13) { badCharCount++; } } } // Remove all bad chars
if (badCharCount > 0) { console.log(badCharCount + ' invalid character(s) where removed.'); }
try { json = JSON.parse(json2); } catch (e) { console.log('Invalid JSON format: ' + obj.args.dbimport + ': ' + e); process.exit(); }
try { json = JSON.parse(json2); } catch (ex) { console.log('Invalid JSON format: ' + obj.args.dbimport + ': ' + e); process.exit(); }
if ((json == null) || (typeof json.length != 'number') || (json.length < 1)) { console.log('Invalid JSON format: ' + obj.args.dbimport + '.'); }
// Escape MongoDB invalid field chars
for (i in json) {
@ -1086,10 +1089,10 @@ function CreateMeshCentralServer(config, args) {
// Import the entire database from a JSON file
if (obj.args.dbmerge == true) { obj.args.dbmerge = obj.getConfigFilePath('meshcentral.db.json'); }
var json = null, json2 = "", badCharCount = 0;
try { json = obj.fs.readFileSync(obj.args.dbmerge, { encoding: 'utf8' }); } catch (e) { console.log('Invalid JSON file: ' + obj.args.dbmerge + ': ' + e); process.exit(); }
try { json = obj.fs.readFileSync(obj.args.dbmerge, { encoding: 'utf8' }); } catch (ex) { console.log('Invalid JSON file: ' + obj.args.dbmerge + ': ' + ex); process.exit(); }
for (i = 0; i < json.length; i++) { if (json.charCodeAt(i) >= 32) { json2 += json[i]; } else { var tt = json.charCodeAt(i); if (tt != 10 && tt != 13) { badCharCount++; } } } // Remove all bad chars
if (badCharCount > 0) { console.log(badCharCount + ' invalid character(s) where removed.'); }
try { json = JSON.parse(json2); } catch (e) { console.log('Invalid JSON format: ' + obj.args.dbmerge + ': ' + e); process.exit(); }
try { json = JSON.parse(json2); } catch (ex) { console.log('Invalid JSON format: ' + obj.args.dbmerge + ': ' + ex); process.exit(); }
if ((json == null) || (typeof json.length != 'number') || (json.length < 1)) { console.log('Invalid JSON format: ' + obj.args.dbimport + '.'); }
// Get all users from current database
@ -1556,7 +1559,17 @@ function CreateMeshCentralServer(config, args) {
var translations = JSON.parse(obj.fs.readFileSync(translationpath).toString());
if (translations['zh-chs']) { translations['zh-hans'] = translations['zh-chs']; delete translations['zh-chs']; }
if (translations['zh-cht']) { translations['zh-hant'] = translations['zh-cht']; delete translations['zh-cht']; }
obj.agentTranslations = JSON.stringify(translations);
// If there is domain customizations to the agent strings, do this here.
for (var i in obj.config.domains) {
var domainTranslations = translations;
if ((typeof obj.config.domains[i].agentcustomization == 'object') && (typeof obj.config.domains[i].agentcustomization.installtext == 'string')) {
domainTranslations = Object.assign({}, domainTranslations); // Shallow clone
for (var j in domainTranslations) { delete domainTranslations[j].description; }
domainTranslations.en.description = obj.config.domains[i].agentcustomization.installtext;
}
obj.config.domains[i].agentTranslations = JSON.stringify(domainTranslations);
}
} catch (ex) { }
// Load the list of mesh agents and install scripts
@ -2428,7 +2441,7 @@ function CreateMeshCentralServer(config, args) {
}
// Update the default mesh core
obj.updateMeshCore = function (func) {
obj.updateMeshCore = function (func, dumpToFile) {
// Figure out where meshcore.js is
var meshcorePath = obj.datapath;
if (obj.fs.existsSync(obj.path.join(meshcorePath, 'meshcore.js')) == false) {
@ -2476,12 +2489,12 @@ function CreateMeshCentralServer(config, args) {
}
}
if (obj.args.minifycore !== false) { try { meshCore = obj.fs.readFileSync(obj.path.join(meshcorePath, 'meshcore.min.js')).toString(); } catch (e) { } } // Favor minified meshcore if present.
if (meshCore == null) { try { meshCore = obj.fs.readFileSync(obj.path.join(meshcorePath, 'meshcore.js')).toString(); } catch (e) { } } // Use non-minified meshcore.
if (obj.args.minifycore !== false) { try { meshCore = obj.fs.readFileSync(obj.path.join(meshcorePath, 'meshcore.min.js')).toString(); } catch (ex) { } } // Favor minified meshcore if present.
if (meshCore == null) { try { meshCore = obj.fs.readFileSync(obj.path.join(meshcorePath, 'meshcore.js')).toString(); } catch (ex) { } } // Use non-minified meshcore.
if (meshCore != null) {
var moduleDirPath = null;
if (obj.args.minifycore !== false) { try { moduleDirPath = obj.path.join(meshcorePath, 'modules_meshcore_min'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (e) { } } // Favor minified modules if present.
if (modulesDir == null) { try { moduleDirPath = obj.path.join(meshcorePath, 'modules_meshcore'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (e) { } } // Use non-minified mofules.
if (obj.args.minifycore !== false) { try { moduleDirPath = obj.path.join(meshcorePath, 'modules_meshcore_min'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (ex) { } } // Favor minified modules if present.
if (modulesDir == null) { try { moduleDirPath = obj.path.join(meshcorePath, 'modules_meshcore'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (ex) { } } // Use non-minified mofules.
if (modulesDir != null) {
for (var i in modulesDir) {
if (modulesDir[i].toLowerCase().endsWith('.json')) {
@ -2500,7 +2513,7 @@ function CreateMeshCentralServer(config, args) {
// We are adding a JS file to the meshcores
var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3);
if (moduleName.endsWith('.min')) { moduleName = moduleName.substring(0, moduleName.length - 4); } // Remove the ".min" for ".min.js" files.
const moduleData = [ 'try { addModule("', moduleName, '", "', obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')), '"); addedModules.push("', moduleName, '"); } catch (e) { }\r\n' ];
const moduleData = [ 'try { addModule("', moduleName, '", "', obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')), '"); addedModules.push("', moduleName, '"); } catch (ex) { }\r\n' ];
// Merge this module
// NOTE: "smbios" module makes some non-AI Linux segfault, only include for IA platforms.
@ -2542,6 +2555,9 @@ function CreateMeshCentralServer(config, args) {
// Add plugins to cores
if (obj.pluginHandler) { obj.pluginHandler.addMeshCoreModules(modulesAdd); }
// If we need to dump modules to file, create a meshcores folder
if (dumpToFile) { try { obj.fs.mkdirSync('meshcores'); } catch (ex) { } }
// Merge the cores and compute the hashes
for (var i in modulesAdd) {
if ((i == 'windows-recovery') || (i == 'linux-recovery')) {
@ -2557,9 +2573,11 @@ function CreateMeshCentralServer(config, args) {
obj.defaultMeshCoresHash[i] = obj.crypto.createHash('sha384').update(obj.defaultMeshCores[i]).digest('binary');
obj.debug('main', 'Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.');
// These lines will write all modules to files. Great for debugging.
//console.log('Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.'); // DEBUG, Print the core size
//obj.fs.writeFile("C:\\temp\\" + i + ".js", obj.defaultMeshCores[i].slice(4), function () { }); // DEBUG, Write the core to file
// Write all modules to files. Great for debugging.
if (dumpToFile) {
console.log('Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes, saving to meshcores/' + i + '.js.'); // Print the core size and filename
obj.fs.writeFile('meshcores/' + i + '.js', obj.defaultMeshCores[i].slice(4), function () { }); // Write the core to file
}
// Compress the mesh cores with DEFLATE
const callback = function MeshCoreDeflateCb(err, buffer) { if (err == null) { obj.defaultMeshCoresDeflate[MeshCoreDeflateCb.i] = buffer; } }
@ -2585,10 +2603,10 @@ function CreateMeshCentralServer(config, args) {
meshCmd = meshCmd.replace("'***Mesh*Cmd*Version***'", '\'' + getCurrentVersion() + '\'');
// Figure out where the modules_meshcmd folder is.
if (obj.args.minifycore !== false) { try { moduleDirPath = obj.path.join(meshcmdPath, 'modules_meshcmd_min'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (e) { } } // Favor minified modules if present.
if (modulesDir == null) { try { moduleDirPath = obj.path.join(meshcmdPath, 'modules_meshcmd'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (e) { } } // Use non-minified mofules.
if (obj.args.minifycore !== false) { if (modulesDir == null) { try { moduleDirPath = obj.path.join(__dirname, 'agents', 'modules_meshcmd_min'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (e) { } } } // Favor minified modules if present.
if (modulesDir == null) { try { moduleDirPath = obj.path.join(__dirname, 'agents', 'modules_meshcmd'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (e) { } } // Use non-minified mofules.
if (obj.args.minifycore !== false) { try { moduleDirPath = obj.path.join(meshcmdPath, 'modules_meshcmd_min'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (ex) { } } // Favor minified modules if present.
if (modulesDir == null) { try { moduleDirPath = obj.path.join(meshcmdPath, 'modules_meshcmd'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (ex) { } } // Use non-minified mofules.
if (obj.args.minifycore !== false) { if (modulesDir == null) { try { moduleDirPath = obj.path.join(__dirname, 'agents', 'modules_meshcmd_min'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (ex) { } } } // Favor minified modules if present.
if (modulesDir == null) { try { moduleDirPath = obj.path.join(__dirname, 'agents', 'modules_meshcmd'); modulesDir = obj.fs.readdirSync(moduleDirPath); } catch (ex) { } } // Use non-minified mofules.
// Read all .js files in the meshcmd modules folder.
if (modulesDir != null) {
@ -2597,7 +2615,7 @@ function CreateMeshCentralServer(config, args) {
// Merge this module
var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3);
if (moduleName.endsWith('.min')) { moduleName = moduleName.substring(0, moduleName.length - 4); } // Remove the ".min" for ".min.js" files.
moduleAdditions.push('try { addModule("', moduleName, '", "', obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')), '"); addedModules.push("', moduleName, '"); } catch (e) { }\r\n');
moduleAdditions.push('try { addModule("', moduleName, '", "', obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')), '"); addedModules.push("', moduleName, '"); } catch (ex) { }\r\n');
}
}
}
@ -2643,7 +2661,7 @@ function CreateMeshCentralServer(config, args) {
obj.meshToolsBinaries[this.toolname] = { hash: data.toString('hex'), hashx: this.hashx, path: this.toolpath, dlname: this.dlname, url: this.url };
obj.meshToolsBinaries[this.toolname].url = 'https://' + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?meshaction=' + this.dlname;
var stats = null;
try { stats = obj.fs.statSync(this.toolpath); } catch (e) { }
try { stats = obj.fs.statSync(this.toolpath); } catch (ex) { }
if (stats != null) { obj.meshToolsBinaries[this.toolname].size = stats.size; }
});
var options = { sourcePath: toolpath, targetStream: hashStream };
@ -2670,7 +2688,7 @@ function CreateMeshCentralServer(config, args) {
obj.meshToolsBinaries[this.toolname].dlname = this.dlname;
obj.meshToolsBinaries[this.toolname].url = 'https://' + obj.certificates.CommonName + ':' + ((typeof obj.args.aliasport == 'number') ? obj.args.aliasport : obj.args.port) + '/meshagents?meshaction=' + this.dlname;
var stats = null;
try { stats = obj.fs.statSync(this.agentpath); } catch (e) { }
try { stats = obj.fs.statSync(this.agentpath); } catch (ex) { }
if (stats != null) { obj.meshToolsBinaries[this.toolname].size = stats.size; }
});
stream.toolname = toolname;
@ -2678,7 +2696,7 @@ function CreateMeshCentralServer(config, args) {
stream.dlname = meshToolsList[toolname].dlname;
stream.hash = obj.crypto.createHash('sha384', stream);
stream.hashx = 0;
} catch (e) { }
} catch (ex) { }
}
}
};
@ -2712,7 +2730,7 @@ function CreateMeshCentralServer(config, args) {
obj.meshAgentInstallScripts[this.info.id].data = this.xdata;
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;
var stats = null;
try { stats = obj.fs.statSync(this.agentpath); } catch (e) { }
try { stats = obj.fs.statSync(this.agentpath); } catch (ex) { }
if (stats != null) { obj.meshAgentInstallScripts[this.info.id].size = stats.size; }
// Place Unit line breaks on Linux scripts if not already present.
@ -2721,7 +2739,7 @@ function CreateMeshCentralServer(config, args) {
stream.info = meshAgentsInstallScriptList[scriptid];
stream.agentpath = scriptpath;
stream.hash = obj.crypto.createHash('sha384', stream);
} catch (e) { }
} catch (ex) { }
}
};
@ -2786,7 +2804,7 @@ function CreateMeshCentralServer(config, args) {
// Fetch all the agent binary information
var stats = null;
try { stats = obj.fs.statSync(agentpath); } catch (e) { }
try { stats = obj.fs.statSync(agentpath); } catch (ex) { }
if ((stats != null)) {
// If file exists
archcount++;
@ -2798,7 +2816,7 @@ function CreateMeshCentralServer(config, args) {
// If this is a windows binary, pull binary information
if (obj.meshAgentsArchitectureNumbers[archid].platform == 'win32') {
try { obj.meshAgentBinaries[archid].pe = obj.exeHandler.parseWindowsExecutable(agentpath); } catch (e) { }
try { obj.meshAgentBinaries[archid].pe = obj.exeHandler.parseWindowsExecutable(agentpath); } catch (ex) { }
}
// If agents must be stored in RAM or if this is a Windows 32/64 agent, load the agent in RAM.
@ -3235,7 +3253,7 @@ function getConfig(createSampleConfig) {
datapath = path.join(__dirname, '../meshcentral-data');
}
if (args.datapath) { datapath = args.datapath; }
try { fs.mkdirSync(datapath); } catch (e) { }
try { fs.mkdirSync(datapath); } catch (ex) { }
// Read configuration file if present and change arguments.
var config = {}, configFilePath = path.join(datapath, 'config.json');
@ -3244,7 +3262,7 @@ function getConfig(createSampleConfig) {
}
if (fs.existsSync(configFilePath)) {
// Load and validate the configuration file
try { config = require(configFilePath); } catch (e) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return null; }
try { config = require(configFilePath); } catch (ex) { console.log('ERROR: Unable to parse ' + configFilePath + '.'); return null; }
if (config.domains == null) { config.domains = {}; }
for (i in config.domains) { if ((i.split('/').length > 1) || (i.split(' ').length > 1)) { console.log("ERROR: Error in config.json, domain names can't have spaces or /."); return null; } }
} else {
@ -3292,7 +3310,7 @@ function InstallModules(modules, func) {
if (typeof dependencies[moduleName] != undefined) { moduleVersion = dependencies[moduleName]; }
require(moduleName);
}
} catch (e) {
} catch (ex) {
if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(moduleNameAndVersion); }
}
}

View File

@ -58,10 +58,11 @@ MNG_ENCAPSULATE_AGENT_COMMAND = 70,
MNG_KVM_DISPLAY_INFO = 82
*/
function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
function CreateDesktopMultiplexor(parent, domain, nodeid, id, func) {
var obj = {};
obj.nodeid = nodeid;
obj.parent = parent;
obj.id = id; // Unique identifier for this session
obj.nodeid = nodeid; // Remote device nodeid for this session
obj.parent = parent; // Parent web server instance
obj.agent = null; // Reference to the connection object that is the agent.
obj.viewers = []; // Array of references to all viewers.
obj.viewersOverflowCount = 0; // Number of viewers currently in overflow state.
@ -180,7 +181,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
// Log joining the multiplex session
if (obj.startTime != null) {
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: peer.user ? peer.user._id : null, username: peer.user.name, msgid: 4, msg: "Joined desktop multiplex session", protocol: 2 };
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: peer.user ? peer.user._id : null, username: peer.user.name, msgid: 143, msgArgs: [obj.id], msg: "Joined desktop multiplex session \"" + obj.id + "\"", protocol: 2 };
parent.parent.DispatchEvent(['*', obj.nodeid, peer.user._id, obj.meshid], obj, event);
}
@ -208,7 +209,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
// Log multiplex session start
if ((obj.agent != null) && (obj.viewers.length > 0) && (obj.startTime == null)) {
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, msgid: 6, msg: "Started desktop multiplex session", protocol: 2 };
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, msgid: 145, msgArgs: [obj.id], msg: "Started desktop multiplex session \"" + obj.id + "\"", protocol: 2 };
if (obj.viewers[0].user != null) { event.userid = obj.viewers[0].user._id; event.username = obj.viewers[0].user.name; }
const targets = ['*', obj.nodeid, obj.meshid];
if (obj.viewers[0].user != null) { targets.push(obj.viewers[0].user._id); }
@ -288,7 +289,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
//var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: peer.user._id, username: peer.user.name, msgid: 5, msg: "Left the desktop multiplex session", protocol: 2 };
const sessionSeconds = Math.floor((Date.now() - peer.startTime) / 1000);
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, msgid: 122, msgArgs: [sessionSeconds], msg: "Left the desktop multiplex session after " + sessionSeconds + " second(s).", protocol: 2, bytesin: inTraffc, bytesout: outTraffc };
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, msgid: 144, msgArgs: [obj.id, sessionSeconds], msg: "Left the desktop multiplex session \"" + obj.id + "\" after " + sessionSeconds + " second(s).", protocol: 2, bytesin: inTraffc, bytesout: outTraffc };
if (peer.user != null) { event.userid = peer.user._id; event.username = peer.user.name; }
if (peer.guestName) { event.guestname = peer.guestName; }
const targets = ['*', obj.nodeid, obj.meshid];
@ -342,7 +343,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
// Add a event entry about this recording
var basefile = parent.parent.path.basename(filename);
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: obj.nodeid, msgid: 7, msgArgs: [obj.sessionLength], msg: "Finished recording session" + (obj.sessionLength ? (', ' + obj.sessionLength + ' second(s)') : ''), filename: basefile, size: obj.recordingFileSize, protocol: 2, icon: obj.icon, name: obj.name, meshid: obj.meshid, userids: obj.userIds, multiplex: true };
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: obj.nodeid, msgid: 146, msgArgs: [obj.id, obj.sessionLength], msg: "Finished recording session \"" + obj.id + "\", " + obj.sessionLength + " second(s)", filename: basefile, size: obj.recordingFileSize, protocol: 2, icon: obj.icon, name: obj.name, meshid: obj.meshid, userids: obj.userIds, multiplex: true };
var mesh = parent.meshes[obj.meshid];
if (mesh != null) { event.meshname = mesh.name; }
if (obj.sessionStart) { event.startTime = obj.sessionStart; event.lengthTime = obj.sessionLength; }
@ -354,7 +355,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
// Log end of multiplex session
if (obj.startTime != null) {
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, msgid: 8, msgArgs: [Math.floor((Date.now() - obj.startTime) / 1000)], msg: "Closed desktop multiplex session" + ', ' + Math.floor((Date.now() - obj.startTime) / 1000) + ' second(s)', protocol: 2 };
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, msgid: 147, msgArgs: [obj.id, Math.floor((Date.now() - obj.startTime) / 1000)], msg: "Closed desktop multiplex session \"" + obj.id + "\", " + Math.floor((Date.now() - obj.startTime) / 1000) + ' second(s)', protocol: 2 };
parent.parent.DispatchEvent(['*', obj.nodeid, obj.meshid], obj, event);
obj.startTime = null;
}
@ -1203,7 +1204,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
if (obj.deskMultiplexor == null) {
parent.desktoprelays[obj.nodeid] = 1; // Indicate that the creating of the desktop multiplexor is pending.
parent.parent.debug('relay', 'DesktopRelay: Creating new desktop multiplexor');
CreateDesktopMultiplexor(parent, domain, obj.nodeid, function (deskMultiplexor) {
CreateDesktopMultiplexor(parent, domain, obj.nodeid, obj.id, function (deskMultiplexor) {
if (deskMultiplexor != null) {
// Desktop multiplexor was created, use it.
obj.deskMultiplexor = deskMultiplexor;

View File

@ -3183,6 +3183,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Do not allow this command if 2FA's are locked
if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return;
// Do not allow this command if backup codes are not allowed
if ((domain.passwordrequirements) && (domain.passwordrequirements.backupcode2factor == false)) return;
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
@ -3211,6 +3214,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Do not allow this command if 2FA's are locked
if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return;
// Do not allow this command if backup codes are not allowed
if ((domain.passwordrequirements) && (domain.passwordrequirements.backupcode2factor == false)) return;
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
@ -3250,6 +3256,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Do not allow this command if 2FA's are locked
if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return;
// Do not allow this command if backup codes are not allowed
if ((domain.passwordrequirements) && (domain.passwordrequirements.backupcode2factor == false)) return;
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
@ -3281,6 +3290,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Do not allow this command if 2FA's are locked
if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return;
// Do not allow this command if backup codes are not allowed
if ((domain.passwordrequirements) && (domain.passwordrequirements.backupcode2factor == false)) return;
// Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break;
@ -4571,7 +4583,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (type == 'csv') {
try {
// Create the CSV file
output = 'id,name,rname,host,icon,ip,osdesc,groupname,av,update,firewall,avdetails,cpu,osbuild,biosDate,biosVendor,biosVersion,boardName,boardVendor,boardVersion,productUuid,agentOpenSSL,agentCommitDate,agentCommitHash,agentCompileTime,netIfCount,macs,addresses,lastConnectTime,lastConnectAddr\r\n';
output = 'id,name,rname,host,icon,ip,osdesc,groupname,av,update,firewall,avdetails,cpu,osbuild,biosDate,biosVendor,biosVersion,boardName,boardVendor,boardVersion,productUuid,totalMemory,agentOpenSSL,agentCommitDate,agentCommitHash,agentCompileTime,netIfCount,macs,addresses,lastConnectTime,lastConnectAddr\r\n';
for (var i = 0; i < results.length; i++) {
const nodeinfo = results[i];
@ -4613,6 +4625,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_version); }
output += ',';
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.identifiers.product_uuid); }
output += ',';
if (nodeinfo.sys.hardware.windows.memory) {
var totalMemory = 0;
for (var j in nodeinfo.sys.hardware.windows.memory) {
if (nodeinfo.sys.hardware.windows.memory[j].Capacity) {
if (typeof nodeinfo.sys.hardware.windows.memory[j].Capacity == 'number') { totalMemory += nodeinfo.sys.hardware.windows.memory[j].Capacity; }
if (typeof nodeinfo.sys.hardware.windows.memory[j].Capacity == 'string') { totalMemory += parseInt(nodeinfo.sys.hardware.windows.memory[j].Capacity); }
}
}
output += csvClean('' + totalMemory);
}
} else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.mobile)) {
// Mobile
output += ',';
@ -4628,6 +4651,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
output += ',';
output += ',';
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.id)) { output += csvClean(nodeinfo.sys.hardware.mobile.id); }
output += ',';
} else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.windows) && (nodeinfo.sys.hardware.linux)) {
// Linux
output += ',';
@ -4646,8 +4670,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_version)) { output += csvClean(nodeinfo.sys.hardware.linux.board_version); }
output += ',';
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.linux.product_uuid); }
output += ',';
} else {
output += ',,,,,,,,,';
output += ',,,,,,,,,,';
}
// Agent information
@ -5265,7 +5290,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Perform email invitation
if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && domain.mailserver) {
domain.mailserver.sendAccountInviteMail(newuserdomain, (user.realname ? user.realname : user.name), newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req));
domain.mailserver.sendAccountInviteMail(newuserdomain, (user.realname ? user.realname : user.name), newusername, command.email.toLowerCase(), command.pass, parent.getLanguageCodes(req), req.query.key);
}
// Log in the auth log
@ -5504,7 +5529,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (parent.parent.authlog) { parent.parent.authLog('https', 'User ' + user.name + ' changed email from ' + oldemail + ' to ' + user.email); }
// Send the verification email
if (domain.mailserver != null) { domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req)); }
if (domain.mailserver != null) { domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req), req.query.key); }
}
});
}
@ -6100,7 +6125,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if ((domain.mailserver != null) && (obj.user.email.toLowerCase() == command.email)) {
// Send the verification email
domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req));
domain.mailserver.sendAccountCheckMail(domain, user.name, user._id, user.email, parent.getLanguageCodes(req), req.query.key);
}
}

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.9.77",
"version": "0.9.79",
"keywords": [
"Remote Device Management",
"Remote Device Monitoring",

File diff suppressed because it is too large Load Diff

View File

@ -727,7 +727,7 @@
<div style="margin-top:5px"><span id="changeEmailId" style="display:none"><a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a></span></div>
<div style="margin-top:5px"><a onclick="account_showChangePassword()" style="cursor:pointer">Change password</a><span id="p2nextPasswordUpdateTime"></span></div>
<div style="margin-top:5px"><a onclick="account_showDeleteAccount()" style="cursor:pointer">Delete account</a></div>
<div style="margin-top:5px"><a onclick="toggleNightMode()" style="cursor:pointer">Set dark mode</a></div>
<div style="margin-top:5px" id="setDarkModeLink"><a onclick="toggleNightMode()" style="cursor:pointer">Set dark mode</a></div>
<div style="margin-top:5px"><a onclick="showNotes(false)" style="cursor:pointer">Personal notes</a></div>
</div>
<br style=clear:both />
@ -1309,6 +1309,9 @@
// Session Refresh Timer
if (sessionTime >= 10) { sessionRefreshTimer = setTimeout(refreshCookieSession, Math.round((sessionTime * 60000) * 0.8)); }
// Hide night mode button if needed
QV('setDarkModeLink', (features2 & 0x00300000) == 0);
// Set the user's desktop shortcut keys
deskKeyboardShortcuts = [];
var deskKeyboardShortcutsStr = getstore('deskKeyShortcuts', '0x0A002E,0x100000,0x100028,0x100026,0x10004C,0x10004D,0x11004D,0x100052,0x020073,0x080057,0x020009,0x100025,0x100027').split(',');
@ -1372,7 +1375,7 @@
QV('p2AccountImage', !accountSettingsLocked);
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
QV('manageAuthApp', (serverinfo.lock2factor != true) && (features & 4096) && ((userinfo.otpsecret == 1) || ((features2 & 0x00020000) == 0)));
QV('manageOtp', (serverinfo.lock2factor != true) && (features & 4096) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));
QV('manageOtp', (serverinfo.lock2factor != true) && ((features2 & 0x40000) == 0) && (features & 4096) && ((userinfo.otpsecret == 1) || (userinfo.otphkeys > 0)));
QV('authPhoneNumberCheck', (userinfo.phone != null));
QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
QV('authAppSetupCheck', userinfo.otpsecret == 1);
@ -2209,6 +2212,8 @@
// Set night mode
var nNightMode = getstore('nightMode', '0')
nightMode = false;
if ((features2 & 0x00100000) != 0) { nNightMode = '1'; }
if ((features2 & 0x00200000) != 0) { nNightMode = '2'; }
if (nNightMode == '1') { nightMode = true; }
else if ((nNightMode == '0') && (window.matchMedia)) { nightMode = window.matchMedia('(prefers-color-scheme: dark)').matches }
if (nightMode) { QC('body').add('night'); QS('body')['background-color'] = '#000'; QS('body')['color'] = 'lightgray'; } else { QC('body').remove('night'); QS('body')['background-color'] = '#FFF'; QS('body')['color'] = 'black'; }

View File

@ -1645,6 +1645,9 @@
// Fix links
if (urlargs.key) { Q('p6backuplink').href += '?key=' + urlargs.key; }
// Hide night mode button if needed
QV('uiViewButton4', (features2 & 0x00300000) == 0);
// Fix HTML words that in english have two or more meanings
Q('DeskType').value = multiTranslate("[KeyboardTyping]|Type");
}
@ -1923,6 +1926,8 @@
// Set night mode
var nNightMode = getstore('nightMode', '0')
nightMode = false;
if ((features2 & 0x00100000) != 0) { nNightMode = '1'; }
if ((features2 & 0x00200000) != 0) { nNightMode = '2'; }
if (nNightMode == '1') { nightMode = true; }
else if ((nNightMode == '0') && (window.matchMedia)) { nightMode = window.matchMedia('(prefers-color-scheme: dark)').matches }
if (nightMode) { QC('body').add('night'); QS('body')['background-color'] = '#000'; } else { QC('body').remove('night'); QS('body')['background-color'] = '#d3d9d6'; }
@ -2116,7 +2121,7 @@
if (userinfo.otphkeys > 0) { authFactorCount += userinfo.otphkeys; } // FIDO hardware factor
if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount++; } // EMail factor
if ((features & 0x02000000) && (features & 0x04000000) && (userinfo.phone != null)) { authFactorCount++; } // SMS factor
if ((authFactorCount > 0) && (userinfo.otpkeys > 0)) { authFactorCount++; } // Backup keys
if ((authFactorCount > 0) && (userinfo.otpkeys > 0) && ((features & 0x40000) == 0)) { authFactorCount++; } // Backup keys
return authFactorCount;
}
@ -2126,7 +2131,7 @@
var accountSettingsLocked = ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 1024) != 0));
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true));
QV('verifyEmailId2', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true) && (accountSettingsLocked == false));
QV('manageOtp', (serverinfo.lock2factor != true) && (authFactorCount > 0));
QV('manageOtp', (serverinfo.lock2factor != true) && (authFactorCount > 0) && ((features2 & 0x40000) == 0));
QV('authPhoneNumberCheck', (userinfo.phone != null));
QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
QV('authAppSetupCheck', userinfo.otpsecret == 1);
@ -2139,7 +2144,7 @@
mainUpdate(4 + 128 + 4096);
// Check if none or at least 2 factors are enabled.
if ((backupCodesWarningDone == false) && (authFactorCount == 1)) {
if ((backupCodesWarningDone == false) && (authFactorCount == 1) && ((features2 & 0x80000) == 0)) {
addNotification({ text: "Please add two-factor backup codes. If the current factor is lost, there is no way to recover this account.", title: "Two factor authentication", tag: 'backupcodes' });
backupCodesWarningDone = true;
}
@ -7411,8 +7416,8 @@
var url = serverinfo.altmessenging[i].url.split('{0}').join(currentNode._id.split('/').join('-'));
var localurl = url;
if (typeof serverinfo.altmessenging[i].localurl == 'string') { localurl = serverinfo.altmessenging[i].localurl.split('{0}').join(currentNode._id.split('/').join('-')); }
meshserver.send({ action: 'msg', type: 'openUrl', nodeid: currentNode._id, url: url });
safeNewWindow(localurl, 'altmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560');
if (url != '') { meshserver.send({ action: 'msg', type: 'openUrl', nodeid: currentNode._id, url: url }); }
if (localurl != '') { safeNewWindow(localurl, 'altmessenger:' + currentNode._id, 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,scrollbars=no,resizable=no,width=400,height=560'); }
}
function deviceToggleBackground() {
@ -13341,11 +13346,11 @@
1: "Account login",
2: "Account logout",
3: "Changed language from {1} to {2}",
4: "Joined desktop multiplex session",
5: "Left the desktop multiplex session",
6: "Started desktop multiplex session",
7: "Finished recording session, {0} second(s)",
8: "Closed desktop multiplex session, {0} second(s)",
4: "Joined desktop multiplex session", // No longer in use, replaced with 143
5: "Left the desktop multiplex session", // No longer in use, replaced with 144
6: "Started desktop multiplex session", // No longer in use, replaced with 145
7: "Finished recording session, {0} second(s)", // No longer in use, replaced with 146
8: "Closed desktop multiplex session, {0} second(s)", // No longer in use, replaced with 147
9: "Ended relay session \"{0}\" from {1} to {2}, {3} second(s)",
10: "Ended terminal session \"{0}\" from {1} to {2}, {3} second(s)",
11: "Ended desktop session \"{0}\" from {1} to {2}, {3} second(s)",
@ -13459,7 +13464,7 @@
119: "This agent is using insecure tunnels, consider updating.",
120: "Started local relay session \"{0}\", protocol {1} to {2}",
121: "Ended local relay session \"{0}\", protocol {1} to {2}, {3} second(s)",
122: "Left the desktop multiplex session after {0} second(s).",
122: "Left the desktop multiplex session after {0} second(s).", // No longer in use, replaced with 144
123: "Left Web-SSH session after {0} second(s).",
124: "Left Web-SFTP session after {0} second(s).",
125: "Left Web-RDP session after {0} second(s).",
@ -13479,7 +13484,12 @@
139: "Added device share {0} recurring weekly.",
140: "Changed device {0} from group {1}: {2}",
141: "Intel(r) AMT policy change",
142: "Device group {0} was changed: {1}"
142: "Device group {0} was changed: {1}",
143: "Joined desktop multiplex session \"{0}\"",
144: "Left the desktop multiplex session \"{0}\" after {1} second(s).",
145: "Started desktop multiplex session \"{0}\"",
146: "Finished recording session \"{0}\", {1} second(s)",
147: "Closed desktop multiplex session \"{0}\", {1} second(s)"
};
var eventsShortMessageId = {

View File

@ -1144,7 +1144,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
}
// Check if email address needs to be confirmed
var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
const emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
if (emailcheck && (user.emailVerified !== true)) {
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
req.session.messageid = 3; // "Email verification required" message
@ -1165,7 +1165,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
}
// Check if email address needs to be confirmed
var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
const emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
if (emailcheck && (user.emailVerified !== true)) {
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
req.session.messageid = 3; // "Email verification required" message
@ -1459,7 +1459,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
// Check everything is ok
if ((domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
const allowAccountReset = ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.allowaccountreset !== false));
if ((allowAccountReset === false) || (domain == null) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (typeof req.body.rpassword1 != 'string') || (typeof req.body.rpassword2 != 'string') || (req.body.rpassword1 != req.body.rpassword2) || (typeof req.body.rpasswordhint != 'string') || (req.session == null) || (typeof req.session.resettokenusername != 'string') || (typeof req.session.resettokenpassword != 'string')) {
parent.debug('web', 'handleResetPasswordRequest: checks failed');
delete req.session.u2f;
delete req.session.loginmode;
@ -1568,7 +1569,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
function handleResetAccountRequest(req, res, direct) {
const domain = checkUserIpAddress(req, res);
if (domain == null) { return; }
if ((domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.args.lanonly == true) || (obj.parent.certificates.CommonName == null) || (obj.parent.certificates.CommonName.indexOf('.') == -1)) { parent.debug('web', 'handleResetAccountRequest: check failed'); res.sendStatus(404); return; }
const allowAccountReset = ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.allowaccountreset !== false));
if ((allowAccountReset === false) || (domain.auth == 'sspi') || (domain.auth == 'ldap') || (obj.args.lanonly == true) || (obj.parent.certificates.CommonName == null) || (obj.parent.certificates.CommonName.indexOf('.') == -1)) { parent.debug('web', 'handleResetAccountRequest: check failed'); res.sendStatus(404); return; }
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
if (req.session.loginToken != null) { res.sendStatus(404); return; } // Do not allow this command when logged in using a login token
@ -2883,6 +2885,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (domain.devicesearchbarserverandclientname) { features2 += 0x00008000; } // Search bar will find both server name and client name
if (domain.ipkvm) { features2 += 0x00010000; } // Indicates support for IP KVM device groups
if ((domain.passwordrequirements) && (domain.passwordrequirements.otp2factor == false)) { features2 += 0x00020000; } // Indicates support for OTP 2FA is disabled
if ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.backupcode2factor === false)) { features2 += 0x00040000; } // Indicates 2FA backup codes are disabled
if ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.single2factorwarning === false)) { features2 += 0x00080000; } // Indicates no warning if a single 2FA is in use
if (domain.nightmode === 1) { features2 += 0x00100000; } // Always night mode
if (domain.nightmode === 2) { features2 += 0x00200000; } // Always day mode
return { features: features, features2: features2 };
}
@ -2903,7 +2909,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
delete req.session.messageid;
delete req.session.passhint;
}
var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
const allowAccountReset = ((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.allowaccountreset !== false));
const emailcheck = (allowAccountReset && (domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
// Check if we are allowed to create new users using the login screen
var newAccountsAllowed = true;
@ -4946,7 +4953,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (domain.agentcustomization.filename != null) { meshsettings += 'fileName=' + domain.agentcustomization.filename + '\r\n'; }
if (domain.agentcustomization.image != null) { meshsettings += 'image=' + domain.agentcustomization.image + '\r\n'; }
}
if (parent.agentTranslations != null) { meshsettings += 'translation=' + parent.agentTranslations + '\r\n'; } // Translation strings, not for MeshCentral Assistant
if (domain.agentTranslations != null) { meshsettings += 'translation=' + domain.agentTranslations + '\r\n'; } // Translation strings, not for MeshCentral Assistant
}
setContentDispositionHeader(res, 'application/octet-stream', meshfilename, null, argentInfo.rname);
if (argentInfo.mtime != null) { res.setHeader('Last-Modified', argentInfo.mtime.toUTCString()); }
@ -5318,7 +5325,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (domain.agentcustomization.filename != null) { meshsettings += 'fileName=' + domain.agentcustomization.filename + '\r\n'; }
if (domain.agentcustomization.image != null) { meshsettings += 'image=' + domain.agentcustomization.image + '\r\n'; }
}
if (parent.agentTranslations != null) { meshsettings += 'translation=' + parent.agentTranslations + '\r\n'; }
if (domain.agentTranslations != null) { meshsettings += 'translation=' + domain.agentTranslations + '\r\n'; }
// Setup the response output
var archive = require('archiver')('zip', { level: 5 }); // Sets the compression method.
@ -5419,7 +5426,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (domain.agentcustomization.filename != null) { meshsettings += 'fileName=' + domain.agentcustomization.filename + '\r\n'; }
if (domain.agentcustomization.image != null) { meshsettings += 'image=' + domain.agentcustomization.image + '\r\n'; }
}
if (parent.agentTranslations != null) { meshsettings += 'translation=' + parent.agentTranslations + '\r\n'; }
if (domain.agentTranslations != null) { meshsettings += 'translation=' + domain.agentTranslations + '\r\n'; }
return meshsettings;
}
@ -6456,7 +6463,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
var user = obj.users[userid];
if ((err == null) && (user)) {
// Check if a 2nd factor is needed
var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
const emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
// See if we support two-factor trusted cookies
var twoFactorCookieDays = 30;
@ -6586,7 +6593,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
// Check if inner authentication is requested
if (req.headers['x-meshauth'] === '*') { func(ws, req, domain, null); return; }
var emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
const emailcheck = ((domain.mailserver != null) && (obj.parent.certificates.CommonName != null) && (obj.parent.certificates.CommonName.indexOf('.') != -1) && (obj.args.lanonly != true) && (domain.auth != 'sspi') && (domain.auth != 'ldap'))
// A web socket session can be authenticated in many ways (Default user, session, user/pass and cookie). Check authentication here.
if ((req.query.user != null) && (req.query.pass != null)) {
@ -7440,6 +7447,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
var mobile = isMobileBrowser(req), minify = (domain.minify == true), p;
if (req.query.mobile == '1') { mobile = true; } else if (req.query.mobile == '0') { mobile = false; }
if (req.query.minify == '1') { minify = true; } else if (req.query.minify == '0') { minify = false; }
if ((domain != null) && (domain.mobilesite === false)) { mobile = false; }
if (mobile) {
if ((domain != null) && (domain.webviewspath != null)) { // If the domain has a web views path, use that first
if (minify) {