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", "agentVersion": "Neue Version",
"elevation": "Zum Installieren/Deinstallieren dieser Software sind erhöhte Berechtigungen erforderlich.", "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", "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": { "es": {
"agent": "Agente", "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 uid = require('user-sessions').consoleUid();
var user = require('user-sessions').getUsername(uid); var user = require('user-sessions').getUsername(uid);
var domain = require('user-sessions').getDomain(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 + '"' } }; 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]; 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); 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 /RUN /TN MeshChatTask\r\n');
child.stdin.write('SCHTASKS /DELETE /F /TN MeshChatTask\r\nexit\r\n'); child.stdin.write('SCHTASKS /DELETE /F /TN MeshChatTask\r\nexit\r\n');
child.waitExit(); child.waitExit();
}
break; break;
case 'linux': case 'linux':
child = require('child_process').execFile('/usr/bin/xdg-open', ['xdg-open', url], { uid: require('user-sessions').consoleUid() }); 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." }, "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." }, "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." }, "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." }, "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" }, "userQuota": { "type": "integer" },
"meshQuota": { "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." }, "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." }, "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." }, "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." }, "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." }, "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." }, "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" }, "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." }, "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." }, "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." }, "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." }, "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." }, "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." }, "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." }, "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." }, "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." } "fileName": { "type": "string", "default": "meshagent", "description": "The agent filename." }
} }

View File

@ -17,7 +17,7 @@
const common = require('./common.js'); const common = require('./common.js');
// If app metrics is available // 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) { function CreateMeshCentralServer(config, args) {
var obj = {}; var obj = {};
@ -76,7 +76,7 @@ function CreateMeshCentralServer(config, args) {
// Server version // Server version
obj.currentVer = null; 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(); getCurrentVersion();
// Setup the default configuration and files paths // 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; } if (obj.config.settings && (typeof obj.config.settings.filespath == 'string')) { obj.filespath = obj.config.settings.filespath; }
// Create data and files folders if needed // Create data and files folders if needed
try { obj.fs.mkdirSync(obj.datapath); } catch (e) { } try { obj.fs.mkdirSync(obj.datapath); } catch (ex) { }
try { obj.fs.mkdirSync(obj.filespath); } catch (e) { } try { obj.fs.mkdirSync(obj.filespath); } catch (ex) { }
// Windows Specific Code, setup service and event log // Windows Specific Code, setup service and event log
obj.service = null; obj.service = null;
@ -134,10 +134,10 @@ function CreateMeshCentralServer(config, args) {
// Start the Meshcentral server // Start the Meshcentral server
obj.Start = function () { obj.Start = function () {
var i; 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 // 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; } } 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; } 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. 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 // Fix a NeDB database
if (obj.args.dbfix) { if (obj.args.dbfix) {
var lines = null, badJsonCount = 0, feildNames = [], fixedDb = []; 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++) { for (var i = 0; i < lines.length; i++) {
var x = null; var x = null;
try { x = JSON.parse(lines[i]); } catch (ex) { badJsonCount++; } try { x = JSON.parse(lines[i]); } catch (ex) { badJsonCount++; }
@ -190,6 +190,9 @@ function CreateMeshCentralServer(config, args) {
// Perform a password hash // 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; } 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 // Perform web site translations into different languages
if (obj.args.translate) { if (obj.args.translate) {
// Check NodeJS version // 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('alreadyinstalled', function () { console.log('MeshCentral service already installed.'); process.exit(); });
svc.on('invalidinstallation', function () { console.log('Invalid MeshCentral service installation.'); 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.xinstall == true) { try { svc.install(); } catch (ex) { logException(ex); } }
if (obj.args.stop == true || obj.args.restart == true) { try { svc.stop(); } catch (e) { logException(e); } } 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 (e) { logException(e); } } if (obj.args.start == true) { try { svc.start(); } catch (ex) { logException(ex); } }
if (obj.args.xuninstall == true) { try { svc.uninstall(); } catch (e) { logException(e); } } if (obj.args.xuninstall == true) { try { svc.uninstall(); } catch (ex) { logException(ex); } }
return; return;
} }
@ -534,7 +537,7 @@ function CreateMeshCentralServer(config, args) {
xxprocess.stderr.on('data', function (data) { }); xxprocess.stderr.on('data', function (data) { });
xxprocess.on('close', function (code) { xxprocess.on('close', function (code) {
var latestVer = null; 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); callback(getCurrentVersion(), latestVer);
}); });
} catch (ex) { callback(getCurrentVersion(), null, ex); } // If the system is running out of memory, an exception here can easily happen. } 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 { try {
var lines = xxprocess.data.split('\r\n').join('\n').split('\n'); 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]; } } 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); callback(tags);
}); });
@ -1045,10 +1048,10 @@ function CreateMeshCentralServer(config, args) {
// Import the entire database from a JSON file // Import the entire database from a JSON file
if (obj.args.dbimport == true) { obj.args.dbimport = obj.getConfigFilePath('meshcentral.db.json'); } if (obj.args.dbimport == true) { obj.args.dbimport = obj.getConfigFilePath('meshcentral.db.json'); }
var json = null, json2 = '', badCharCount = 0; 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 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.'); } 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 + '.'); } if ((json == null) || (typeof json.length != 'number') || (json.length < 1)) { console.log('Invalid JSON format: ' + obj.args.dbimport + '.'); }
// Escape MongoDB invalid field chars // Escape MongoDB invalid field chars
for (i in json) { for (i in json) {
@ -1086,10 +1089,10 @@ function CreateMeshCentralServer(config, args) {
// Import the entire database from a JSON file // Import the entire database from a JSON file
if (obj.args.dbmerge == true) { obj.args.dbmerge = obj.getConfigFilePath('meshcentral.db.json'); } if (obj.args.dbmerge == true) { obj.args.dbmerge = obj.getConfigFilePath('meshcentral.db.json'); }
var json = null, json2 = "", badCharCount = 0; 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 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.'); } 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 + '.'); } if ((json == null) || (typeof json.length != 'number') || (json.length < 1)) { console.log('Invalid JSON format: ' + obj.args.dbimport + '.'); }
// Get all users from current database // Get all users from current database
@ -1556,7 +1559,17 @@ function CreateMeshCentralServer(config, args) {
var translations = JSON.parse(obj.fs.readFileSync(translationpath).toString()); 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-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']; } 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) { } } catch (ex) { }
// Load the list of mesh agents and install scripts // Load the list of mesh agents and install scripts
@ -2428,7 +2441,7 @@ function CreateMeshCentralServer(config, args) {
} }
// Update the default mesh core // Update the default mesh core
obj.updateMeshCore = function (func) { obj.updateMeshCore = function (func, dumpToFile) {
// Figure out where meshcore.js is // Figure out where meshcore.js is
var meshcorePath = obj.datapath; var meshcorePath = obj.datapath;
if (obj.fs.existsSync(obj.path.join(meshcorePath, 'meshcore.js')) == false) { 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 (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 (e) { } } // Use non-minified meshcore. if (meshCore == null) { try { meshCore = obj.fs.readFileSync(obj.path.join(meshcorePath, 'meshcore.js')).toString(); } catch (ex) { } } // Use non-minified meshcore.
if (meshCore != null) { if (meshCore != null) {
var moduleDirPath = 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 (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 (e) { } } // Use non-minified mofules. 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) { if (modulesDir != null) {
for (var i in modulesDir) { for (var i in modulesDir) {
if (modulesDir[i].toLowerCase().endsWith('.json')) { if (modulesDir[i].toLowerCase().endsWith('.json')) {
@ -2500,7 +2513,7 @@ function CreateMeshCentralServer(config, args) {
// We are adding a JS file to the meshcores // We are adding a JS file to the meshcores
var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3); 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. 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 // Merge this module
// NOTE: "smbios" module makes some non-AI Linux segfault, only include for IA platforms. // 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 // Add plugins to cores
if (obj.pluginHandler) { obj.pluginHandler.addMeshCoreModules(modulesAdd); } 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 // Merge the cores and compute the hashes
for (var i in modulesAdd) { for (var i in modulesAdd) {
if ((i == 'windows-recovery') || (i == 'linux-recovery')) { 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.defaultMeshCoresHash[i] = obj.crypto.createHash('sha384').update(obj.defaultMeshCores[i]).digest('binary');
obj.debug('main', 'Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.'); obj.debug('main', 'Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.');
// These lines will write all modules to files. Great for debugging. // Write all modules to files. Great for debugging.
//console.log('Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.'); // DEBUG, Print the core size if (dumpToFile) {
//obj.fs.writeFile("C:\\temp\\" + i + ".js", obj.defaultMeshCores[i].slice(4), function () { }); // DEBUG, Write the core to file 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 // Compress the mesh cores with DEFLATE
const callback = function MeshCoreDeflateCb(err, buffer) { if (err == null) { obj.defaultMeshCoresDeflate[MeshCoreDeflateCb.i] = buffer; } } 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() + '\''); meshCmd = meshCmd.replace("'***Mesh*Cmd*Version***'", '\'' + getCurrentVersion() + '\'');
// Figure out where the modules_meshcmd folder is. // 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 (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 (e) { } } // Use non-minified mofules. 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 (e) { } } } // Favor minified modules if present. 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 (e) { } } // Use non-minified mofules. 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. // Read all .js files in the meshcmd modules folder.
if (modulesDir != null) { if (modulesDir != null) {
@ -2597,7 +2615,7 @@ function CreateMeshCentralServer(config, args) {
// Merge this module // Merge this module
var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3); 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. 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] = { 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; 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; 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; } if (stats != null) { obj.meshToolsBinaries[this.toolname].size = stats.size; }
}); });
var options = { sourcePath: toolpath, targetStream: hashStream }; 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].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; 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; 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; } if (stats != null) { obj.meshToolsBinaries[this.toolname].size = stats.size; }
}); });
stream.toolname = toolname; stream.toolname = toolname;
@ -2678,7 +2696,7 @@ function CreateMeshCentralServer(config, args) {
stream.dlname = meshToolsList[toolname].dlname; stream.dlname = meshToolsList[toolname].dlname;
stream.hash = obj.crypto.createHash('sha384', stream); stream.hash = obj.crypto.createHash('sha384', stream);
stream.hashx = 0; 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].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; 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; 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; } if (stats != null) { obj.meshAgentInstallScripts[this.info.id].size = stats.size; }
// Place Unit line breaks on Linux scripts if not already present. // Place Unit line breaks on Linux scripts if not already present.
@ -2721,7 +2739,7 @@ function CreateMeshCentralServer(config, args) {
stream.info = meshAgentsInstallScriptList[scriptid]; stream.info = meshAgentsInstallScriptList[scriptid];
stream.agentpath = scriptpath; stream.agentpath = scriptpath;
stream.hash = obj.crypto.createHash('sha384', stream); 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 // Fetch all the agent binary information
var stats = null; var stats = null;
try { stats = obj.fs.statSync(agentpath); } catch (e) { } try { stats = obj.fs.statSync(agentpath); } catch (ex) { }
if ((stats != null)) { if ((stats != null)) {
// If file exists // If file exists
archcount++; archcount++;
@ -2798,7 +2816,7 @@ function CreateMeshCentralServer(config, args) {
// If this is a windows binary, pull binary information // If this is a windows binary, pull binary information
if (obj.meshAgentsArchitectureNumbers[archid].platform == 'win32') { 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. // 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'); datapath = path.join(__dirname, '../meshcentral-data');
} }
if (args.datapath) { datapath = args.datapath; } 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. // Read configuration file if present and change arguments.
var config = {}, configFilePath = path.join(datapath, 'config.json'); var config = {}, configFilePath = path.join(datapath, 'config.json');
@ -3244,7 +3262,7 @@ function getConfig(createSampleConfig) {
} }
if (fs.existsSync(configFilePath)) { if (fs.existsSync(configFilePath)) {
// Load and validate the configuration file // 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 = {}; } 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; } } 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 { } else {
@ -3292,7 +3310,7 @@ function InstallModules(modules, func) {
if (typeof dependencies[moduleName] != undefined) { moduleVersion = dependencies[moduleName]; } if (typeof dependencies[moduleName] != undefined) { moduleVersion = dependencies[moduleName]; }
require(moduleName); require(moduleName);
} }
} catch (e) { } catch (ex) {
if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(moduleNameAndVersion); } if (previouslyInstalledModules[modules[i]] !== true) { missingModules.push(moduleNameAndVersion); }
} }
} }

View File

@ -58,10 +58,11 @@ MNG_ENCAPSULATE_AGENT_COMMAND = 70,
MNG_KVM_DISPLAY_INFO = 82 MNG_KVM_DISPLAY_INFO = 82
*/ */
function CreateDesktopMultiplexor(parent, domain, nodeid, func) { function CreateDesktopMultiplexor(parent, domain, nodeid, id, func) {
var obj = {}; var obj = {};
obj.nodeid = nodeid; obj.id = id; // Unique identifier for this session
obj.parent = parent; 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.agent = null; // Reference to the connection object that is the agent.
obj.viewers = []; // Array of references to all viewers. obj.viewers = []; // Array of references to all viewers.
obj.viewersOverflowCount = 0; // Number of viewers currently in overflow state. 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 // Log joining the multiplex session
if (obj.startTime != null) { 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); 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 // Log multiplex session start
if ((obj.agent != null) && (obj.viewers.length > 0) && (obj.startTime == null)) { 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; } 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]; const targets = ['*', obj.nodeid, obj.meshid];
if (obj.viewers[0].user != null) { targets.push(obj.viewers[0].user._id); } 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 }; //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); 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.user != null) { event.userid = peer.user._id; event.username = peer.user.name; }
if (peer.guestName) { event.guestname = peer.guestName; } if (peer.guestName) { event.guestname = peer.guestName; }
const targets = ['*', obj.nodeid, obj.meshid]; const targets = ['*', obj.nodeid, obj.meshid];
@ -342,7 +343,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, func) {
// Add a event entry about this recording // Add a event entry about this recording
var basefile = parent.parent.path.basename(filename); 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]; var mesh = parent.meshes[obj.meshid];
if (mesh != null) { event.meshname = mesh.name; } if (mesh != null) { event.meshname = mesh.name; }
if (obj.sessionStart) { event.startTime = obj.sessionStart; event.lengthTime = obj.sessionLength; } 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 // Log end of multiplex session
if (obj.startTime != null) { 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); parent.parent.DispatchEvent(['*', obj.nodeid, obj.meshid], obj, event);
obj.startTime = null; obj.startTime = null;
} }
@ -1203,7 +1204,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
if (obj.deskMultiplexor == null) { if (obj.deskMultiplexor == null) {
parent.desktoprelays[obj.nodeid] = 1; // Indicate that the creating of the desktop multiplexor is pending. parent.desktoprelays[obj.nodeid] = 1; // Indicate that the creating of the desktop multiplexor is pending.
parent.parent.debug('relay', 'DesktopRelay: Creating new desktop multiplexor'); 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) { if (deskMultiplexor != null) {
// Desktop multiplexor was created, use it. // Desktop multiplexor was created, use it.
obj.deskMultiplexor = deskMultiplexor; 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 // Do not allow this command if 2FA's are locked
if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return; 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 // Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break; 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 // Do not allow this command if 2FA's are locked
if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return; 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 // Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break; 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 // Do not allow this command if 2FA's are locked
if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return; 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 // Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break; 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 // Do not allow this command if 2FA's are locked
if ((domain.passwordrequirements) && (domain.passwordrequirements.lock2factor == true)) return; 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 // Do not allow this command when logged in using a login token
if (req.session.loginToken != null) break; if (req.session.loginToken != null) break;
@ -4571,7 +4583,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
if (type == 'csv') { if (type == 'csv') {
try { try {
// Create the CSV file // 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++) { for (var i = 0; i < results.length; i++) {
const nodeinfo = results[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); } if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_version); }
output += ','; output += ',';
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.identifiers.product_uuid); } 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)) { } else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.mobile)) {
// Mobile // Mobile
output += ','; output += ',';
@ -4628,6 +4651,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
output += ','; output += ',';
output += ','; output += ',';
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.id)) { output += csvClean(nodeinfo.sys.hardware.mobile.id); } 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)) { } else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.windows) && (nodeinfo.sys.hardware.linux)) {
// Linux // Linux
output += ','; 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); } if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_version)) { output += csvClean(nodeinfo.sys.hardware.linux.board_version); }
output += ','; output += ',';
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.linux.product_uuid); } if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.linux.product_uuid); }
output += ',';
} else { } else {
output += ',,,,,,,,,'; output += ',,,,,,,,,,';
} }
// Agent information // Agent information
@ -5265,7 +5290,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Perform email invitation // Perform email invitation
if ((command.emailInvitation == true) && (command.emailVerified == true) && command.email && domain.mailserver) { 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 // 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); } if (parent.parent.authlog) { parent.parent.authLog('https', 'User ' + user.name + ' changed email from ' + oldemail + ' to ' + user.email); }
// Send the verification 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)) { if ((domain.mailserver != null) && (obj.user.email.toLowerCase() == command.email)) {
// Send the verification 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", "name": "meshcentral",
"version": "0.9.77", "version": "0.9.79",
"keywords": [ "keywords": [
"Remote Device Management", "Remote Device Management",
"Remote Device Monitoring", "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"><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_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="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 style="margin-top:5px"><a onclick="showNotes(false)" style="cursor:pointer">Personal notes</a></div>
</div> </div>
<br style=clear:both /> <br style=clear:both />
@ -1309,6 +1309,9 @@
// Session Refresh Timer // Session Refresh Timer
if (sessionTime >= 10) { sessionRefreshTimer = setTimeout(refreshCookieSession, Math.round((sessionTime * 60000) * 0.8)); } 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 // Set the user's desktop shortcut keys
deskKeyboardShortcuts = []; deskKeyboardShortcuts = [];
var deskKeyboardShortcutsStr = getstore('deskKeyShortcuts', '0x0A002E,0x100000,0x100028,0x100026,0x10004C,0x10004D,0x11004D,0x100052,0x020073,0x080057,0x020009,0x100025,0x100027').split(','); 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('p2AccountImage', !accountSettingsLocked);
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true)); 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('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('authPhoneNumberCheck', (userinfo.phone != null));
QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true)); QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
QV('authAppSetupCheck', userinfo.otpsecret == 1); QV('authAppSetupCheck', userinfo.otpsecret == 1);
@ -2209,6 +2212,8 @@
// Set night mode // Set night mode
var nNightMode = getstore('nightMode', '0') var nNightMode = getstore('nightMode', '0')
nightMode = false; nightMode = false;
if ((features2 & 0x00100000) != 0) { nNightMode = '1'; }
if ((features2 & 0x00200000) != 0) { nNightMode = '2'; }
if (nNightMode == '1') { nightMode = true; } if (nNightMode == '1') { nightMode = true; }
else if ((nNightMode == '0') && (window.matchMedia)) { nightMode = window.matchMedia('(prefers-color-scheme: dark)').matches } 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'; } 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 // Fix links
if (urlargs.key) { Q('p6backuplink').href += '?key=' + urlargs.key; } 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 // Fix HTML words that in english have two or more meanings
Q('DeskType').value = multiTranslate("[KeyboardTyping]|Type"); Q('DeskType').value = multiTranslate("[KeyboardTyping]|Type");
} }
@ -1923,6 +1926,8 @@
// Set night mode // Set night mode
var nNightMode = getstore('nightMode', '0') var nNightMode = getstore('nightMode', '0')
nightMode = false; nightMode = false;
if ((features2 & 0x00100000) != 0) { nNightMode = '1'; }
if ((features2 & 0x00200000) != 0) { nNightMode = '2'; }
if (nNightMode == '1') { nightMode = true; } if (nNightMode == '1') { nightMode = true; }
else if ((nNightMode == '0') && (window.matchMedia)) { nightMode = window.matchMedia('(prefers-color-scheme: dark)').matches } 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'; } 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 (userinfo.otphkeys > 0) { authFactorCount += userinfo.otphkeys; } // FIDO hardware factor
if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount++; } // EMail factor if ((features & 0x00800000) && (userinfo.otpekey == 1)) { authFactorCount++; } // EMail factor
if ((features & 0x02000000) && (features & 0x04000000) && (userinfo.phone != null)) { authFactorCount++; } // SMS 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; return authFactorCount;
} }
@ -2126,7 +2131,7 @@
var accountSettingsLocked = ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 1024) != 0)); var accountSettingsLocked = ((userinfo.siteadmin != 0xFFFFFFFF) && ((userinfo.siteadmin & 1024) != 0));
QV('verifyEmailId', (userinfo.emailVerified !== true) && (userinfo.email != null) && (serverinfo.emailcheck == true)); 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('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('authPhoneNumberCheck', (userinfo.phone != null));
QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true)); QV('authEmailSetupCheck', (userinfo.otpekey == 1) && (userinfo.email != null) && (userinfo.emailVerified == true));
QV('authAppSetupCheck', userinfo.otpsecret == 1); QV('authAppSetupCheck', userinfo.otpsecret == 1);
@ -2139,7 +2144,7 @@
mainUpdate(4 + 128 + 4096); mainUpdate(4 + 128 + 4096);
// Check if none or at least 2 factors are enabled. // 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' }); 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; backupCodesWarningDone = true;
} }
@ -7411,8 +7416,8 @@
var url = serverinfo.altmessenging[i].url.split('{0}').join(currentNode._id.split('/').join('-')); var url = serverinfo.altmessenging[i].url.split('{0}').join(currentNode._id.split('/').join('-'));
var localurl = url; var localurl = url;
if (typeof serverinfo.altmessenging[i].localurl == 'string') { localurl = serverinfo.altmessenging[i].localurl.split('{0}').join(currentNode._id.split('/').join('-')); } 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 }); if (url != '') { 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 (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() { function deviceToggleBackground() {
@ -13341,11 +13346,11 @@
1: "Account login", 1: "Account login",
2: "Account logout", 2: "Account logout",
3: "Changed language from {1} to {2}", 3: "Changed language from {1} to {2}",
4: "Joined desktop multiplex session", 4: "Joined desktop multiplex session", // No longer in use, replaced with 143
5: "Left the desktop multiplex session", 5: "Left the desktop multiplex session", // No longer in use, replaced with 144
6: "Started desktop multiplex session", 6: "Started desktop multiplex session", // No longer in use, replaced with 145
7: "Finished recording session, {0} second(s)", 7: "Finished recording session, {0} second(s)", // No longer in use, replaced with 146
8: "Closed desktop multiplex session, {0} second(s)", 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)", 9: "Ended relay session \"{0}\" from {1} to {2}, {3} second(s)",
10: "Ended terminal 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)", 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.", 119: "This agent is using insecure tunnels, consider updating.",
120: "Started local relay session \"{0}\", protocol {1} to {2}", 120: "Started local relay session \"{0}\", protocol {1} to {2}",
121: "Ended local relay session \"{0}\", protocol {1} to {2}, {3} second(s)", 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).", 123: "Left Web-SSH session after {0} second(s).",
124: "Left Web-SFTP session after {0} second(s).", 124: "Left Web-SFTP session after {0} second(s).",
125: "Left Web-RDP 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.", 139: "Added device share {0} recurring weekly.",
140: "Changed device {0} from group {1}: {2}", 140: "Changed device {0} from group {1}: {2}",
141: "Intel(r) AMT policy change", 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 = { 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 // 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)) { if (emailcheck && (user.emailVerified !== true)) {
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page'); parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
req.session.messageid = 3; // "Email verification required" message 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 // 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)) { if (emailcheck && (user.emailVerified !== true)) {
parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page'); parent.debug('web', 'Redirecting using ' + user.name + ' to email check login page');
req.session.messageid = 3; // "Email verification required" message 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 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 // 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'); parent.debug('web', 'handleResetPasswordRequest: checks failed');
delete req.session.u2f; delete req.session.u2f;
delete req.session.loginmode; delete req.session.loginmode;
@ -1568,7 +1569,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
function handleResetAccountRequest(req, res, direct) { function handleResetAccountRequest(req, res, direct) {
const domain = checkUserIpAddress(req, res); const domain = checkUserIpAddress(req, res);
if (domain == null) { return; } 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 ((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 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.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.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 ((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 }; 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.messageid;
delete req.session.passhint; 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 // Check if we are allowed to create new users using the login screen
var newAccountsAllowed = true; 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.filename != null) { meshsettings += 'fileName=' + domain.agentcustomization.filename + '\r\n'; }
if (domain.agentcustomization.image != null) { meshsettings += 'image=' + domain.agentcustomization.image + '\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); setContentDispositionHeader(res, 'application/octet-stream', meshfilename, null, argentInfo.rname);
if (argentInfo.mtime != null) { res.setHeader('Last-Modified', argentInfo.mtime.toUTCString()); } 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.filename != null) { meshsettings += 'fileName=' + domain.agentcustomization.filename + '\r\n'; }
if (domain.agentcustomization.image != null) { meshsettings += 'image=' + domain.agentcustomization.image + '\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 // Setup the response output
var archive = require('archiver')('zip', { level: 5 }); // Sets the compression method. 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.filename != null) { meshsettings += 'fileName=' + domain.agentcustomization.filename + '\r\n'; }
if (domain.agentcustomization.image != null) { meshsettings += 'image=' + domain.agentcustomization.image + '\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; return meshsettings;
} }
@ -6456,7 +6463,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
var user = obj.users[userid]; var user = obj.users[userid];
if ((err == null) && (user)) { if ((err == null) && (user)) {
// Check if a 2nd factor is needed // 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 // See if we support two-factor trusted cookies
var twoFactorCookieDays = 30; var twoFactorCookieDays = 30;
@ -6586,7 +6593,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
// Check if inner authentication is requested // Check if inner authentication is requested
if (req.headers['x-meshauth'] === '*') { func(ws, req, domain, null); return; } 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. // 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)) { 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; 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.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 (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 (mobile) {
if ((domain != null) && (domain.webviewspath != null)) { // If the domain has a web views path, use that first if ((domain != null) && (domain.webviewspath != null)) { // If the domain has a web views path, use that first
if (minify) { if (minify) {