mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Compare commits
64 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88a765bb13 | ||
|
|
7ad4b917be | ||
|
|
d10173a018 | ||
|
|
0e3a6b4915 | ||
|
|
b949cecc5f | ||
|
|
c7cbf2f12a | ||
|
|
d49afdd7bf | ||
|
|
133e77c8c6 | ||
|
|
e404e86b9f | ||
|
|
c6da201af8 | ||
|
|
9a27d7637c | ||
|
|
5aa2467409 | ||
|
|
9398afd07e | ||
|
|
b2cd84035b | ||
|
|
97547d72a3 | ||
|
|
7faf043c35 | ||
|
|
9df0330896 | ||
|
|
42f61ea46e | ||
|
|
0d65080a8a | ||
|
|
bd4d8b12d4 | ||
|
|
18ae8bdbf4 | ||
|
|
46c76f7234 | ||
|
|
e65bf77111 | ||
|
|
f19ad6c664 | ||
|
|
fe2f12149d | ||
|
|
91bd5ae702 | ||
|
|
38f5bf2e0f | ||
|
|
79f00bcaab | ||
|
|
c55065505b | ||
|
|
e0e8a3fcaa | ||
|
|
3f77cfa93a | ||
|
|
5ee9aa2410 | ||
|
|
0ab3f01ca6 | ||
|
|
4b621a01fb | ||
|
|
f2681de87d | ||
|
|
c90fa55c99 | ||
|
|
edeef03f00 | ||
|
|
d7fe87d1db | ||
|
|
9d4f51e970 | ||
|
|
0b376fe5a0 | ||
|
|
9fd40751b2 | ||
|
|
d246307fae | ||
|
|
711bb56a93 | ||
|
|
5734bcc33a | ||
|
|
1310c57397 | ||
|
|
854d6c00d2 | ||
|
|
c96d7ff1ca | ||
|
|
712f06db3c | ||
|
|
cac505e2cd | ||
|
|
9d962bc523 | ||
|
|
f079692b16 | ||
|
|
3ee06abfe8 | ||
|
|
b46ddf2f70 | ||
|
|
f7b958d28b | ||
|
|
64c8d2c238 | ||
|
|
31f2224a93 | ||
|
|
de685556c8 | ||
|
|
92375ddc93 | ||
|
|
ea80f8595e | ||
|
|
763f76b68f | ||
|
|
1a02539f23 | ||
|
|
90b71e924f | ||
|
|
73c18c4dd5 | ||
|
|
def62075c7 |
66 changed files with 12308 additions and 12700 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -295,8 +295,9 @@ if (process.platform == 'win32' && require('user-sessions').isRoot()) {
|
||||||
// Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
|
// Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
|
||||||
try {
|
try {
|
||||||
var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
|
var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
|
||||||
try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (ex) { }
|
var serviceName = (_MSH().serviceName ? _MSH().serviceName : (require('_agentNodeId').serviceName() ? require('_agentNodeId').serviceName() : 'Mesh Agent'));
|
||||||
if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (ex) { } }
|
try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize'); } catch (ex) { }
|
||||||
|
if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize', actualSize); } catch (ex) { } }
|
||||||
} catch (ex) { }
|
} catch (ex) { }
|
||||||
|
|
||||||
// Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
|
// Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
|
||||||
|
|
@ -310,6 +311,16 @@ if (process.platform == 'win32' && require('user-sessions').isRoot()) {
|
||||||
try { meshCheck = require('service-manager').manager.getService(svcname).isMe(); } catch (ex) { }
|
try { meshCheck = require('service-manager').manager.getService(svcname).isMe(); } catch (ex) { }
|
||||||
if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService(svcname)) { require('win-bcd').enableSafeModeService(svcname); }
|
if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService(svcname)) { require('win-bcd').enableSafeModeService(svcname); }
|
||||||
} catch (ex) { }
|
} catch (ex) { }
|
||||||
|
|
||||||
|
// Check the Agent Uninstall MetaData for DisplayVersion and update if not the same and only on windows
|
||||||
|
if (process.platform == 'win32') {
|
||||||
|
try {
|
||||||
|
var writtenDisplayVersion = 0, actualDisplayVersion = process.versions.commitDate.toString();
|
||||||
|
var serviceName = (_MSH().serviceName ? _MSH().serviceName : (require('_agentNodeId').serviceName() ? require('_agentNodeId').serviceName() : 'Mesh Agent'));
|
||||||
|
try { writtenDisplayVersion = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'DisplayVersion'); } catch (ex) { }
|
||||||
|
if (writtenDisplayVersion != actualDisplayVersion) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'DisplayVersion', actualDisplayVersion); } catch (ex) { } }
|
||||||
|
} catch (ex) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.platform != 'win32') {
|
if (process.platform != 'win32') {
|
||||||
|
|
@ -655,33 +666,39 @@ var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ?
|
||||||
try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (ex) { }
|
try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (ex) { }
|
||||||
|
|
||||||
// Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
|
// Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
|
||||||
|
function onUserSessionChanged(user, locked) {
|
||||||
|
userSession.enumerateUsers().then(function (users) {
|
||||||
|
if (process.platform == 'linux') {
|
||||||
|
if (userSession._startTime == null) {
|
||||||
|
userSession._startTime = Date.now();
|
||||||
|
userSession._count = users.length;
|
||||||
|
}
|
||||||
|
else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count) {
|
||||||
|
userSession.removeAllListeners('changed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var u = [], a = users.Active;
|
||||||
|
if(meshCoreObj.lusers == null) { meshCoreObj.lusers = []; }
|
||||||
|
for (var i = 0; i < a.length; i++) {
|
||||||
|
var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
|
||||||
|
if (user && locked && (JSON.stringify(a[i]) === JSON.stringify(user))) { if (meshCoreObj.lusers.indexOf(un) == -1) { meshCoreObj.lusers.push(un); } }
|
||||||
|
else if (user && !locked && (JSON.stringify(a[i]) === JSON.stringify(user))) { meshCoreObj.lusers.splice(meshCoreObj.lusers.indexOf(un), 1); }
|
||||||
|
if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
|
||||||
|
}
|
||||||
|
meshCoreObj.lusers = meshCoreObj.lusers;
|
||||||
|
meshCoreObj.users = u;
|
||||||
|
meshCoreObjChanged();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var userSession = require('user-sessions');
|
var userSession = require('user-sessions');
|
||||||
userSession.on('changed', function onUserSessionChanged() {
|
userSession.on('changed', function () { onUserSessionChanged(null, false); });
|
||||||
userSession.enumerateUsers().then(function (users) {
|
|
||||||
if (process.platform == 'linux') {
|
|
||||||
if (userSession._startTime == null) {
|
|
||||||
userSession._startTime = Date.now();
|
|
||||||
userSession._count = users.length;
|
|
||||||
}
|
|
||||||
else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count) {
|
|
||||||
userSession.removeAllListeners('changed');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var u = [], a = users.Active;
|
|
||||||
for (var i = 0; i < a.length; i++) {
|
|
||||||
var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
|
|
||||||
if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
|
|
||||||
}
|
|
||||||
meshCoreObj.users = u;
|
|
||||||
meshCoreObjChanged();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
userSession.emit('changed');
|
userSession.emit('changed');
|
||||||
//userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); });
|
userSession.on('locked', function (user) { if(user != undefined && user != null) { onUserSessionChanged(user, true); } });
|
||||||
//userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); });
|
userSession.on('unlocked', function (user) { if(user != undefined && user != null) { onUserSessionChanged(user, false); } });
|
||||||
} catch (ex) { }
|
} catch (ex) { }
|
||||||
|
|
||||||
var meshServerConnectionState = 0;
|
var meshServerConnectionState = 0;
|
||||||
|
|
@ -1158,6 +1175,7 @@ function handleServerCommand(data) {
|
||||||
tunnel.soptions = data.soptions;
|
tunnel.soptions = data.soptions;
|
||||||
tunnel.consentTimeout = (tunnel.soptions && tunnel.soptions.consentTimeout) ? tunnel.soptions.consentTimeout : 30;
|
tunnel.consentTimeout = (tunnel.soptions && tunnel.soptions.consentTimeout) ? tunnel.soptions.consentTimeout : 30;
|
||||||
tunnel.consentAutoAccept = (tunnel.soptions && (tunnel.soptions.consentAutoAccept === true));
|
tunnel.consentAutoAccept = (tunnel.soptions && (tunnel.soptions.consentAutoAccept === true));
|
||||||
|
tunnel.consentAutoAcceptIfNoUser = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfNoUser === true));
|
||||||
tunnel.oldStyle = (tunnel.soptions && tunnel.soptions.oldStyle) ? tunnel.soptions.oldStyle : false;
|
tunnel.oldStyle = (tunnel.soptions && tunnel.soptions.oldStyle) ? tunnel.soptions.oldStyle : false;
|
||||||
tunnel.tcpaddr = data.tcpaddr;
|
tunnel.tcpaddr = data.tcpaddr;
|
||||||
tunnel.tcpport = data.tcpport;
|
tunnel.tcpport = data.tcpport;
|
||||||
|
|
@ -1572,7 +1590,7 @@ function handleServerCommand(data) {
|
||||||
mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options);
|
mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options);
|
||||||
mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
|
mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
|
||||||
mesh.cmdchild.stdout.on('data', function (c) { replydata += c.toString(); });
|
mesh.cmdchild.stdout.on('data', function (c) { replydata += c.toString(); });
|
||||||
mesh.cmdchild.stderr.on('data', function (c) { replydata + c.toString(); });
|
mesh.cmdchild.stderr.on('data', function (c) { replydata += c.toString(); });
|
||||||
mesh.cmdchild.stdin.write(data.cmds.split('\r').join('') + '\nexit\n');
|
mesh.cmdchild.stdin.write(data.cmds.split('\r').join('') + '\nexit\n');
|
||||||
mesh.cmdchild.on('exit', function () {
|
mesh.cmdchild.on('exit', function () {
|
||||||
if (data.reply) {
|
if (data.reply) {
|
||||||
|
|
@ -2297,6 +2315,59 @@ function terminal_end()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function terminal_consent_ask(ws) {
|
||||||
|
ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
|
||||||
|
var consentMessage = currentTranslation['terminalConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username);
|
||||||
|
var consentTitle = 'MeshCentral';
|
||||||
|
if (ws.httprequest.soptions != null) {
|
||||||
|
if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; }
|
||||||
|
if (ws.httprequest.soptions.consentMsgTerminal != null) { consentMessage = ws.httprequest.soptions.consentMsgTerminal.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
|
||||||
|
}
|
||||||
|
if (process.platform == 'win32') {
|
||||||
|
var enhanced = false;
|
||||||
|
if (ws.httprequest.oldStyle === false) {
|
||||||
|
try { require('win-userconsent'); enhanced = true; } catch (ex) { }
|
||||||
|
}
|
||||||
|
if (enhanced) {
|
||||||
|
var ipr = server_getUserImage(ws.httprequest.userid);
|
||||||
|
ipr.consentTitle = consentTitle;
|
||||||
|
ipr.consentMessage = consentMessage;
|
||||||
|
ipr.consentTimeout = ws.httprequest.consentTimeout;
|
||||||
|
ipr.consentAutoAccept = ws.httprequest.consentAutoAccept;
|
||||||
|
ipr.username = ws.httprequest.realname;
|
||||||
|
ipr.tsid = ws.tsid;
|
||||||
|
ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
|
||||||
|
ws.httprequest.tpromise._consent = ipr.then(function (img) {
|
||||||
|
this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground });
|
||||||
|
this.__childPromise.close = this.consent.close.bind(this.consent);
|
||||||
|
return (this.consent);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ws.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ws.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout);
|
||||||
|
}
|
||||||
|
ws.httprequest.tpromise._consent.retPromise = ws.httprequest.tpromise;
|
||||||
|
ws.httprequest.tpromise._consent.then(function (always) {
|
||||||
|
if (always && process.platform == 'win32') { server_set_consentTimer(this.retPromise.httprequest.userid); }
|
||||||
|
// Success
|
||||||
|
MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
|
||||||
|
this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
|
||||||
|
this.retPromise._consent = null;
|
||||||
|
this.retPromise._res();
|
||||||
|
}, function (e) {
|
||||||
|
if (this.retPromise.that) {
|
||||||
|
if(this.retPromise.that.httprequest){ // User Consent Denied
|
||||||
|
MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
|
||||||
|
} else { } // Connection was closed server side, maybe log some messages somewhere?
|
||||||
|
this.retPromise._consent = null;
|
||||||
|
this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
|
||||||
|
} else { } // no websocket, maybe log some messages somewhere?
|
||||||
|
this.retPromise._rej(e.toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function terminal_promise_connection_rejected(e)
|
function terminal_promise_connection_rejected(e)
|
||||||
{
|
{
|
||||||
// FAILED to connect terminal
|
// FAILED to connect terminal
|
||||||
|
|
@ -2609,6 +2680,101 @@ function kvm_tunnel_consentpromise_closehandler()
|
||||||
if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); }
|
if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function kvm_consent_ok(ws) {
|
||||||
|
// User Consent Prompt is not required because no user is present
|
||||||
|
if (ws.httprequest.consent && (ws.httprequest.consent & 1)){
|
||||||
|
// User Notifications is required
|
||||||
|
MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
|
||||||
|
var notifyMessage = currentTranslation['desktopNotify'].replace('{0}', ws.httprequest.realname);
|
||||||
|
var notifyTitle = "MeshCentral";
|
||||||
|
if (ws.httprequest.soptions != null) {
|
||||||
|
if (ws.httprequest.soptions.notifyTitle != null) { notifyTitle = ws.httprequest.soptions.notifyTitle; }
|
||||||
|
if (ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
|
||||||
|
}
|
||||||
|
try { require('toaster').Toast(notifyTitle, notifyMessage, ws.tsid); } catch (ex) { }
|
||||||
|
} else {
|
||||||
|
MeshServerLogEx(36, null, "Started remote desktop without notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
|
||||||
|
}
|
||||||
|
if (ws.httprequest.consent && (ws.httprequest.consent & 0x40)) {
|
||||||
|
// Connection Bar is required
|
||||||
|
if (ws.httprequest.desktop.kvm.connectionBar) {
|
||||||
|
ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
|
||||||
|
ws.httprequest.desktop.kvm.connectionBar.close();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(ws.httprequest.privacybartext.replace('{0}', ws.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', ws.httprequest.desktop.kvm.users.join(', ')).replace(/'/g, "\\'\\"), require('MeshAgent')._tsid, color_options);
|
||||||
|
MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
|
||||||
|
} catch (ex) {
|
||||||
|
MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or not Supported (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
|
||||||
|
}
|
||||||
|
if (ws.httprequest.desktop.kvm.connectionBar) {
|
||||||
|
ws.httprequest.desktop.kvm.connectionBar.state = {
|
||||||
|
userid: ws.httprequest.userid,
|
||||||
|
xuserid: ws.httprequest.xuserid,
|
||||||
|
username: ws.httprequest.username,
|
||||||
|
sessionid: ws.httprequest.sessionid,
|
||||||
|
remoteaddr: ws.httprequest.remoteaddr,
|
||||||
|
guestname: ws.httprequest.guestname,
|
||||||
|
desktop: ws.httprequest.desktop
|
||||||
|
};
|
||||||
|
ws.httprequest.desktop.kvm.connectionBar.on('close', function () {
|
||||||
|
console.info1('Connection Bar Forcefully closed');
|
||||||
|
MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.state.remoteaddr + ")", this.state);
|
||||||
|
for (var i in this.state.desktop.kvm._pipedStreams) {
|
||||||
|
this.state.desktop.kvm._pipedStreams[i].end();
|
||||||
|
}
|
||||||
|
this.state.desktop.kvm.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ws.httprequest.desktop.kvm.pipe(ws, { dataTypeSkip: 1 });
|
||||||
|
if (ws.httprequest.autolock) {
|
||||||
|
destopLockHelper_pipe(ws.httprequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function kvm_consent_ask(ws){
|
||||||
|
// Send a console message back using the console channel, "\n" is supported.
|
||||||
|
ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
|
||||||
|
var consentMessage = currentTranslation['desktopConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username);
|
||||||
|
var consentTitle = 'MeshCentral';
|
||||||
|
if (ws.httprequest.soptions != null) {
|
||||||
|
if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; }
|
||||||
|
if (ws.httprequest.soptions.consentMsgDesktop != null) { consentMessage = ws.httprequest.soptions.consentMsgDesktop.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
|
||||||
|
}
|
||||||
|
var pr;
|
||||||
|
if (process.platform == 'win32') {
|
||||||
|
var enhanced = false;
|
||||||
|
if (ws.httprequest.oldStyle === false) {
|
||||||
|
try { require('win-userconsent'); enhanced = true; } catch (ex) { }
|
||||||
|
}
|
||||||
|
if (enhanced) {
|
||||||
|
var ipr = server_getUserImage(ws.httprequest.userid);
|
||||||
|
ipr.consentTitle = consentTitle;
|
||||||
|
ipr.consentMessage = consentMessage;
|
||||||
|
ipr.consentTimeout = ws.httprequest.consentTimeout;
|
||||||
|
ipr.consentAutoAccept = ws.httprequest.consentAutoAccept;
|
||||||
|
ipr.tsid = ws.tsid;
|
||||||
|
ipr.username = ws.httprequest.realname;
|
||||||
|
ipr.translation = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
|
||||||
|
pr = ipr.then(function (img) {
|
||||||
|
this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translation, background: color_options.background, foreground: color_options.foreground });
|
||||||
|
this.__childPromise.close = this.consent.close.bind(this.consent);
|
||||||
|
return (this.consent);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null, ws.tsid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null, ws.tsid);
|
||||||
|
}
|
||||||
|
pr.ws = ws;
|
||||||
|
ws.pause();
|
||||||
|
ws._consentpromise = pr;
|
||||||
|
ws.prependOnceListener('end', kvm_tunnel_consentpromise_closehandler);
|
||||||
|
pr.then(kvm_consentpromise_resolved, kvm_consentpromise_rejected);
|
||||||
|
}
|
||||||
|
|
||||||
function kvm_consentpromise_rejected(e)
|
function kvm_consentpromise_rejected(e)
|
||||||
{
|
{
|
||||||
if (this.ws) {
|
if (this.ws) {
|
||||||
|
|
@ -2688,6 +2854,67 @@ function kvm_consentpromise_resolved(always)
|
||||||
this.ws = null;
|
this.ws = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function files_consent_ok(ws){
|
||||||
|
// User Consent Prompt is not required
|
||||||
|
if (ws.httprequest.consent && (ws.httprequest.consent & 4)) {
|
||||||
|
// User Notifications is required
|
||||||
|
MeshServerLogEx(42, null, "Started remote files with toast notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
|
||||||
|
var notifyMessage = currentTranslation['fileNotify'].replace('{0}', ws.httprequest.realname);
|
||||||
|
var notifyTitle = "MeshCentral";
|
||||||
|
if (ws.httprequest.soptions != null) {
|
||||||
|
if (ws.httprequest.soptions.notifyTitle != null) { notifyTitle = ws.httprequest.soptions.notifyTitle; }
|
||||||
|
if (ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = ws.httprequest.soptions.notifyMsgFiles.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
|
||||||
|
}
|
||||||
|
try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { }
|
||||||
|
} else {
|
||||||
|
MeshServerLogEx(43, null, "Started remote files without notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
|
||||||
|
}
|
||||||
|
ws.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
function files_consent_ask(ws){
|
||||||
|
// Send a console message back using the console channel, "\n" is supported.
|
||||||
|
ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
|
||||||
|
var consentMessage = currentTranslation['fileConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username);
|
||||||
|
var consentTitle = 'MeshCentral';
|
||||||
|
|
||||||
|
if (ws.httprequest.soptions != null) {
|
||||||
|
if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; }
|
||||||
|
if (ws.httprequest.soptions.consentMsgFiles != null) { consentMessage = ws.httprequest.soptions.consentMsgFiles.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
|
||||||
|
}
|
||||||
|
var pr;
|
||||||
|
if (process.platform == 'win32') {
|
||||||
|
var enhanced = false;
|
||||||
|
if (ws.httprequest.oldStyle === false) {
|
||||||
|
try { require('win-userconsent'); enhanced = true; } catch (ex) { }
|
||||||
|
}
|
||||||
|
if (enhanced) {
|
||||||
|
var ipr = server_getUserImage(ws.httprequest.userid);
|
||||||
|
ipr.consentTitle = consentTitle;
|
||||||
|
ipr.consentMessage = consentMessage;
|
||||||
|
ipr.consentTimeout = ws.httprequest.consentTimeout;
|
||||||
|
ipr.consentAutoAccept = ws.httprequest.consentAutoAccept;
|
||||||
|
ipr.username = ws.httprequest.realname;
|
||||||
|
ipr.tsid = ws.tsid;
|
||||||
|
ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
|
||||||
|
pr = ipr.then(function (img) {
|
||||||
|
this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground });
|
||||||
|
this.__childPromise.close = this.consent.close.bind(this.consent);
|
||||||
|
return (this.consent);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null);
|
||||||
|
}
|
||||||
|
pr.ws = ws;
|
||||||
|
ws.pause();
|
||||||
|
ws._consentpromise = pr;
|
||||||
|
ws.prependOnceListener('end', files_tunnel_endhandler);
|
||||||
|
pr.then(files_consentpromise_resolved, files_consentpromise_rejected);
|
||||||
|
}
|
||||||
|
|
||||||
function files_consentpromise_resolved(always)
|
function files_consentpromise_resolved(always)
|
||||||
{
|
{
|
||||||
if (always && process.platform == 'win32') { server_set_consentTimer(this.ws.httprequest.userid); }
|
if (always && process.platform == 'win32') { server_set_consentTimer(this.ws.httprequest.userid); }
|
||||||
|
|
@ -2801,6 +3028,12 @@ function onTunnelData(data)
|
||||||
|
|
||||||
this.descriptorMetadata = "Remote Terminal";
|
this.descriptorMetadata = "Remote Terminal";
|
||||||
|
|
||||||
|
// Look for a TSID
|
||||||
|
var tsid = null;
|
||||||
|
if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
|
||||||
|
require('MeshAgent')._tsid = tsid;
|
||||||
|
this.tsid = tsid;
|
||||||
|
|
||||||
if (process.platform == 'win32')
|
if (process.platform == 'win32')
|
||||||
{
|
{
|
||||||
if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9)) {
|
if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9)) {
|
||||||
|
|
@ -2817,76 +3050,31 @@ function onTunnelData(data)
|
||||||
this.end = terminal_end;
|
this.end = terminal_end;
|
||||||
|
|
||||||
// Perform User-Consent if needed.
|
// Perform User-Consent if needed.
|
||||||
if (this.httprequest.consent && (this.httprequest.consent & 16))
|
if (this.httprequest.consent && (this.httprequest.consent & 16)) {
|
||||||
{
|
// User asked for consent so now we check if we can auto accept if no user is present/loggedin
|
||||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
|
if (this.httprequest.consentAutoAcceptIfNoUser) {
|
||||||
var consentMessage = currentTranslation['terminalConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
|
var p = require('user-sessions').enumerateUsers();
|
||||||
var consentTitle = 'MeshCentral';
|
p.sessionid = this.httprequest.sessionid;
|
||||||
|
p.ws = this;
|
||||||
if (this.httprequest.soptions != null)
|
p.then(function (u) {
|
||||||
{
|
var v = [];
|
||||||
if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
|
for (var i in u) {
|
||||||
if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
|
if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
|
||||||
}
|
}
|
||||||
if (process.platform == 'win32')
|
if (v.length == 0) { // No user is present, auto accept
|
||||||
{
|
this.ws.httprequest.tpromise._res();
|
||||||
var enhanced = false;
|
} else {
|
||||||
if (this.httprequest.oldStyle === false) {
|
// User is present so we still need consent
|
||||||
try { require('win-userconsent'); enhanced = true; } catch (ex) { }
|
terminal_consent_ask(this.ws);
|
||||||
}
|
}
|
||||||
if (enhanced)
|
|
||||||
{
|
|
||||||
var ipr = server_getUserImage(this.httprequest.userid);
|
|
||||||
ipr.consentTitle = consentTitle;
|
|
||||||
ipr.consentMessage = consentMessage;
|
|
||||||
ipr.consentTimeout = this.httprequest.consentTimeout;
|
|
||||||
ipr.consentAutoAccept = this.httprequest.consentAutoAccept;
|
|
||||||
ipr.username = this.httprequest.realname;
|
|
||||||
ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
|
|
||||||
this.httprequest.tpromise._consent = ipr.then(function (img)
|
|
||||||
{
|
|
||||||
this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground });
|
|
||||||
this.__childPromise.close = this.consent.close.bind(this.consent);
|
|
||||||
return (this.consent);
|
|
||||||
});
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout);
|
|
||||||
}
|
|
||||||
this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
|
|
||||||
this.httprequest.tpromise._consent.then(
|
|
||||||
function (always)
|
|
||||||
{
|
|
||||||
if (always && process.platform == 'win32') { server_set_consentTimer(this.retPromise.httprequest.userid); }
|
|
||||||
|
|
||||||
// Success
|
|
||||||
MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
|
|
||||||
this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
|
|
||||||
this.retPromise._consent = null;
|
|
||||||
this.retPromise._res();
|
|
||||||
},
|
|
||||||
function (e) {
|
|
||||||
if (this.retPromise.that) {
|
|
||||||
if(this.retPromise.that.httprequest){ // User Consent Denied
|
|
||||||
MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
|
|
||||||
} else { } // Connection was closed server side, maybe log some messages somewhere?
|
|
||||||
this.retPromise._consent = null;
|
|
||||||
this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
|
|
||||||
} else { } // no websocket, maybe log some messages somewhere?
|
|
||||||
this.retPromise._rej(e.toString());
|
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
terminal_consent_ask(this);
|
||||||
{
|
}
|
||||||
|
} else {
|
||||||
// User-Consent is not required, so just resolve this promise
|
// User-Consent is not required, so just resolve this promise
|
||||||
this.httprequest.tpromise._res();
|
this.httprequest.tpromise._res();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.httprequest.tpromise.then(terminal_promise_consent_resolved, terminal_promise_consent_rejected);
|
this.httprequest.tpromise.then(terminal_promise_consent_resolved, terminal_promise_consent_rejected);
|
||||||
}
|
}
|
||||||
else if (this.httprequest.protocol == 2)
|
else if (this.httprequest.protocol == 2)
|
||||||
|
|
@ -2910,6 +3098,7 @@ function onTunnelData(data)
|
||||||
var tsid = null;
|
var tsid = null;
|
||||||
if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
|
if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
|
||||||
require('MeshAgent')._tsid = tsid;
|
require('MeshAgent')._tsid = tsid;
|
||||||
|
this.tsid = tsid;
|
||||||
|
|
||||||
// If MacOS, Wake up device with caffeinate
|
// If MacOS, Wake up device with caffeinate
|
||||||
if(process.platform == 'darwin'){
|
if(process.platform == 'darwin'){
|
||||||
|
|
@ -2981,119 +3170,33 @@ function onTunnelData(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform notification if needed. Toast messages may not be supported on all platforms.
|
// Perform notification if needed. Toast messages may not be supported on all platforms.
|
||||||
if (this.httprequest.consent && (this.httprequest.consent & 8))
|
if (this.httprequest.consent && (this.httprequest.consent & 8)) {
|
||||||
{
|
|
||||||
// User Consent Prompt is required
|
// User asked for consent but now we check if can auto accept if no user is present
|
||||||
// Send a console message back using the console channel, "\n" is supported.
|
if (this.httprequest.consentAutoAcceptIfNoUser) {
|
||||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
|
// Get list of users to check if we any actual users logged in, and if users logged in, we still need consent
|
||||||
var consentMessage = currentTranslation['desktopConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
|
var p = require('user-sessions').enumerateUsers();
|
||||||
var consentTitle = 'MeshCentral';
|
p.sessionid = this.httprequest.sessionid;
|
||||||
if (this.httprequest.soptions != null)
|
p.ws = this;
|
||||||
{
|
p.then(function (u) {
|
||||||
if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
|
var v = [];
|
||||||
if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
|
for (var i in u) {
|
||||||
|
if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
|
||||||
|
}
|
||||||
|
if (v.length == 0) { // No user is present, auto accept
|
||||||
|
kvm_consent_ok(this.ws);
|
||||||
|
} else {
|
||||||
|
// User is present so we still need consent
|
||||||
|
kvm_consent_ask(this.ws);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// User Consent Prompt is required
|
||||||
|
kvm_consent_ask(this);
|
||||||
}
|
}
|
||||||
var pr;
|
} else {
|
||||||
if (process.platform == 'win32')
|
|
||||||
{
|
|
||||||
var enhanced = false;
|
|
||||||
if (this.httprequest.oldStyle === false) {
|
|
||||||
try { require('win-userconsent'); enhanced = true; } catch (ex) { }
|
|
||||||
}
|
|
||||||
if (enhanced)
|
|
||||||
{
|
|
||||||
var ipr = server_getUserImage(this.httprequest.userid);
|
|
||||||
ipr.consentTitle = consentTitle;
|
|
||||||
ipr.consentMessage = consentMessage;
|
|
||||||
ipr.consentTimeout = this.httprequest.consentTimeout;
|
|
||||||
ipr.consentAutoAccept = this.httprequest.consentAutoAccept;
|
|
||||||
ipr.tsid = tsid;
|
|
||||||
ipr.username = this.httprequest.realname;
|
|
||||||
ipr.translation = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
|
|
||||||
pr = ipr.then(function (img)
|
|
||||||
{
|
|
||||||
this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translation, background: color_options.background, foreground: color_options.foreground });
|
|
||||||
this.__childPromise.close = this.consent.close.bind(this.consent);
|
|
||||||
return (this.consent);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null, tsid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null, tsid);
|
|
||||||
}
|
|
||||||
pr.ws = this;
|
|
||||||
this.pause();
|
|
||||||
this._consentpromise = pr;
|
|
||||||
this.prependOnceListener('end', kvm_tunnel_consentpromise_closehandler);
|
|
||||||
pr.then(kvm_consentpromise_resolved, kvm_consentpromise_rejected);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// User Consent Prompt is not required
|
// User Consent Prompt is not required
|
||||||
if (this.httprequest.consent && (this.httprequest.consent & 1))
|
kvm_consent_ok(this);
|
||||||
{
|
|
||||||
// User Notifications is required
|
|
||||||
MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
|
|
||||||
var notifyMessage = currentTranslation['desktopNotify'].replace('{0}', this.httprequest.realname);
|
|
||||||
var notifyTitle = "MeshCentral";
|
|
||||||
if (this.httprequest.soptions != null) {
|
|
||||||
if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
|
|
||||||
if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
|
|
||||||
}
|
|
||||||
try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (ex) { }
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
|
|
||||||
}
|
|
||||||
if (this.httprequest.consent && (this.httprequest.consent & 0x40))
|
|
||||||
{
|
|
||||||
// Connection Bar is required
|
|
||||||
if (this.httprequest.desktop.kvm.connectionBar)
|
|
||||||
{
|
|
||||||
this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
|
|
||||||
this.httprequest.desktop.kvm.connectionBar.close();
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')).replace(/'/g, "\\'\\"), require('MeshAgent')._tsid, color_options);
|
|
||||||
MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
|
|
||||||
} catch (ex) {
|
|
||||||
MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
|
|
||||||
}
|
|
||||||
if (this.httprequest.desktop.kvm.connectionBar)
|
|
||||||
{
|
|
||||||
this.httprequest.desktop.kvm.connectionBar.state =
|
|
||||||
{
|
|
||||||
userid: this.httprequest.userid,
|
|
||||||
xuserid: this.httprequest.xuserid,
|
|
||||||
username: this.httprequest.username,
|
|
||||||
sessionid: this.httprequest.sessionid,
|
|
||||||
remoteaddr: this.httprequest.remoteaddr,
|
|
||||||
guestname: this.httprequest.guestname,
|
|
||||||
desktop: this.httprequest.desktop
|
|
||||||
};
|
|
||||||
this.httprequest.desktop.kvm.connectionBar.on('close', function ()
|
|
||||||
{
|
|
||||||
console.info1('Connection Bar Forcefully closed');
|
|
||||||
MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.state.remoteaddr + ")", this.state);
|
|
||||||
for (var i in this.state.desktop.kvm._pipedStreams)
|
|
||||||
{
|
|
||||||
this.state.desktop.kvm._pipedStreams[i].end();
|
|
||||||
}
|
|
||||||
this.state.desktop.kvm.end();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
|
|
||||||
if (this.httprequest.autolock)
|
|
||||||
{
|
|
||||||
destopLockHelper_pipe(this.httprequest);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.removeAllListeners('data');
|
this.removeAllListeners('data');
|
||||||
|
|
@ -3115,6 +3218,12 @@ function onTunnelData(data)
|
||||||
|
|
||||||
this.descriptorMetadata = "Remote Files";
|
this.descriptorMetadata = "Remote Files";
|
||||||
|
|
||||||
|
// Look for a TSID
|
||||||
|
var tsid = null;
|
||||||
|
if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
|
||||||
|
require('MeshAgent')._tsid = tsid;
|
||||||
|
this.tsid = tsid;
|
||||||
|
|
||||||
// Add the files session to the count to update the server
|
// Add the files session to the count to update the server
|
||||||
if (this.httprequest.userid != null) {
|
if (this.httprequest.userid != null) {
|
||||||
var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest);
|
var userid = getUserIdAndGuestNameFromHttpRequest(this.httprequest);
|
||||||
|
|
@ -3137,71 +3246,31 @@ function onTunnelData(data)
|
||||||
// Perform notification if needed. Toast messages may not be supported on all platforms.
|
// Perform notification if needed. Toast messages may not be supported on all platforms.
|
||||||
if (this.httprequest.consent && (this.httprequest.consent & 32))
|
if (this.httprequest.consent && (this.httprequest.consent & 32))
|
||||||
{
|
{
|
||||||
// User Consent Prompt is required
|
// User asked for consent so now we check if we can auto accept if no user is present/loggedin
|
||||||
// Send a console message back using the console channel, "\n" is supported.
|
if (this.httprequest.consentAutoAcceptIfNoUser) {
|
||||||
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
|
var p = require('user-sessions').enumerateUsers();
|
||||||
var consentMessage = currentTranslation['fileConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
|
p.sessionid = this.httprequest.sessionid;
|
||||||
var consentTitle = 'MeshCentral';
|
p.ws = this;
|
||||||
|
p.then(function (u) {
|
||||||
if (this.httprequest.soptions != null)
|
var v = [];
|
||||||
{
|
for (var i in u) {
|
||||||
if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
|
if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
|
||||||
if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
|
}
|
||||||
}
|
if (v.length == 0) { // No user is present, auto accept
|
||||||
var pr;
|
// User Consent Prompt is not required
|
||||||
if (process.platform == 'win32')
|
files_consent_ok(this.ws);
|
||||||
{
|
} else {
|
||||||
var enhanced = false;
|
// User is present so we still need consent
|
||||||
if (this.httprequest.oldStyle === false) {
|
files_consent_ask(this.ws);
|
||||||
try { require('win-userconsent'); enhanced = true; } catch (ex) { }
|
}
|
||||||
}
|
});
|
||||||
if (enhanced)
|
|
||||||
{
|
|
||||||
var ipr = server_getUserImage(this.httprequest.userid);
|
|
||||||
ipr.consentTitle = consentTitle;
|
|
||||||
ipr.consentMessage = consentMessage;
|
|
||||||
ipr.consentTimeout = this.httprequest.consentTimeout;
|
|
||||||
ipr.consentAutoAccept = this.httprequest.consentAutoAccept;
|
|
||||||
ipr.username = this.httprequest.realname;
|
|
||||||
ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
|
|
||||||
pr = ipr.then(function (img)
|
|
||||||
{
|
|
||||||
this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground });
|
|
||||||
this.__childPromise.close = this.consent.close.bind(this.consent);
|
|
||||||
return (this.consent);
|
|
||||||
});
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null);
|
|
||||||
}
|
|
||||||
pr.ws = this;
|
|
||||||
this.pause();
|
|
||||||
this._consentpromise = pr;
|
|
||||||
this.prependOnceListener('end', files_tunnel_endhandler);
|
|
||||||
pr.then(files_consentpromise_resolved, files_consentpromise_rejected);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// User Consent Prompt is not required
|
|
||||||
if (this.httprequest.consent && (this.httprequest.consent & 4)) {
|
|
||||||
// User Notifications is required
|
|
||||||
MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
|
|
||||||
var notifyMessage = currentTranslation['fileNotify'].replace('{0}', this.httprequest.realname);
|
|
||||||
var notifyTitle = "MeshCentral";
|
|
||||||
if (this.httprequest.soptions != null) {
|
|
||||||
if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
|
|
||||||
if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
|
|
||||||
}
|
|
||||||
try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { }
|
|
||||||
} else {
|
} else {
|
||||||
MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
|
// User Consent Prompt is required
|
||||||
|
files_consent_ask(this);
|
||||||
}
|
}
|
||||||
this.resume();
|
} else {
|
||||||
|
// User Consent Prompt is not required
|
||||||
|
files_consent_ok(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup files
|
// Setup files
|
||||||
|
|
@ -3689,7 +3758,14 @@ function onTunnelControlData(data, ws) {
|
||||||
{ // Desktop
|
{ // Desktop
|
||||||
// Switch the user input from websocket to webrtc at this point.
|
// Switch the user input from websocket to webrtc at this point.
|
||||||
ws.unpipe(ws.httprequest.desktop.kvm);
|
ws.unpipe(ws.httprequest.desktop.kvm);
|
||||||
try { ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); } catch (ex) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text.
|
if ((ws.httprequest.desktopviewonly != true) && ((ws.httprequest.rights == 0xFFFFFFFF) || (((ws.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((ws.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)))) {
|
||||||
|
// If we have remote control rights, pipe the KVM input
|
||||||
|
try { ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); } catch (ex) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text.
|
||||||
|
} else {
|
||||||
|
// We need to only pipe non-mouse & non-keyboard inputs.
|
||||||
|
// sendConsoleText('Warning: No Remote Desktop Input Rights.');
|
||||||
|
// TODO!!!
|
||||||
|
}
|
||||||
ws.resume(); // Resume the websocket to keep receiving control data
|
ws.resume(); // Resume the websocket to keep receiving control data
|
||||||
}
|
}
|
||||||
ws.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}'); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
|
ws.write('{\"ctrlChannel\":\"102938\",\"type\":\"webrtc2\"}'); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
|
||||||
|
|
@ -4290,7 +4366,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
|
||||||
}
|
}
|
||||||
case 'agentmsg': {
|
case 'agentmsg': {
|
||||||
if (args['_'].length == 0) {
|
if (args['_'].length == 0) {
|
||||||
response = "Proper usage:\r\n agentmsg add \"[message]\" [iconIndex]\r\n agentmsg remove [index]\r\n agentmsg list"; // Display usage
|
response = "Proper usage:\r\n agentmsg add \"[message]\" [iconIndex]\r\n agentmsg remove [id]\r\n agentmsg list"; // Display usage
|
||||||
} else {
|
} else {
|
||||||
if ((args['_'][0] == 'add') && (args['_'].length > 1)) {
|
if ((args['_'][0] == 'add') && (args['_'].length > 1)) {
|
||||||
var msgID, iconIndex = 0;
|
var msgID, iconIndex = 0;
|
||||||
|
|
@ -4508,10 +4584,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
|
||||||
if (process.platform == 'win32') {
|
if (process.platform == 'win32') {
|
||||||
// Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
|
// Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
|
||||||
var writtenSize = 0;
|
var writtenSize = 0;
|
||||||
try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (ex) { response = ex; }
|
var serviceName = (_MSH().serviceName ? _MSH().serviceName : (require('_agentNodeId').serviceName() ? require('_agentNodeId').serviceName() : 'Mesh Agent'));
|
||||||
|
try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize'); } catch (ex) { response = ex; }
|
||||||
if (writtenSize != actualSize) {
|
if (writtenSize != actualSize) {
|
||||||
response = "Size updated from: " + writtenSize + " to: " + actualSize;
|
response = "Size updated from: " + writtenSize + " to: " + actualSize;
|
||||||
try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (ex) { response = ex; }
|
try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize', actualSize); } catch (ex) { response = ex; }
|
||||||
} else
|
} else
|
||||||
{ response = "Agent Size: " + actualSize + " kb"; }
|
{ response = "Agent Size: " + actualSize + " kb"; }
|
||||||
} else
|
} else
|
||||||
|
|
@ -5591,7 +5668,7 @@ function windows_execve(name, agentfilename, sessionid) {
|
||||||
sendAgentMessage('Self Update failed because msvcrt.dll is missing', 3);
|
sendAgentMessage('Self Update failed because msvcrt.dll is missing', 3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true });
|
var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true });
|
||||||
var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize);
|
var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize);
|
||||||
var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true });
|
var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true });
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -719,7 +719,8 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
|
||||||
}
|
}
|
||||||
else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i.trim(), header[i]); } // Set the headers if not blocked
|
else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i.trim(), header[i]); } // Set the headers if not blocked
|
||||||
}
|
}
|
||||||
obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future
|
// Dont set any Content-Security-Policy at all because some applications like Node-Red, access external websites from there javascript which would be forbidden by the below CSP
|
||||||
|
//obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future
|
||||||
//obj.res.set('Content-Security-Policy', "default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline';"); // Set an "allow all" policy, see if the can restrict this in the future
|
//obj.res.set('Content-Security-Policy', "default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline';"); // Set an "allow all" policy, see if the can restrict this in the future
|
||||||
obj.res.set('Cache-Control', 'no-store'); // Tell the browser not to cache the responses since since the relay port can be used for many relays
|
obj.res.set('Cache-Control', 'no-store'); // Tell the browser not to cache the responses since since the relay port can be used for many relays
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,12 +155,12 @@ module.exports.objKeysToLower = function (obj, exceptions, parent) {
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Escape and unescape field names so there are no invalid characters for MongoDB
|
// Escape and unescape field names so there are no invalid characters for MongoDB/NeDB ("$", ",", ".", see https://github.com/seald/nedb/tree/master?tab=readme-ov-file#inserting-documents)
|
||||||
module.exports.escapeFieldName = function (name) { if ((name.indexOf('%') == -1) && (name.indexOf('.') == -1) && (name.indexOf('$') == -1)) return name; return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24'); };
|
module.exports.escapeFieldName = function (name) { if ((name.indexOf(',') == -1) && (name.indexOf('%') == -1) && (name.indexOf('.') == -1) && (name.indexOf('$') == -1)) return name; return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24').split(',').join('%2C'); };
|
||||||
module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); };
|
module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2C').join(',').split('%2E').join('.').split('%24').join('$').split('%25').join('%'); };
|
||||||
|
|
||||||
// Escape all links, SSH and RDP usernames
|
// Escape all links, SSH and RDP usernames
|
||||||
// This is required for databases like NeDB that don't accept "." as part of a field name.
|
// This is required for databases like NeDB that don't accept "." or "," as part of a field name.
|
||||||
module.exports.escapeLinksFieldNameEx = function (docx) { if ((docx.links == null) && (docx.ssh == null) && (docx.rdp == null)) { return docx; } return module.exports.escapeLinksFieldName(docx); };
|
module.exports.escapeLinksFieldNameEx = function (docx) { if ((docx.links == null) && (docx.ssh == null) && (docx.rdp == null)) { return docx; } return module.exports.escapeLinksFieldName(docx); };
|
||||||
module.exports.escapeLinksFieldName = function (docx) {
|
module.exports.escapeLinksFieldName = function (docx) {
|
||||||
var doc = Object.assign({}, docx);
|
var doc = Object.assign({}, docx);
|
||||||
|
|
|
||||||
298
db.js
298
db.js
|
|
@ -781,10 +781,10 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
parent.debug('db', 'SQlite config options: ' + JSON.stringify(obj.sqliteConfig, null, 4));
|
parent.debug('db', 'SQlite config options: ' + JSON.stringify(obj.sqliteConfig, null, 4));
|
||||||
if (obj.sqliteConfig.journalMode == 'memory') { console.log('[WARNING] journal_mode=memory: this can lead to database corruption if there is a crash during a transaction. See https://www.sqlite.org/pragma.html#pragma_journal_mode') };
|
if (obj.sqliteConfig.journalMode == 'memory') { console.log('[WARNING] journal_mode=memory: this can lead to database corruption if there is a crash during a transaction. See https://www.sqlite.org/pragma.html#pragma_journal_mode') };
|
||||||
//.cached not usefull
|
//.cached not usefull
|
||||||
obj.file = new sqlite3.Database(parent.path.join(parent.datapath, databaseName + '.sqlite'), sqlite3.OPEN_READWRITE, function (err) {
|
obj.file = new sqlite3.Database(path.join(parent.datapath, databaseName + '.sqlite'), sqlite3.OPEN_READWRITE, function (err) {
|
||||||
if (err && (err.code == 'SQLITE_CANTOPEN')) {
|
if (err && (err.code == 'SQLITE_CANTOPEN')) {
|
||||||
// Database needs to be created
|
// Database needs to be created
|
||||||
obj.file = new sqlite3.Database(parent.path.join(parent.datapath, databaseName + '.sqlite'), function (err) {
|
obj.file = new sqlite3.Database(path.join(parent.datapath, databaseName + '.sqlite'), function (err) {
|
||||||
if (err) { console.log("SQLite Error: " + err); process.exit(1); }
|
if (err) { console.log("SQLite Error: " + err); process.exit(1); }
|
||||||
obj.file.exec(`
|
obj.file.exec(`
|
||||||
CREATE TABLE main (id VARCHAR(256) PRIMARY KEY NOT NULL, type CHAR(32), domain CHAR(64), extra CHAR(255), extraex CHAR(255), doc JSON);
|
CREATE TABLE main (id VARCHAR(256) PRIMARY KEY NOT NULL, type CHAR(32), domain CHAR(64), extra CHAR(255), extraex CHAR(255), doc JSON);
|
||||||
|
|
@ -975,7 +975,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
} else {
|
} else {
|
||||||
if ((info.versionArray[0] < 3) || ((info.versionArray[0] == 3) && (info.versionArray[1] < 6))) {
|
if ((info.versionArray[0] < 3) || ((info.versionArray[0] == 3) && (info.versionArray[1] < 6))) {
|
||||||
// We are running with mongoDB older than 3.6, this is not good.
|
// We are running with mongoDB older than 3.6, this is not good.
|
||||||
parent.addServerWarning("Current version of MongoDB (" + info.version + ") is too old, please upgrade to MongoDB 3.6 or better.");
|
parent.addServerWarning("Current version of MongoDB (" + info.version + ") is too old, please upgrade to MongoDB 3.6 or better.", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1294,7 +1294,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
|
|
||||||
// Setup the SMBIOS collection, for NeDB we don't setup SMBIOS since NeDB will corrupt the database. Remove any existing ones.
|
// Setup the SMBIOS collection, for NeDB we don't setup SMBIOS since NeDB will corrupt the database. Remove any existing ones.
|
||||||
//obj.smbiosfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-smbios.db'), autoload: true, corruptAlertThreshold: 1 });
|
//obj.smbiosfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-smbios.db'), autoload: true, corruptAlertThreshold: 1 });
|
||||||
parent.fs.unlink(parent.getConfigFilePath('meshcentral-smbios.db'), function () { });
|
fs.unlink(parent.getConfigFilePath('meshcentral-smbios.db'), function () { });
|
||||||
|
|
||||||
// Setup the server stats collection and setup indexes
|
// Setup the server stats collection and setup indexes
|
||||||
obj.serverstatsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-stats.db'), autoload: true, corruptAlertThreshold: 1 });
|
obj.serverstatsfile = new Datastore({ filename: parent.getConfigFilePath('meshcentral-stats.db'), autoload: true, corruptAlertThreshold: 1 });
|
||||||
|
|
@ -3187,7 +3187,6 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
// Return a human readable string with current backup configuration
|
// Return a human readable string with current backup configuration
|
||||||
obj.getBackupConfig = function () {
|
obj.getBackupConfig = function () {
|
||||||
var r = '', backupPath = parent.backuppath;
|
var r = '', backupPath = parent.backuppath;
|
||||||
if (parent.config.settings.autobackup && parent.config.settings.autobackup.backuppath) { backupPath = parent.config.settings.autobackup.backuppath; }
|
|
||||||
|
|
||||||
let dbname = 'meshcentral';
|
let dbname = 'meshcentral';
|
||||||
if (parent.args.mongodbname) { dbname = parent.args.mongodbname; }
|
if (parent.args.mongodbname) { dbname = parent.args.mongodbname; }
|
||||||
|
|
@ -3197,7 +3196,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
|
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const fileSuffix = currentDate.getFullYear() + '-' + padNumber(currentDate.getMonth() + 1, 2) + '-' + padNumber(currentDate.getDate(), 2) + '-' + padNumber(currentDate.getHours(), 2) + '-' + padNumber(currentDate.getMinutes(), 2);
|
const fileSuffix = currentDate.getFullYear() + '-' + padNumber(currentDate.getMonth() + 1, 2) + '-' + padNumber(currentDate.getDate(), 2) + '-' + padNumber(currentDate.getHours(), 2) + '-' + padNumber(currentDate.getMinutes(), 2);
|
||||||
obj.newAutoBackupFile = ((typeof parent.config.settings.autobackup.backupname == 'string') ? parent.config.settings.autobackup.backupname : 'meshcentral-autobackup-') + fileSuffix;
|
obj.newAutoBackupFile = parent.config.settings.autobackup.backupname + fileSuffix;
|
||||||
|
|
||||||
r += 'DB Name: ' + dbname + '\r\n';
|
r += 'DB Name: ' + dbname + '\r\n';
|
||||||
r += 'DB Type: ' + DB_LIST[obj.databaseType] + '\r\n';
|
r += 'DB Type: ' + DB_LIST[obj.databaseType] + '\r\n';
|
||||||
|
|
@ -3207,15 +3206,14 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
if (parent.config.settings.autobackup == null) {
|
if (parent.config.settings.autobackup == null) {
|
||||||
r += 'No Settings/AutoBackup\r\n';
|
r += 'No Settings/AutoBackup\r\n';
|
||||||
} else {
|
} else {
|
||||||
|
if (parent.config.settings.autobackup.backuphour != null && parent.config.settings.autobackup.backuphour != -1) {
|
||||||
|
r += 'Backup between: ' + parent.config.settings.autobackup.backuphour + 'H-' + (parent.config.settings.autobackup.backuphour + 1) + 'H\r\n';
|
||||||
|
}
|
||||||
if (parent.config.settings.autobackup.backupintervalhours != null) {
|
if (parent.config.settings.autobackup.backupintervalhours != null) {
|
||||||
r += 'Backup Interval (Hours): ';
|
r += 'Backup Interval (Hours): ' + parent.config.settings.autobackup.backupintervalhours + '\r\n';
|
||||||
if (typeof parent.config.settings.autobackup.backupintervalhours != 'number') { r += 'Bad backupintervalhours type\r\n'; }
|
|
||||||
else { r += parent.config.settings.autobackup.backupintervalhours + '\r\n'; }
|
|
||||||
}
|
}
|
||||||
if (parent.config.settings.autobackup.keeplastdaysbackup != null) {
|
if (parent.config.settings.autobackup.keeplastdaysbackup != null) {
|
||||||
r += 'Keep Last Backups (Days): ';
|
r += 'Keep Last Backups (Days): ' + parent.config.settings.autobackup.keeplastdaysbackup + '\r\n';
|
||||||
if (typeof parent.config.settings.autobackup.keeplastdaysbackup != 'number') { r += 'Bad keeplastdaysbackup type\r\n'; }
|
|
||||||
else { r += parent.config.settings.autobackup.keeplastdaysbackup + '\r\n'; }
|
|
||||||
}
|
}
|
||||||
if (parent.config.settings.autobackup.zippassword != null) {
|
if (parent.config.settings.autobackup.zippassword != null) {
|
||||||
r += 'ZIP Password: ';
|
r += 'ZIP Password: ';
|
||||||
|
|
@ -3330,48 +3328,70 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the server is capable of performing a backup
|
// Check that the server is capable of performing a backup
|
||||||
|
// Tries configured custom location with fallback to default location
|
||||||
|
// Now runs after autobackup config init in meshcentral.js so config options are checked
|
||||||
obj.checkBackupCapability = function (func) {
|
obj.checkBackupCapability = function (func) {
|
||||||
if ((parent.config.settings.autobackup == null) || (parent.config.settings.autobackup == false)) { func(); return; };
|
if ((parent.config.settings.autobackup == null) || (parent.config.settings.autobackup == false)) { return; };
|
||||||
|
//block backup until validated. Gets put back if all checks are ok.
|
||||||
|
let backupInterval = parent.config.settings.autobackup.backupintervalhours;
|
||||||
|
parent.config.settings.autobackup.backupintervalhours = -1;
|
||||||
let backupPath = parent.backuppath;
|
let backupPath = parent.backuppath;
|
||||||
if (parent.config.settings.autobackup && parent.config.settings.autobackup.backuppath) { backupPath = parent.config.settings.autobackup.backuppath; }
|
|
||||||
try { parent.fs.mkdirSync(backupPath); } catch (e) { }
|
|
||||||
if (parent.fs.existsSync(backupPath) == false) { func(1, "Backup folder \"" + backupPath + "\" does not exist, auto-backup will not be performed."); return; }
|
|
||||||
|
|
||||||
|
if (backupPath.startsWith(parent.datapath)) {
|
||||||
|
func(1, "Backup path can't be set within meshcentral-data folder. No backups will be made.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check create/write backupdir
|
||||||
|
try { fs.mkdirSync(backupPath); }
|
||||||
|
catch (e) {
|
||||||
|
// EEXIST error = dir already exists
|
||||||
|
if (e.code != 'EEXIST' ) {
|
||||||
|
//Unable to create backuppath
|
||||||
|
console.error(e.message);
|
||||||
|
func(1, 'Unable to create ' + backupPath + '. No backups will be made. Error: ' + e.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const testFile = path.join(backupPath, (parent.config.settings.autobackup.backupname + ".test"));
|
||||||
|
|
||||||
|
try { fs.writeFileSync( testFile, "DeleteMe"); }
|
||||||
|
catch (e) {
|
||||||
|
//Unable to create file
|
||||||
|
console.error (e.message);
|
||||||
|
func(1, "Backuppath (" + backupPath + ") can't be written to. No backups will be made. Error: " + e.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try { fs.unlinkSync(testFile); parent.debug('backup', 'Backuppath ' + backupPath + ' accesscheck successful');}
|
||||||
|
catch (e) {
|
||||||
|
console.error (e.message);
|
||||||
|
func(1, "Backuppathtestfile (" + testFile + ") can't be deleted, check filerights. Error: " + e.message);
|
||||||
|
// Assume write rights, no delete rights. Continue with warning.
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check database dumptools
|
||||||
if ((obj.databaseType == DB_MONGOJS) || (obj.databaseType == DB_MONGODB)) {
|
if ((obj.databaseType == DB_MONGOJS) || (obj.databaseType == DB_MONGODB)) {
|
||||||
// Check that we have access to MongoDump
|
// Check that we have access to MongoDump
|
||||||
var cmd = buildMongoDumpCommand();
|
var cmd = buildMongoDumpCommand();
|
||||||
cmd += (parent.platform == 'win32') ? ' --archive=\"nul\"' : ' --archive=\"/dev/null\"';
|
cmd += (parent.platform == 'win32') ? ' --archive=\"nul\"' : ' --archive=\"/dev/null\"';
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
child_process.exec(cmd, { cwd: backupPath }, function (error, stdout, stderr) {
|
child_process.exec(cmd, { cwd: backupPath }, function (error, stdout, stderr) {
|
||||||
try {
|
if ((error != null) && (error != '')) {
|
||||||
if ((error != null) && (error != '')) {
|
func(1, "Unable to find mongodump tool, backup will not be performed. Command tried: " + cmd);
|
||||||
if (parent.platform == 'win32') {
|
return;
|
||||||
func(1, "Unable to find mongodump.exe, MongoDB database auto-backup will not be performed.");
|
} else {parent.config.settings.autobackup.backupintervalhours = backupInterval;}
|
||||||
} else {
|
|
||||||
func(1, "Unable to find mongodump, MongoDB database auto-backup will not be performed.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
} catch (ex) { console.log(ex); }
|
|
||||||
});
|
});
|
||||||
} else if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL)) {
|
} else if ((obj.databaseType == DB_MARIADB) || (obj.databaseType == DB_MYSQL)) {
|
||||||
// Check that we have access to mysqldump
|
// Check that we have access to mysqldump
|
||||||
var cmd = buildSqlDumpCommand();
|
var cmd = buildSqlDumpCommand();
|
||||||
cmd += ' > ' + ((parent.platform == 'win32') ? '\"nul\"' : '\"/dev/null\"');
|
cmd += ' > ' + ((parent.platform == 'win32') ? '\"nul\"' : '\"/dev/null\"');
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
child_process.exec(cmd, { cwd: backupPath }, function(error, stdout, stdin) {
|
child_process.exec(cmd, { cwd: backupPath, timeout: 1000*30 }, function(error, stdout, stdin) {
|
||||||
try {
|
if ((error != null) && (error != '')) {
|
||||||
if ((error != null) && (error != '')) {
|
func(1, "Unable to find mysqldump tool, backup will not be performed. Command tried: " + cmd);
|
||||||
if (parent.platform == 'win32') {
|
return;
|
||||||
func(1, "Unable to find mysqldump.exe, MySQL/MariaDB database auto-backup will not be performed.");
|
} else {parent.config.settings.autobackup.backupintervalhours = backupInterval;}
|
||||||
} else {
|
|
||||||
func(1, "Unable to find mysqldump, MySQL/MariaDB database auto-backup will not be performed.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
} catch (ex) { console.log(ex); }
|
|
||||||
});
|
});
|
||||||
} else if (obj.databaseType == DB_POSTGRESQL) {
|
} else if (obj.databaseType == DB_POSTGRESQL) {
|
||||||
// Check that we have access to pg_dump
|
// Check that we have access to pg_dump
|
||||||
|
|
@ -3382,17 +3402,14 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
+ ' > ' + ((parent.platform == 'win32') ? '\"nul\"' : '\"/dev/null\"');
|
+ ' > ' + ((parent.platform == 'win32') ? '\"nul\"' : '\"/dev/null\"');
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
child_process.exec(cmd, { cwd: backupPath }, function(error, stdout, stdin) {
|
child_process.exec(cmd, { cwd: backupPath }, function(error, stdout, stdin) {
|
||||||
try {
|
if ((error != null) && (error != '')) {
|
||||||
if ((error != null) && (error != '')) {
|
func(1, "Unable to find pg_dump tool, backup will not be performed. Command tried: " + cmd);
|
||||||
func(1, "Unable to find pg_dump, PostgreSQL database auto-backup will not be performed.");
|
return;
|
||||||
} else {
|
} else {parent.config.settings.autobackup.backupintervalhours = backupInterval;}
|
||||||
func();
|
|
||||||
}
|
|
||||||
} catch (ex) { console.log(ex); }
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
func();
|
//all ok, enable backup
|
||||||
}
|
parent.config.settings.autobackup.backupintervalhours = backupInterval;}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MongoDB pending bulk read operation, perform fast bulk document reads.
|
// MongoDB pending bulk read operation, perform fast bulk document reads.
|
||||||
|
|
@ -3506,19 +3523,18 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
|
|
||||||
// Perform a server backup
|
// Perform a server backup
|
||||||
obj.performBackup = function (func) {
|
obj.performBackup = function (func) {
|
||||||
parent.debug('db','Entering performBackup');
|
parent.debug('backup','Entering performBackup');
|
||||||
try {
|
try {
|
||||||
if (obj.performingBackup) return 'Backup alreay in progress.';
|
if (obj.performingBackup) return 'Backup alreay in progress.';
|
||||||
if (parent.config.settings.autobackup.backupintervalhours == -1) { if (func) { func('Unable to create backup if backuppath is set to the data folder.'); return 'Backup aborted.' }};
|
if (parent.config.settings.autobackup.backupintervalhours == -1) { if (func) { func('Backup disabled.'); return 'Backup disabled.' }};
|
||||||
obj.performingBackup = true;
|
obj.performingBackup = true;
|
||||||
let backupPath = parent.backuppath;
|
let backupPath = parent.backuppath;
|
||||||
let dataPath = parent.datapath;
|
let dataPath = parent.datapath;
|
||||||
|
|
||||||
if (parent.config.settings.autobackup && parent.config.settings.autobackup.backuppath) { backupPath = parent.config.settings.autobackup.backuppath; }
|
|
||||||
try { parent.fs.mkdirSync(backupPath); } catch (e) { }
|
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const fileSuffix = currentDate.getFullYear() + '-' + padNumber(currentDate.getMonth() + 1, 2) + '-' + padNumber(currentDate.getDate(), 2) + '-' + padNumber(currentDate.getHours(), 2) + '-' + padNumber(currentDate.getMinutes(), 2);
|
const fileSuffix = currentDate.getFullYear() + '-' + padNumber(currentDate.getMonth() + 1, 2) + '-' + padNumber(currentDate.getDate(), 2) + '-' + padNumber(currentDate.getHours(), 2) + '-' + padNumber(currentDate.getMinutes(), 2);
|
||||||
obj.newAutoBackupFile = path.join(backupPath, ((typeof parent.config.settings.autobackup.backupname == 'string') ? parent.config.settings.autobackup.backupname : 'meshcentral-autobackup-') + fileSuffix + '.zip');
|
obj.newAutoBackupFile = path.join(backupPath, parent.config.settings.autobackup.backupname + fileSuffix + '.zip');
|
||||||
|
parent.debug('backup','newAutoBackupFile=' + obj.newAutoBackupFile);
|
||||||
|
|
||||||
if ((obj.databaseType == DB_MONGOJS) || (obj.databaseType == DB_MONGODB)) {
|
if ((obj.databaseType == DB_MONGOJS) || (obj.databaseType == DB_MONGODB)) {
|
||||||
// Perform a MongoDump
|
// Perform a MongoDump
|
||||||
|
|
@ -3530,13 +3546,14 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
var cmd = buildMongoDumpCommand();
|
var cmd = buildMongoDumpCommand();
|
||||||
cmd += (dburl) ? ' --archive=\"' + obj.newDBDumpFile + '\"' :
|
cmd += (dburl) ? ' --archive=\"' + obj.newDBDumpFile + '\"' :
|
||||||
' --db=\"' + dbname + '\" --archive=\"' + obj.newDBDumpFile + '\"';
|
' --db=\"' + dbname + '\" --archive=\"' + obj.newDBDumpFile + '\"';
|
||||||
|
parent.debug('backup','Mongodump cmd: ' + cmd);
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
const dumpProcess = child_process.exec(
|
const dumpProcess = child_process.exec(
|
||||||
cmd,
|
cmd,
|
||||||
{ cwd: parent.parentpath },
|
{ cwd: parent.parentpath },
|
||||||
(error)=> {if (error) {obj.backupStatus |= BACKUPFAIL_DBDUMP; console.log('ERROR: Unable to perform MongoDB backup: ' + error + '\r\n'); obj.createBackupfile(func);}}
|
(error)=> {if (error) {obj.backupStatus |= BACKUPFAIL_DBDUMP; console.error('ERROR: Unable to perform MongoDB backup: ' + error + '\r\n'); obj.createBackupfile(func);}}
|
||||||
);
|
);
|
||||||
|
|
||||||
dumpProcess.on('exit', (code) => {
|
dumpProcess.on('exit', (code) => {
|
||||||
if (code != 0) {console.log(`Mongodump child process exited with code ${code}`); obj.backupStatus |= BACKUPFAIL_DBDUMP;}
|
if (code != 0) {console.log(`Mongodump child process exited with code ${code}`); obj.backupStatus |= BACKUPFAIL_DBDUMP;}
|
||||||
obj.createBackupfile(func);
|
obj.createBackupfile(func);
|
||||||
|
|
@ -3549,15 +3566,16 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
|
|
||||||
var cmd = buildSqlDumpCommand();
|
var cmd = buildSqlDumpCommand();
|
||||||
cmd += ' --result-file=\"' + obj.newDBDumpFile + '\"';
|
cmd += ' --result-file=\"' + obj.newDBDumpFile + '\"';
|
||||||
|
parent.debug('backup','Maria/MySQLdump cmd: ' + cmd);
|
||||||
|
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
const dumpProcess = child_process.exec(
|
const dumpProcess = child_process.exec(
|
||||||
cmd,
|
cmd,
|
||||||
{ cwd: parent.parentpath },
|
{ cwd: parent.parentpath },
|
||||||
(error)=> {if (error) {obj.backupStatus |= BACKUPFAIL_DBDUMP; console.log('ERROR: Unable to perform MySQL backup: ' + error + '\r\n'); obj.createBackupfile(func);}}
|
(error)=> {if (error) {obj.backupStatus |= BACKUPFAIL_DBDUMP; console.error('ERROR: Unable to perform MySQL backup: ' + error + '\r\n'); obj.createBackupfile(func);}}
|
||||||
);
|
);
|
||||||
dumpProcess.on('exit', (code) => {
|
dumpProcess.on('exit', (code) => {
|
||||||
if (code != 0) {console.log(`MySQLdump child process exited with code ${code}`); obj.backupStatus |= BACKUPFAIL_DBDUMP;}
|
if (code != 0) {console.error(`MySQLdump child process exited with code ${code}`); obj.backupStatus |= BACKUPFAIL_DBDUMP;}
|
||||||
obj.createBackupfile(func);
|
obj.createBackupfile(func);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -3565,8 +3583,9 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
//.db3 suffix to escape escape backupfile glob to exclude the sqlite db files
|
//.db3 suffix to escape escape backupfile glob to exclude the sqlite db files
|
||||||
obj.newDBDumpFile = path.join(backupPath, databaseName + '-sqlitedump-' + fileSuffix + '.db3');
|
obj.newDBDumpFile = path.join(backupPath, databaseName + '-sqlitedump-' + fileSuffix + '.db3');
|
||||||
// do a VACUUM INTO in favor of the backup API to compress the export, see https://www.sqlite.org/backup.html
|
// do a VACUUM INTO in favor of the backup API to compress the export, see https://www.sqlite.org/backup.html
|
||||||
|
parent.debug('backup','SQLitedump: VACUUM INTO ' + obj.newDBDumpFile);
|
||||||
obj.file.exec('VACUUM INTO \'' + obj.newDBDumpFile + '\'', function (err) {
|
obj.file.exec('VACUUM INTO \'' + obj.newDBDumpFile + '\'', function (err) {
|
||||||
if (err) { console.log('SQLite start-backup error: ' + err); obj.backupStatus |=BACKUPFAIL_DBDUMP;};
|
if (err) { console.error('SQLite backup error: ' + err); obj.backupStatus |=BACKUPFAIL_DBDUMP;};
|
||||||
//always finish/clean up
|
//always finish/clean up
|
||||||
obj.createBackupfile(func);
|
obj.createBackupfile(func);
|
||||||
});
|
});
|
||||||
|
|
@ -3578,6 +3597,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
+ ' --dbname=postgresql://' + parent.config.settings.postgres.user + ":" +parent.config.settings.postgres.password
|
+ ' --dbname=postgresql://' + parent.config.settings.postgres.user + ":" +parent.config.settings.postgres.password
|
||||||
+ "@" + parent.config.settings.postgres.host + ":" + parent.config.settings.postgres.port + "/" + databaseName
|
+ "@" + parent.config.settings.postgres.host + ":" + parent.config.settings.postgres.port + "/" + databaseName
|
||||||
+ " --file=" + obj.newDBDumpFile;
|
+ " --file=" + obj.newDBDumpFile;
|
||||||
|
parent.debug('backup','Postgresqldump cmd: ' + cmd);
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
const dumpProcess = child_process.exec(
|
const dumpProcess = child_process.exec(
|
||||||
cmd,
|
cmd,
|
||||||
|
|
@ -3589,15 +3609,15 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
obj.createBackupfile(func);
|
obj.createBackupfile(func);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
//NeDB backup, no db dump needed, just make a file backup
|
// NeDB/Acebase backup, no db dump needed, just make a file backup
|
||||||
obj.createBackupfile(func);
|
obj.createBackupfile(func);
|
||||||
}
|
}
|
||||||
} catch (ex) { console.log(ex); };
|
} catch (ex) { console.error(ex); parent.addServerWarning( 'Something went wrong during performBackup, check errorlog: ' +ex.message, true); };
|
||||||
return 'Starting auto-backup...';
|
return 'Starting auto-backup...';
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.createBackupfile = function(func) {
|
obj.createBackupfile = function(func) {
|
||||||
parent.debug('db', 'Entering createFileBackup');
|
parent.debug('backup', 'Entering createBackupfile');
|
||||||
let archiver = require('archiver');
|
let archiver = require('archiver');
|
||||||
let archive = null;
|
let archive = null;
|
||||||
let zipLevel = Math.min(Math.max(Number(parent.config.settings.autobackup.zipcompression ? parent.config.settings.autobackup.zipcompression : 5),1),9);
|
let zipLevel = Math.min(Math.max(Number(parent.config.settings.autobackup.zipcompression ? parent.config.settings.autobackup.zipcompression : 5),1),9);
|
||||||
|
|
@ -3611,8 +3631,8 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
if (func) { func('Creating encrypted ZIP'); }
|
if (func) { func('Creating encrypted ZIP'); }
|
||||||
} catch (ex) { // registering encryption failed, do not fall back to non-encrypted, fail backup and skip old backup removal as a precaution to not lose any backups
|
} catch (ex) { // registering encryption failed, do not fall back to non-encrypted, fail backup and skip old backup removal as a precaution to not lose any backups
|
||||||
obj.backupStatus |= BACKUPFAIL_ZIPMODULE;
|
obj.backupStatus |= BACKUPFAIL_ZIPMODULE;
|
||||||
if (func) { func('Zipencryptionmodule failed, aborting'); }
|
if (func) { func('Zipencryptionmodule failed, aborting');}
|
||||||
console.log('Zipencryptionmodule failed, aborting');
|
console.error('Zipencryptionmodule failed, aborting');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (func) { func('Creating a NON-ENCRYPTED ZIP'); }
|
if (func) { func('Creating a NON-ENCRYPTED ZIP'); }
|
||||||
|
|
@ -3622,51 +3642,36 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
//original behavior, just a filebackup if dbdump fails : (obj.backupStatus == 0 || obj.backupStatus == BACKUPFAIL_DBDUMP)
|
//original behavior, just a filebackup if dbdump fails : (obj.backupStatus == 0 || obj.backupStatus == BACKUPFAIL_DBDUMP)
|
||||||
if (obj.backupStatus == 0) {
|
if (obj.backupStatus == 0) {
|
||||||
// Zip the data directory with the dbdump|NeDB files
|
// Zip the data directory with the dbdump|NeDB files
|
||||||
let output = parent.fs.createWriteStream(obj.newAutoBackupFile);
|
let output = fs.createWriteStream(obj.newAutoBackupFile);
|
||||||
|
|
||||||
|
// Archive finalized and closed
|
||||||
output.on('close', function () {
|
output.on('close', function () {
|
||||||
if (obj.backupStatus == 0) {
|
if (obj.backupStatus == 0) {
|
||||||
//remove dump archive file, because zipped and otherwise fills up
|
let mesg = 'Auto-backup completed: ' + obj.newAutoBackupFile + ', backup-size: ' + ((archive.pointer() / 1048576).toFixed(2)) + "Mb";
|
||||||
if (obj.databaseType != DB_NEDB) {
|
console.log(mesg);
|
||||||
try { parent.fs.unlink(obj.newDBDumpFile, function () { }); } catch (ex) {console.log('Failed to clean up dbdump file')};
|
if (func) { func(mesg); };
|
||||||
};
|
|
||||||
obj.performCloudBackup(obj.newAutoBackupFile, func);
|
obj.performCloudBackup(obj.newAutoBackupFile, func);
|
||||||
// Remove old backups
|
obj.removeExpiredBackupfiles(func);
|
||||||
if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.keeplastdaysbackup == 'number')) {
|
|
||||||
let cutoffDate = new Date();
|
|
||||||
cutoffDate.setDate(cutoffDate.getDate() - parent.config.settings.autobackup.keeplastdaysbackup);
|
|
||||||
parent.fs.readdir(parent.backuppath, function (err, dir) {
|
|
||||||
try {
|
|
||||||
if ((err == null) && (dir.length > 0)) {
|
|
||||||
let fileName = (typeof parent.config.settings.autobackup.backupname == 'string') ? parent.config.settings.autobackup.backupname : 'meshcentral-autobackup-';
|
|
||||||
for (var i in dir) {
|
|
||||||
var name = dir[i];
|
|
||||||
if (name.startsWith(fileName) && name.endsWith('.zip')) {
|
|
||||||
var timex = name.substring(23, name.length - 4).split('-');
|
|
||||||
if (timex.length == 5) {
|
|
||||||
var fileDate = new Date(parseInt(timex[0]), parseInt(timex[1]) - 1, parseInt(timex[2]), parseInt(timex[3]), parseInt(timex[4]));
|
|
||||||
if (fileDate && (cutoffDate > fileDate)) { try { parent.fs.unlink(parent.path.join(parent.backuppath, name), function () { }); } catch (ex) { } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ex) { console.log(ex); }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.log('Auto-backup completed.');
|
|
||||||
if (func) { func('Auto-backup completed.'); };
|
|
||||||
} else {
|
} else {
|
||||||
console.log('Zipbackup failed ('+ (+obj.backupStatus).toString(16).slice(-4) + '), deleting incomplete backup: ' + obj.newAutoBackupFile );
|
let mesg = 'Zipbackup failed (' + obj.backupStatus.toString(2).slice(-8) + '), deleting incomplete backup: ' + obj.newAutoBackupFile;
|
||||||
if (func) { func('Zipbackup failed ('+ (+obj.backupStatus).toString(16).slice(-4) + '), deleting incomplete backup: ' + obj.newAutoBackupFile) };
|
if (func) { func(mesg) }
|
||||||
try { parent.fs.unlink(obj.newAutoBackupFile, function () { }); parent.fs.unlink(obj.newDBDumpFile, function () { }); } catch (ex) {console.log('Failed to delete incomplete backup files')};
|
else { parent.addServerWarning(mesg, true ) };
|
||||||
|
if (fs.existsSync(obj.newAutoBackupFile)) { fs.unlink(obj.newAutoBackupFile, function (err) { console.error('Failed to clean up backupfile: ' + err.message) }) };
|
||||||
|
};
|
||||||
|
if (obj.databaseType != DB_NEDB) {
|
||||||
|
//remove dump archive file, because zipped and otherwise fills up
|
||||||
|
if (fs.existsSync(obj.newDBDumpFile)) { fs.unlink(obj.newDBDumpFile, function (err) { if (err) {console.error('Failed to clean up dbdump file: ' + err.message) } }) };
|
||||||
};
|
};
|
||||||
obj.performingBackup = false;
|
obj.performingBackup = false;
|
||||||
obj.backupStatus = 0x0;
|
obj.backupStatus = 0x0;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
output.on('end', function () { });
|
output.on('end', function () { });
|
||||||
output.on('error', function (err) {
|
output.on('error', function (err) {
|
||||||
if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) {
|
if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) {
|
||||||
console.log('Output error: ' + err);
|
console.error('Output error: ' + err.message);
|
||||||
if (func) { func('Output error: ' + err); };
|
if (func) { func('Output error: ' + err.message); };
|
||||||
obj.backupStatus |= BACKUPFAIL_ZIPCREATE;
|
obj.backupStatus |= BACKUPFAIL_ZIPCREATE;
|
||||||
archive.abort();
|
archive.abort();
|
||||||
};
|
};
|
||||||
|
|
@ -3676,16 +3681,16 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
//an ENOENT warning is given, but the archiver module has no option to/does not skip/resume
|
//an ENOENT warning is given, but the archiver module has no option to/does not skip/resume
|
||||||
//so the backup needs te be aborted as it otherwise leaves an incomplete zip and never 'ends'
|
//so the backup needs te be aborted as it otherwise leaves an incomplete zip and never 'ends'
|
||||||
if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) {
|
if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) {
|
||||||
console.log('Zip warning: ' + err);
|
console.log('Zip warning: ' + err.message);
|
||||||
if (func) { func('Zip warning: ' + err); };
|
if (func) { func('Zip warning: ' + err.message); };
|
||||||
obj.backupStatus |= BACKUPFAIL_ZIPCREATE;
|
obj.backupStatus |= BACKUPFAIL_ZIPCREATE;
|
||||||
archive.abort();
|
archive.abort();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
archive.on('error', function (err) {
|
archive.on('error', function (err) {
|
||||||
if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) {
|
if ((obj.backupStatus & BACKUPFAIL_ZIPCREATE) == 0) {
|
||||||
console.log('Zip error: ' + err);
|
console.error('Zip error: ' + err.message);
|
||||||
if (func) { func('Zip error: ' + err); };
|
if (func) { func('Zip error: ' + err.message); };
|
||||||
obj.backupStatus |= BACKUPFAIL_ZIPCREATE;
|
obj.backupStatus |= BACKUPFAIL_ZIPCREATE;
|
||||||
archive.abort();
|
archive.abort();
|
||||||
}
|
}
|
||||||
|
|
@ -3718,22 +3723,67 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
archive.finalize();
|
archive.finalize();
|
||||||
} else {
|
} else {
|
||||||
//failed somewhere before zipping
|
//failed somewhere before zipping
|
||||||
console.log('Backup failed ('+ (+obj.backupStatus).toString(16).slice(-4) + ')');
|
console.error('Backup failed ('+ obj.backupStatus.toString(2).slice(-8) + ')');
|
||||||
if (func) { func('Backup failed ('+ (+obj.backupStatus).toString(16).slice(-4) + ')') };
|
if (func) { func('Backup failed ('+ obj.backupStatus.toString(2).slice(-8) + ')') }
|
||||||
|
else {
|
||||||
|
parent.addServerWarning('Backup failed ('+ obj.backupStatus.toString(2).slice(-8) + ')', true);
|
||||||
|
}
|
||||||
//Just in case something's there
|
//Just in case something's there
|
||||||
try { parent.fs.unlink(obj.newDBDumpFile, function () { }); } catch (ex) { };
|
if (fs.existsSync(obj.newDBDumpFile)) { fs.unlink(obj.newDBDumpFile, function (err) { if (err) {console.error('Failed to clean up dbdump file: ' + err.message) } }); };
|
||||||
obj.backupStatus = 0x0;
|
obj.backupStatus = 0x0;
|
||||||
obj.performingBackup = false;
|
obj.performingBackup = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Remove expired backupfiles by filenamedate
|
||||||
|
obj.removeExpiredBackupfiles = function (func) {
|
||||||
|
if (parent.config.settings.autobackup && (typeof parent.config.settings.autobackup.keeplastdaysbackup == 'number')) {
|
||||||
|
let cutoffDate = new Date();
|
||||||
|
cutoffDate.setDate(cutoffDate.getDate() - parent.config.settings.autobackup.keeplastdaysbackup);
|
||||||
|
fs.readdir(parent.backuppath, function (err, dir) {
|
||||||
|
try {
|
||||||
|
if (err == null) {
|
||||||
|
if (dir.length > 0) {
|
||||||
|
let fileName = parent.config.settings.autobackup.backupname;
|
||||||
|
let checked = 0;
|
||||||
|
let removed = 0;
|
||||||
|
for (var i in dir) {
|
||||||
|
var name = dir[i];
|
||||||
|
parent.debug('backup', "checking file: ", path.join(parent.backuppath, name));
|
||||||
|
if (name.startsWith(fileName) && name.endsWith('.zip')) {
|
||||||
|
var timex = name.substring(fileName.length, name.length - 4).split('-');
|
||||||
|
if (timex.length == 5) {
|
||||||
|
checked++;
|
||||||
|
var fileDate = new Date(parseInt(timex[0]), parseInt(timex[1]) - 1, parseInt(timex[2]), parseInt(timex[3]), parseInt(timex[4]));
|
||||||
|
if (fileDate && (cutoffDate > fileDate)) {
|
||||||
|
console.log("Removing expired backup file: ", path.join(parent.backuppath, name));
|
||||||
|
fs.unlink(path.join(parent.backuppath, name), function (err) { if (err) { console.error(err.message); if (func) {func('Error removing: ' + err.message); } } });
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { parent.debug('backup', "file: " + name + " timestamp failure: ", timex); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mesg= 'Checked ' + checked + ' candidates in ' + parent.backuppath + '. Removed ' + removed + ' expired backupfiles using cutoffDate: '+ cutoffDate.toLocaleString('default', { dateStyle: 'short', timeStyle: 'short' });
|
||||||
|
parent.debug (mesg);
|
||||||
|
if (func) { func(mesg); }
|
||||||
|
} else { console.error('No files found in ' + parent.backuppath + '. There should be at least one.')}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ console.error(err); parent.addServerWarning( 'Reading files in backup directory ' + parent.backuppath + ' failed, check errorlog: ' + err.message, true); }
|
||||||
|
} catch (ex) { console.error(ex); parent.addServerWarning( 'Something went wrong during removeExpiredBackupfiles, check errorlog: ' +ex.message, true); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Perform cloud backup
|
// Perform cloud backup
|
||||||
obj.performCloudBackup = function (filename, func) {
|
obj.performCloudBackup = function (filename, func) {
|
||||||
|
|
||||||
// WebDAV Backup
|
// WebDAV Backup
|
||||||
if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.webdav == 'object')) {
|
if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.webdav == 'object')) {
|
||||||
const xdateTimeSort = function (a, b) { if (a.xdate > b.xdate) return 1; if (a.xdate < b.xdate) return -1; return 0; }
|
parent.debug( 'backup', 'Entering WebDAV backup');
|
||||||
|
if (func) { func('Entering WebDAV backup.'); }
|
||||||
|
|
||||||
|
const xdateTimeSort = function (a, b) { if (a.xdate > b.xdate) return 1; if (a.xdate < b.xdate) return -1; return 0; }
|
||||||
// Fetch the folder name
|
// Fetch the folder name
|
||||||
var webdavfolderName = 'MeshCentral-Backups';
|
var webdavfolderName = 'MeshCentral-Backups';
|
||||||
if (typeof parent.config.settings.autobackup.webdav.foldername == 'string') { webdavfolderName = parent.config.settings.autobackup.webdav.foldername; }
|
if (typeof parent.config.settings.autobackup.webdav.foldername == 'string') { webdavfolderName = parent.config.settings.autobackup.webdav.foldername; }
|
||||||
|
|
@ -3741,23 +3791,28 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
// Clean up our WebDAV folder
|
// Clean up our WebDAV folder
|
||||||
function performWebDavCleanup(client) {
|
function performWebDavCleanup(client) {
|
||||||
if ((typeof parent.config.settings.autobackup.webdav.maxfiles == 'number') && (parent.config.settings.autobackup.webdav.maxfiles > 1)) {
|
if ((typeof parent.config.settings.autobackup.webdav.maxfiles == 'number') && (parent.config.settings.autobackup.webdav.maxfiles > 1)) {
|
||||||
let fileName = (typeof parent.config.settings.autobackup.backupname == 'string') ? parent.config.settings.autobackup.backupname : 'meshcentral-autobackup-';
|
let fileName = parent.config.settings.autobackup.backupname;
|
||||||
//only files matching our backupfilename
|
//only files matching our backupfilename
|
||||||
let directoryItems = client.getDirectoryContents(webdavfolderName, { deep: false, glob: "/**/" + fileName + "*.zip" });
|
let directoryItems = client.getDirectoryContents(webdavfolderName, { deep: false, glob: "/**/" + fileName + "*.zip" });
|
||||||
directoryItems.then(
|
directoryItems.then(
|
||||||
function (files) {
|
function (files) {
|
||||||
for (var i in files) { files[i].xdate = new Date(files[i].lastmod); }
|
for (var i in files) { files[i].xdate = new Date(files[i].lastmod); }
|
||||||
files.sort(xdateTimeSort);
|
files.sort(xdateTimeSort);
|
||||||
|
parent.debug('backup','WebDAV filtered directory contents: ' + JSON.stringify(files, null, 4));
|
||||||
while (files.length >= parent.config.settings.autobackup.webdav.maxfiles) {
|
while (files.length >= parent.config.settings.autobackup.webdav.maxfiles) {
|
||||||
client.deleteFile(files.shift().filename).then(function (state) {
|
let delFile = files.shift().filename;
|
||||||
if (func) { func('WebDAV file deleted.'); }
|
client.deleteFile(delFile).then(function (state) {
|
||||||
|
parent.debug('backup','WebDAV file deleted: ' + delFile);
|
||||||
|
if (func) { func('WebDAV file deleted: ' + delFile); }
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
if (func) { func('WebDAV (deleteFile) error: ' + err); }
|
console.error(err);
|
||||||
|
if (func) { func('WebDAV (deleteFile) error: ' + err.message); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).catch(function (err) {
|
).catch(function (err) {
|
||||||
if (func) { func('WebDAV (getDirectoryContents) error: ' + err); }
|
console.error(err);
|
||||||
|
if (func) { func('WebDAV (getDirectoryContents) error: ' + err.message); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3766,14 +3821,14 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
function performWebDavUpload(client, filepath) {
|
function performWebDavUpload(client, filepath) {
|
||||||
require('fs').stat(filepath, function(err,stat){
|
require('fs').stat(filepath, function(err,stat){
|
||||||
var fileStream = require('fs').createReadStream(filepath);
|
var fileStream = require('fs').createReadStream(filepath);
|
||||||
fileStream.on('close', function () { if (func) { func('WebDAV upload completed'); } })
|
fileStream.on('close', function () { console.log('WebDAV upload completed: ' + webdavfolderName + '/' + require('path').basename(filepath)); if (func) { func('WebDAV upload completed: ' + webdavfolderName + '/' + require('path').basename(filepath)); } })
|
||||||
fileStream.on('error', function (err) { if (func) { func('WebDAV (fileUpload) error: ' + err); } })
|
fileStream.on('error', function (err) { console.error(err); if (func) { func('WebDAV (fileUpload) error: ' + err.message); } })
|
||||||
fileStream.pipe(client.createWriteStream('/' + webdavfolderName + '/' + require('path').basename(filepath), { headers: { "Content-Length": stat.size } }));
|
fileStream.pipe(client.createWriteStream('/' + webdavfolderName + '/' + require('path').basename(filepath), { headers: { "Content-Length": stat.size } }));
|
||||||
if (func) { func('Uploading using WebDAV...'); }
|
parent.debug('backup', 'Uploading using WebDAV to: ' + parent.config.settings.autobackup.webdav.url);
|
||||||
|
if (func) { func('Uploading using WebDAV to: ' + parent.config.settings.autobackup.webdav.url); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func) { func('Attempting WebDAV upload...'); }
|
|
||||||
const { createClient } = require('webdav');
|
const { createClient } = require('webdav');
|
||||||
const client = createClient(parent.config.settings.autobackup.webdav.url, {
|
const client = createClient(parent.config.settings.autobackup.webdav.url, {
|
||||||
username: parent.config.settings.autobackup.webdav.username,
|
username: parent.config.settings.autobackup.webdav.username,
|
||||||
|
|
@ -3787,19 +3842,23 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
performWebDavUpload(client, filename);
|
performWebDavUpload(client, filename);
|
||||||
}else{
|
}else{
|
||||||
client.createDirectory(webdavfolderName, {recursive: true}).then(function (a) {
|
client.createDirectory(webdavfolderName, {recursive: true}).then(function (a) {
|
||||||
if (func) { func('WebDAV folder created'); }
|
console.log('backup','WebDAV folder created: ' + webdavfolderName);
|
||||||
|
if (func) { func('WebDAV folder created: ' + webdavfolderName); }
|
||||||
performWebDavUpload(client, filename);
|
performWebDavUpload(client, filename);
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
if (func) { func('WebDAV (createDirectory) error: ' + err); }
|
console.error(err);
|
||||||
|
if (func) { func('WebDAV (createDirectory) error: ' + err.message); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
if (func) { func('WebDAV (exists) error: ' + err); }
|
console.error(err);
|
||||||
|
if (func) { func('WebDAV (exists) error: ' + err.message); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Google Drive Backup
|
// Google Drive Backup
|
||||||
if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.googledrive == 'object')) {
|
if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.googledrive == 'object')) {
|
||||||
|
parent.debug( 'backup', 'Entering Google Drive backup');
|
||||||
obj.Get('GoogleDriveBackup', function (err, docs) {
|
obj.Get('GoogleDriveBackup', function (err, docs) {
|
||||||
if ((err != null) || (docs.length != 1) || (docs[0].state != 3)) return;
|
if ((err != null) || (docs.length != 1) || (docs[0].state != 3)) return;
|
||||||
if (func) { func('Attempting Google Drive upload...'); }
|
if (func) { func('Attempting Google Drive upload...'); }
|
||||||
|
|
@ -3878,6 +3937,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||||
|
|
||||||
// S3 Backup
|
// S3 Backup
|
||||||
if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.s3 == 'object')) {
|
if ((typeof parent.config.settings.autobackup == 'object') && (typeof parent.config.settings.autobackup.s3 == 'object')) {
|
||||||
|
parent.debug( 'backup', 'Entering S3 backup');
|
||||||
var s3folderName = 'MeshCentral-Backups';
|
var s3folderName = 'MeshCentral-Backups';
|
||||||
if (typeof parent.config.settings.autobackup.s3.foldername == 'string') { s3folderName = parent.config.settings.autobackup.s3.foldername; }
|
if (typeof parent.config.settings.autobackup.s3.foldername == 'string') { s3folderName = parent.config.settings.autobackup.s3.foldername; }
|
||||||
// Construct the config object
|
// Construct the config object
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,10 @@ Use of the optional file `plugin_name.js` in the optional folder `modules_meshco
|
||||||
Much of MeshCentral revolves around returning objects for your structures, and plugins are no different. Within your plugin you can traverse all the way up to the web server and MeshCentral Server classes to access all the functionality those layers provide. This is done by passing the current object to newly created objects, and assigning that reference to a `parent` variable within that object.
|
Much of MeshCentral revolves around returning objects for your structures, and plugins are no different. Within your plugin you can traverse all the way up to the web server and MeshCentral Server classes to access all the functionality those layers provide. This is done by passing the current object to newly created objects, and assigning that reference to a `parent` variable within that object.
|
||||||
|
|
||||||
|
|
||||||
|
## Ping-Pong
|
||||||
|
|
||||||
|
If you build a plugin which makes use of `meshrelay.ashx`, keep in mind to either handle ping-pong messages (`serverPing`, `serverPong`) on the control channel or to request MeshCentral to not send such messages through sending the `noping=1` parameter in the connection URL. For a deeper sight search for "PING/PONG" in `meshrelay.js`.
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
Versioning your plugin correctly and consistently is essential to ensure users of your plugin are prompted to upgrade when it is available. Semantic versioning is recommended.
|
Versioning your plugin correctly and consistently is essential to ensure users of your plugin are prompted to upgrade when it is available. Semantic versioning is recommended.
|
||||||
|
|
|
||||||
2
mcrec.js
2
mcrec.js
|
|
@ -321,7 +321,7 @@ function setup() { InstallModules(['image-size'], start); }
|
||||||
function start() { startEx(process.argv); }
|
function start() { startEx(process.argv); }
|
||||||
function startEx(argv) {
|
function startEx(argv) {
|
||||||
if (argv.length > 2) { indexFile(argv[2]); } else {
|
if (argv.length > 2) { indexFile(argv[2]); } else {
|
||||||
log("MeshCentral Session Recodings Processor");
|
log("MeshCentral Session Recordings Processor");
|
||||||
log("This tool will index a .mcrec file so that the player can seek thru the file.");
|
log("This tool will index a .mcrec file so that the player can seek thru the file.");
|
||||||
log("");
|
log("");
|
||||||
log(" Usage: node mcrec [file]");
|
log(" Usage: node mcrec [file]");
|
||||||
|
|
|
||||||
|
|
@ -1936,8 +1936,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||||
change = 1; // Don't save this change as an event to the db, so no log=1.
|
change = 1; // Don't save this change as an event to the db, so no log=1.
|
||||||
parent.removePmtFromAllOtherNodes(device); // We need to make sure to remove this push messaging token from any other device on this server, all domains included.
|
parent.removePmtFromAllOtherNodes(device); // We need to make sure to remove this push messaging token from any other device on this server, all domains included.
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((command.users != null) && (Array.isArray(command.users)) && (device.users != command.users)) { device.users = command.users; change = 1; } // Don't save this to the db.
|
if ((command.users != null) && (Array.isArray(command.users)) && (device.users != command.users)) { device.users = command.users; change = 1; } // Don't save this to the db.
|
||||||
|
if ((command.lusers != null) && (Array.isArray(command.lusers)) && (device.lusers != command.lusers)) { device.lusers = command.lusers; change = 1; } // Don't save this to the db.
|
||||||
if ((mesh.mtype == 2) && (!args.wanonly)) {
|
if ((mesh.mtype == 2) && (!args.wanonly)) {
|
||||||
// In WAN mode, the hostname of a computer is not important. Don't log hostname changes.
|
// In WAN mode, the hostname of a computer is not important. Don't log hostname changes.
|
||||||
if (device.host != obj.remoteaddr) { device.host = obj.remoteaddr; change = 1; changes.push('host'); }
|
if (device.host != obj.remoteaddr) { device.host = obj.remoteaddr; change = 1; changes.push('host'); }
|
||||||
|
|
|
||||||
|
|
@ -886,6 +886,11 @@
|
||||||
"default": 24,
|
"default": 24,
|
||||||
"description": "How often should the autobackup run in hours from the second meshcentral starts up? Default is every 24 hours"
|
"description": "How often should the autobackup run in hours from the second meshcentral starts up? Default is every 24 hours"
|
||||||
},
|
},
|
||||||
|
"backupHour": {
|
||||||
|
"type": "integer",
|
||||||
|
"default": 0,
|
||||||
|
"description": "At which hour the autobackup should run. This forces a daily backup, overrules a custom 'backupIntervalHours'."
|
||||||
|
},
|
||||||
"keepLastDaysBackup": {
|
"keepLastDaysBackup": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"default": 10,
|
"default": 10,
|
||||||
|
|
@ -1168,6 +1173,11 @@
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"description": "Valid numbers are 1 and 2, changes the style of the login page and some secondary pages."
|
"description": "Valid numbers are 1 and 2, changes the style of the login page and some secondary pages."
|
||||||
},
|
},
|
||||||
|
"showModernUIToggle": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "When set to true, the user will be able to toggle between the modern and classic UI."
|
||||||
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "MeshCentral",
|
"default": "MeshCentral",
|
||||||
|
|
@ -1962,6 +1972,11 @@
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "If true, user consent is accepted after the timeout."
|
"description": "If true, user consent is accepted after the timeout."
|
||||||
},
|
},
|
||||||
|
"autoAcceptIfNoUser": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "If true, user consent is accepted if no user is logged in."
|
||||||
|
},
|
||||||
"oldStyle": {
|
"oldStyle": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
|
@ -2165,6 +2180,11 @@
|
||||||
"default": null,
|
"default": null,
|
||||||
"description": "When set, idle users will be disconnected after a set amounts of minutes."
|
"description": "When set, idle users will be disconnected after a set amounts of minutes."
|
||||||
},
|
},
|
||||||
|
"logoutOnIdleSessionTimeout": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Determines whether MeshCentral should logout after the session idle timeout elapsed or should just disconnect remote desktop, terminal and files."
|
||||||
|
},
|
||||||
"userConsentFlags": {
|
"userConsentFlags": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Use this section to require user consent for this domain.",
|
"description": "Use this section to require user consent for this domain.",
|
||||||
|
|
@ -2895,12 +2915,10 @@
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "string",
|
|
||||||
"description": "SMTP username."
|
"description": "SMTP username."
|
||||||
},
|
},
|
||||||
"pass": {
|
"pass": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "string",
|
|
||||||
"description": "SMTP password."
|
"description": "SMTP password."
|
||||||
},
|
},
|
||||||
"tls": {
|
"tls": {
|
||||||
|
|
@ -3253,7 +3271,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"newAccounts": {
|
"newAccounts": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|
@ -3461,8 +3478,7 @@
|
||||||
"required": [
|
"required": [
|
||||||
"client_id",
|
"client_id",
|
||||||
"client_secret"
|
"client_secret"
|
||||||
],
|
]
|
||||||
"additionalProperties": false
|
|
||||||
},
|
},
|
||||||
"issuer": {
|
"issuer": {
|
||||||
"type": [
|
"type": [
|
||||||
|
|
@ -3552,8 +3568,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"additionalProperties": false
|
|
||||||
},
|
},
|
||||||
"custom": {
|
"custom": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
@ -3604,8 +3619,7 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "REQUIRED IF USING GROUPS: Customer ID from Google Workspace Admin Console (https://admin.google.com/ac/accountsettings/profile)"
|
"description": "REQUIRED IF USING GROUPS: Customer ID from Google Workspace Admin Console (https://admin.google.com/ac/accountsettings/profile)"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"additionalProperties": false
|
|
||||||
},
|
},
|
||||||
"groups": {
|
"groups": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|
@ -3657,8 +3671,7 @@
|
||||||
"default": "groups",
|
"default": "groups",
|
||||||
"description": "Custom claim to use."
|
"description": "Custom claim to use."
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"additionalProperties": false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3723,8 +3736,7 @@
|
||||||
"description": "EAB HMAC KEY",
|
"description": "EAB HMAC KEY",
|
||||||
"default": ""
|
"default": ""
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"additionalProperties": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
@ -3819,12 +3831,10 @@
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "string",
|
|
||||||
"description": "SMTP username."
|
"description": "SMTP username."
|
||||||
},
|
},
|
||||||
"pass": {
|
"pass": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "string",
|
|
||||||
"description": "SMTP password."
|
"description": "SMTP password."
|
||||||
},
|
},
|
||||||
"tls": {
|
"tls": {
|
||||||
|
|
|
||||||
|
|
@ -583,8 +583,11 @@ function CreateMeshCentralServer(config, args) {
|
||||||
// Launch MeshCentral as a child server and monitor it.
|
// Launch MeshCentral as a child server and monitor it.
|
||||||
obj.launchChildServer = function (startArgs) {
|
obj.launchChildServer = function (startArgs) {
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
|
const isInspectorAttached = (()=> { try { return require('node:inspector').url() !== undefined; } catch (_) { return false; } }).call();
|
||||||
|
const logFromChildProcess = isInspectorAttached ? () => {} : console.log.bind(console);
|
||||||
try { if (process.traceDeprecation === true) { startArgs.unshift('--trace-deprecation'); } } catch (ex) { }
|
try { if (process.traceDeprecation === true) { startArgs.unshift('--trace-deprecation'); } } catch (ex) { }
|
||||||
try { if (process.traceProcessWarnings === true) { startArgs.unshift('--trace-warnings'); } } catch (ex) { }
|
try { if (process.traceProcessWarnings === true) { startArgs.unshift('--trace-warnings'); } } catch (ex) { }
|
||||||
|
if (startArgs[0] != "--disable-proto=delete") startArgs.unshift("--disable-proto=delete")
|
||||||
childProcess = child_process.execFile(process.argv[0], startArgs, { maxBuffer: Infinity, cwd: obj.parentpath }, function (error, stdout, stderr) {
|
childProcess = child_process.execFile(process.argv[0], startArgs, { maxBuffer: Infinity, cwd: obj.parentpath }, function (error, stdout, stderr) {
|
||||||
if (childProcess.xrestart == 1) {
|
if (childProcess.xrestart == 1) {
|
||||||
setTimeout(function () { obj.launchChildServer(startArgs); }, 500); // This is an expected restart.
|
setTimeout(function () { obj.launchChildServer(startArgs); }, 500); // This is an expected restart.
|
||||||
|
|
@ -656,12 +659,12 @@ function CreateMeshCentralServer(config, args) {
|
||||||
else if (data.indexOf('Starting self upgrade to: ') >= 0) { obj.args.specificupdate = data.substring(26).split('\r')[0].split('\n')[0]; childProcess.xrestart = 3; }
|
else if (data.indexOf('Starting self upgrade to: ') >= 0) { obj.args.specificupdate = data.substring(26).split('\r')[0].split('\n')[0]; childProcess.xrestart = 3; }
|
||||||
var datastr = data;
|
var datastr = data;
|
||||||
while (datastr.endsWith('\r') || datastr.endsWith('\n')) { datastr = datastr.substring(0, datastr.length - 1); }
|
while (datastr.endsWith('\r') || datastr.endsWith('\n')) { datastr = datastr.substring(0, datastr.length - 1); }
|
||||||
console.log(datastr);
|
logFromChildProcess(datastr);
|
||||||
});
|
});
|
||||||
childProcess.stderr.on('data', function (data) {
|
childProcess.stderr.on('data', function (data) {
|
||||||
var datastr = data;
|
var datastr = data;
|
||||||
while (datastr.endsWith('\r') || datastr.endsWith('\n')) { datastr = datastr.substring(0, datastr.length - 1); }
|
while (datastr.endsWith('\r') || datastr.endsWith('\n')) { datastr = datastr.substring(0, datastr.length - 1); }
|
||||||
console.log('ERR: ' + datastr);
|
logFromChildProcess('ERR: ' + datastr);
|
||||||
if (data.startsWith('le.challenges[tls-sni-01].loopback')) { return; } // Ignore this error output from GreenLock
|
if (data.startsWith('le.challenges[tls-sni-01].loopback')) { return; } // Ignore this error output from GreenLock
|
||||||
if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); }
|
if (data[data.length - 1] == '\n') { data = data.substring(0, data.length - 1); }
|
||||||
obj.logError(data);
|
obj.logError(data);
|
||||||
|
|
@ -1348,7 +1351,7 @@ function CreateMeshCentralServer(config, args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the database is capable of performing a backup
|
// Check if the database is capable of performing a backup
|
||||||
obj.db.checkBackupCapability(function (err, msg) { if (msg != null) { obj.addServerWarning(msg, true) } });
|
// Moved behind autobackup config init in startex4: obj.db.checkBackupCapability(function (err, msg) { if (msg != null) { obj.addServerWarning(msg, true) } });
|
||||||
|
|
||||||
// Load configuration for database if needed
|
// Load configuration for database if needed
|
||||||
if (obj.args.loadconfigfromdb) {
|
if (obj.args.loadconfigfromdb) {
|
||||||
|
|
@ -1656,7 +1659,7 @@ function CreateMeshCentralServer(config, args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup agent error log
|
// Setup agent error log
|
||||||
if ((obj.config) && (obj.config.settings) && (obj.config.settings.agentlogdump != null)) {
|
if ((obj.config) && (obj.config.settings) && (obj.config.settings.agentlogdump)) {
|
||||||
obj.fs.open(obj.path.join(obj.datapath, 'agenterrorlogs.txt'), 'a', function (err, fd) { obj.agentErrorLog = fd; })
|
obj.fs.open(obj.path.join(obj.datapath, 'agenterrorlogs.txt'), 'a', function (err, fd) { obj.agentErrorLog = fd; })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2016,6 +2019,7 @@ function CreateMeshCentralServer(config, args) {
|
||||||
|
|
||||||
// Start periodic maintenance
|
// Start periodic maintenance
|
||||||
obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
|
obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 60 * 60); // Run this every hour
|
||||||
|
//obj.maintenanceTimer = setInterval(obj.maintenanceActions, 1000 * 10 * 1); // DEBUG: Run this more often
|
||||||
|
|
||||||
// Dispatch an event that the server is now running
|
// Dispatch an event that the server is now running
|
||||||
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' });
|
obj.DispatchEvent(['*'], obj, { etype: 'server', action: 'started', msg: 'Server started' });
|
||||||
|
|
@ -2105,18 +2109,19 @@ function CreateMeshCentralServer(config, args) {
|
||||||
if (obj.config.settings.autobackup == null || obj.config.settings.autobackup === true) { obj.config.settings.autobackup = {backupintervalhours: 24, keeplastdaysbackup: 10}; };
|
if (obj.config.settings.autobackup == null || obj.config.settings.autobackup === true) { obj.config.settings.autobackup = {backupintervalhours: 24, keeplastdaysbackup: 10}; };
|
||||||
if (typeof obj.config.settings.autobackup.backupintervalhours != 'number') { obj.config.settings.autobackup.backupintervalhours = 24; };
|
if (typeof obj.config.settings.autobackup.backupintervalhours != 'number') { obj.config.settings.autobackup.backupintervalhours = 24; };
|
||||||
if (typeof obj.config.settings.autobackup.keeplastdaysbackup != 'number') { obj.config.settings.autobackup.keeplastdaysbackup = 10; };
|
if (typeof obj.config.settings.autobackup.keeplastdaysbackup != 'number') { obj.config.settings.autobackup.keeplastdaysbackup = 10; };
|
||||||
|
if (obj.config.settings.autobackup.backuphour != null ) { obj.config.settings.autobackup.backupintervalhours = 24; if ((typeof obj.config.settings.autobackup.backuphour != 'number') || (obj.config.settings.autobackup.backuphour > 23 || obj.config.settings.autobackup.backuphour < 0 )) { obj.config.settings.autobackup.backuphour = 0; }}
|
||||||
|
else {obj.config.settings.autobackup.backuphour = -1 };
|
||||||
//arrayfi in case of string and remove possible ', ' space. !! If a string instead of an array is passed, it will be split by ',' so *{.txt,.log} won't work in that case !!
|
//arrayfi in case of string and remove possible ', ' space. !! If a string instead of an array is passed, it will be split by ',' so *{.txt,.log} won't work in that case !!
|
||||||
if (!obj.config.settings.autobackup.backupignorefilesglob) {obj.config.settings.autobackup.backupignorefilesglob = []}
|
if (!obj.config.settings.autobackup.backupignorefilesglob) {obj.config.settings.autobackup.backupignorefilesglob = []}
|
||||||
else if (typeof obj.config.settings.autobackup.backupignorefilesglob == 'string') { obj.config.settings.autobackup.backupignorefilesglob = obj.config.settings.autobackup.backupignorefilesglob.replaceAll(', ', ',').split(','); };
|
else if (typeof obj.config.settings.autobackup.backupignorefilesglob == 'string') { obj.config.settings.autobackup.backupignorefilesglob = obj.config.settings.autobackup.backupignorefilesglob.replaceAll(', ', ',').split(','); };
|
||||||
if (!obj.config.settings.autobackup.backupskipfoldersglob) {obj.config.settings.autobackup.backupskipfoldersglob = []}
|
if (!obj.config.settings.autobackup.backupskipfoldersglob) {obj.config.settings.autobackup.backupskipfoldersglob = []}
|
||||||
else if (typeof obj.config.settings.autobackup.backupskipfoldersglob == 'string') { obj.config.settings.autobackup.backupskipfoldersglob = obj.config.settings.autobackup.backupskipfoldersglob.replaceAll(', ', ',').split(','); };
|
else if (typeof obj.config.settings.autobackup.backupskipfoldersglob == 'string') { obj.config.settings.autobackup.backupskipfoldersglob = obj.config.settings.autobackup.backupskipfoldersglob.replaceAll(', ', ',').split(','); };
|
||||||
|
if (typeof obj.config.settings.autobackup.backuppath == 'string') { obj.backuppath = (obj.config.settings.autobackup.backuppath = (obj.path.resolve(obj.config.settings.autobackup.backuppath))) } else { obj.config.settings.autobackup.backuppath = obj.backuppath };
|
||||||
|
if (typeof obj.config.settings.autobackup.backupname != 'string') { obj.config.settings.autobackup.backupname = 'meshcentral-autobackup-'};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that autobackup path is not within the "meshcentral-data" folder.
|
// Check if the database is capable of performing a backup
|
||||||
if ((typeof obj.config.settings.autobackup == 'object') && (typeof obj.config.settings.autobackup.backuppath == 'string') && (obj.path.normalize(obj.config.settings.autobackup.backuppath).startsWith(obj.path.normalize(obj.datapath)))) {
|
obj.db.checkBackupCapability(function (err, msg) { if (msg != null) { obj.addServerWarning(msg, true) } });
|
||||||
addServerWarning("Backup path can't be set within meshcentral-data folder, backup settings ignored.", 21);
|
|
||||||
obj.config.settings.autobackup = {backupintervalhours: -1}; //block console autobackup
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load Intel AMT passwords from the "amtactivation.log" file
|
// Load Intel AMT passwords from the "amtactivation.log" file
|
||||||
obj.loadAmtActivationLogPasswords(function (amtPasswords) {
|
obj.loadAmtActivationLogPasswords(function (amtPasswords) {
|
||||||
|
|
@ -2278,14 +2283,19 @@ function CreateMeshCentralServer(config, args) {
|
||||||
|
|
||||||
// Check if we need to perform an automatic backup
|
// Check if we need to perform an automatic backup
|
||||||
function checkAutobackup() {
|
function checkAutobackup() {
|
||||||
if (obj.config.settings.autobackup.backupintervalhours >= 1) {
|
if (obj.config.settings.autobackup.backupintervalhours >= 1 ) {
|
||||||
obj.db.Get('LastAutoBackupTime', function (err, docs) {
|
obj.db.Get('LastAutoBackupTime', function (err, docs) {
|
||||||
if (err != null) return;
|
if (err != null) { console.error("checkAutobackup: Error getting LastBackupTime from DB"); return}
|
||||||
var lastBackup = 0;
|
var lastBackup = 0;
|
||||||
const now = new Date().getTime();
|
const currentdate = new Date();
|
||||||
|
let currentHour = currentdate.getHours();
|
||||||
|
let now = currentdate.getTime();
|
||||||
if (docs.length == 1) { lastBackup = docs[0].value; }
|
if (docs.length == 1) { lastBackup = docs[0].value; }
|
||||||
const delta = now - lastBackup;
|
const delta = now - lastBackup;
|
||||||
if (delta > (obj.config.settings.autobackup.backupintervalhours * 60 * 60 * 1000)) {
|
//const delta = 9999999999; // DEBUG: backup always
|
||||||
|
obj.debug ('backup', 'Entering checkAutobackup, lastAutoBackupTime: ' + new Date(lastBackup).toLocaleString('default', { dateStyle: 'medium', timeStyle: 'short' }) + ', delta: ' + (delta/(1000*60*60)).toFixed(2) + ' hours');
|
||||||
|
//start autobackup if interval has passed or at configured hour, whichever comes first. When an hour schedule is missed, it will make a backup immediately.
|
||||||
|
if ((delta > (obj.config.settings.autobackup.backupintervalhours * 60 * 60 * 1000)) || ((currentHour == obj.config.settings.autobackup.backuphour) && (delta >= 2 * 60 * 60 * 1000))) {
|
||||||
// A new auto-backup is required.
|
// A new auto-backup is required.
|
||||||
obj.db.Set({ _id: 'LastAutoBackupTime', value: now }); // Save the current time in the database
|
obj.db.Set({ _id: 'LastAutoBackupTime', value: now }); // Save the current time in the database
|
||||||
obj.db.performBackup(); // Perform the backup
|
obj.db.performBackup(); // Perform the backup
|
||||||
|
|
@ -3936,6 +3946,7 @@ function CreateMeshCentralServer(config, args) {
|
||||||
function logWarnEvent(msg) { if (obj.servicelog != null) { obj.servicelog.warn(msg); } console.log(msg); }
|
function logWarnEvent(msg) { if (obj.servicelog != null) { obj.servicelog.warn(msg); } console.log(msg); }
|
||||||
function logErrorEvent(msg) { if (obj.servicelog != null) { obj.servicelog.error(msg); } console.error(msg); }
|
function logErrorEvent(msg) { if (obj.servicelog != null) { obj.servicelog.error(msg); } console.error(msg); }
|
||||||
obj.getServerWarnings = function () { return serverWarnings; }
|
obj.getServerWarnings = function () { return serverWarnings; }
|
||||||
|
// TODO: migrate from other addServerWarning function and add timestamp
|
||||||
obj.addServerWarning = function (msg, id, args, print) { serverWarnings.push({ msg: msg, id: id, args: args }); if (print !== false) { console.log("WARNING: " + msg); } }
|
obj.addServerWarning = function (msg, id, args, print) { serverWarnings.push({ msg: msg, id: id, args: args }); if (print !== false) { console.log("WARNING: " + msg); } }
|
||||||
|
|
||||||
// auth.log functions
|
// auth.log functions
|
||||||
|
|
@ -4106,6 +4117,7 @@ function InstallModuleEx(modulenames, args, func) {
|
||||||
process.on('SIGINT', function () { if (meshserver != null) { meshserver.Stop(); meshserver = null; } console.log('Server Ctrl-C exit...'); process.exit(); });
|
process.on('SIGINT', function () { if (meshserver != null) { meshserver.Stop(); meshserver = null; } console.log('Server Ctrl-C exit...'); process.exit(); });
|
||||||
|
|
||||||
// Add a server warning, warnings will be shown to the administrator on the web application
|
// Add a server warning, warnings will be shown to the administrator on the web application
|
||||||
|
// TODO: migrate to obj.addServerWarning?
|
||||||
const serverWarnings = [];
|
const serverWarnings = [];
|
||||||
function addServerWarning(msg, id, args, print) { serverWarnings.push({ msg: msg, id: id, args: args }); if (print !== false) { console.log("WARNING: " + msg); } }
|
function addServerWarning(msg, id, args, print) { serverWarnings.push({ msg: msg, id: id, args: args }); if (print !== false) { console.log("WARNING: " + msg); } }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2243,6 +2243,7 @@ function serverConnect() {
|
||||||
case 'removeDeviceShare':
|
case 'removeDeviceShare':
|
||||||
case 'userbroadcast': { // BROADCAST
|
case 'userbroadcast': { // BROADCAST
|
||||||
if ((settings.cmd == 'shell') || (settings.cmd == 'upload') || (settings.cmd == 'download')) return;
|
if ((settings.cmd == 'shell') || (settings.cmd == 'upload') || (settings.cmd == 'download')) return;
|
||||||
|
if ((data.type == 'runcommands') && (settings.cmd != 'runcommand')) return;
|
||||||
if ((settings.multiresponse != null) && (settings.multiresponse > 1)) { settings.multiresponse--; break; }
|
if ((settings.multiresponse != null) && (settings.multiresponse > 1)) { settings.multiresponse--; break; }
|
||||||
if (data.responseid == 'meshctrl') {
|
if (data.responseid == 'meshctrl') {
|
||||||
if (data.meshid) { console.log(data.result, data.meshid); }
|
if (data.meshid) { console.log(data.result, data.meshid); }
|
||||||
|
|
@ -2665,8 +2666,8 @@ function getDevicesThatMatchFilter(nodes, x) {
|
||||||
} else if (tagSearch != null) {
|
} else if (tagSearch != null) {
|
||||||
// Tag filter
|
// Tag filter
|
||||||
for (var d in nodes) {
|
for (var d in nodes) {
|
||||||
if ((nodes[d].tags == null) && (tagSearch == '')) { r.push(d); }
|
if ((nodes[d].tags == null) && (tagSearch == '')) { r.push(nodes[d]); }
|
||||||
else if (nodes[d].tags != null) { for (var j in nodes[d].tags) { if (nodes[d].tags[j].toLowerCase() == tagSearch) { r.push(d); break; } } }
|
else if (nodes[d].tags != null) { for (var j in nodes[d].tags) { if (nodes[d].tags[j].toLowerCase() == tagSearch) { r.push(nodes[d]); break; } } }
|
||||||
}
|
}
|
||||||
} else if (agentTagSearch != null) {
|
} else if (agentTagSearch != null) {
|
||||||
// Agent Tag filter
|
// Agent Tag filter
|
||||||
|
|
|
||||||
|
|
@ -847,7 +847,7 @@ function CreateDesktopMultiplexor(parent, domain, nodeid, id, func) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Write the recording file header
|
// Write the recording file header
|
||||||
parent.parent.debug('relay', 'Relay: Started recoding to file: ' + recFullFilename);
|
parent.parent.debug('relay', 'Relay: Started recording to file: ' + recFullFilename);
|
||||||
var metadata = { magic: 'MeshCentralRelaySession', ver: 1, nodeid: obj.nodeid, meshid: obj.meshid, time: new Date().toLocaleString(), protocol: 2, devicename: obj.name, devicegroup: obj.meshname };
|
var metadata = { magic: 'MeshCentralRelaySession', ver: 1, nodeid: obj.nodeid, meshid: obj.meshid, time: new Date().toLocaleString(), protocol: 2, devicename: obj.name, devicegroup: obj.meshname };
|
||||||
var firstBlock = JSON.stringify(metadata);
|
var firstBlock = JSON.stringify(metadata);
|
||||||
recordingEntry(fd, 1, 0, firstBlock, function () {
|
recordingEntry(fd, 1, 0, firstBlock, function () {
|
||||||
|
|
@ -1347,6 +1347,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
|
||||||
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
||||||
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
||||||
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
||||||
|
if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
|
||||||
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
||||||
}
|
}
|
||||||
if (typeof domain.notificationmessages == 'object') {
|
if (typeof domain.notificationmessages == 'object') {
|
||||||
|
|
|
||||||
10
meshrelay.js
10
meshrelay.js
|
|
@ -445,15 +445,15 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||||
relayinfo.peer1.sendPeerImage();
|
relayinfo.peer1.sendPeerImage();
|
||||||
} else {
|
} else {
|
||||||
// Write the recording file header
|
// Write the recording file header
|
||||||
parent.parent.debug('relay', 'Relay: Started recoding to file: ' + recFullFilename);
|
parent.parent.debug('relay', 'Relay: Started recording to file: ' + recFullFilename);
|
||||||
var metadata = {
|
var metadata = {
|
||||||
magic: 'MeshCentralRelaySession',
|
magic: 'MeshCentralRelaySession',
|
||||||
ver: 1,
|
ver: 1,
|
||||||
userid: sessionUser._id,
|
userid: sessionUser._id,
|
||||||
username: sessionUser.name,
|
username: sessionUser.name,
|
||||||
sessionid: obj.id,
|
sessionid: obj.id,
|
||||||
ipaddr1: (obj.req == null) ? null : obj.req.clientIp,
|
ipaddr1: ((obj.peer == null) || (obj.peer.req == null)) ? null : obj.peer.req.clientIp,
|
||||||
ipaddr2: ((obj.peer == null) || (obj.peer.req == null)) ? null : obj.peer.req.clientIp,
|
ipaddr2: (obj.req == null) ? null : obj.req.clientIp,
|
||||||
time: new Date().toLocaleString(),
|
time: new Date().toLocaleString(),
|
||||||
protocol: (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.p),
|
protocol: (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.p),
|
||||||
nodeid: (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.nodeid)
|
nodeid: (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.nodeid)
|
||||||
|
|
@ -896,6 +896,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||||
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
||||||
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
||||||
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
||||||
|
if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
|
||||||
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
||||||
}
|
}
|
||||||
if (typeof domain.notificationmessages == 'object') {
|
if (typeof domain.notificationmessages == 'object') {
|
||||||
|
|
@ -934,6 +935,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||||
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
||||||
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
||||||
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
||||||
|
if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
|
||||||
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
||||||
}
|
}
|
||||||
if (typeof domain.notificationmessages == 'object') {
|
if (typeof domain.notificationmessages == 'object') {
|
||||||
|
|
@ -952,6 +954,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||||
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
||||||
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
||||||
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
||||||
|
if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
|
||||||
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
||||||
}
|
}
|
||||||
if (typeof domain.notificationmessages == 'object') {
|
if (typeof domain.notificationmessages == 'object') {
|
||||||
|
|
@ -1004,6 +1007,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||||
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
||||||
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
||||||
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
||||||
|
if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
|
||||||
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
||||||
}
|
}
|
||||||
if (typeof domain.notificationmessages == 'object') {
|
if (typeof domain.notificationmessages == 'object') {
|
||||||
|
|
|
||||||
602
meshuser.js
602
meshuser.js
|
|
@ -600,7 +600,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof domain.userconsentflags == 'number') { serverinfo.consent = domain.userconsentflags; }
|
if (typeof domain.userconsentflags == 'number') { serverinfo.consent = domain.userconsentflags; }
|
||||||
if ((typeof domain.usersessionidletimeout == 'number') && (domain.usersessionidletimeout > 0)) { serverinfo.timeout = (domain.usersessionidletimeout * 60 * 1000); }
|
if ((typeof domain.usersessionidletimeout == 'number') && (domain.usersessionidletimeout > 0)) {serverinfo.timeout = (domain.usersessionidletimeout * 60 * 1000); }
|
||||||
|
if (typeof domain.logoutonidlesessiontimeout == 'boolean') {
|
||||||
|
serverinfo.logoutonidlesessiontimeout = domain.logoutonidlesessiontimeout;
|
||||||
|
} else {
|
||||||
|
// Default
|
||||||
|
serverinfo.logoutonidlesessiontimeout = true;
|
||||||
|
}
|
||||||
if (user.siteadmin === SITERIGHT_ADMIN) {
|
if (user.siteadmin === SITERIGHT_ADMIN) {
|
||||||
if (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) { serverinfo.manageAllDeviceGroups = true; }
|
if (parent.parent.config.settings.managealldevicegroups.indexOf(user._id) >= 0) { serverinfo.manageAllDeviceGroups = true; }
|
||||||
if (obj.crossDomain === true) { serverinfo.crossDomain = []; for (var i in parent.parent.config.domains) { serverinfo.crossDomain.push(i); } }
|
if (obj.crossDomain === true) { serverinfo.crossDomain = []; for (var i in parent.parent.config.domains) { serverinfo.crossDomain.push(i); } }
|
||||||
|
|
@ -922,7 +928,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
// Get a short file and send it back on the web socket
|
// Get a short file and send it back on the web socket
|
||||||
if (common.validateString(command.file, 1, 4096) == false) return;
|
if (common.validateString(command.file, 1, 4096) == false) return;
|
||||||
const scpath = meshPathToRealPath(command.path, user); // This will also check access rights
|
const scpath = meshPathToRealPath(command.path, user); // This will also check access rights
|
||||||
if (scpath == null) break;
|
if ((scpath == null) || (command.file !== parent.path.basename(command.file))) break;
|
||||||
const filePath = parent.path.join(scpath, command.file);
|
const filePath = parent.path.join(scpath, command.file);
|
||||||
fs.stat(filePath, function (err, stat) {
|
fs.stat(filePath, function (err, stat) {
|
||||||
if ((err != null) || (stat == null) || (stat.size >= 204800)) return;
|
if ((err != null) || (stat == null) || (stat.size >= 204800)) return;
|
||||||
|
|
@ -937,7 +943,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
if (common.validateString(command.file, 1, 4096) == false) return;
|
if (common.validateString(command.file, 1, 4096) == false) return;
|
||||||
if (typeof command.data != 'string') return;
|
if (typeof command.data != 'string') return;
|
||||||
const scpath = meshPathToRealPath(command.path, user); // This will also check access rights
|
const scpath = meshPathToRealPath(command.path, user); // This will also check access rights
|
||||||
if (scpath == null) break;
|
if ((scpath == null) || (command.file !== parent.path.basename(command.file))) break;
|
||||||
const filePath = parent.path.join(scpath, command.file);
|
const filePath = parent.path.join(scpath, command.file);
|
||||||
var data = null;
|
var data = null;
|
||||||
try { data = Buffer.from(command.data, 'base64'); } catch (ex) { return; }
|
try { data = Buffer.from(command.data, 'base64'); } catch (ex) { return; }
|
||||||
|
|
@ -997,6 +1003,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
|
||||||
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
|
||||||
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
|
||||||
|
if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
|
||||||
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
|
||||||
}
|
}
|
||||||
if (typeof domain.notificationmessages == 'object') {
|
if (typeof domain.notificationmessages == 'object') {
|
||||||
|
|
@ -3072,7 +3079,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
}
|
}
|
||||||
if (commandsOk == true) {
|
if (commandsOk == true) {
|
||||||
var theCommand = { action: 'runcommands', type: command.type, cmds: command.cmds, runAsUser: command.runAsUser, reply: command.reply, responseid: command.responseid };
|
var theCommand = { action: 'runcommands', type: command.type, cmds: command.cmds, runAsUser: command.runAsUser, reply: command.reply, responseid: command.responseid };
|
||||||
if (parent.parent.multiServer != null) { // peering setup
|
var agent = parent.wsagents[node._id];
|
||||||
|
if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) {
|
||||||
|
// Send the commands to the agent
|
||||||
|
try { agent.send(JSON.stringify(theCommand)); } catch (ex) { }
|
||||||
|
if (command.responseid != null && command.reply == false) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } }
|
||||||
|
// Send out an event that these commands where run on this device
|
||||||
|
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
|
||||||
|
var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'runcommands', msg: 'Running commands', msgid: msgid, cmds: command.cmds, cmdType: command.type, runAsUser: command.runAsUser, domain: domain.id };
|
||||||
|
parent.parent.DispatchEvent(targets, obj, event);
|
||||||
|
} else if (parent.parent.multiServer != null) { // peering setup
|
||||||
// Send the commands to the agent
|
// Send the commands to the agent
|
||||||
parent.parent.multiServer.DispatchMessage({ action: 'agentCommand', nodeid: node._id, command: theCommand});
|
parent.parent.multiServer.DispatchMessage({ action: 'agentCommand', nodeid: node._id, command: theCommand});
|
||||||
if (command.responseid != null && command.reply == false) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } }
|
if (command.responseid != null && command.reply == false) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } }
|
||||||
|
|
@ -3080,20 +3096,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
|
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
|
||||||
var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'runcommands', msg: 'Running commands', msgid: msgid, cmds: command.cmds, cmdType: command.type, runAsUser: command.runAsUser, domain: domain.id };
|
var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'runcommands', msg: 'Running commands', msgid: msgid, cmds: command.cmds, cmdType: command.type, runAsUser: command.runAsUser, domain: domain.id };
|
||||||
parent.parent.multiServer.DispatchEvent(targets, obj, event);
|
parent.parent.multiServer.DispatchEvent(targets, obj, event);
|
||||||
} else { // normal setup
|
} else {
|
||||||
// Get the agent and run the commands
|
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } }
|
||||||
var agent = parent.wsagents[node._id];
|
|
||||||
if ((agent != null) && (agent.authenticated == 2) && (agent.agentInfo != null)) {
|
|
||||||
// Send the commands to the agent
|
|
||||||
try { agent.send(JSON.stringify(theCommand)); } catch (ex) { }
|
|
||||||
if (command.responseid != null && command.reply == false) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'OK' })); } catch (ex) { } }
|
|
||||||
// Send out an event that these commands where run on this device
|
|
||||||
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
|
|
||||||
var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'runcommands', msg: 'Running commands', msgid: msgid, cmds: command.cmds, cmdType: command.type, runAsUser: command.runAsUser, domain: domain.id };
|
|
||||||
parent.parent.DispatchEvent(targets, obj, event);
|
|
||||||
} else {
|
|
||||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Agent not connected' })); } catch (ex) { } }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Invalid command type' })); } catch (ex) { } }
|
if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'runcommands', responseid: command.responseid, result: 'Invalid command type' })); } catch (ex) { } }
|
||||||
|
|
@ -5072,285 +5076,295 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
case 'getDeviceDetails': {
|
case 'getDeviceDetails': {
|
||||||
if ((common.validateStrArray(command.nodeids, 1) == false) && (command.nodeids != null)) break; // Check nodeids
|
if ((common.validateStrArray(command.nodeids, 1) == false) && (command.nodeids != null)) break; // Check nodeids
|
||||||
if (common.validateString(command.type, 3, 4) == false) break; // Check type
|
if (common.validateString(command.type, 3, 4) == false) break; // Check type
|
||||||
|
|
||||||
|
const links = parent.GetAllMeshIdWithRights(user);
|
||||||
|
const extraids = getUserExtraIds();
|
||||||
|
db.GetAllTypeNoTypeFieldMeshFiltered(links, extraids, domain.id, 'node', null, obj.deviceSkip, obj.deviceLimit, function (err, docs) {
|
||||||
|
if (docs == null) return;
|
||||||
|
const ids = [];
|
||||||
|
if (command.nodeids != null) {
|
||||||
|
// Create a list of node ids and query them for last device connection time
|
||||||
|
for (var i in command.nodeids) { ids.push('lc' + command.nodeids[i]); }
|
||||||
|
} else {
|
||||||
|
// Create a list of node ids for this user and query them for last device connection time
|
||||||
|
for (var i in docs) { ids.push('lc' + docs[i]._id); }
|
||||||
|
}
|
||||||
|
db.GetAllIdsOfType(ids, domain.id, 'lastconnect', function (err, docs) {
|
||||||
|
const lastConnects = {};
|
||||||
|
if (docs != null) { for (var i in docs) { lastConnects[docs[i]._id] = docs[i]; } }
|
||||||
|
|
||||||
// Create a list of node ids and query them for last device connection time
|
getDeviceDetailedInfo(command.nodeids, command.type, function (results, type) {
|
||||||
const ids = []
|
for (var i = 0; i < results.length; i++) {
|
||||||
for (var i in command.nodeids) { ids.push('lc' + command.nodeids[i]); }
|
// Remove any device system and network information is we do not have details rights to this device
|
||||||
db.GetAllIdsOfType(ids, domain.id, 'lastconnect', function (err, docs) {
|
if ((parent.GetNodeRights(user, results[i].node.meshid, results[i].node._id) & MESHRIGHT_DEVICEDETAILS) == 0) {
|
||||||
const lastConnects = {};
|
delete results[i].sys; delete results[i].net;
|
||||||
if (docs != null) { for (var i in docs) { lastConnects[docs[i]._id] = docs[i]; } }
|
|
||||||
|
|
||||||
getDeviceDetailedInfo(command.nodeids, command.type, function (results, type) {
|
|
||||||
for (var i = 0; i < results.length; i++) {
|
|
||||||
// Remove any device system and network information is we do not have details rights to this device
|
|
||||||
if ((parent.GetNodeRights(user, results[i].node.meshid, results[i].node._id) & MESHRIGHT_DEVICEDETAILS) == 0) {
|
|
||||||
delete results[i].sys; delete results[i].net;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge any last connection information
|
|
||||||
const lc = lastConnects['lc' + results[i].node._id];
|
|
||||||
if (lc != null) { delete lc._id; delete lc.type; delete lc.meshid; delete lc.domain; results[i].lastConnect = lc; }
|
|
||||||
|
|
||||||
// Remove any connectivity and power state information, that should not be in the database anyway.
|
|
||||||
// TODO: Find why these are sometimes saved in the db.
|
|
||||||
if (results[i].node.conn != null) { delete results[i].node.conn; }
|
|
||||||
if (results[i].node.pwr != null) { delete results[i].node.pwr; }
|
|
||||||
if (results[i].node.agct != null) { delete results[i].node.agct; }
|
|
||||||
if (results[i].node.cict != null) { delete results[i].node.cict; }
|
|
||||||
|
|
||||||
// Add the connection state
|
|
||||||
var state = parent.parent.GetConnectivityState(results[i].node._id);
|
|
||||||
if (state) {
|
|
||||||
results[i].node.conn = state.connectivity;
|
|
||||||
results[i].node.pwr = state.powerState;
|
|
||||||
if ((state.connectivity & 1) != 0) { var agent = parent.wsagents[results[i].node._id]; if (agent != null) { results[i].node.agct = agent.connectTime; } }
|
|
||||||
|
|
||||||
// Use the connection time of the CIRA/Relay connection
|
|
||||||
if ((state.connectivity & 2) != 0) {
|
|
||||||
var ciraConnection = parent.parent.mpsserver.GetConnectionToNode(results[i].node._id, null, true);
|
|
||||||
if ((ciraConnection != null) && (ciraConnection.tag != null)) { results[i].node.cict = ciraConnection.tag.connectTime; }
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var output = null;
|
// Merge any last connection information
|
||||||
if (type == 'csv') {
|
const lc = lastConnects['lc' + results[i].node._id];
|
||||||
try {
|
if (lc != null) { delete lc._id; delete lc.type; delete lc.meshid; delete lc.domain; results[i].lastConnect = lc; }
|
||||||
// Create the CSV file
|
|
||||||
output = 'id,name,rname,host,icon,ip,osdesc,groupname,av,update,firewall,bitlocker,avdetails,tags,cpu,osbuild,biosDate,biosVendor,biosVersion,biosSerial,biosMode,boardName,boardVendor,boardVersion,productUuid,tpmversion,tpmmanufacturer,tpmmanufacturerversion,tpmisactivated,tpmisenabled,tpmisowned,totalMemory,agentOpenSSL,agentCommitDate,agentCommitHash,agentCompileTime,netIfCount,macs,addresses,lastConnectTime,lastConnectAddr\r\n';
|
|
||||||
for (var i = 0; i < results.length; i++) {
|
|
||||||
const nodeinfo = results[i];
|
|
||||||
|
|
||||||
// Node information
|
// Remove any connectivity and power state information, that should not be in the database anyway.
|
||||||
if (nodeinfo.node != null) {
|
// TODO: Find why these are sometimes saved in the db.
|
||||||
const n = nodeinfo.node;
|
if (results[i].node.conn != null) { delete results[i].node.conn; }
|
||||||
output += csvClean(n._id) + ',' + csvClean(n.name) + ',' + csvClean(n.rname ? n.rname : '') + ',' + csvClean(n.host ? n.host : '') + ',' + (n.icon ? n.icon : 1) + ',' + (n.ip ? n.ip : '') + ',' + (n.osdesc ? csvClean(n.osdesc) : '') + ',' + csvClean(parent.meshes[n.meshid].name);
|
if (results[i].node.pwr != null) { delete results[i].node.pwr; }
|
||||||
if (typeof n.wsc == 'object') {
|
if (results[i].node.agct != null) { delete results[i].node.agct; }
|
||||||
output += ',' + csvClean(n.wsc.antiVirus ? n.wsc.antiVirus : '') + ',' + csvClean(n.wsc.autoUpdate ? n.wsc.autoUpdate : '') + ',' + csvClean(n.wsc.firewall ? n.wsc.firewall : '')
|
if (results[i].node.cict != null) { delete results[i].node.cict; }
|
||||||
} else { output += ',,,'; }
|
|
||||||
if (typeof n.volumes == 'object') {
|
// Add the connection state
|
||||||
var bitlockerdetails = '', firstbitlocker = true;
|
var state = parent.parent.GetConnectivityState(results[i].node._id);
|
||||||
for (var a in n.volumes) { if (typeof n.volumes[a].protectionStatus !== 'undefined') { if (firstbitlocker) { firstbitlocker = false; } else { bitlockerdetails += '|'; } bitlockerdetails += a + '/' + n.volumes[a].volumeStatus; } }
|
if (state) {
|
||||||
output += ',' + csvClean(bitlockerdetails);
|
results[i].node.conn = state.connectivity;
|
||||||
} else {
|
results[i].node.pwr = state.powerState;
|
||||||
output += ',';
|
if ((state.connectivity & 1) != 0) { var agent = parent.wsagents[results[i].node._id]; if (agent != null) { results[i].node.agct = agent.connectTime; } }
|
||||||
}
|
|
||||||
if (typeof n.av == 'object') {
|
// Use the connection time of the CIRA/Relay connection
|
||||||
var avdetails = '', firstav = true;
|
if ((state.connectivity & 2) != 0) {
|
||||||
for (var a in n.av) { if (typeof n.av[a].product == 'string') { if (firstav) { firstav = false; } else { avdetails += '|'; } avdetails += (n.av[a].product + '/' + ((n.av[a].enabled) ? 'enabled' : 'disabled') + '/' + ((n.av[a].updated) ? 'updated' : 'notupdated')); } }
|
var ciraConnection = parent.parent.mpsserver.GetConnectionToNode(results[i].node._id, null, true);
|
||||||
output += ',' + csvClean(avdetails);
|
if ((ciraConnection != null) && (ciraConnection.tag != null)) { results[i].node.cict = ciraConnection.tag.connectTime; }
|
||||||
} else {
|
|
||||||
output += ',';
|
|
||||||
}
|
|
||||||
if (typeof n.tags == 'object') {
|
|
||||||
var tagsdetails = '', firsttags = true;
|
|
||||||
for (var a in n.tags) { if (firsttags) { firsttags = false; } else { tagsdetails += '|'; } tagsdetails += n.tags[a]; }
|
|
||||||
output += ',' + csvClean(tagsdetails);
|
|
||||||
} else {
|
|
||||||
output += ',';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
output += ',,,,,,,,,,,,,,,,,,,';
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// System infomation
|
var output = null;
|
||||||
if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.windows)) {
|
if (type == 'csv') {
|
||||||
// Windows
|
try {
|
||||||
output += ',';
|
// Create the CSV file
|
||||||
if (nodeinfo.sys.hardware.windows.cpu && (nodeinfo.sys.hardware.windows.cpu.length > 0) && (typeof nodeinfo.sys.hardware.windows.cpu[0].Name == 'string')) { output += csvClean(nodeinfo.sys.hardware.windows.cpu[0].Name); }
|
output = 'id,name,rname,host,icon,ip,osdesc,groupname,av,update,firewall,bitlocker,avdetails,tags,lastbootuptime,cpu,osbuild,biosDate,biosVendor,biosVersion,biosSerial,biosMode,boardName,boardVendor,boardVersion,productUuid,tpmversion,tpmmanufacturer,tpmmanufacturerversion,tpmisactivated,tpmisenabled,tpmisowned,totalMemory,agentOpenSSL,agentCommitDate,agentCommitHash,agentCompileTime,netIfCount,macs,addresses,lastConnectTime,lastConnectAddr\r\n';
|
||||||
output += ',';
|
for (var i = 0; i < results.length; i++) {
|
||||||
if (nodeinfo.sys.hardware.windows.osinfo && (nodeinfo.sys.hardware.windows.osinfo.BuildNumber)) { output += csvClean(nodeinfo.sys.hardware.windows.osinfo.BuildNumber); }
|
const nodeinfo = results[i];
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_date)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_date); }
|
// Node information
|
||||||
output += ',';
|
if (nodeinfo.node != null) {
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_vendor)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_vendor); }
|
const n = nodeinfo.node;
|
||||||
output += ',';
|
output += csvClean(n._id) + ',' + csvClean(n.name) + ',' + csvClean(n.rname ? n.rname : '') + ',' + csvClean(n.host ? n.host : '') + ',' + (n.icon ? n.icon : 1) + ',' + (n.ip ? n.ip : '') + ',' + (n.osdesc ? csvClean(n.osdesc) : '') + ',' + csvClean(parent.meshes[n.meshid].name);
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_version); }
|
if (typeof n.wsc == 'object') {
|
||||||
output += ',';
|
output += ',' + csvClean(n.wsc.antiVirus ? n.wsc.antiVirus : '') + ',' + csvClean(n.wsc.autoUpdate ? n.wsc.autoUpdate : '') + ',' + csvClean(n.wsc.firewall ? n.wsc.firewall : '')
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_serial)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_serial); }
|
} else { output += ',,,'; }
|
||||||
output += ',';
|
if (typeof n.volumes == 'object') {
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_mode)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_mode); }
|
var bitlockerdetails = '', firstbitlocker = true;
|
||||||
output += ',';
|
for (var a in n.volumes) { if (typeof n.volumes[a].protectionStatus !== 'undefined') { if (firstbitlocker) { firstbitlocker = false; } else { bitlockerdetails += '|'; } bitlockerdetails += a + '/' + n.volumes[a].volumeStatus; } }
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_name)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_name); }
|
output += ',' + csvClean(bitlockerdetails);
|
||||||
output += ',';
|
} else {
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_vendor)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_vendor); }
|
output += ',';
|
||||||
output += ',';
|
|
||||||
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.tpm && nodeinfo.sys.hardware.tpm.SpecVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.SpecVersion); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerId) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerId); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerVersion); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsActivated) { output += csvClean(nodeinfo.sys.hardware.tpm.IsActivated ? 'true' : 'false'); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsEnabled) { output += csvClean(nodeinfo.sys.hardware.tpm.IsEnabled ? 'true' : 'false'); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsOwned) { output += csvClean(nodeinfo.sys.hardware.tpm.IsOwned ? 'true' : 'false'); }
|
|
||||||
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);
|
if (typeof n.av == 'object') {
|
||||||
|
var avdetails = '', firstav = true;
|
||||||
|
for (var a in n.av) { if (typeof n.av[a].product == 'string') { if (firstav) { firstav = false; } else { avdetails += '|'; } avdetails += (n.av[a].product + '/' + ((n.av[a].enabled) ? 'enabled' : 'disabled') + '/' + ((n.av[a].updated) ? 'updated' : 'notupdated')); } }
|
||||||
|
output += ',' + csvClean(avdetails);
|
||||||
|
} else {
|
||||||
|
output += ',';
|
||||||
|
}
|
||||||
|
if (typeof n.tags == 'object') {
|
||||||
|
var tagsdetails = '', firsttags = true;
|
||||||
|
for (var a in n.tags) { if (firsttags) { firsttags = false; } else { tagsdetails += '|'; } tagsdetails += n.tags[a]; }
|
||||||
|
output += ',' + csvClean(tagsdetails);
|
||||||
|
} else {
|
||||||
|
output += ',';
|
||||||
|
}
|
||||||
|
if (typeof n.lastbootuptime == 'number') { output += ',' + n.lastbootuptime; } else { output += ','; }
|
||||||
|
} else {
|
||||||
|
output += ',,,,,,,,,,,,,,,,,,,,';
|
||||||
}
|
}
|
||||||
} else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.mobile)) {
|
|
||||||
// Mobile
|
// System infomation
|
||||||
output += ',';
|
if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.windows)) {
|
||||||
output += ',';
|
// Windows
|
||||||
output += ',';
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.windows.cpu && (nodeinfo.sys.hardware.windows.cpu.length > 0) && (typeof nodeinfo.sys.hardware.windows.cpu[0].Name == 'string')) { output += csvClean(nodeinfo.sys.hardware.windows.cpu[0].Name); }
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.bootloader)) { output += csvClean(nodeinfo.sys.hardware.mobile.bootloader); }
|
if (nodeinfo.sys.hardware.windows.osinfo && (nodeinfo.sys.hardware.windows.osinfo.BuildNumber)) { output += csvClean(nodeinfo.sys.hardware.windows.osinfo.BuildNumber); }
|
||||||
output += ',';
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_date)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_date); }
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.model)) { output += csvClean(nodeinfo.sys.hardware.mobile.model); }
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_vendor)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_vendor); }
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.brand)) { output += csvClean(nodeinfo.sys.hardware.mobile.brand); }
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_version); }
|
||||||
output += ',';
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_serial)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_serial); }
|
||||||
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.id)) { output += csvClean(nodeinfo.sys.hardware.mobile.id); }
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_mode)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_mode); }
|
||||||
output += ',';
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_name)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_name); }
|
||||||
output += ',';
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_vendor)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_vendor); }
|
||||||
output += ',';
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.board_version)) { output += csvClean(nodeinfo.sys.hardware.identifiers.board_version); }
|
||||||
} else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.linux)) {
|
output += ',';
|
||||||
// Linux
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.product_uuid)) { output += csvClean(nodeinfo.sys.hardware.identifiers.product_uuid); }
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.cpu_name)) { output += csvClean(nodeinfo.sys.hardware.identifiers.cpu_name); }
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.SpecVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.SpecVersion); }
|
||||||
output += ',,';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_date)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_date); }
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerId) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerId); }
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_vendor)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_vendor); }
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerVersion); }
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_version)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_version); }
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsActivated) { output += csvClean(nodeinfo.sys.hardware.tpm.IsActivated ? 'true' : 'false'); }
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.product_serial)) { output += csvClean(nodeinfo.sys.hardware.linux.product_serial); }
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsEnabled) { output += csvClean(nodeinfo.sys.hardware.tpm.IsEnabled ? 'true' : 'false'); }
|
||||||
else if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_serial)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_serial); }
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsOwned) { output += csvClean(nodeinfo.sys.hardware.tpm.IsOwned ? 'true' : 'false'); }
|
||||||
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_mode)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_mode); }
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.windows.memory) {
|
||||||
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_name)) { output += csvClean(nodeinfo.sys.hardware.linux.board_name); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_vendor)) { output += csvClean(nodeinfo.sys.hardware.linux.board_vendor); }
|
|
||||||
output += ',';
|
|
||||||
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 += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.SpecVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.SpecVersion); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerId) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerId); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerVersion); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsActivated) { output += csvClean(nodeinfo.sys.hardware.tpm.IsActivated ? 'true' : 'false'); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsEnabled) { output += csvClean(nodeinfo.sys.hardware.tpm.IsEnabled ? 'true' : 'false'); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsOwned) { output += csvClean(nodeinfo.sys.hardware.tpm.IsOwned ? 'true' : 'false'); }
|
|
||||||
output += ',';
|
|
||||||
if (nodeinfo.sys.hardware.linux.memory) {
|
|
||||||
if (nodeinfo.sys.hardware.linux.memory.Memory_Device) {
|
|
||||||
var totalMemory = 0;
|
var totalMemory = 0;
|
||||||
for (var j in nodeinfo.sys.hardware.linux.memory.Memory_Device) {
|
for (var j in nodeinfo.sys.hardware.windows.memory) {
|
||||||
if (nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size) {
|
if (nodeinfo.sys.hardware.windows.memory[j].Capacity) {
|
||||||
if (typeof nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size == 'number') { totalMemory += nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size; }
|
if (typeof nodeinfo.sys.hardware.windows.memory[j].Capacity == 'number') { totalMemory += nodeinfo.sys.hardware.windows.memory[j].Capacity; }
|
||||||
if (typeof nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size == 'string') { totalMemory += parseInt(nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size); }
|
if (typeof nodeinfo.sys.hardware.windows.memory[j].Capacity == 'string') { totalMemory += parseInt(nodeinfo.sys.hardware.windows.memory[j].Capacity); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output += csvClean('' + (totalMemory * Math.pow(1024, 3)));
|
output += csvClean('' + totalMemory);
|
||||||
}
|
}
|
||||||
}
|
} else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.mobile)) {
|
||||||
} else {
|
// Mobile
|
||||||
output += ',,,,,,,,,,,,,,,,,,';
|
output += ',';
|
||||||
}
|
output += ',';
|
||||||
|
output += ',';
|
||||||
// Agent information
|
output += ',';
|
||||||
if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.agentvers)) {
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.bootloader)) { output += csvClean(nodeinfo.sys.hardware.mobile.bootloader); }
|
||||||
if (nodeinfo.sys.hardware.agentvers.openssl) { output += csvClean(nodeinfo.sys.hardware.agentvers.openssl); }
|
output += ',';
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.sys.hardware.agentvers.commitDate) { output += csvClean(nodeinfo.sys.hardware.agentvers.commitDate); }
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.model)) { output += csvClean(nodeinfo.sys.hardware.mobile.model); }
|
||||||
if (nodeinfo.sys.hardware.agentvers.commitHash) { output += csvClean(nodeinfo.sys.hardware.agentvers.commitHash); }
|
output += ',';
|
||||||
output += ',';
|
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.brand)) { output += csvClean(nodeinfo.sys.hardware.mobile.brand); }
|
||||||
if (nodeinfo.sys.hardware.agentvers.compileTime) { output += csvClean(nodeinfo.sys.hardware.agentvers.compileTime); }
|
output += ',';
|
||||||
} else {
|
output += ',';
|
||||||
output += ',,,,';
|
if (nodeinfo.sys.hardware.mobile && (nodeinfo.sys.hardware.mobile.id)) { output += csvClean(nodeinfo.sys.hardware.mobile.id); }
|
||||||
}
|
output += ',';
|
||||||
|
output += ',';
|
||||||
// Network interfaces
|
output += ',';
|
||||||
if ((nodeinfo.net) && (nodeinfo.net.netif2)) {
|
output += ',';
|
||||||
output += ',';
|
output += ',';
|
||||||
output += Object.keys(nodeinfo.net.netif2).length; // Interface count
|
output += ',';
|
||||||
var macs = [], addresses = [];
|
output += ',';
|
||||||
for (var j in nodeinfo.net.netif2) {
|
} else if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.linux)) {
|
||||||
if (Array.isArray(nodeinfo.net.netif2[j])) {
|
// Linux
|
||||||
for (var k = 0; k < nodeinfo.net.netif2[j].length; k++) {
|
output += ',';
|
||||||
if (typeof nodeinfo.net.netif2[j][k].mac == 'string') { macs.push(nodeinfo.net.netif2[j][k].mac); }
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.cpu_name)) { output += csvClean(nodeinfo.sys.hardware.identifiers.cpu_name); }
|
||||||
if (typeof nodeinfo.net.netif2[j][k].address == 'string') { addresses.push(nodeinfo.net.netif2[j][k].address); }
|
output += ',,';
|
||||||
|
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_date)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_date); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_vendor)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_vendor); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.bios_version)) { output += csvClean(nodeinfo.sys.hardware.linux.bios_version); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.product_serial)) { output += csvClean(nodeinfo.sys.hardware.linux.product_serial); }
|
||||||
|
else if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_serial)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_serial); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.identifiers && (nodeinfo.sys.hardware.identifiers.bios_mode)) { output += csvClean(nodeinfo.sys.hardware.identifiers.bios_mode); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_name)) { output += csvClean(nodeinfo.sys.hardware.linux.board_name); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.linux && (nodeinfo.sys.hardware.linux.board_vendor)) { output += csvClean(nodeinfo.sys.hardware.linux.board_vendor); }
|
||||||
|
output += ',';
|
||||||
|
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 += ',';
|
||||||
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.SpecVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.SpecVersion); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerId) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerId); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.ManufacturerVersion) { output += csvClean(nodeinfo.sys.hardware.tpm.ManufacturerVersion); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsActivated) { output += csvClean(nodeinfo.sys.hardware.tpm.IsActivated ? 'true' : 'false'); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsEnabled) { output += csvClean(nodeinfo.sys.hardware.tpm.IsEnabled ? 'true' : 'false'); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.tpm && nodeinfo.sys.hardware.tpm.IsOwned) { output += csvClean(nodeinfo.sys.hardware.tpm.IsOwned ? 'true' : 'false'); }
|
||||||
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.linux.memory) {
|
||||||
|
if (nodeinfo.sys.hardware.linux.memory.Memory_Device) {
|
||||||
|
var totalMemory = 0;
|
||||||
|
for (var j in nodeinfo.sys.hardware.linux.memory.Memory_Device) {
|
||||||
|
if (nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size) {
|
||||||
|
if (typeof nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size == 'number') { totalMemory += nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size; }
|
||||||
|
if (typeof nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size == 'string') { totalMemory += parseInt(nodeinfo.sys.hardware.linux.memory.Memory_Device[j].Size); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output += csvClean('' + (totalMemory * Math.pow(1024, 3)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
output += ',,,,,,,,,,,,,,,,,,';
|
||||||
}
|
}
|
||||||
output += ',';
|
|
||||||
output += csvClean(macs.join(' ')); // MACS
|
|
||||||
output += ',';
|
|
||||||
output += csvClean(addresses.join(' ')); // Addresses
|
|
||||||
} else {
|
|
||||||
output += ',,,';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Last connection information
|
// Agent information
|
||||||
if (nodeinfo.lastConnect) {
|
if ((nodeinfo.sys) && (nodeinfo.sys.hardware) && (nodeinfo.sys.hardware.agentvers)) {
|
||||||
output += ',';
|
output += ',';
|
||||||
if (nodeinfo.lastConnect.time) {
|
if (nodeinfo.sys.hardware.agentvers.openssl) { output += csvClean(nodeinfo.sys.hardware.agentvers.openssl); }
|
||||||
// Last connection time
|
output += ',';
|
||||||
if ((typeof command.l == 'string') && (typeof command.tz == 'string')) {
|
if (nodeinfo.sys.hardware.agentvers.commitDate) { output += csvClean(nodeinfo.sys.hardware.agentvers.commitDate); }
|
||||||
output += csvClean(new Date(nodeinfo.lastConnect.time).toLocaleString(command.l, { timeZone: command.tz }))
|
output += ',';
|
||||||
} else {
|
if (nodeinfo.sys.hardware.agentvers.commitHash) { output += csvClean(nodeinfo.sys.hardware.agentvers.commitHash); }
|
||||||
output += nodeinfo.lastConnect.time;
|
output += ',';
|
||||||
|
if (nodeinfo.sys.hardware.agentvers.compileTime) { output += csvClean(nodeinfo.sys.hardware.agentvers.compileTime); }
|
||||||
|
} else {
|
||||||
|
output += ',,,,';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network interfaces
|
||||||
|
if ((nodeinfo.net) && (nodeinfo.net.netif2)) {
|
||||||
|
output += ',';
|
||||||
|
output += Object.keys(nodeinfo.net.netif2).length; // Interface count
|
||||||
|
var macs = [], addresses = [];
|
||||||
|
for (var j in nodeinfo.net.netif2) {
|
||||||
|
if (Array.isArray(nodeinfo.net.netif2[j])) {
|
||||||
|
for (var k = 0; k < nodeinfo.net.netif2[j].length; k++) {
|
||||||
|
if (typeof nodeinfo.net.netif2[j][k].mac == 'string') { macs.push(nodeinfo.net.netif2[j][k].mac); }
|
||||||
|
if (typeof nodeinfo.net.netif2[j][k].address == 'string') { addresses.push(nodeinfo.net.netif2[j][k].address); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
output += ',';
|
||||||
|
output += csvClean(macs.join(' ')); // MACS
|
||||||
|
output += ',';
|
||||||
|
output += csvClean(addresses.join(' ')); // Addresses
|
||||||
|
} else {
|
||||||
|
output += ',,,';
|
||||||
}
|
}
|
||||||
output += ',';
|
|
||||||
if (typeof nodeinfo.lastConnect.addr == 'string') { output += csvClean(nodeinfo.lastConnect.addr); } // Last connection address and port
|
// Last connection information
|
||||||
} else {
|
if (nodeinfo.lastConnect) {
|
||||||
output += ',,';
|
output += ',';
|
||||||
|
if (nodeinfo.lastConnect.time) {
|
||||||
|
// Last connection time
|
||||||
|
if ((typeof command.l == 'string') && (typeof command.tz == 'string')) {
|
||||||
|
output += csvClean(new Date(nodeinfo.lastConnect.time).toLocaleString(command.l, { timeZone: command.tz }))
|
||||||
|
} else {
|
||||||
|
output += nodeinfo.lastConnect.time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output += ',';
|
||||||
|
if (typeof nodeinfo.lastConnect.addr == 'string') { output += csvClean(nodeinfo.lastConnect.addr); } // Last connection address and port
|
||||||
|
} else {
|
||||||
|
output += ',,';
|
||||||
|
}
|
||||||
|
|
||||||
|
output += '\r\n';
|
||||||
}
|
}
|
||||||
|
} catch (ex) { console.log(ex); }
|
||||||
|
} else {
|
||||||
|
// Create the JSON file
|
||||||
|
|
||||||
output += '\r\n';
|
// Add the device group name to each device
|
||||||
|
for (var i = 0; i < results.length; i++) {
|
||||||
|
const nodeinfo = results[i];
|
||||||
|
if (nodeinfo.node) {
|
||||||
|
const mesh = parent.meshes[nodeinfo.node.meshid];
|
||||||
|
if (mesh) { results[i].node.groupname = mesh.name; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (ex) { console.log(ex); }
|
|
||||||
} else {
|
|
||||||
// Create the JSON file
|
|
||||||
|
|
||||||
// Add the device group name to each device
|
output = JSON.stringify(results, null, 2);
|
||||||
for (var i = 0; i < results.length; i++) {
|
|
||||||
const nodeinfo = results[i];
|
|
||||||
if (nodeinfo.node) {
|
|
||||||
const mesh = parent.meshes[nodeinfo.node.meshid];
|
|
||||||
if (mesh) { results[i].node.groupname = mesh.name; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
try { ws.send(JSON.stringify({ action: 'getDeviceDetails', data: output, type: type })); } catch (ex) { }
|
||||||
output = JSON.stringify(results, null, 2);
|
});
|
||||||
}
|
|
||||||
try { ws.send(JSON.stringify({ action: 'getDeviceDetails', data: output, type: type })); } catch (ex) { }
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'endDesktopMultiplex': {
|
case 'endDesktopMultiplex': {
|
||||||
|
|
@ -5599,7 +5613,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
'heapdump': [serverUserCommandHeapDump, ""],
|
'heapdump': [serverUserCommandHeapDump, ""],
|
||||||
'heapdump2': [serverUserCommandHeapDump2, ""],
|
'heapdump2': [serverUserCommandHeapDump2, ""],
|
||||||
'help': [serverUserCommandHelp, ""],
|
'help': [serverUserCommandHelp, ""],
|
||||||
'info': [serverUserCommandInfo, "Returns the most immidiatly useful information about this server, including MeshCentral and NodeJS versions. This is often information required to file a bug."],
|
'info': [serverUserCommandInfo, "Returns the most immidiatly useful information about this server, including MeshCentral and NodeJS versions. This is often information required to file a bug. Optionally use info h for human readable form."],
|
||||||
'le': [serverUserCommandLe, ""],
|
'le': [serverUserCommandLe, ""],
|
||||||
'lecheck': [serverUserCommandLeCheck, ""],
|
'lecheck': [serverUserCommandLeCheck, ""],
|
||||||
'leevents': [serverUserCommandLeEvents, ""],
|
'leevents': [serverUserCommandLeEvents, ""],
|
||||||
|
|
@ -7545,7 +7559,26 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
}
|
}
|
||||||
|
|
||||||
function serverUserCommandInfo(cmdData) {
|
function serverUserCommandInfo(cmdData) {
|
||||||
var info = {};
|
function convertSeconds (s, form) {
|
||||||
|
if (!['long', 'shortprecise'].includes(form)) {
|
||||||
|
form = 'shortprecise';
|
||||||
|
}
|
||||||
|
let t = {}, r = '';
|
||||||
|
t.d = Math.floor(s / (24 * 3600));
|
||||||
|
s %= 24 * 3600;
|
||||||
|
t.h= Math.floor(s / 3600);
|
||||||
|
s %= 3600;
|
||||||
|
t.m = Math.floor(s / 60);
|
||||||
|
t.s =(s%60).toFixed(0);
|
||||||
|
if ( form == 'long') {
|
||||||
|
r = t.d + ((t.d == 1) ? ' day, ' : ' days, ') + t.h + ((t.h == 1) ? ' hour, ' : ' hours, ') + t.m + ((t.m == 1) ? ' minute, ' : ' minutes, ') + t.s+ ((t.s == 1) ? ' second' : ' seconds');
|
||||||
|
} else if (form == 'shortprecise') {
|
||||||
|
r = String(t.d).padStart(2, '0') + ':' + String(t.h).padStart(2, '0') + ':' + String(t.m).padStart(2, '0') + ':' + String((s%60).toFixed(2)).padStart(5, '0') + 's';
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
var info = {}, arg = null, t = {}, r = '';
|
||||||
|
if ((cmdData.cmdargs['_'] != null) && (cmdData.cmdargs['_'][0] != null)) { arg = cmdData.cmdargs['_'][0].toLowerCase(); }
|
||||||
try { info.meshVersion = 'v' + parent.parent.currentVer; } catch (ex) { }
|
try { info.meshVersion = 'v' + parent.parent.currentVer; } catch (ex) { }
|
||||||
try { info.nodeVersion = process.version; } catch (ex) { }
|
try { info.nodeVersion = process.version; } catch (ex) { }
|
||||||
try { info.runMode = (["Hybrid (LAN + WAN) mode", "WAN mode", "LAN mode"][(args.lanonly ? 2 : (args.wanonly ? 1 : 0))]); } catch (ex) { }
|
try { info.runMode = (["Hybrid (LAN + WAN) mode", "WAN mode", "LAN mode"][(args.lanonly ? 2 : (args.wanonly ? 1 : 0))]); } catch (ex) { }
|
||||||
|
|
@ -7557,9 +7590,24 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||||
try { info.platform = process.platform; } catch (ex) { }
|
try { info.platform = process.platform; } catch (ex) { }
|
||||||
try { info.arch = process.arch; } catch (ex) { }
|
try { info.arch = process.arch; } catch (ex) { }
|
||||||
try { info.pid = process.pid; } catch (ex) { }
|
try { info.pid = process.pid; } catch (ex) { }
|
||||||
try { info.uptime = process.uptime(); } catch (ex) { }
|
if (arg == 'h') {
|
||||||
try { info.cpuUsage = process.cpuUsage(); } catch (ex) { }
|
try {
|
||||||
try { info.memoryUsage = process.memoryUsage(); } catch (ex) { }
|
info.uptime = convertSeconds(process.uptime(), 'long');
|
||||||
|
info.cpuUsage = {
|
||||||
|
system: (convertSeconds(process.cpuUsage().system /1000000)),
|
||||||
|
user: (convertSeconds(process.cpuUsage().user /1000000))
|
||||||
|
}
|
||||||
|
info.memoryUsage = {};
|
||||||
|
for (const [key,value] of Object.entries(process.memoryUsage())){
|
||||||
|
info.memoryUsage[key] = ([value]/1048576).toFixed(2) + 'Mb';
|
||||||
|
}
|
||||||
|
} catch (ex) { }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try { info.uptime = process.uptime(); } catch (ex) { }
|
||||||
|
try { info.cpuUsage = process.cpuUsage(); } catch (ex) { }
|
||||||
|
try { info.memoryUsage = process.memoryUsage(); } catch (ex) { }
|
||||||
|
}
|
||||||
try { info.warnings = parent.parent.getServerWarnings(); } catch (ex) { console.log(ex); }
|
try { info.warnings = parent.parent.getServerWarnings(); } catch (ex) { console.log(ex); }
|
||||||
try { info.allDevGroupManagers = parent.parent.config.settings.managealldevicegroups; } catch (ex) { }
|
try { info.allDevGroupManagers = parent.parent.config.settings.managealldevicegroups; } catch (ex) { }
|
||||||
try { if (process.traceDeprecation == true) { info.traceDeprecation = true; } } catch (ex) { }
|
try { if (process.traceDeprecation == true) { info.traceDeprecation = true; } } catch (ex) { }
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ module.exports.CreateMonitoring = function (parent, args) {
|
||||||
blockedUsers: { description: "Blocked Users" }, // blockedUsers
|
blockedUsers: { description: "Blocked Users" }, // blockedUsers
|
||||||
blockedAgents: { description: "Blocked Agents" }, // blockedAgents
|
blockedAgents: { description: "Blocked Agents" }, // blockedAgents
|
||||||
};
|
};
|
||||||
obj.guageMetrics = { // Guage Metrics always start at 0 and can increase and decrease
|
obj.gaugeMetrics = { // Gauge Metrics always start at 0 and can increase and decrease
|
||||||
ConnectedIntelAMT: { description: "Connected Intel AMT" }, // parent.mpsserver.ciraConnections[i].length
|
ConnectedIntelAMT: { description: "Connected Intel AMT" }, // parent.mpsserver.ciraConnections[i].length
|
||||||
UserAccounts: { description: "User Accounts" }, // Object.keys(parent.webserver.users).length
|
UserAccounts: { description: "User Accounts" }, // Object.keys(parent.webserver.users).length
|
||||||
DeviceGroups: { description: "Device Groups" }, // parent.webserver.meshes (ONLY WHERE deleted=null)
|
DeviceGroups: { description: "Device Groups" }, // parent.webserver.meshes (ONLY WHERE deleted=null)
|
||||||
|
|
@ -42,6 +42,7 @@ module.exports.CreateMonitoring = function (parent, args) {
|
||||||
RelaySessions: { description: "Relay Sessions" }, // parent.webserver.relaySessionCount
|
RelaySessions: { description: "Relay Sessions" }, // parent.webserver.relaySessionCount
|
||||||
RelayCount: { description: "Relay Count" } // Object.keys(parent.webserver.wsrelays).length30bb4fb74dfb758d36be52a7
|
RelayCount: { description: "Relay Count" } // Object.keys(parent.webserver.wsrelays).length30bb4fb74dfb758d36be52a7
|
||||||
}
|
}
|
||||||
|
obj.collectors = [];
|
||||||
if (parent.config.settings.prometheus != null) { // Create Prometheus Monitoring Endpoint
|
if (parent.config.settings.prometheus != null) { // Create Prometheus Monitoring Endpoint
|
||||||
if ((typeof parent.config.settings.prometheus == 'number') && ((parent.config.settings.prometheus < 1) || (parent.config.settings.prometheus > 65535))) {
|
if ((typeof parent.config.settings.prometheus == 'number') && ((parent.config.settings.prometheus < 1) || (parent.config.settings.prometheus > 65535))) {
|
||||||
console.log('Promethus port number is invalid, Prometheus metrics endpoint has be disabled');
|
console.log('Promethus port number is invalid, Prometheus metrics endpoint has be disabled');
|
||||||
|
|
@ -51,8 +52,8 @@ module.exports.CreateMonitoring = function (parent, args) {
|
||||||
obj.prometheus = require('prom-client');
|
obj.prometheus = require('prom-client');
|
||||||
const collectDefaultMetrics = obj.prometheus.collectDefaultMetrics;
|
const collectDefaultMetrics = obj.prometheus.collectDefaultMetrics;
|
||||||
collectDefaultMetrics();
|
collectDefaultMetrics();
|
||||||
for (const key in obj.guageMetrics) {
|
for (const key in obj.gaugeMetrics) {
|
||||||
obj.guageMetrics[key].prometheus = new obj.prometheus.Gauge({ name: 'meshcentral_' + String(key).toLowerCase(), help: obj.guageMetrics[key].description });
|
obj.gaugeMetrics[key].prometheus = new obj.prometheus.Gauge({ name: 'meshcentral_' + String(key).toLowerCase(), help: obj.gaugeMetrics[key].description });
|
||||||
}
|
}
|
||||||
for (const key in obj.counterMetrics) {
|
for (const key in obj.counterMetrics) {
|
||||||
obj.counterMetrics[key].prometheus = new obj.prometheus.Counter({ name: 'meshcentral_' + String(key).toLowerCase(), help: obj.counterMetrics[key].description });
|
obj.counterMetrics[key].prometheus = new obj.prometheus.Counter({ name: 'meshcentral_' + String(key).toLowerCase(), help: obj.counterMetrics[key].description });
|
||||||
|
|
@ -67,7 +68,7 @@ module.exports.CreateMonitoring = function (parent, args) {
|
||||||
// Count the number of device groups that are not deleted
|
// Count the number of device groups that are not deleted
|
||||||
var activeDeviceGroups = 0;
|
var activeDeviceGroups = 0;
|
||||||
for (var i in parent.webserver.meshes) { if (parent.webserver.meshes[i].deleted == null) { activeDeviceGroups++; } } // This is not ideal for performance, we want to dome something better.
|
for (var i in parent.webserver.meshes) { if (parent.webserver.meshes[i].deleted == null) { activeDeviceGroups++; } } // This is not ideal for performance, we want to dome something better.
|
||||||
var guages = {
|
var gauges = {
|
||||||
UserAccounts: Object.keys(parent.webserver.users).length,
|
UserAccounts: Object.keys(parent.webserver.users).length,
|
||||||
DeviceGroups: activeDeviceGroups,
|
DeviceGroups: activeDeviceGroups,
|
||||||
AgentSessions: Object.keys(parent.webserver.wsagents).length,
|
AgentSessions: Object.keys(parent.webserver.wsagents).length,
|
||||||
|
|
@ -79,10 +80,10 @@ module.exports.CreateMonitoring = function (parent, args) {
|
||||||
};
|
};
|
||||||
if (parent.mpsserver != null) {
|
if (parent.mpsserver != null) {
|
||||||
for (var i in parent.mpsserver.ciraConnections) {
|
for (var i in parent.mpsserver.ciraConnections) {
|
||||||
guages.ConnectedIntelAMT += parent.mpsserver.ciraConnections[i].length;
|
gauges.ConnectedIntelAMT += parent.mpsserver.ciraConnections[i].length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const key in guages) { obj.guageMetrics[key].prometheus.set(guages[key]); }
|
for (const key in gauges) { obj.gaugeMetrics[key].prometheus.set(gauges[key]); }
|
||||||
// Take a look at agent errors
|
// Take a look at agent errors
|
||||||
var agentstats = parent.webserver.getAgentStats();
|
var agentstats = parent.webserver.getAgentStats();
|
||||||
const counters = {
|
const counters = {
|
||||||
|
|
@ -103,6 +104,7 @@ module.exports.CreateMonitoring = function (parent, args) {
|
||||||
};
|
};
|
||||||
for (const key in counters) { obj.counterMetrics[key].prometheus.reset(); obj.counterMetrics[key].prometheus.inc(counters[key]); }
|
for (const key in counters) { obj.counterMetrics[key].prometheus.reset(); obj.counterMetrics[key].prometheus.inc(counters[key]); }
|
||||||
res.set('Content-Type', obj.prometheus.register.contentType);
|
res.set('Content-Type', obj.prometheus.register.contentType);
|
||||||
|
await Promise.all(obj.collectors.map((collector) => (collector(req, res))));
|
||||||
res.end(await obj.prometheus.register.metrics());
|
res.end(await obj.prometheus.register.metrics());
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.log(ex);
|
console.log(ex);
|
||||||
|
|
@ -111,4 +113,5 @@ module.exports.CreateMonitoring = function (parent, args) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "1.1.37",
|
"version": "1.1.42",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Device Management",
|
"Remote Device Management",
|
||||||
"Remote Device Monitoring",
|
"Remote Device Monitoring",
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ module.exports.pluginHandler = function (parent) {
|
||||||
try {
|
try {
|
||||||
obj.plugins[p][hookName](...args);
|
obj.plugins[p][hookName](...args);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Error occurred while running plugin hook" + p + ':' + hookName + ' (' + e + ')');
|
console.log("Error occurred while running plugin hook " + p + ':' + hookName, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
963
public/scripts/agent-desktop-0.0.2-min.js
vendored
963
public/scripts/agent-desktop-0.0.2-min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -155,7 +155,6 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
if (Msg[1] == 1) { obj.ProcessCopyRectMsg(Msg[2]); }
|
if (Msg[1] == 1) { obj.ProcessCopyRectMsg(Msg[2]); }
|
||||||
else if (Msg[1] == 2) { obj.Canvas.drawImage(Msg[2], obj.rotX(Msg[3], Msg[4]), obj.rotY(Msg[3], Msg[4])); delete Msg[2]; }
|
else if (Msg[1] == 2) { obj.Canvas.drawImage(Msg[2], obj.rotX(Msg[3], Msg[4]), obj.rotY(Msg[3], Msg[4])); delete Msg[2]; }
|
||||||
obj.PendingOperations.splice(i, 1);
|
obj.PendingOperations.splice(i, 1);
|
||||||
delete Msg;
|
|
||||||
obj.TilesDrawn++;
|
obj.TilesDrawn++;
|
||||||
if ((obj.TilesDrawn == obj.tilesReceived) && (obj.KillDraw < obj.TilesDrawn)) { obj.KillDraw = obj.TilesDrawn = obj.tilesReceived = 0; }
|
if ((obj.TilesDrawn == obj.tilesReceived) && (obj.KillDraw < obj.TilesDrawn)) { obj.KillDraw = obj.TilesDrawn = obj.tilesReceived = 0; }
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -221,12 +220,16 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
|
||||||
if ((cmd == 3) || (cmd == 4) || (cmd == 7)) { X = (view[4] << 8) + view[5]; Y = (view[6] << 8) + view[7]; }
|
if ((cmd == 3) || (cmd == 4) || (cmd == 7)) { X = (view[4] << 8) + view[5]; Y = (view[6] << 8) + view[7]; }
|
||||||
if (obj.debugmode > 2) { console.log('CMD', cmd, cmdsize, X, Y); }
|
if (obj.debugmode > 2) { console.log('CMD', cmd, cmdsize, X, Y); }
|
||||||
|
|
||||||
|
// Fix for view being too large for String.fromCharCode.apply()
|
||||||
|
var chunkSize = 10000;
|
||||||
|
let result = '';
|
||||||
|
for (let i = 0; i < view.length; i += chunkSize) { result += String.fromCharCode.apply(null, view.slice(i, i + chunkSize)); }
|
||||||
// Record the command if needed
|
// Record the command if needed
|
||||||
if (obj.recordedData != null) {
|
if (obj.recordedData != null) {
|
||||||
if (cmdsize > 65000) {
|
if (cmdsize > 65000) {
|
||||||
obj.recordedData.push(recordingEntry(2, 1, obj.shortToStr(27) + obj.shortToStr(8) + obj.intToStr(cmdsize) + obj.shortToStr(cmd) + obj.shortToStr(0) + obj.shortToStr(0) + obj.shortToStr(0) + String.fromCharCode.apply(null, view)));
|
obj.recordedData.push(recordingEntry(2, 1, obj.shortToStr(27) + obj.shortToStr(8) + obj.intToStr(cmdsize) + obj.shortToStr(cmd) + obj.shortToStr(0) + obj.shortToStr(0) + obj.shortToStr(0) + result));
|
||||||
} else {
|
} else {
|
||||||
obj.recordedData.push(recordingEntry(2, 1, String.fromCharCode.apply(null, view)));
|
obj.recordedData.push(recordingEntry(2, 1, result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2
public/scripts/amt-wsman-0.2.0-min.js
vendored
2
public/scripts/amt-wsman-0.2.0-min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -4,8 +4,8 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
// Load saved theme from local storage
|
// Load saved theme from local storage
|
||||||
const savedTheme = localStorage.getItem("theme");
|
const savedTheme = localStorage.getItem("theme");
|
||||||
if (savedTheme) {
|
if (savedTheme) {
|
||||||
const safeTheme = encodeURIComponent(savedTheme);
|
const safeTheme = ((savedTheme != 'default') ? encodeURIComponent(savedTheme) : encodeURIComponent('..'));
|
||||||
themeStylesheet.href = `styles/themes/${safeTheme}/bootstrap.min.css`;
|
themeStylesheet.href = `styles/themes/${safeTheme}/bootstrap-min.css`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Select2 on all select elements with the 'select2' class
|
// Initialize Select2 on all select elements with the 'select2' class
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,16 @@ body {
|
||||||
right: 3px;
|
right: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textnewui {
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-top: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.LogoffLinkColor {
|
.LogoffLinkColor {
|
||||||
color:white;
|
color:white;
|
||||||
}
|
}
|
||||||
|
|
@ -693,6 +703,10 @@ body {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.DeviceCheckbox {
|
||||||
|
margin-top: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.deviceBarCheckbox {
|
.deviceBarCheckbox {
|
||||||
width:22px;
|
width:22px;
|
||||||
float:left;
|
float:left;
|
||||||
|
|
@ -813,15 +827,15 @@ NoMeshesPanel img {
|
||||||
.deviceNotifySmallDot {
|
.deviceNotifySmallDot {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
right:10px;
|
right:10px;
|
||||||
top:0px;
|
top:4px;
|
||||||
height:10px;
|
height:10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.deviceNotifySmallDotSub {
|
.deviceNotifySmallDotSub {
|
||||||
text-align:center;
|
text-align:center;
|
||||||
color:#FFF;
|
color:#FFF;
|
||||||
height:10px;
|
height:14px;
|
||||||
width:10px;
|
width:14px;
|
||||||
padding:2px;
|
padding:2px;
|
||||||
background-color:#00F;
|
background-color:#00F;
|
||||||
border-radius:10px;
|
border-radius:10px;
|
||||||
|
|
@ -2877,7 +2891,7 @@ nav .lbbuttonsel2 {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewSelector3 {
|
.viewSelector3, .uiSelector7 {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
background: url(../images/views.png) -56px 0px;
|
background: url(../images/views.png) -56px 0px;
|
||||||
|
|
@ -2977,6 +2991,13 @@ nav .lbbuttonsel2 {
|
||||||
background-color: #AAA;
|
background-color: #AAA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.uiSelector_end {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
float: left;
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.uiSelectorSel {
|
.uiSelectorSel {
|
||||||
background-color: #BBB;
|
background-color: #BBB;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
|
|
||||||
|
|
@ -263,6 +263,16 @@ body {
|
||||||
right: 3px;
|
right: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textnewui {
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-top: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.LogoffLinkColor {
|
.LogoffLinkColor {
|
||||||
color:white;
|
color:white;
|
||||||
}
|
}
|
||||||
|
|
@ -2896,7 +2906,7 @@ a {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewSelector3 {
|
.viewSelector3, .uiSelector7 {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
background: url(../images/views.png) -56px 0px;
|
background: url(../images/views.png) -56px 0px;
|
||||||
|
|
@ -2996,6 +3006,13 @@ a {
|
||||||
background-color: #AAA;
|
background-color: #AAA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.uiSelector_end {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
float: left;
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.uiSelectorSel {
|
.uiSelectorSel {
|
||||||
background-color: #BBB;
|
background-color: #BBB;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,7 @@
|
||||||
"domains": {
|
"domains": {
|
||||||
"": {
|
"": {
|
||||||
"_siteStyle": 2,
|
"_siteStyle": 2,
|
||||||
|
"_showModernUIToggle": true,
|
||||||
"title": "MyServer",
|
"title": "MyServer",
|
||||||
"title2": "Servername",
|
"title2": "Servername",
|
||||||
"_titlePicture": "title-sample.png",
|
"_titlePicture": "title-sample.png",
|
||||||
|
|
@ -342,6 +343,7 @@
|
||||||
"files": "{0} requesting remote files access. Grant access?",
|
"files": "{0} requesting remote files access. Grant access?",
|
||||||
"consentTimeout": 30,
|
"consentTimeout": 30,
|
||||||
"autoAcceptOnTimeout": false,
|
"autoAcceptOnTimeout": false,
|
||||||
|
"autoAcceptIfNoUser": false,
|
||||||
"oldStyle": true
|
"oldStyle": true
|
||||||
},
|
},
|
||||||
"_notificationMessages": {
|
"_notificationMessages": {
|
||||||
|
|
@ -384,6 +386,8 @@
|
||||||
"_agentBlockedIP": "127.0.0.1,::1",
|
"_agentBlockedIP": "127.0.0.1,::1",
|
||||||
"___userSessionIdleTimeout__": "Number of user idle minutes before auto-disconnect",
|
"___userSessionIdleTimeout__": "Number of user idle minutes before auto-disconnect",
|
||||||
"_userSessionIdleTimeout": 30,
|
"_userSessionIdleTimeout": 30,
|
||||||
|
"___logoutOnIdleSessionTimeout": "Determines whether MeshCentral should logout after the session idle timeout elapsed or should just disconnect remote desktop, terminal and files.",
|
||||||
|
"_logoutOnIdleSessionTimeout": false,
|
||||||
"userConsentFlags": {
|
"userConsentFlags": {
|
||||||
"desktopnotify": true,
|
"desktopnotify": true,
|
||||||
"terminalnotify": true,
|
"terminalnotify": true,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ var meshCentralSourceFiles = [
|
||||||
"../views/messenger.handlebars",
|
"../views/messenger.handlebars",
|
||||||
"../views/player.handlebars",
|
"../views/player.handlebars",
|
||||||
"../views/sharing.handlebars",
|
"../views/sharing.handlebars",
|
||||||
|
"../views/sharing-mobile.handlebars",
|
||||||
"../views/mstsc.handlebars",
|
"../views/mstsc.handlebars",
|
||||||
"../views/ssh.handlebars",
|
"../views/ssh.handlebars",
|
||||||
"../emails/account-check.html",
|
"../emails/account-check.html",
|
||||||
|
|
@ -64,6 +65,7 @@ var minifyMeshCentralSourceFiles = [
|
||||||
"../views/agentinvite.handlebars",
|
"../views/agentinvite.handlebars",
|
||||||
"../views/invite.handlebars",
|
"../views/invite.handlebars",
|
||||||
"../views/default.handlebars",
|
"../views/default.handlebars",
|
||||||
|
"../views/default3.handlebars",
|
||||||
"../views/default-mobile.handlebars",
|
"../views/default-mobile.handlebars",
|
||||||
"../views/download.handlebars",
|
"../views/download.handlebars",
|
||||||
"../views/download2.handlebars",
|
"../views/download2.handlebars",
|
||||||
|
|
@ -452,7 +454,8 @@ function startEx(argv) {
|
||||||
removeScriptTypeAttributes: true,
|
removeScriptTypeAttributes: true,
|
||||||
removeTagWhitespace: true,
|
removeTagWhitespace: true,
|
||||||
preserveLineBreaks: false,
|
preserveLineBreaks: false,
|
||||||
useShortDoctype: true
|
useShortDoctype: true,
|
||||||
|
log: function(a) { if (typeof a !== 'string') { console.log(a); } } // Log errors from UglifyJS to console output
|
||||||
});
|
});
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.log(ex);
|
console.log(ex);
|
||||||
|
|
@ -783,10 +786,12 @@ function getStringsHtml(name, node) {
|
||||||
|
|
||||||
// Check if the "value" attribute exists and needs to be translated
|
// Check if the "value" attribute exists and needs to be translated
|
||||||
var subnodeignore = false;
|
var subnodeignore = false;
|
||||||
|
var subnodevalueignore = false;
|
||||||
if ((subnode.attributes != null) && (subnode.attributes.length > 0)) {
|
if ((subnode.attributes != null) && (subnode.attributes.length > 0)) {
|
||||||
var subnodevalue = null, subnodeplaceholder = null, subnodetitle = null;
|
var subnodevalue = null, subnodeplaceholder = null, subnodetitle = null;
|
||||||
for (var j in subnode.attributes) {
|
for (var j in subnode.attributes) {
|
||||||
if ((subnode.attributes[j].name == 'notrans') && (subnode.attributes[j].value == '1')) { subnodeignore = true; }
|
if ((subnode.attributes[j].name == 'notrans') && (subnode.attributes[j].value == '1')) { subnodeignore = true; }
|
||||||
|
if ((subnode.attributes[j].name == 'notransval') && (subnode.attributes[j].value == '1')) { subnodevalueignore = true; }
|
||||||
if ((subnode.attributes[j].name == 'type') && (subnode.attributes[j].value == 'hidden')) { subnodeignore = true; }
|
if ((subnode.attributes[j].name == 'type') && (subnode.attributes[j].value == 'hidden')) { subnodeignore = true; }
|
||||||
if (subnode.attributes[j].name == 'value') { subnodevalue = subnode.attributes[j].value; }
|
if (subnode.attributes[j].name == 'value') { subnodevalue = subnode.attributes[j].value; }
|
||||||
if (subnode.attributes[j].name == 'placeholder') { subnodeplaceholder = subnode.attributes[j].value; }
|
if (subnode.attributes[j].name == 'placeholder') { subnodeplaceholder = subnode.attributes[j].value; }
|
||||||
|
|
@ -795,7 +800,7 @@ function getStringsHtml(name, node) {
|
||||||
if ((subnodevalue != null) && isNumber(subnodevalue) == true) { subnodevalue = null; }
|
if ((subnodevalue != null) && isNumber(subnodevalue) == true) { subnodevalue = null; }
|
||||||
if ((subnodeplaceholder != null) && isNumber(subnodeplaceholder) == true) { subnodeplaceholder = null; }
|
if ((subnodeplaceholder != null) && isNumber(subnodeplaceholder) == true) { subnodeplaceholder = null; }
|
||||||
if ((subnodetitle != null) && isNumber(subnodetitle) == true) { subnodetitle = null; }
|
if ((subnodetitle != null) && isNumber(subnodetitle) == true) { subnodetitle = null; }
|
||||||
if ((subnodeignore == false) && (subnodevalue != null)) {
|
if ((subnodeignore == false) && (subnodevalueignore == false) && (subnodevalue != null)) {
|
||||||
// Add a new string to the list (value)
|
// Add a new string to the list (value)
|
||||||
if (sourceStrings[subnodevalue] == null) { sourceStrings[subnodevalue] = { en: subnodevalue, xloc: [name] }; } else { if (sourceStrings[subnodevalue].xloc == null) { sourceStrings[subnodevalue].xloc = []; } sourceStrings[subnodevalue].xloc.push(name); }
|
if (sourceStrings[subnodevalue] == null) { sourceStrings[subnodevalue] = { en: subnodevalue, xloc: [name] }; } else { if (sourceStrings[subnodevalue].xloc == null) { sourceStrings[subnodevalue].xloc = []; } sourceStrings[subnodevalue].xloc.push(name); }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21666
translate/translate.json
21666
translate/translate.json
File diff suppressed because it is too large
Load diff
|
|
@ -1304,6 +1304,7 @@
|
||||||
delete urlargs.viewmode;
|
delete urlargs.viewmode;
|
||||||
delete urlargs.gotonode;
|
delete urlargs.gotonode;
|
||||||
delete urlargs.gotodevicename;
|
delete urlargs.gotodevicename;
|
||||||
|
delete urlargs.gotodeviceip;
|
||||||
delete urlargs.gotomesh;
|
delete urlargs.gotomesh;
|
||||||
delete urlargs.panel;
|
delete urlargs.panel;
|
||||||
|
|
||||||
|
|
@ -1324,7 +1325,7 @@
|
||||||
var logoutControls = JSON.parse(decodeURIComponent('{{{logoutControls}}}'));
|
var logoutControls = JSON.parse(decodeURIComponent('{{{logoutControls}}}'));
|
||||||
var authCookieRenewTimer = null;
|
var authCookieRenewTimer = null;
|
||||||
var webRelayPort = parseInt('{{{webRelayPort}}}');
|
var webRelayPort = parseInt('{{{webRelayPort}}}');
|
||||||
var hidePowerTimeline = {{{hidePowerTimeline}}};
|
var hidePowerTimeline = '{{{hidePowerTimeline}}}';
|
||||||
var webRelayDns = '{{{webRelayDns}}}';
|
var webRelayDns = '{{{webRelayDns}}}';
|
||||||
var meshserver = null;
|
var meshserver = null;
|
||||||
var xdr = null;
|
var xdr = null;
|
||||||
|
|
@ -1521,7 +1522,26 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSessionActivity() { sessionActivity = Date.now(); }
|
function setSessionActivity() { sessionActivity = Date.now(); }
|
||||||
function checkIdleSessionTimeout() { var delta = (Date.now() - sessionActivity); if (delta > serverinfo.timeout) { window.location.href = 'logout'; } }
|
function checkIdleSessionTimeout() {
|
||||||
|
var delta = (Date.now() - sessionActivity);
|
||||||
|
if (delta > serverinfo.timeout) {
|
||||||
|
if (desktop != null) { // Disconnect remote desktop
|
||||||
|
desktop.Stop();
|
||||||
|
desktopNode = desktop = null;
|
||||||
|
}
|
||||||
|
if (terminal != null) { // Disconnect terminal
|
||||||
|
terminal.Stop();
|
||||||
|
terminal = null;
|
||||||
|
}
|
||||||
|
if (files != null) { // Disconnect files
|
||||||
|
files.Stop();
|
||||||
|
files = null;
|
||||||
|
}
|
||||||
|
if (serverinfo.logoutonidlesessiontimeout) {
|
||||||
|
window.location.href = 'logout';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onMessage(server, message) {
|
function onMessage(server, message) {
|
||||||
switch (message.action) {
|
switch (message.action) {
|
||||||
|
|
@ -2025,6 +2045,8 @@
|
||||||
// Change the node
|
// Change the node
|
||||||
node.name = message.event.node.name;
|
node.name = message.event.node.name;
|
||||||
node.rname = message.event.node.rname;
|
node.rname = message.event.node.rname;
|
||||||
|
node.lusers = message.event.node.lusers;
|
||||||
|
node.users = message.event.node.users;
|
||||||
node.host = message.event.node.host;
|
node.host = message.event.node.host;
|
||||||
node.desc = message.event.node.desc;
|
node.desc = message.event.node.desc;
|
||||||
node.publicip = message.event.node.publicip;
|
node.publicip = message.event.node.publicip;
|
||||||
|
|
@ -2229,6 +2251,10 @@
|
||||||
var foundNode = null;
|
var foundNode = null;
|
||||||
if (nodes != null) { for (var i in nodes) { if (nodes[i].name == args.gotodevicename) { foundNode = nodes[i]._id; } } }
|
if (nodes != null) { for (var i in nodes) { if (nodes[i].name == args.gotodevicename) { foundNode = nodes[i]._id; } } }
|
||||||
if (foundNode) { gotoDevice(foundNode, xviewmode); go(xviewmode); }
|
if (foundNode) { gotoDevice(foundNode, xviewmode); go(xviewmode); }
|
||||||
|
} else if (args.gotodeviceip != null) {
|
||||||
|
var foundNode = null;
|
||||||
|
if (nodes != null) { for (var i in nodes) { if (nodes[i].ip == args.gotodeviceip) { foundNode = nodes[i]._id; } } }
|
||||||
|
if (foundNode) { gotoDevice(foundNode, xviewmode); go(xviewmode); }
|
||||||
} else if (args.gotomesh != null) {
|
} else if (args.gotomesh != null) {
|
||||||
if (meshes['mesh/' + domain + '/' + args.gotomesh] == null) return; // This device group is not loaded yet
|
if (meshes['mesh/' + domain + '/' + args.gotomesh] == null) return; // This device group is not loaded yet
|
||||||
gotoMesh('mesh/' + domain + '/' + args.gotomesh);
|
gotoMesh('mesh/' + domain + '/' + args.gotomesh);
|
||||||
|
|
@ -4255,7 +4281,7 @@
|
||||||
|
|
||||||
// Draw device power bars. The bars are 766px wide.
|
// Draw device power bars. The bars are 766px wide.
|
||||||
function drawDeviceTimeline() {
|
function drawDeviceTimeline() {
|
||||||
if (currentNode.mtype == 3 || hidePowerTimeline) { QH('p10html2', '<br />'); return; }
|
if (currentNode.mtype == 3 || hidePowerTimeline === 'true') { QH('p10html2', '<br />'); return; }
|
||||||
var timeline = null, now = Date.now();
|
var timeline = null, now = Date.now();
|
||||||
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
|
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
|
||||||
|
|
||||||
|
|
@ -6262,7 +6288,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Active Users
|
// Active Users
|
||||||
if (node.users && (node.users.length > 0)) { x += addDetailItem(((node.users.length > 1)?"Active Users":"Active User"), EscapeHtml(node.users.join(', '))); }
|
if (node.users && node.users.length > 0) {
|
||||||
|
var u = node.users.map(function(user) {
|
||||||
|
return addKeyLinkConditional(EscapeHtml(user), "Locked", (node.lusers && node.lusers.indexOf(user) >= 0));
|
||||||
|
}).join(', ');
|
||||||
|
x += addDetailItem((node.users.length > 1 ? "Active Users" : "Active User"), u);
|
||||||
|
}
|
||||||
|
|
||||||
if (x != '') { sections.push({ name: "Operating System", html: x, img: 'software' }); }
|
if (x != '') { sections.push({ name: "Operating System", html: x, img: 'software' }); }
|
||||||
|
|
||||||
|
|
@ -6788,7 +6819,19 @@
|
||||||
if (e.shiftKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'default' }); } // Upload default core
|
if (e.shiftKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'default' }); } // Upload default core
|
||||||
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'clear' }); } // Clear the core
|
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeid: consoleNode._id, type: 'clear' }); } // Clear the core
|
||||||
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
|
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
|
||||||
else { setDialogMode(2, "Perform Agent Action", 3, p15uploadCoreEx, addHtmlValue("Action", '<select id=d3coreMode style=width:230px><option value=1>' + "Upload default server core" + '</option><option value=2>' + "Clear the core" + '</option><option value=6>' + "Upload recovery core" + '</option><option value=7>' + "Upload tiny core" + '</option><option value=3>' + "Upload a core file" + '</option><option value=4>' + "Soft disconnect agent" + '</option><option value=5>' + "Hard disconnect agent" + '</option><option value=8>' + "Restart agent service" + '</select>')); }
|
else {
|
||||||
|
var htmlValue = '<select id=d3coreMode style=width:230px>' +
|
||||||
|
'<option value=1>' + "Upload default server core" + '</option>' +
|
||||||
|
'<option value=2>' + "Clear the core" + '</option>' +
|
||||||
|
'<option value=3>' + "Upload a core file" + '</option>' +
|
||||||
|
'<option value=4>' + "Soft disconnect agent" + '</option>' +
|
||||||
|
'<option value=5>' + "Hard disconnect agent" + '</option>' +
|
||||||
|
'<option value=6>' + "Upload recovery core" + '</option>' +
|
||||||
|
'<option value=7>' + "Upload tiny core" + '</option>' +
|
||||||
|
'<option value=8>' + "Restart agent service" + '</option>' +
|
||||||
|
'<option value=9>' + "Force agent update" + '</option></select>';
|
||||||
|
setDialogMode(2, "Perform Agent Action", 3, p15uploadCoreEx, addHtmlValue("Action", htmlValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function p15uploadCoreEx() {
|
function p15uploadCoreEx() {
|
||||||
|
|
@ -6816,6 +6859,9 @@
|
||||||
} else if (Q('d3coreMode').value == 8) {
|
} else if (Q('d3coreMode').value == 8) {
|
||||||
// Restart MeshAgent service
|
// Restart MeshAgent service
|
||||||
meshserver.send({ action: 'msg', type: 'console', nodeid: consoleNode._id, value:'service restart' });
|
meshserver.send({ action: 'msg', type: 'console', nodeid: consoleNode._id, value:'service restart' });
|
||||||
|
} else if (Q('d3coreMode').value == 9) {
|
||||||
|
// Update mesh agent
|
||||||
|
meshserver.send({ action: 'updateAgents', nodeids: [consoleNode._id] });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7574,7 +7620,7 @@
|
||||||
function addLink(x, f) { return '<a style=cursor:pointer;text-decoration:none onclick=\'' + f + '\'>♦ ' + x + '</a>'; }
|
function addLink(x, f) { return '<a style=cursor:pointer;text-decoration:none onclick=\'' + f + '\'>♦ ' + x + '</a>'; }
|
||||||
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
|
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
|
||||||
function addKeyLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=' + f + ' onkeypress="if (event.key==\'Enter\') { ' + f + ' } ">' + x + ' <img class=hoverButton src=images/key16.png></span>'; }
|
function addKeyLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=' + f + ' onkeypress="if (event.key==\'Enter\') { ' + f + ' } ">' + x + ' <img class=hoverButton src=images/key16.png></span>'; }
|
||||||
function addKeyLinkConditional(x, f, c) { if (c) return addKeyLink(x, f); return x; }
|
function addKeyLinkConditional(x, t, c) { if (c) return '<span title=\'' + t + '\'>' + x + ' <img class=hoverButton src=images/key16.png></span>'; return x }
|
||||||
function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); }
|
function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); }
|
||||||
function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format('{0} bytes', size); }
|
function getFileSizeStr(size) { if (typeof size != 'number') { size = 0; } if (size == 1) return "1 byte"; return format('{0} bytes', size); }
|
||||||
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,9 @@
|
||||||
<div id=notificationCount onclick="clickNotificationIcon()" class="unselectable" style="display: none;" title="Click to view current notifications">0</div>
|
<div id=notificationCount onclick="clickNotificationIcon()" class="unselectable" style="display: none;" title="Click to view current notifications">0</div>
|
||||||
</div>
|
</div>
|
||||||
<p id="logoutControl"><span id=logoutControlSpan class="logoncontrolspan"></span><span id=idleTimeoutNotify style="color:yellow"></span></p>
|
<p id="logoutControl"><span id=logoutControlSpan class="logoncontrolspan"></span><span id=idleTimeoutNotify style="color:yellow"></span></p>
|
||||||
|
<div class=textnewui id=textnewui onmouseup=toggleBootstrapUIMode() onkeypress="if (event.key=='Enter') { toggleBootstrapUIMode(); }">
|
||||||
|
<b>Try the new MeshCentral UI</b>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="page_leftbar">
|
<div id="page_leftbar">
|
||||||
<div style="height:16px"></div>
|
<div style="height:16px"></div>
|
||||||
|
|
@ -199,11 +202,13 @@
|
||||||
<div tabindex=0 id=uiViewButton1 class=uiSelector onclick=userInterfaceSelectMenu(1) title="Left bar interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(1)"><div class="uiSelector1"></div></div>
|
<div tabindex=0 id=uiViewButton1 class=uiSelector onclick=userInterfaceSelectMenu(1) title="Left bar interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(1)"><div class="uiSelector1"></div></div>
|
||||||
<div tabindex=0 id=uiViewButton2 class=uiSelector onclick=userInterfaceSelectMenu(2) title="Top bar interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(2)"><div class="uiSelector2"></div></div>
|
<div tabindex=0 id=uiViewButton2 class=uiSelector onclick=userInterfaceSelectMenu(2) title="Top bar interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(2)"><div class="uiSelector2"></div></div>
|
||||||
<div tabindex=0 id=uiViewButton3 class=uiSelector onclick=userInterfaceSelectMenu(3) title="Fixed width interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(3)"><div class="uiSelector3"></div></div>
|
<div tabindex=0 id=uiViewButton3 class=uiSelector onclick=userInterfaceSelectMenu(3) title="Fixed width interface" onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(3)"><div class="uiSelector3"></div></div>
|
||||||
|
<div tabindex=0 id=uiViewButton7 class=uiSelector onclick=toggleBootstrapUIMode() title="Toggle Modern UI" onkeypress="if (event.key == 'Enter') toggleBootstrapUIMode()"><div class="uiSelector7"></div></div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div tabindex=0 id=uiViewButton6 class=uiSelector onclick="showNotes(false)" title="Personal Notes" onkeypress="if (event.key == 'Enter') showNotes(false)"><div class="uiSelector6"></div></div>
|
<div tabindex=0 id=uiViewButton6 class=uiSelector onclick="showNotes(false)" title="Personal Notes" onkeypress="if (event.key == 'Enter') showNotes(false)"><div class="uiSelector6"></div></div>
|
||||||
<div tabindex=0 id=uiViewButton4 class=uiSelector onclick=toggleNightMode() title="Toggle night mode" onkeypress="if (event.key == 'Enter') toggleNightMode()"><div class="uiSelector4"></div></div>
|
<div tabindex=0 id=uiViewButton4 class=uiSelector onclick=toggleNightMode() title="Toggle night mode" onkeypress="if (event.key == 'Enter') toggleNightMode()"><div class="uiSelector4"></div></div>
|
||||||
<div tabindex=0 id=uiViewButton5 class=uiSelector onclick=toggleFooterBarMode() title="Toggle footer bar" onkeypress="if (event.key == 'Enter') toggleFooterBarMode()"><div class="uiSelector5"></div></div>
|
<div tabindex=0 id=uiViewButton5 class=uiSelector onclick=toggleFooterBarMode() title="Toggle footer bar" onkeypress="if (event.key == 'Enter') toggleFooterBarMode()"><div class="uiSelector5"></div></div>
|
||||||
|
<div class=uiSelector_end> </div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -476,23 +481,23 @@
|
||||||
<td class="auto-style1">
|
<td class="auto-style1">
|
||||||
Filter
|
Filter
|
||||||
<select id=p3filterevents onchange=refreshEvents()>
|
<select id=p3filterevents onchange=refreshEvents()>
|
||||||
<option value="">All Logs</option>
|
<option notransval=1 value="">All Logs</option>
|
||||||
<option value=agentlog>Agent Logs</option>
|
<option notransval=1 value=agentlog>Agent Logs</option>
|
||||||
<option value=relaylog>Relay Logs</option>
|
<option notransval=1 value=relaylog>Relay Logs</option>
|
||||||
<option value=manual>Manual Logs</option>
|
<option notransval=1 value=manual>Manual Logs</option>
|
||||||
<option value=runcommands>Run Command Logs</option>
|
<option notransval=1 value=runcommands>Run Command Logs</option>
|
||||||
<option value=batchupload>Batch Upload Logs</option>
|
<option notransval=1 value=batchupload>Batch Upload Logs</option>
|
||||||
<option value=changenode>Change Node Logs</option>
|
<option notransval=1 value=changenode>Change Node Logs</option>
|
||||||
<option value=removenode>Remove Node Logs</option>
|
<option notransval=1 value=removenode>Remove Node Logs</option>
|
||||||
</select>
|
</select>
|
||||||
Show
|
Show
|
||||||
<select id=p3limitdropdown onchange=refreshEvents()>
|
<select id=p3limitdropdown onchange=refreshEvents()>
|
||||||
<option value=60>Last 60</option>
|
<option notransval=1 value=60>Last 60</option>
|
||||||
<option value=120>Last 120</option>
|
<option notransval=1 value=120>Last 120</option>
|
||||||
<option value=250>Last 250</option>
|
<option notransval=1 value=250>Last 250</option>
|
||||||
<option value=500>Last 500</option>
|
<option notransval=1 value=500>Last 500</option>
|
||||||
<option value=1000>Last 1000</option>
|
<option notransval=1 value=1000>Last 1000</option>
|
||||||
<option value="">No limit</option>
|
<option notransval=1 value="">No limit</option>
|
||||||
</select>
|
</select>
|
||||||
<a href=# onclick=p3showDownloadEventsDialog(2)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
|
<a href=# onclick=p3showDownloadEventsDialog(2)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -993,22 +998,22 @@
|
||||||
<td class="auto-style1">
|
<td class="auto-style1">
|
||||||
Filter
|
Filter
|
||||||
<select id=p16filterevents onchange=refreshDeviceEvents()>
|
<select id=p16filterevents onchange=refreshDeviceEvents()>
|
||||||
<option value="">All Logs</option>
|
<option notransval=1 value="">All Logs</option>
|
||||||
<option value=agentlog>Agent Logs</option>
|
<option notransval=1 value=agentlog>Agent Logs</option>
|
||||||
<option value=relaylog>Relay Logs</option>
|
<option notransval=1 value=relaylog>Relay Logs</option>
|
||||||
<option value=manual>Manual Logs</option>
|
<option notransval=1 value=manual>Manual Logs</option>
|
||||||
<option value=runcommands>Run Command Logs</option>
|
<option notransval=1 value=runcommands>Run Command Logs</option>
|
||||||
<option value=batchupload>Batch Upload Logs</option>
|
<option notransval=1 value=batchupload>Batch Upload Logs</option>
|
||||||
<option value=changenode>Change Node Logs</option>
|
<option notransval=1 value=changenode>Change Node Logs</option>
|
||||||
<option value=removenode>Remove Node Logs</option>
|
<option notransval=1 value=removenode>Remove Node Logs</option>
|
||||||
</select>
|
</select>
|
||||||
Show
|
Show
|
||||||
<select id=p16limitdropdown onchange=refreshDeviceEvents()>
|
<select id=p16limitdropdown onchange=refreshDeviceEvents()>
|
||||||
<option value=60>Last 60</option>
|
<option notransval=1 value=60>Last 60</option>
|
||||||
<option value=120>Last 120</option>
|
<option notransval=1 value=120>Last 120</option>
|
||||||
<option value=250>Last 250</option>
|
<option notransval=1 value=250>Last 250</option>
|
||||||
<option value=500>Last 500</option>
|
<option notransval=1 value=500>Last 500</option>
|
||||||
<option value=1000>Last 1000</option>
|
<option notransval=1 value=1000>Last 1000</option>
|
||||||
</select>
|
</select>
|
||||||
<a href=# onclick=p3showDownloadEventsDialog(1)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
|
<a href=# onclick=p3showDownloadEventsDialog(1)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -1133,23 +1138,23 @@
|
||||||
<td class="auto-style1">
|
<td class="auto-style1">
|
||||||
Filter
|
Filter
|
||||||
<select id=p31filterevents onchange=refreshUsersEvents()>
|
<select id=p31filterevents onchange=refreshUsersEvents()>
|
||||||
<option value="">All Logs</option>
|
<option notransval=1 value="">All Logs</option>
|
||||||
<option value=agentlog>Agent Logs</option>
|
<option notransval=1 value=agentlog>Agent Logs</option>
|
||||||
<option value=relaylog>Relay Logs</option>
|
<option notransval=1 value=relaylog>Relay Logs</option>
|
||||||
<option value=manual>Manual Logs</option>
|
<option notransval=1 value=manual>Manual Logs</option>
|
||||||
<option value=runcommands>Run Command Logs</option>
|
<option notransval=1 value=runcommands>Run Command Logs</option>
|
||||||
<option value=batchupload>Batch Upload Logs</option>
|
<option notransval=1 value=batchupload>Batch Upload Logs</option>
|
||||||
<option value=changenode>Change Node Logs</option>
|
<option notransval=1 value=changenode>Change Node Logs</option>
|
||||||
<option value=removenode>Remove Node Logs</option>
|
<option notransval=1 value=removenode>Remove Node Logs</option>
|
||||||
</select>
|
</select>
|
||||||
Show
|
Show
|
||||||
<select id=p31limitdropdown onchange=refreshUsersEvents()>
|
<select id=p31limitdropdown onchange=refreshUsersEvents()>
|
||||||
<option value=60>Last 60</option>
|
<option notransval=1 value=60>Last 60</option>
|
||||||
<option value=120>Last 120</option>
|
<option notransval=1 value=120>Last 120</option>
|
||||||
<option value=250>Last 250</option>
|
<option notransval=1 value=250>Last 250</option>
|
||||||
<option value=500>Last 500</option>
|
<option notransval=1 value=500>Last 500</option>
|
||||||
<option value=1000>Last 1000</option>
|
<option notransval=1 value=1000>Last 1000</option>
|
||||||
<option value="">No limit</option>
|
<option notransval=1 value="">No limit</option>
|
||||||
</select>
|
</select>
|
||||||
<a href=# onclick=p3showDownloadEventsDialog(3)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
|
<a href=# onclick=p3showDownloadEventsDialog(3)><img src=images/link4.png height=10 width=10 title="Download Events" style=cursor:pointer></a>
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -1453,16 +1458,16 @@
|
||||||
<div style="margin-top:8px">
|
<div style="margin-top:8px">
|
||||||
<div>Display Size</div>
|
<div>Display Size</div>
|
||||||
<select id="d7rdpsize">
|
<select id="d7rdpsize">
|
||||||
<option value="canvas">Canvas Size</option>
|
<option notransval=1 value="canvas">Canvas Size</option>
|
||||||
<option value="browser">Browser Size</option>
|
<option notransval=1 value="browser">Browser Size</option>
|
||||||
<option value="screen">Screen Size</option>
|
<option notransval=1 value="screen">Screen Size</option>
|
||||||
<option value="640x480">640x480</option>
|
<option notransval=1 value="640x480">640x480</option>
|
||||||
<option value="1024x768">1024x768</option>
|
<option notransval=1 value="1024x768">1024x768</option>
|
||||||
<option value="1280x800">1280x800</option>
|
<option notransval=1 value="1280x800">1280x800</option>
|
||||||
<option value="1440x900">1440x900</option>
|
<option notransval=1 value="1440x900">1440x900</option>
|
||||||
<option value="1600x900">1600x900</option>
|
<option notransval=1 value="1600x900">1600x900</option>
|
||||||
<option value="1680x1050">1680x1050</option>
|
<option notransval=1 value="1680x1050">1680x1050</option>
|
||||||
<option value="1920x1080">1920x1080</option>
|
<option notransval=1 value="1920x1080">1920x1080</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -1474,7 +1479,7 @@
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp4" />Disable Theming</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp4" />Disable Theming</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp6" />Disable Cursor Shadow</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp6" />Disable Cursor Shadow</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp7" />Disable Cursor Settings</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp7" />Disable Cursor Settings</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp8" />Enable Font Smooting</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp8" />Enable Font Smoothing</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp9" />Enable Desktop Composision</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp9" />Enable Desktop Composision</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdpclip" />Automatic Clipboard</label>
|
<label style="display:block"><input type="checkbox" id="d7rdpclip" />Automatic Clipboard</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdpsmb" />Swap Mouse Buttons</label>
|
<label style="display:block"><input type="checkbox" id="d7rdpsmb" />Swap Mouse Buttons</label>
|
||||||
|
|
@ -1548,8 +1553,8 @@
|
||||||
var sessionTime = parseInt('{{{sessiontime}}}');
|
var sessionTime = parseInt('{{{sessiontime}}}');
|
||||||
var webRelayPort = parseInt('{{{webRelayPort}}}');
|
var webRelayPort = parseInt('{{{webRelayPort}}}');
|
||||||
var webRelayDns = '{{{webRelayDns}}}';
|
var webRelayDns = '{{{webRelayDns}}}';
|
||||||
var hidePowerTimeline = {{{hidePowerTimeline}}};
|
var hidePowerTimeline = '{{{hidePowerTimeline}}}';
|
||||||
var showNotesPanel = {{{showNotesPanel}}};
|
var showNotesPanel = '{{{showNotesPanel}}}';
|
||||||
var sessionRefreshTimer = null;
|
var sessionRefreshTimer = null;
|
||||||
var domain = '{{{domain}}}';
|
var domain = '{{{domain}}}';
|
||||||
var domainUrl = '{{{domainurl}}}';
|
var domainUrl = '{{{domainurl}}}';
|
||||||
|
|
@ -1642,6 +1647,7 @@
|
||||||
delete urlargs.viewmode;
|
delete urlargs.viewmode;
|
||||||
delete urlargs.gotonode;
|
delete urlargs.gotonode;
|
||||||
delete urlargs.gotodevicename;
|
delete urlargs.gotodevicename;
|
||||||
|
delete urlargs.gotodeviceip;
|
||||||
delete urlargs.gotomesh;
|
delete urlargs.gotomesh;
|
||||||
delete urlargs.gotouser;
|
delete urlargs.gotouser;
|
||||||
delete urlargs.gotougrp;
|
delete urlargs.gotougrp;
|
||||||
|
|
@ -1722,6 +1728,9 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show the modern ui switcher
|
||||||
|
QV('textnewui', ((features2 & 0x40000000) == 0) ? false : true);
|
||||||
|
|
||||||
// Connect to the mesh server
|
// Connect to the mesh server
|
||||||
meshserver = MeshServerCreateControl(domainUrl);
|
meshserver = MeshServerCreateControl(domainUrl);
|
||||||
meshserver.onStateChanged = onStateChanged;
|
meshserver.onStateChanged = onStateChanged;
|
||||||
|
|
@ -2182,6 +2191,24 @@
|
||||||
QV('body', true);
|
QV('body', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveUserInterfaceMode() {
|
||||||
|
var nUiViewMode = 2;
|
||||||
|
if (Q('ui1').checked) { nUiViewMode = 3; }
|
||||||
|
if (getstore('uiViewMode', 2) != nUiViewMode) {
|
||||||
|
putstore('uiViewMode', nUiViewMode);
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleBootstrapUIMode() {
|
||||||
|
if (xxdialogMode) return;
|
||||||
|
var uiViewMode = getstore('uiViewMode', 2);
|
||||||
|
var x = '<input type=radio id=ui0 name=uiradio value=2 ' + ((uiViewMode == 2)?'checked':'') + '><label for=ui0>' + "Classic" + '</label><br>';
|
||||||
|
x += '<input type=radio id=ui1 name=uiradio value=3 ' + ((uiViewMode == 3)?'checked':'') + '><label for=ui1>' + "Modern" + '</label><br>';
|
||||||
|
setDialogMode(2, "User Interface", 3, saveUserInterfaceMode, x);
|
||||||
|
QV('uiMenu', false);
|
||||||
|
}
|
||||||
|
|
||||||
function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
|
function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
|
||||||
function reload() {
|
function reload() {
|
||||||
var x = window.location.href;
|
var x = window.location.href;
|
||||||
|
|
@ -2420,15 +2447,28 @@
|
||||||
files.Stop();
|
files.Stop();
|
||||||
files = null;
|
files = null;
|
||||||
}
|
}
|
||||||
window.location.href = 'logout';
|
if (serverinfo.logoutonidlesessiontimeout) {
|
||||||
|
window.location.href = 'logout';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var ds = Math.round((serverinfo.timeout - delta) / 1000);
|
var ds = Math.round((serverinfo.timeout - delta) / 1000);
|
||||||
|
var sessionInProgress = desktop != null || terminal != null || files != null;
|
||||||
|
var show = serverinfo.logoutonidlesessiontimeout || sessionInProgress;
|
||||||
|
var isLogout = serverinfo.logoutonidlesessiontimeout;
|
||||||
|
var theText = ''; // Initialize theText
|
||||||
if (ds <= 60) {
|
if (ds <= 60) {
|
||||||
QH('idleTimeoutNotify', '<br />' + format((ds == 1)?"1 second until disconnect":"{0} seconds until disconnect", ds));
|
theText = isLogout
|
||||||
|
? (ds == 1 ? "1 second until logout" : "{0} seconds until logout")
|
||||||
|
: (ds == 1 ? "1 second until disconnect" : "{0} seconds until disconnect");
|
||||||
} else {
|
} else {
|
||||||
ds = Math.round(ds / 60);
|
ds = Math.round(ds / 60);
|
||||||
if (ds <= 5) { QH('idleTimeoutNotify', '<br />' + format((ds == 1)?"1 minute until disconnect":"{0} minutes until disconnect", ds)); }
|
if (ds <= 5) {
|
||||||
|
theText = isLogout
|
||||||
|
? (ds == 1 ? "1 minute until logout" : "{0} minutes until logout")
|
||||||
|
: (ds == 1 ? "1 minute until disconnect" : "{0} minutes until disconnect");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
QH('idleTimeoutNotify', show && theText ? '<br />' + format(theText, ds) : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2837,11 +2877,11 @@
|
||||||
if (net.name) { x += addHtmlValue2("Name", '<b>' + EscapeHtml(net.name) + '</b>'); }
|
if (net.name) { x += addHtmlValue2("Name", '<b>' + EscapeHtml(net.name) + '</b>'); }
|
||||||
if (net.desc) { x += addHtmlValue2("Description", EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
|
if (net.desc) { x += addHtmlValue2("Description", EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
|
||||||
if (net.dnssuffix) { x += addHtmlValue2("DNS suffix", EscapeHtml(net.dnssuffix) + ' <img src="images/link4.png" title="' + "Copy name to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.dnssuffix) + '") width=10 height=10>'); }
|
if (net.dnssuffix) { x += addHtmlValue2("DNS suffix", EscapeHtml(net.dnssuffix) + ' <img src="images/link4.png" title="' + "Copy name to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.dnssuffix) + '") width=10 height=10>'); }
|
||||||
if (net.mac) { x += addHtmlValue2("MAC address", '<a href="https://dnslytics.com/mac-address-lookup/' + net.mac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.mac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.mac.toLowerCase()) + '") width=10 height=10>'); }
|
if (net.mac) { x += addHtmlValue2("MAC address", '<a href="https://maclookup.app/search/result?mac=' + net.mac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.mac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.mac.toLowerCase()) + '") width=10 height=10>'); }
|
||||||
if (net.v4addr) { x += addHtmlValue2("IPv4 address", EscapeHtml(net.v4addr) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4addr) + '") width=10 height=10>'); }
|
if (net.v4addr) { x += addHtmlValue2("IPv4 address", EscapeHtml(net.v4addr) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4addr) + '") width=10 height=10>'); }
|
||||||
if (net.v4mask) { x += addHtmlValue2("IPv4 mask", EscapeHtml(net.v4mask) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4mask) + '") width=10 height=10>'); }
|
if (net.v4mask) { x += addHtmlValue2("IPv4 mask", EscapeHtml(net.v4mask) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4mask) + '") width=10 height=10>'); }
|
||||||
if (net.v4gateway) { x += addHtmlValue2("IPv4 gateway", EscapeHtml(net.v4gateway) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4gateway) + '") width=10 height=10>'); }
|
if (net.v4gateway) { x += addHtmlValue2("IPv4 gateway", EscapeHtml(net.v4gateway) + ' <img src="images/link4.png" title="' + "Copy address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4gateway) + '") width=10 height=10>'); }
|
||||||
if (net.gatewaymac) { x += addHtmlValue2("Gateway MAC", '<a href="https://dnslytics.com/mac-address-lookup/' + net.gatewaymac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.gatewaymac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.gatewaymac.toLowerCase()) + '") width=10 height=10>'); }
|
if (net.gatewaymac) { x += addHtmlValue2("Gateway MAC", '<a href="https://maclookup.app/search/result?mac=' + net.gatewaymac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.gatewaymac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net.gatewaymac.toLowerCase()) + '") width=10 height=10>'); }
|
||||||
}
|
}
|
||||||
} else if (message.netif2 != null) {
|
} else if (message.netif2 != null) {
|
||||||
// New style
|
// New style
|
||||||
|
|
@ -2850,7 +2890,7 @@
|
||||||
if ((Array.isArray(net) == false) || (net.length < 1) || (net[0] == null) || ((typeof net[0].mac == 'string') && (net[0].mac.startsWith('00:00:00:00')))) continue;
|
if ((Array.isArray(net) == false) || (net.length < 1) || (net[0] == null) || ((typeof net[0].mac == 'string') && (net[0].mac.startsWith('00:00:00:00')))) continue;
|
||||||
x += '<hr />'
|
x += '<hr />'
|
||||||
x += addHtmlValue2("Name", '<b>' + EscapeHtml(i) + '</b>');
|
x += addHtmlValue2("Name", '<b>' + EscapeHtml(i) + '</b>');
|
||||||
if (typeof net[0].mac == 'string') { x += addHtmlValue2("MAC address", '<a href="https://dnslytics.com/mac-address-lookup/' + net[0].mac.split(':').join('').substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net[0].mac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net[0].mac.toLowerCase()) + '") width=10 height=10>'); }
|
if (typeof net[0].mac == 'string') { x += addHtmlValue2("MAC address", '<a href="https://maclookup.app/search/result?mac=' + net[0].mac.split(':').join('').substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net[0].mac.toLowerCase()) + '</a> <img src="images/link4.png" title="' + "Copy MAC address to clipboard" + '" style="cursor:pointer" onclick=copyTextToClip2("' + encodeURIComponentEx(net[0].mac.toLowerCase()) + '") width=10 height=10>'); }
|
||||||
if (net[0].fqdn) { x += addHtmlValue2("FQDN", net[0].fqdn); }
|
if (net[0].fqdn) { x += addHtmlValue2("FQDN", net[0].fqdn); }
|
||||||
for (var j = 0; j < net.length; j++) {
|
for (var j = 0; j < net.length; j++) {
|
||||||
var netif = net[j];
|
var netif = net[j];
|
||||||
|
|
@ -2998,7 +3038,7 @@
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
Q('notesPanelArea').innerHTML = (message.notes && marked && DOMPurify) ? DOMPurify.sanitize(marked.parse(decodeURIComponent(message.notes), { breaks: true }), { USE_PROFILES: { html: true } }) : '';
|
Q('notesPanelArea').innerHTML = (message.notes && marked && DOMPurify) ? DOMPurify.sanitize(marked.parse(decodeURIComponent(message.notes), { breaks: true }), { USE_PROFILES: { html: true } }) : '';
|
||||||
if (showNotesPanel && message.notes) { QV('notesPanel',true); }else{ QV('notesPanel', false); }
|
if ((showNotesPanel === 'true') && message.notes) { QV('notesPanel',true); }else{ QV('notesPanel', false); }
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -3502,6 +3542,7 @@
|
||||||
// Change the node
|
// Change the node
|
||||||
node.name = message.event.node.name;
|
node.name = message.event.node.name;
|
||||||
node.rname = message.event.node.rname;
|
node.rname = message.event.node.rname;
|
||||||
|
node.lusers = message.event.node.lusers;
|
||||||
node.users = message.event.node.users;
|
node.users = message.event.node.users;
|
||||||
node.host = message.event.node.host;
|
node.host = message.event.node.host;
|
||||||
node.desc = message.event.node.desc;
|
node.desc = message.event.node.desc;
|
||||||
|
|
@ -4018,6 +4059,10 @@
|
||||||
var foundNode = null;
|
var foundNode = null;
|
||||||
if (nodes != null) { for (var i in nodes) { if (nodes[i].name == args.gotodevicename) { foundNode = nodes[i]._id; } } }
|
if (nodes != null) { for (var i in nodes) { if (nodes[i].name == args.gotodevicename) { foundNode = nodes[i]._id; } } }
|
||||||
if (foundNode) { gotoDevice(foundNode, xviewmode); goBackStack.push(1); }
|
if (foundNode) { gotoDevice(foundNode, xviewmode); goBackStack.push(1); }
|
||||||
|
} else if (args.gotodeviceip != null) {
|
||||||
|
var foundNode = null;
|
||||||
|
if (nodes != null) { for (var i in nodes) { if (nodes[i].ip == args.gotodeviceip) { foundNode = nodes[i]._id; } } }
|
||||||
|
if (foundNode) { gotoDevice(foundNode, xviewmode); goBackStack.push(1); }
|
||||||
} else if (args.gotomesh != null) {
|
} else if (args.gotomesh != null) {
|
||||||
if (meshes['mesh/' + domain + '/' + args.gotomesh] == null) return; // This device group is not loaded yet
|
if (meshes['mesh/' + domain + '/' + args.gotomesh] == null) return; // This device group is not loaded yet
|
||||||
gotoMesh('mesh/' + domain + '/' + args.gotomesh);
|
gotoMesh('mesh/' + domain + '/' + args.gotomesh);
|
||||||
|
|
@ -5395,7 +5440,7 @@
|
||||||
x += addHtmlValue("New Password*", '<input id=dp1password1 type=password style=width:230px autocomplete=off maxlength=32 onchange=validateAmtAcmSetupEx() onkeyup=validateAmtAcmSetupEx() />');
|
x += addHtmlValue("New Password*", '<input id=dp1password1 type=password style=width:230px autocomplete=off maxlength=32 onchange=validateAmtAcmSetupEx() onkeyup=validateAmtAcmSetupEx() />');
|
||||||
x += addHtmlValue("New Password*", '<input id=dp1password2 type=password style=width:230px autocomplete=off maxlength=32 onchange=validateAmtAcmSetupEx() onkeyup=validateAmtAcmSetupEx() />');
|
x += addHtmlValue("New Password*", '<input id=dp1password2 type=password style=width:230px autocomplete=off maxlength=32 onchange=validateAmtAcmSetupEx() onkeyup=validateAmtAcmSetupEx() />');
|
||||||
if ((features2 & 0x00000020) && (currentMesh.mtype == 1) && (serverinfo.amtProvServerMeshId == currentMesh._id)) { x += '<label><input id=dp1lanprov type=checkbox /> ' + "Use for bare-metal LAN activation." + '</label>'; } // Intel AMT LAN provisioning server is active.
|
if ((features2 & 0x00000020) && (currentMesh.mtype == 1) && (serverinfo.amtProvServerMeshId == currentMesh._id)) { x += '<label><input id=dp1lanprov type=checkbox /> ' + "Use for bare-metal LAN activation." + '</label>'; } // Intel AMT LAN provisioning server is active.
|
||||||
x += '<div><span id=dp10passNotify style="font-size:10px"> ' + "* 8 characters, 1 upper, 1 lower, 1 numeric, 1 non-alpha numeric." + '</span></div>';
|
x += '<div><span id=dp10passNotify style="font-size:10px"> ' + "* 8-16 characters, 1 upper, 1 lower, 1 numeric, 1 non-alpha numeric." + '</span></div>';
|
||||||
setDialogMode(2, "Intel® AMT ACM", 3, showAmtAcmSetupEx, x);
|
setDialogMode(2, "Intel® AMT ACM", 3, showAmtAcmSetupEx, x);
|
||||||
Q('dp1password0').focus();
|
Q('dp1password0').focus();
|
||||||
validateAmtAcmSetupEx();
|
validateAmtAcmSetupEx();
|
||||||
|
|
@ -6056,7 +6101,7 @@
|
||||||
meshserver.send({ action: 'getDeviceDetails', nodeids: chkNodeIds, tz: tz, tf: new Date().getTimezoneOffset(), l: getLang(), type: 'csv' }); // With details
|
meshserver.send({ action: 'getDeviceDetails', nodeids: chkNodeIds, tz: tz, tf: new Date().getTimezoneOffset(), l: getLang(), type: 'csv' }); // With details
|
||||||
} else {
|
} else {
|
||||||
// Without details
|
// Without details
|
||||||
var csv = "id,name,rname,host,icon,ip,osdesc,state,groupname,conn,pwr,av,update,firewall,bitlocker,avdetails,tags" + '\r\n', r = [];
|
var csv = "id,name,rname,host,icon,ip,osdesc,state,groupname,conn,pwr,av,update,firewall,bitlocker,avdetails,tags,lastbootuptime" + '\r\n', r = [];
|
||||||
for (var i in chkNodeIds) {
|
for (var i in chkNodeIds) {
|
||||||
var n = getNodeFromId(chkNodeIds[i]);
|
var n = getNodeFromId(chkNodeIds[i]);
|
||||||
csv += '"' + n._id.split(',').join('') + '","' + n.name.split(',').join('') + '","' + (n.rname?(n.rname.split(',').join('')):'') + '","' + (n.host?(n.host.split(',').join('')):'') + '","' + n.icon + '","' + (n.ip?n.ip:'') + '","' + (n.osdesc?(n.osdesc.split(',').join('')):'') + '","' + n.state + '","' + meshes[n.meshid].name.split(',').join('') + '","' + (n.conn?n.conn:'') + '","' + (n.pwr?n.pwr:'') + '"';
|
csv += '"' + n._id.split(',').join('') + '","' + n.name.split(',').join('') + '","' + (n.rname?(n.rname.split(',').join('')):'') + '","' + (n.host?(n.host.split(',').join('')):'') + '","' + n.icon + '","' + (n.ip?n.ip:'') + '","' + (n.osdesc?(n.osdesc.split(',').join('')):'') + '","' + n.state + '","' + meshes[n.meshid].name.split(',').join('') + '","' + (n.conn?n.conn:'') + '","' + (n.pwr?n.pwr:'') + '"';
|
||||||
|
|
@ -6082,6 +6127,7 @@
|
||||||
else {
|
else {
|
||||||
csv += ',';
|
csv += ',';
|
||||||
}
|
}
|
||||||
|
if (typeof n.lastbootuptime == 'number') { csv += ',"' + n.lastbootuptime + '"'; }
|
||||||
csv += '\r\n';
|
csv += '\r\n';
|
||||||
}
|
}
|
||||||
saveAs(stringToUtf8Blob(csv), "devicelist.csv");
|
saveAs(stringToUtf8Blob(csv), "devicelist.csv");
|
||||||
|
|
@ -7616,7 +7662,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Active Users
|
// Active Users
|
||||||
if (node.users && (node.users.length > 0)) { x += addDeviceAttribute(((node.users.length > 1)?"Active Users":"Active User"), EscapeHtml(node.users.join(', '))); }
|
if (node.users && node.users.length > 0) {
|
||||||
|
var u = node.users.map(function(user) {
|
||||||
|
return addKeyLinkConditional(EscapeHtml(user), "Locked", (node.lusers && node.lusers.indexOf(user) >= 0));
|
||||||
|
}).join(', ');
|
||||||
|
x += addDeviceAttribute((node.users.length > 1 ? "Active Users" : "Active User"), u);
|
||||||
|
}
|
||||||
|
|
||||||
// Display device user consent
|
// Display device user consent
|
||||||
if ((node.agent != null) && (node.agent.id != 14) && (node.mtype != 3)) {
|
if ((node.agent != null) && (node.agent.id != 14) && (node.mtype != 3)) {
|
||||||
|
|
@ -8203,7 +8254,7 @@
|
||||||
if (noteid == null) { noteid = encodeURIComponentEx('p'+userinfo._id); }
|
if (noteid == null) { noteid = encodeURIComponentEx('p'+userinfo._id); }
|
||||||
var x = '<textarea id=d2devNotes ro=' + readonly + ' noteid=' + noteid + ' readonly style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea>';
|
var x = '<textarea id=d2devNotes ro=' + readonly + ' noteid=' + noteid + ' readonly style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll></textarea>';
|
||||||
if (noteid.startsWith('node%2F%2F')) { x += ' <span style=font-size:10px>' + "Device group notes can be viewed and changed by other device group administrators." + '</span>'; }
|
if (noteid.startsWith('node%2F%2F')) { x += ' <span style=font-size:10px>' + "Device group notes can be viewed and changed by other device group administrators." + '</span>'; }
|
||||||
if (showNotesPanel) { x += ' <span style=font-size:10px><a target=_blank href=\'https://www.markdownguide.org/cheat-sheet/\'>' + "Markdown syntax supported" + '</a></span>'; }
|
if (showNotesPanel === 'true') { x += ' <span style=font-size:10px><a target=_blank href=\'https://www.markdownguide.org/cheat-sheet/\'>' + "Markdown syntax supported" + '</a></span>'; }
|
||||||
setDialogMode(2, "Notes", 3, showNotesEx, x, noteid);
|
setDialogMode(2, "Notes", 3, showNotesEx, x, noteid);
|
||||||
meshserver.send({ action: 'getNotes', id: decodeURIComponent(noteid) });
|
meshserver.send({ action: 'getNotes', id: decodeURIComponent(noteid) });
|
||||||
}
|
}
|
||||||
|
|
@ -8211,7 +8262,7 @@
|
||||||
function showNotesEx(buttons, tag) {
|
function showNotesEx(buttons, tag) {
|
||||||
Q('notesPanelArea').innerHTML = (marked && DOMPurify) ? DOMPurify.sanitize(marked.parse(Q('d2devNotes').value, { breaks: true }), { USE_PROFILES: { html: true } }) : Q('d2devNotes').value;
|
Q('notesPanelArea').innerHTML = (marked && DOMPurify) ? DOMPurify.sanitize(marked.parse(Q('d2devNotes').value, { breaks: true }), { USE_PROFILES: { html: true } }) : Q('d2devNotes').value;
|
||||||
meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponentEx(Q('d2devNotes').value) });
|
meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponentEx(Q('d2devNotes').value) });
|
||||||
if (showNotesPanel && Q('d2devNotes').value != '') { QV('notesPanel',true); }else{ QV('notesPanel', false); }
|
if ((showNotesPanel === 'true') && Q('d2devNotes').value != '') { QV('notesPanel',true); }else{ QV('notesPanel', false); }
|
||||||
}
|
}
|
||||||
|
|
||||||
function openIpKvmRemoteControl(nodeid) {
|
function openIpKvmRemoteControl(nodeid) {
|
||||||
|
|
@ -8632,7 +8683,7 @@
|
||||||
|
|
||||||
// Draw device power bars. The bars are 766px wide.
|
// Draw device power bars. The bars are 766px wide.
|
||||||
function drawDeviceTimeline() {
|
function drawDeviceTimeline() {
|
||||||
if ((currentNode == null) || (xxcurrentView < 10) || (xxcurrentView > 19) || (currentNode.mtype == 3) || (hidePowerTimeline)) return;
|
if ((currentNode == null) || (xxcurrentView < 10) || (xxcurrentView > 19) || (currentNode.mtype == 3) || (hidePowerTimeline === 'true')) return;
|
||||||
var timeline = null, now = Date.now();
|
var timeline = null, now = Date.now();
|
||||||
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
|
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
|
||||||
|
|
||||||
|
|
@ -11316,7 +11367,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function p13openfilefolder() {
|
function p13openfilefolder() {
|
||||||
setDialogMode(2, "Open File/Folder", 3, p13openfilefolderEx, "Are you sure you want to open this file/folder on the remote devices desktop ?");
|
setDialogMode(2, "Open File/Folder", 3, p13openfilefolderEx, "Are you sure you want to open this file/folder on the remote devices desktop?");
|
||||||
}
|
}
|
||||||
function p13openfilefolderEx() {
|
function p13openfilefolderEx() {
|
||||||
var openfilefolder = "", checkboxes = document.getElementsByName('fd');
|
var openfilefolder = "", checkboxes = document.getElementsByName('fd');
|
||||||
|
|
@ -12693,7 +12744,19 @@
|
||||||
if (e.shiftKey == true) { meshserver.send({ action: 'uploadagentcore', nodeids: [ consoleNode._id ], type: 'default' }); } // Upload default core
|
if (e.shiftKey == true) { meshserver.send({ action: 'uploadagentcore', nodeids: [ consoleNode._id ], type: 'default' }); } // Upload default core
|
||||||
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeids: [ consoleNode._id ], type: 'clear' }); } // Clear the core
|
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeids: [ consoleNode._id ], type: 'clear' }); } // Clear the core
|
||||||
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
|
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
|
||||||
else { setDialogMode(2, "Perform Agent Action", 3, p15uploadCoreEx, addHtmlValue("Action", '<select id=d3coreMode style=width:230px><option value=1>' + "Upload default server core" + '</option><option value=2>' + "Clear the core" + '</option><option value=6>' + "Upload recovery core" + '</option><option value=7>' + "Upload tiny core" + '</option><option value=3>' + "Upload a core file" + '</option><option value=4>' + "Soft disconnect agent" + '</option><option value=5>' + "Hard disconnect agent" + '</option><option value=8>' + "Restart agent service" + '</select>')); }
|
else {
|
||||||
|
var htmlValue = '<select id=d3coreMode style=width:230px>' +
|
||||||
|
'<option value=1>' + "Upload default server core" + '</option>' +
|
||||||
|
'<option value=2>' + "Clear the core" + '</option>' +
|
||||||
|
'<option value=3>' + "Upload a core file" + '</option>' +
|
||||||
|
'<option value=4>' + "Soft disconnect agent" + '</option>' +
|
||||||
|
'<option value=5>' + "Hard disconnect agent" + '</option>' +
|
||||||
|
'<option value=6>' + "Upload recovery core" + '</option>' +
|
||||||
|
'<option value=7>' + "Upload tiny core" + '</option>' +
|
||||||
|
'<option value=8>' + "Restart agent service" + '</option>' +
|
||||||
|
'<option value=9>' + "Force agent update" + '</option></select>';
|
||||||
|
setDialogMode(2, "Perform Agent Action", 3, p15uploadCoreEx, addHtmlValue("Action", htmlValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function p15uploadCoreEx() {
|
function p15uploadCoreEx() {
|
||||||
|
|
@ -12721,6 +12784,9 @@
|
||||||
} else if (Q('d3coreMode').value == 8) {
|
} else if (Q('d3coreMode').value == 8) {
|
||||||
// Restart MeshAgent service
|
// Restart MeshAgent service
|
||||||
meshserver.send({ action: 'msg', type: 'console', nodeid: consoleNode._id, value:'service restart' });
|
meshserver.send({ action: 'msg', type: 'console', nodeid: consoleNode._id, value:'service restart' });
|
||||||
|
} else if (Q('d3coreMode').value == 9) {
|
||||||
|
// Update mesh agent
|
||||||
|
meshserver.send({ action: 'updateAgents', nodeids: [ consoleNode._id ] });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -13839,7 +13905,7 @@
|
||||||
x += addHtmlValue("Unknown password", '<select id=dp20amtbadpass style=width:230px><option value=0>' + "Do nothing" + '</option><option value=1>' + "If in CCM, reactivate Intel® AMT" + '</option></select>');
|
x += addHtmlValue("Unknown password", '<select id=dp20amtbadpass style=width:230px><option value=0>' + "Do nothing" + '</option><option value=1>' + "If in CCM, reactivate Intel® AMT" + '</option></select>');
|
||||||
x += '</div>';
|
x += '</div>';
|
||||||
if ((features & 0x400) == 0) { x += addHtmlValue('<span title="' + "Client Initiated Remote Access" + '">' + "CIRA setup" + '</span>', '<select id=dp20amtcira style=width:230px><option value=0>' + "Do nothing" + '</option><option value=1>' + "Don't connect to server" + '</option><option value=2>' + "Connect to server" + '</option></select>'); }
|
if ((features & 0x400) == 0) { x += addHtmlValue('<span title="' + "Client Initiated Remote Access" + '">' + "CIRA setup" + '</span>', '<select id=dp20amtcira style=width:230px><option value=0>' + "Do nothing" + '</option><option value=1>' + "Don't connect to server" + '</option><option value=2>' + "Connect to server" + '</option></select>'); }
|
||||||
x += '<span id=dp10passNotify style="font-size:10px"> ' + "* 8 characters, 1 upper, 1 lower, 1 numeric, 1 non-alpha numeric." + '</span>';
|
x += '<span id=dp10passNotify style="font-size:10px"> ' + "* 8-16 characters, 1 upper, 1 lower, 1 numeric, 1 non-alpha numeric." + '</span>';
|
||||||
if ((currentMesh.mtype == 2) && (ptype == 2)) { x += '<span style="font-size:10px"> ' + "This policy will not impact devices with Intel® AMT in ACM mode." + '</span>'; }
|
if ((currentMesh.mtype == 2) && (ptype == 2)) { x += '<span style="font-size:10px"> ' + "This policy will not impact devices with Intel® AMT in ACM mode." + '</span>'; }
|
||||||
}
|
}
|
||||||
if (ptype == 0) { x = '<table style=padding-top:4px><tr><td><img style=padding-right:8px src=images/rcheckbox60.png width=60 height=60><td>' + "When this policy is selected, Intel® AMT is not managed by this server. Intel AMT can still be used by manually activating and configuring it." + '</table>'; }
|
if (ptype == 0) { x = '<table style=padding-top:4px><tr><td><img style=padding-right:8px src=images/rcheckbox60.png width=60 height=60><td>' + "When this policy is selected, Intel® AMT is not managed by this server. Intel AMT can still be used by manually activating and configuring it." + '</table>'; }
|
||||||
|
|
@ -15867,7 +15933,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function p4downloadUserInfoCSV() {
|
function p4downloadUserInfoCSV() {
|
||||||
var csv = "id, name, email, creation, lastlogin, groups, authfactors, siteadmin, useradmin, locked" + '\r\n';
|
var csv = "id,name,email,creation,lastlogin,groups,authfactors,siteadmin,useradmin,locked" + '\r\n';
|
||||||
for (var i in users) {
|
for (var i in users) {
|
||||||
var multiFactor = false, factors = [];
|
var multiFactor = false, factors = [];
|
||||||
if ((users[i].otpsecret > 0) || (users[i].otphkeys > 0)) {
|
if ((users[i].otpsecret > 0) || (users[i].otphkeys > 0)) {
|
||||||
|
|
@ -19161,7 +19227,7 @@
|
||||||
function addLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=\'' + f + '\' onkeypress="if (event.key==\'Enter\') {' + f + '} ">' + x + ' <img class=hoverButton src=images/link5.png></span>'; }
|
function addLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=\'' + f + '\' onkeypress="if (event.key==\'Enter\') {' + f + '} ">' + x + ' <img class=hoverButton src=images/link5.png></span>'; }
|
||||||
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
|
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
|
||||||
function addKeyLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=' + f + ' onkeypress="if (event.key==\'Enter\') { ' + f + ' } ">' + x + ' <img class=hoverButton src=images/key16.png></span>'; }
|
function addKeyLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=' + f + ' onkeypress="if (event.key==\'Enter\') { ' + f + ' } ">' + x + ' <img class=hoverButton src=images/key16.png></span>'; }
|
||||||
function addKeyLinkConditional(x, f, c) { if (c) return addKeyLink(x, f); return x; }
|
function addKeyLinkConditional(x, t, c) { if (c) return '<span title=\'' + t + '\'>' + x + ' <img class=hoverButton src=images/key16.png></span>'; return x }
|
||||||
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||||
function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
|
function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
|
||||||
function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
||||||
|
|
@ -19271,4 +19337,4 @@
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,9 @@
|
||||||
<img id="topMenuIcon" class=noselect
|
<img id="topMenuIcon" class=noselect
|
||||||
style="position:absolute;right:0;top:10px;color:#c8c8c8;font-size:44px;margin-right:8px;cursor:pointer;display:none"
|
style="position:absolute;right:0;top:10px;color:#c8c8c8;font-size:44px;margin-right:8px;cursor:pointer;display:none"
|
||||||
onclick=topMenu() src="/images/3bars-30.png" width=30 height=30 />
|
onclick=topMenu() src="/images/3bars-30.png" width=30 height=30 />
|
||||||
|
<div class=textnewui id=textnewui onmouseup=toggleBootstrapUIMode() onkeypress="if (event.key=='Enter') { toggleBootstrapUIMode(); }">
|
||||||
|
<b>Try the new MeshCentral UI</b>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar flex-column" id="page_leftbar">
|
<div class="sidebar flex-column" id="page_leftbar">
|
||||||
<div style="height:24px"></div>
|
<div style="height:24px"></div>
|
||||||
|
|
@ -190,6 +193,11 @@
|
||||||
onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(3)">
|
onkeypress="if (event.key == 'Enter') userInterfaceSelectMenu(3)">
|
||||||
<div class="uiSelector3"></div>
|
<div class="uiSelector3"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div tabindex=0 id=uiViewButton7 class=uiSelector
|
||||||
|
onclick=toggleBootstrapUIMode() title="Toggle Modern UI"
|
||||||
|
onkeypress="if (event.key == 'Enter') toggleBootstrapUIMode()">
|
||||||
|
<div class="uiSelector7"></div>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div tabindex=0 id=uiViewButton6 class=uiSelector onclick="showNotes(false)"
|
<div tabindex=0 id=uiViewButton6 class=uiSelector onclick="showNotes(false)"
|
||||||
|
|
@ -207,6 +215,7 @@
|
||||||
onkeypress="if (event.key == 'Enter') toggleFooterBarMode()">
|
onkeypress="if (event.key == 'Enter') toggleFooterBarMode()">
|
||||||
<div class="uiSelector5"></div>
|
<div class="uiSelector5"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class=uiSelector_end> </div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -612,23 +621,23 @@
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<label for="p3filterevents" class="me-1">Filter</label>
|
<label for="p3filterevents" class="me-1">Filter</label>
|
||||||
<select id=p3filterevents class="form-select-sm me-2" onchange=refreshEvents()>
|
<select id=p3filterevents class="form-select-sm me-2" onchange=refreshEvents()>
|
||||||
<option value="">All Logs</option>
|
<option notransval=1 value="">All Logs</option>
|
||||||
<option value=agentlog>Agent Logs</option>
|
<option notransval=1 value=agentlog>Agent Logs</option>
|
||||||
<option value=relaylog>Relay Logs</option>
|
<option notransval=1 value=relaylog>Relay Logs</option>
|
||||||
<option value=manual>Manual Logs</option>
|
<option notransval=1 value=manual>Manual Logs</option>
|
||||||
<option value=runcommands>Run Command Logs</option>
|
<option notransval=1 value=runcommands>Run Command Logs</option>
|
||||||
<option value=batchupload>Batch Upload Logs</option>
|
<option notransval=1 value=batchupload>Batch Upload Logs</option>
|
||||||
<option value=changenode>Change Node Logs</option>
|
<option notransval=1 value=changenode>Change Node Logs</option>
|
||||||
<option value=removenode>Remove Node Logs</option>
|
<option notransval=1 value=removenode>Remove Node Logs</option>
|
||||||
</select>
|
</select>
|
||||||
<label for="p3limitdropdown" class="me-1">Show</label>
|
<label for="p3limitdropdown" class="me-1">Show</label>
|
||||||
<select id=p3limitdropdown class="form-select-sm me-2" onchange=refreshEvents()>
|
<select id=p3limitdropdown class="form-select-sm me-2" onchange=refreshEvents()>
|
||||||
<option value=60>Last 60</option>
|
<option notransval=1 value=60>Last 60</option>
|
||||||
<option value=120>Last 120</option>
|
<option notransval=1 value=120>Last 120</option>
|
||||||
<option value=250>Last 250</option>
|
<option notransval=1 value=250>Last 250</option>
|
||||||
<option value=500>Last 500</option>
|
<option notransval=1 value=500>Last 500</option>
|
||||||
<option value=1000>Last 1000</option>
|
<option notransval=1 value=1000>Last 1000</option>
|
||||||
<option value="">No limit</option>
|
<option notransval=1 value="">No limit</option>
|
||||||
</select>
|
</select>
|
||||||
<a href=# onclick=p3showDownloadEventsDialog(2)><i class="fa-solid fa-download" title="Download Events"></i></a>
|
<a href=# onclick=p3showDownloadEventsDialog(2)><i class="fa-solid fa-download" title="Download Events"></i></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1334,22 +1343,22 @@
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<label class="me-1" for="p16filterevents">Filter</label>
|
<label class="me-1" for="p16filterevents">Filter</label>
|
||||||
<select id=p16filterevents class="form-control-sm me-2" onchange=refreshDeviceEvents()>
|
<select id=p16filterevents class="form-control-sm me-2" onchange=refreshDeviceEvents()>
|
||||||
<option value="">All Logs</option>
|
<option notransval=1 value="">All Logs</option>
|
||||||
<option value=agentlog>Agent Logs</option>
|
<option notransval=1 value=agentlog>Agent Logs</option>
|
||||||
<option value=relaylog>Relay Logs</option>
|
<option notransval=1 value=relaylog>Relay Logs</option>
|
||||||
<option value=manual>Manual Logs</option>
|
<option notransval=1 value=manual>Manual Logs</option>
|
||||||
<option value=runcommands>Run Command Logs</option>
|
<option notransval=1 value=runcommands>Run Command Logs</option>
|
||||||
<option value=batchupload>Batch Upload Logs</option>
|
<option notransval=1 value=batchupload>Batch Upload Logs</option>
|
||||||
<option value=changenode>Change Node Logs</option>
|
<option notransval=1 value=changenode>Change Node Logs</option>
|
||||||
<option value=removenode>Remove Node Logs</option>
|
<option notransval=1 value=removenode>Remove Node Logs</option>
|
||||||
</select>
|
</select>
|
||||||
<label class="me-1" for="p16limitdropdown">Show</label>
|
<label class="me-1" for="p16limitdropdown">Show</label>
|
||||||
<select id=p16limitdropdown class="form-control-sm me-2" onchange=refreshDeviceEvents()>
|
<select id=p16limitdropdown class="form-control-sm me-2" onchange=refreshDeviceEvents()>
|
||||||
<option value=60>Last 60</option>
|
<option notransval=1 value=60>Last 60</option>
|
||||||
<option value=120>Last 120</option>
|
<option notransval=1 value=120>Last 120</option>
|
||||||
<option value=250>Last 250</option>
|
<option notransval=1 value=250>Last 250</option>
|
||||||
<option value=500>Last 500</option>
|
<option notransval=1 value=500>Last 500</option>
|
||||||
<option value=1000>Last 1000</option>
|
<option notransval=1 value=1000>Last 1000</option>
|
||||||
</select>
|
</select>
|
||||||
<i onclick=p3showDownloadEventsDialog(1) class="fa-solid fa-download" title="Download Events" style=cursor:pointer></i>
|
<i onclick=p3showDownloadEventsDialog(1) class="fa-solid fa-download" title="Download Events" style=cursor:pointer></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1498,23 +1507,23 @@
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<label for="p31filterevents" class="me-1">Filter</label>
|
<label for="p31filterevents" class="me-1">Filter</label>
|
||||||
<select id=p31filterevents class="form-select-sm me-2" onchange=refreshUsersEvents()>
|
<select id=p31filterevents class="form-select-sm me-2" onchange=refreshUsersEvents()>
|
||||||
<option value="">All Logs</option>
|
<option notransval=1 value="">All Logs</option>
|
||||||
<option value=agentlog>Agent Logs</option>
|
<option notransval=1 value=agentlog>Agent Logs</option>
|
||||||
<option value=relaylog>Relay Logs</option>
|
<option notransval=1 value=relaylog>Relay Logs</option>
|
||||||
<option value=manual>Manual Logs</option>
|
<option notransval=1 value=manual>Manual Logs</option>
|
||||||
<option value=runcommands>Run Command Logs</option>
|
<option notransval=1 value=runcommands>Run Command Logs</option>
|
||||||
<option value=batchupload>Batch Upload Logs</option>
|
<option notransval=1 value=batchupload>Batch Upload Logs</option>
|
||||||
<option value=changenode>Change Node Logs</option>
|
<option notransval=1 value=changenode>Change Node Logs</option>
|
||||||
<option value=removenode>Remove Node Logs</option>
|
<option notransval=1 value=removenode>Remove Node Logs</option>
|
||||||
</select>
|
</select>
|
||||||
<label for="p31limitdropdown" class="me-1">Show</label>
|
<label for="p31limitdropdown" class="me-1">Show</label>
|
||||||
<select id=p31limitdropdown class="form-select-sm me-2" onchange=refreshUsersEvents()>
|
<select id=p31limitdropdown class="form-select-sm me-2" onchange=refreshUsersEvents()>
|
||||||
<option value=60>Last 60</option>
|
<option notransval=1 value=60>Last 60</option>
|
||||||
<option value=120>Last 120</option>
|
<option notransval=1 value=120>Last 120</option>
|
||||||
<option value=250>Last 250</option>
|
<option notransval=1 value=250>Last 250</option>
|
||||||
<option value=500>Last 500</option>
|
<option notransval=1 value=500>Last 500</option>
|
||||||
<option value=1000>Last 1000</option>
|
<option notransval=1 value=1000>Last 1000</option>
|
||||||
<option value="">No limit</option>
|
<option notransval=1 value="">No limit</option>
|
||||||
</select>
|
</select>
|
||||||
<a href=# onclick=p3showDownloadEventsDialog(3)><i class="fa-solid fa-download" role="button" title="Download Events"></i></a>
|
<a href=# onclick=p3showDownloadEventsDialog(3)><i class="fa-solid fa-download" role="button" title="Download Events"></i></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1531,7 +1540,7 @@
|
||||||
<div class="areaHead d-flex align-items-center flex-wrap p-1">
|
<div class="areaHead d-flex align-items-center flex-wrap p-1">
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
<input value="Refresh" type="button" class="btn btn-primary btn-sm me-2" onclick="refreshServerTimelineStats()" />
|
<input value="Refresh" type="button" class="btn btn-primary btn-sm me-2" onclick="refreshServerTimelineStats()" />
|
||||||
<div class="form-check"><input class="form-check-input me-1" type=checkbox id=p40log onclick="updateServerTimelineHours()" / /><label class="form-check-label" for="p40log">Log-X</label></div>
|
<div class="form-check"><input class="form-check-input me-1" type=checkbox id=p40log onclick="updateServerTimelineHours()" /><label class="form-check-label" for="p40log">Log-X</label></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="toright2 d-flex align-items-center ms-auto">
|
<div class="toright2 d-flex align-items-center ms-auto">
|
||||||
<select id=p40server style="display:none" onchange=updateServerTimelineStats()></select>
|
<select id=p40server style="display:none" onchange=updateServerTimelineStats()></select>
|
||||||
|
|
@ -1848,16 +1857,16 @@
|
||||||
<div style="margin-top:8px">
|
<div style="margin-top:8px">
|
||||||
<div>Display Size</div>
|
<div>Display Size</div>
|
||||||
<select id="d7rdpsize">
|
<select id="d7rdpsize">
|
||||||
<option value="canvas">Canvas Size</option>
|
<option notransval=1 value="canvas">Canvas Size</option>
|
||||||
<option value="browser">Browser Size</option>
|
<option notransval=1 value="browser">Browser Size</option>
|
||||||
<option value="screen">Screen Size</option>
|
<option notransval=1 value="screen">Screen Size</option>
|
||||||
<option value="640x480">640x480</option>
|
<option notransval=1 value="640x480">640x480</option>
|
||||||
<option value="1024x768">1024x768</option>
|
<option notransval=1 value="1024x768">1024x768</option>
|
||||||
<option value="1280x800">1280x800</option>
|
<option notransval=1 value="1280x800">1280x800</option>
|
||||||
<option value="1440x900">1440x900</option>
|
<option notransval=1 value="1440x900">1440x900</option>
|
||||||
<option value="1600x900">1600x900</option>
|
<option notransval=1 value="1600x900">1600x900</option>
|
||||||
<option value="1680x1050">1680x1050</option>
|
<option notransval=1 value="1680x1050">1680x1050</option>
|
||||||
<option value="1920x1080">1920x1080</option>
|
<option notransval=1 value="1920x1080">1920x1080</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -1869,7 +1878,7 @@
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp4" />Disable Theming</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp4" />Disable Theming</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp6" />Disable Cursor Shadow</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp6" />Disable Cursor Shadow</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp7" />Disable Cursor Settings</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp7" />Disable Cursor Settings</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp8" />Enable Font Smooting</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp8" />Enable Font Smoothing</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdp9" />Enable Desktop Composision</label>
|
<label style="display:block"><input type="checkbox" id="d7rdp9" />Enable Desktop Composision</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdpclip" />Automatic Clipboard</label>
|
<label style="display:block"><input type="checkbox" id="d7rdpclip" />Automatic Clipboard</label>
|
||||||
<label style="display:block"><input type="checkbox" id="d7rdpsmb" />Swap Mouse Buttons</label>
|
<label style="display:block"><input type="checkbox" id="d7rdpsmb" />Swap Mouse Buttons</label>
|
||||||
|
|
@ -1971,8 +1980,8 @@
|
||||||
var sessionTime = parseInt('{{{sessiontime}}}');
|
var sessionTime = parseInt('{{{sessiontime}}}');
|
||||||
var webRelayPort = parseInt('{{{webRelayPort}}}');
|
var webRelayPort = parseInt('{{{webRelayPort}}}');
|
||||||
var webRelayDns = '{{{webRelayDns}}}';
|
var webRelayDns = '{{{webRelayDns}}}';
|
||||||
var hidePowerTimeline = {{{ hidePowerTimeline }}};
|
var hidePowerTimeline = '{{{hidePowerTimeline}}}';
|
||||||
var showNotesPanel = {{{ showNotesPanel }}};
|
var showNotesPanel = '{{{showNotesPanel}}}';
|
||||||
var sessionRefreshTimer = null;
|
var sessionRefreshTimer = null;
|
||||||
var domain = '{{{domain}}}';
|
var domain = '{{{domain}}}';
|
||||||
var domainUrl = '{{{domainurl}}}';
|
var domainUrl = '{{{domainurl}}}';
|
||||||
|
|
@ -2001,7 +2010,7 @@
|
||||||
var footerBar = (getstore('footerBar', '1') == '1');
|
var footerBar = (getstore('footerBar', '1') == '1');
|
||||||
var sessionActivity = Date.now();
|
var sessionActivity = Date.now();
|
||||||
var updateSessionTimer = null;
|
var updateSessionTimer = null;
|
||||||
var pluginHandlerBuilder = {{{ pluginHandler }}};
|
var pluginHandlerBuilder = {{{pluginHandler}}};
|
||||||
var pluginHandler = null;
|
var pluginHandler = null;
|
||||||
if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
|
if (pluginHandlerBuilder != null) { pluginHandler = new pluginHandlerBuilder(); }
|
||||||
var installedPluginList = null;
|
var installedPluginList = null;
|
||||||
|
|
@ -2065,6 +2074,7 @@
|
||||||
delete urlargs.viewmode;
|
delete urlargs.viewmode;
|
||||||
delete urlargs.gotonode;
|
delete urlargs.gotonode;
|
||||||
delete urlargs.gotodevicename;
|
delete urlargs.gotodevicename;
|
||||||
|
delete urlargs.gotodeviceip;
|
||||||
delete urlargs.gotomesh;
|
delete urlargs.gotomesh;
|
||||||
delete urlargs.gotouser;
|
delete urlargs.gotouser;
|
||||||
delete urlargs.gotougrp;
|
delete urlargs.gotougrp;
|
||||||
|
|
@ -2148,6 +2158,9 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show the modern ui switcher
|
||||||
|
QV('textnewui', ((features2 & 0x40000000) == 0) ? false : true);
|
||||||
|
|
||||||
// Connect to the mesh server
|
// Connect to the mesh server
|
||||||
meshserver = MeshServerCreateControl(domainUrl);
|
meshserver = MeshServerCreateControl(domainUrl);
|
||||||
meshserver.onStateChanged = onStateChanged;
|
meshserver.onStateChanged = onStateChanged;
|
||||||
|
|
@ -2621,6 +2634,31 @@
|
||||||
QV('body', true);
|
QV('body', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveUserInterfaceMode() {
|
||||||
|
var nUiViewMode = 3;
|
||||||
|
if (Q('ui0').checked) { nUiViewMode = 2; }
|
||||||
|
if (getstore('uiViewMode', 3) != nUiViewMode) {
|
||||||
|
putstore('uiViewMode', nUiViewMode);
|
||||||
|
// Check if the URL includes 'sitestyle=' and remove it
|
||||||
|
var url = new URL(window.location.href);
|
||||||
|
if (url.searchParams.has('sitestyle')) {
|
||||||
|
url.searchParams.delete('sitestyle');
|
||||||
|
window.history.replaceState({}, document.title, url.toString());
|
||||||
|
}
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleBootstrapUIMode() {
|
||||||
|
if (xxdialogMode) return;
|
||||||
|
var uiViewMode = getstore('uiViewMode', 3);
|
||||||
|
var x = '<div class=form-check><input type=radio class=form-check-input id=ui0 name=uiradio value=2 ' + ((uiViewMode == 2)?'checked':'') + '><label class=form-check-label for=ui0>' + "Classic" + '</label></div>';
|
||||||
|
x += '<div class=form-check><input type=radio class=form-check-input id=ui1 name=uiradio value=3 ' + ((uiViewMode == 3)?'checked':'') + '><label class=form-check-label for=ui1>' + "Modern" + '</label></div>';
|
||||||
|
setModalContent('xxAddAgent', "User Interface", x);
|
||||||
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', saveUserInterfaceMode);
|
||||||
|
QV('uiMenu', false);
|
||||||
|
}
|
||||||
|
|
||||||
function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
|
function getNodeFromId(id) { if (nodes != null) { for (var i in nodes) { if (nodes[i]._id == id) return nodes[i]; } } return null; }
|
||||||
function reload() {
|
function reload() {
|
||||||
var x = window.location.href;
|
var x = window.location.href;
|
||||||
|
|
@ -2859,15 +2897,28 @@
|
||||||
files.Stop();
|
files.Stop();
|
||||||
files = null;
|
files = null;
|
||||||
}
|
}
|
||||||
window.location.href = 'logout';
|
if (serverinfo.logoutonidlesessiontimeout) {
|
||||||
|
window.location.href = 'logout';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var ds = Math.round((serverinfo.timeout - delta) / 1000);
|
var ds = Math.round((serverinfo.timeout - delta) / 1000);
|
||||||
|
var sessionInProgress = (desktop != null || terminal != null || files != null);
|
||||||
|
var show = serverinfo.logoutonidlesessiontimeout || sessionInProgress;
|
||||||
|
var isLogout = serverinfo.logoutonidlesessiontimeout;
|
||||||
|
var theText = '';
|
||||||
if (ds <= 60) {
|
if (ds <= 60) {
|
||||||
QH('idleTimeoutNotify', '<br />' + format((ds == 1) ? "1 second until disconnect" : "{0} seconds until disconnect", ds));
|
theText = isLogout
|
||||||
|
? (ds == 1 ? "1 second until logout" : "{0} seconds until logout")
|
||||||
|
: (ds == 1 ? "1 second until disconnect" : "{0} seconds until disconnect");
|
||||||
} else {
|
} else {
|
||||||
ds = Math.round(ds / 60);
|
ds = Math.round(ds / 60);
|
||||||
if (ds <= 5) { QH('idleTimeoutNotify', '<br />' + format((ds == 1) ? "1 minute until disconnect" : "{0} minutes until disconnect", ds)); }
|
if (ds <= 5) {
|
||||||
|
theText = isLogout
|
||||||
|
? (ds == 1 ? "1 minute until logout" : "{0} minutes until logout")
|
||||||
|
: (ds == 1 ? "1 minute until disconnect" : "{0} minutes until disconnect");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
QH('idleTimeoutNotify', show && theText ? '<br />' + format(theText, ds) : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3276,11 +3327,11 @@
|
||||||
if (net.name) { x += addHtmlValue2("Name", '<b>' + EscapeHtml(net.name) + '</b>'); }
|
if (net.name) { x += addHtmlValue2("Name", '<b>' + EscapeHtml(net.name) + '</b>'); }
|
||||||
if (net.desc) { x += addHtmlValue2("Description", EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
|
if (net.desc) { x += addHtmlValue2("Description", EscapeHtml(net.desc).replace('(R)', '®').replace('(r)', '®')); }
|
||||||
if (net.dnssuffix) { x += addHtmlValue2("DNS suffix", EscapeHtml(net.dnssuffix) + ' <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy name to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.dnssuffix) + '")></i>'); }
|
if (net.dnssuffix) { x += addHtmlValue2("DNS suffix", EscapeHtml(net.dnssuffix) + ' <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy name to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.dnssuffix) + '")></i>'); }
|
||||||
if (net.mac) { x += addHtmlValue2("MAC address", '<a href="https://dnslytics.com/mac-address-lookup/' + net.mac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.mac.toLowerCase()) + '</a> <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy MAC address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.mac.toLowerCase()) + '")></i>'); }
|
if (net.mac) { x += addHtmlValue2("MAC address", '<a href="https://maclookup.app/search/result?mac=' + net.mac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.mac.toLowerCase()) + '</a> <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy MAC address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.mac.toLowerCase()) + '")></i>'); }
|
||||||
if (net.v4addr) { x += addHtmlValue2("IPv4 address", EscapeHtml(net.v4addr) + ' <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4addr) + '")></i>'); }
|
if (net.v4addr) { x += addHtmlValue2("IPv4 address", EscapeHtml(net.v4addr) + ' <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4addr) + '")></i>'); }
|
||||||
if (net.v4mask) { x += addHtmlValue2("IPv4 mask", EscapeHtml(net.v4mask) + ' <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4mask) + '")></i>'); }
|
if (net.v4mask) { x += addHtmlValue2("IPv4 mask", EscapeHtml(net.v4mask) + ' <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4mask) + '")></i>'); }
|
||||||
if (net.v4gateway) { x += addHtmlValue2("IPv4 gateway", EscapeHtml(net.v4gateway) + ' <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4gateway) + '")></i>'); }
|
if (net.v4gateway) { x += addHtmlValue2("IPv4 gateway", EscapeHtml(net.v4gateway) + ' <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.v4gateway) + '")></i>'); }
|
||||||
if (net.gatewaymac) { x += addHtmlValue2("Gateway MAC", '<a href="https://dnslytics.com/mac-address-lookup/' + net.gatewaymac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.gatewaymac.toLowerCase()) + '</a> <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy MAC address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.gatewaymac.toLowerCase()) + '")></i>'); }
|
if (net.gatewaymac) { x += addHtmlValue2("Gateway MAC", '<a href="https://maclookup.app/search/result?mac=' + net.gatewaymac.substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net.gatewaymac.toLowerCase()) + '</a> <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy MAC address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net.gatewaymac.toLowerCase()) + '")></i>'); }
|
||||||
}
|
}
|
||||||
} else if (message.netif2 != null) {
|
} else if (message.netif2 != null) {
|
||||||
// New style
|
// New style
|
||||||
|
|
@ -3289,7 +3340,7 @@
|
||||||
if ((Array.isArray(net) == false) || (net.length < 1) || (net[0] == null) || ((typeof net[0].mac == 'string') && (net[0].mac.startsWith('00:00:00:00')))) continue;
|
if ((Array.isArray(net) == false) || (net.length < 1) || (net[0] == null) || ((typeof net[0].mac == 'string') && (net[0].mac.startsWith('00:00:00:00')))) continue;
|
||||||
x += '<hr />'
|
x += '<hr />'
|
||||||
x += addHtmlValue2("Name", '<b>' + EscapeHtml(i) + '</b>');
|
x += addHtmlValue2("Name", '<b>' + EscapeHtml(i) + '</b>');
|
||||||
if (typeof net[0].mac == 'string') { x += addHtmlValue2("MAC address", '<a href="https://dnslytics.com/mac-address-lookup/' + net[0].mac.split(':').join('').substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net[0].mac.toLowerCase()) + '</a> <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy MAC address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net[0].mac.toLowerCase()) + '")></i>'); }
|
if (typeof net[0].mac == 'string') { x += addHtmlValue2("MAC address", '<a href="https://maclookup.app/search/result?mac=' + net[0].mac.split(':').join('').substring(0, 6) + '" rel="noreferrer noopener" target="MeshMACLoopup">' + EscapeHtml(net[0].mac.toLowerCase()) + '</a> <i class="fa-fw fa-regular fa-clipboard fa-sm" role=button title="' + "Copy MAC address to clipboard" + '" onclick=copyTextToClip2("' + encodeURIComponentEx(net[0].mac.toLowerCase()) + '")></i>'); }
|
||||||
if (net[0].fqdn) { x += addHtmlValue2("FQDN", net[0].fqdn); }
|
if (net[0].fqdn) { x += addHtmlValue2("FQDN", net[0].fqdn); }
|
||||||
for (var j = 0; j < net.length; j++) {
|
for (var j = 0; j < net.length; j++) {
|
||||||
var netif = net[j];
|
var netif = net[j];
|
||||||
|
|
@ -3442,7 +3493,7 @@
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Q('notesPanelArea').innerHTML = (message.notes && marked && DOMPurify) ? DOMPurify.sanitize(marked.parse(decodeURIComponent(message.notes), { breaks: true }), { USE_PROFILES: { html: true } }) : '';
|
Q('notesPanelArea').innerHTML = (message.notes && marked && DOMPurify) ? DOMPurify.sanitize(marked.parse(decodeURIComponent(message.notes), { breaks: true }), { USE_PROFILES: { html: true } }) : '';
|
||||||
if (showNotesPanel && message.notes) { QV('notesPanel', true); } else { QV('notesPanel', false); }
|
if ((showNotesPanel === 'true') && message.notes) { QV('notesPanel', true); } else { QV('notesPanel', false); }
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -3953,6 +4004,7 @@
|
||||||
// Change the node
|
// Change the node
|
||||||
node.name = message.event.node.name;
|
node.name = message.event.node.name;
|
||||||
node.rname = message.event.node.rname;
|
node.rname = message.event.node.rname;
|
||||||
|
node.lusers = message.event.node.lusers;
|
||||||
node.users = message.event.node.users;
|
node.users = message.event.node.users;
|
||||||
node.host = message.event.node.host;
|
node.host = message.event.node.host;
|
||||||
node.desc = message.event.node.desc;
|
node.desc = message.event.node.desc;
|
||||||
|
|
@ -4474,6 +4526,10 @@
|
||||||
var foundNode = null;
|
var foundNode = null;
|
||||||
if (nodes != null) { for (var i in nodes) { if (nodes[i].name == args.gotodevicename) { foundNode = nodes[i]._id; } } }
|
if (nodes != null) { for (var i in nodes) { if (nodes[i].name == args.gotodevicename) { foundNode = nodes[i]._id; } } }
|
||||||
if (foundNode) { gotoDevice(foundNode, xviewmode); goBackStack.push(1); }
|
if (foundNode) { gotoDevice(foundNode, xviewmode); goBackStack.push(1); }
|
||||||
|
} else if (args.gotodeviceip != null) {
|
||||||
|
var foundNode = null;
|
||||||
|
if (nodes != null) { for (var i in nodes) { if (nodes[i].ip == args.gotodeviceip) { foundNode = nodes[i]._id; } } }
|
||||||
|
if (foundNode) { gotoDevice(foundNode, xviewmode); goBackStack.push(1); }
|
||||||
} else if (args.gotomesh != null) {
|
} else if (args.gotomesh != null) {
|
||||||
if (meshes['mesh/' + domain + '/' + args.gotomesh] == null) return; // This device group is not loaded yet
|
if (meshes['mesh/' + domain + '/' + args.gotomesh] == null) return; // This device group is not loaded yet
|
||||||
gotoMesh('mesh/' + domain + '/' + args.gotomesh);
|
gotoMesh('mesh/' + domain + '/' + args.gotomesh);
|
||||||
|
|
@ -5336,7 +5392,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.desc && (deviceViewSettings.devsCols.indexOf('desc') >= 0)) { name = '<div style=float:right' + (stars[node._id] == 1 ? ';padding-right:15px' : '') + '>' + EscapeHtml(node.desc) + '</div><div>' + name + '</div>'; }
|
if (node.desc && (deviceViewSettings.devsCols.indexOf('desc') >= 0)) { name = '<div class="flex-grow-1">' + name + '</div><div style=float:right' + (stars[node._id] == 1 ? ';padding-right:15px' : '') + '>' + EscapeHtml(node.desc) + '</div>'; }
|
||||||
|
|
||||||
var collapseName = node.meshid;
|
var collapseName = node.meshid;
|
||||||
if (sort == 1) { collapseName = ('pwr:' + (node.pwr ? node.pwr : 0)); }
|
if (sort == 1) { collapseName = ('pwr:' + (node.pwr ? node.pwr : 0)); }
|
||||||
|
|
@ -5346,7 +5402,7 @@
|
||||||
r += '<div class=deviceBarCheckbox><input class="' + node.meshid + ' DeviceCheckbox form-check-input me-2" value=devid_' + node._id + ' type=checkbox onchange=p1devcheck(event) ' + (checkedNodeids[node._id] ? ' checked' : '') + '></div>';
|
r += '<div class=deviceBarCheckbox><input class="' + node.meshid + ' DeviceCheckbox form-check-input me-2" value=devid_' + node._id + ' type=checkbox onchange=p1devcheck(event) ' + (checkedNodeids[node._id] ? ' checked' : '') + '></div>';
|
||||||
r += '<div class=deviceBarIcon onmouseup=gotoDevice(\'' + node._id + '\',null,null,event)><div class="j' + icon + '" style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
|
r += '<div class=deviceBarIcon onmouseup=gotoDevice(\'' + node._id + '\',null,null,event)><div class="j' + icon + '" style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
|
||||||
r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
|
r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
|
||||||
r += '<div class=style10 style=cursor:pointer;font-size:14px;max-height:18px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap title="' + title + '" onmouseup=gotoDevice(\'' + node._id + '\',null,null,event)>' + name + '</div></div>' + devNotify + '</td>';
|
r += '<div class="style10 d-flex align-items-center" style=cursor:pointer;font-size:14px;max-height:18px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap title="' + title + '" onmouseup=gotoDevice(\'' + node._id + '\',null,null,event)>' + name + '</div></div>' + devNotify + '</td>';
|
||||||
|
|
||||||
// Use defaults if needed
|
// Use defaults if needed
|
||||||
if (deviceViewSettings == null) { deviceViewSettings = {}; }
|
if (deviceViewSettings == null) { deviceViewSettings = {}; }
|
||||||
|
|
@ -5921,7 +5977,7 @@
|
||||||
x += addHtmlFormFloating("New Password*", '<input id=dp1password1 type=password class="form-control" autocomplete=off maxlength=32 onchange=validateAmtAcmSetupEx() onkeyup=validateAmtAcmSetupEx() />');
|
x += addHtmlFormFloating("New Password*", '<input id=dp1password1 type=password class="form-control" autocomplete=off maxlength=32 onchange=validateAmtAcmSetupEx() onkeyup=validateAmtAcmSetupEx() />');
|
||||||
x += addHtmlFormFloating("New Password*", '<input id=dp1password2 type=password class="form-control" autocomplete=off maxlength=32 onchange=validateAmtAcmSetupEx() onkeyup=validateAmtAcmSetupEx() />');
|
x += addHtmlFormFloating("New Password*", '<input id=dp1password2 type=password class="form-control" autocomplete=off maxlength=32 onchange=validateAmtAcmSetupEx() onkeyup=validateAmtAcmSetupEx() />');
|
||||||
if ((features2 & 0x00000020) && (currentMesh.mtype == 1) && (serverinfo.amtProvServerMeshId == currentMesh._id)) { x += '<label><input id=dp1lanprov type=checkbox class="form-check-input me-2" /> ' + "Use for bare-metal LAN activation." + '</label>'; } // Intel AMT LAN provisioning server is active.
|
if ((features2 & 0x00000020) && (currentMesh.mtype == 1) && (serverinfo.amtProvServerMeshId == currentMesh._id)) { x += '<label><input id=dp1lanprov type=checkbox class="form-check-input me-2" /> ' + "Use for bare-metal LAN activation." + '</label>'; } // Intel AMT LAN provisioning server is active.
|
||||||
x += '<div><span id=dp10passNotify style="font-size:10px"> ' + "* 8 characters, 1 upper, 1 lower, 1 numeric, 1 non-alpha numeric." + '</span></div>';
|
x += '<div><span id=dp10passNotify style="font-size:10px"> ' + "* 8-16 characters, 1 upper, 1 lower, 1 numeric, 1 non-alpha numeric." + '</span></div>';
|
||||||
setModalContent('xxAddAgent', "Intel® AMT ACM", x);
|
setModalContent('xxAddAgent', "Intel® AMT ACM", x);
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', showAmtAcmSetupEx);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', showAmtAcmSetupEx);
|
||||||
Q('dp1password0').focus();
|
Q('dp1password0').focus();
|
||||||
|
|
@ -6268,7 +6324,11 @@
|
||||||
*/
|
*/
|
||||||
function showModal(modalId, okButtonId, okCallback, b = null, tag = null) {
|
function showModal(modalId, okButtonId, okCallback, b = null, tag = null) {
|
||||||
if (xxModal == null) {
|
if (xxModal == null) {
|
||||||
QE(okButtonId, true);
|
['idx_dlgOkButton', 'idx_dlgCancelButton'].forEach(function (id) { // clear existing onclick, enable buttons and show them
|
||||||
|
Q(id).onclick = null;
|
||||||
|
QE(id, true);
|
||||||
|
QV(id, true);
|
||||||
|
});
|
||||||
xxModal = new bootstrap.Modal(document.getElementById(modalId));
|
xxModal = new bootstrap.Modal(document.getElementById(modalId));
|
||||||
var hiddenModal = function (event) {
|
var hiddenModal = function (event) {
|
||||||
if (xxModal) { xxModal.dispose(); xxModal = null; }
|
if (xxModal) { xxModal.dispose(); xxModal = null; }
|
||||||
|
|
@ -6280,6 +6340,7 @@
|
||||||
xxModal.show();
|
xxModal.show();
|
||||||
document.getElementById(okButtonId).onclick = function () {
|
document.getElementById(okButtonId).onclick = function () {
|
||||||
if (typeof okCallback === 'function' && okCallback) {
|
if (typeof okCallback === 'function' && okCallback) {
|
||||||
|
xxdialogMode = 0; // reset xxdialogMode back to 0 because we might be opening up another dialog and it checks if one is already open
|
||||||
var callbackResult = okCallback(b, tag);
|
var callbackResult = okCallback(b, tag);
|
||||||
// Close the modal by default unless `false` is explicitly returned from the callback function
|
// Close the modal by default unless `false` is explicitly returned from the callback function
|
||||||
if (callbackResult !== false) { xxModal.hide(); }
|
if (callbackResult !== false) { xxModal.hide(); }
|
||||||
|
|
@ -6701,7 +6762,7 @@
|
||||||
meshserver.send({ action: 'getDeviceDetails', nodeids: chkNodeIds, tz: tz, tf: new Date().getTimezoneOffset(), l: getLang(), type: 'csv' }); // With details
|
meshserver.send({ action: 'getDeviceDetails', nodeids: chkNodeIds, tz: tz, tf: new Date().getTimezoneOffset(), l: getLang(), type: 'csv' }); // With details
|
||||||
} else {
|
} else {
|
||||||
// Without details
|
// Without details
|
||||||
var csv = "id,name,rname,host,icon,ip,osdesc,state,groupname,conn,pwr,av,update,firewall,bitlocker,avdetails,tags" + '\r\n', r = [];
|
var csv = "id,name,rname,host,icon,ip,osdesc,state,groupname,conn,pwr,av,update,firewall,bitlocker,avdetails,tags,lastbootuptime" + '\r\n', r = [];
|
||||||
for (var i in chkNodeIds) {
|
for (var i in chkNodeIds) {
|
||||||
var n = getNodeFromId(chkNodeIds[i]);
|
var n = getNodeFromId(chkNodeIds[i]);
|
||||||
csv += '"' + n._id.split(',').join('') + '","' + n.name.split(',').join('') + '","' + (n.rname ? (n.rname.split(',').join('')) : '') + '","' + (n.host ? (n.host.split(',').join('')) : '') + '","' + n.icon + '","' + (n.ip ? n.ip : '') + '","' + (n.osdesc ? (n.osdesc.split(',').join('')) : '') + '","' + n.state + '","' + meshes[n.meshid].name.split(',').join('') + '","' + (n.conn ? n.conn : '') + '","' + (n.pwr ? n.pwr : '') + '"';
|
csv += '"' + n._id.split(',').join('') + '","' + n.name.split(',').join('') + '","' + (n.rname ? (n.rname.split(',').join('')) : '') + '","' + (n.host ? (n.host.split(',').join('')) : '') + '","' + n.icon + '","' + (n.ip ? n.ip : '') + '","' + (n.osdesc ? (n.osdesc.split(',').join('')) : '') + '","' + n.state + '","' + meshes[n.meshid].name.split(',').join('') + '","' + (n.conn ? n.conn : '') + '","' + (n.pwr ? n.pwr : '') + '"';
|
||||||
|
|
@ -6730,6 +6791,7 @@
|
||||||
else {
|
else {
|
||||||
csv += ',';
|
csv += ',';
|
||||||
}
|
}
|
||||||
|
if (typeof n.lastbootuptime == 'number') { csv += ',"' + n.lastbootuptime + '"'; }
|
||||||
csv += '\r\n';
|
csv += '\r\n';
|
||||||
}
|
}
|
||||||
saveAs(stringToUtf8Blob(csv), "devicelist.csv");
|
saveAs(stringToUtf8Blob(csv), "devicelist.csv");
|
||||||
|
|
@ -8269,8 +8331,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Active Users
|
// Active Users
|
||||||
if (node.users && node.conn && (node.users.length > 0) && (node.conn & 1)) { x += addDeviceAttribute(((node.users.length > 1) ? "Active Users" : "Active User"), EscapeHtml(node.users.join(', '))); }
|
if (node.users && node.users.length > 0) {
|
||||||
|
var u = node.users.map(function(user) {
|
||||||
|
return addKeyLinkConditional(EscapeHtml(user), "Locked", (node.lusers && node.lusers.indexOf(user) >= 0));
|
||||||
|
}).join(', ');
|
||||||
|
x += addDeviceAttribute((node.users.length > 1 ? "Active Users" : "Active User"), u);
|
||||||
|
}
|
||||||
// Display device user consent
|
// Display device user consent
|
||||||
if ((node.agent != null) && (node.agent.id != 14) && (node.mtype != 3)) {
|
if ((node.agent != null) && (node.agent.id != 14) && (node.mtype != 3)) {
|
||||||
var meshFeatures = [];
|
var meshFeatures = [];
|
||||||
|
|
@ -8864,7 +8930,7 @@
|
||||||
if (noteid == null) { noteid = encodeURIComponentEx('p' + userinfo._id); }
|
if (noteid == null) { noteid = encodeURIComponentEx('p' + userinfo._id); }
|
||||||
var x = '<textarea id=d2devNotes ro=' + readonly + ' noteid=' + noteid + ' readonly class="form-control" style=width:100%;height:200px;resize:none;overflow-y:scroll></textarea>';
|
var x = '<textarea id=d2devNotes ro=' + readonly + ' noteid=' + noteid + ' readonly class="form-control" style=width:100%;height:200px;resize:none;overflow-y:scroll></textarea>';
|
||||||
if (noteid.startsWith('node%2F%2F')) { x += '<span style=font-size:10px>' + "Device group notes can be viewed and changed by other device group administrators." + '<span>'; }
|
if (noteid.startsWith('node%2F%2F')) { x += '<span style=font-size:10px>' + "Device group notes can be viewed and changed by other device group administrators." + '<span>'; }
|
||||||
if (showNotesPanel) { x += ' <span style=font-size:10px><a target=_blank href=\'https://www.markdownguide.org/cheat-sheet/\'>' + "Markdown syntax supported" + '</a></span>'; }
|
if (showNotesPanel === 'true') { x += ' <span style=font-size:10px><a target=_blank href=\'https://www.markdownguide.org/cheat-sheet/\'>' + "Markdown syntax supported" + '</a></span>'; }
|
||||||
setModalContent('xxAddAgent', "Notes", x);
|
setModalContent('xxAddAgent', "Notes", x);
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', function () {
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', function () {
|
||||||
showNotesEx(2, noteid);
|
showNotesEx(2, noteid);
|
||||||
|
|
@ -8876,7 +8942,7 @@
|
||||||
function showNotesEx(buttons, tag) {
|
function showNotesEx(buttons, tag) {
|
||||||
Q('notesPanelArea').innerHTML = (marked && DOMPurify) ? DOMPurify.sanitize(marked.parse(Q('d2devNotes').value, { breaks: true }), { USE_PROFILES: { html: true } }) : Q('d2devNotes').value;
|
Q('notesPanelArea').innerHTML = (marked && DOMPurify) ? DOMPurify.sanitize(marked.parse(Q('d2devNotes').value, { breaks: true }), { USE_PROFILES: { html: true } }) : Q('d2devNotes').value;
|
||||||
meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponentEx(Q('d2devNotes').value) });
|
meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponentEx(Q('d2devNotes').value) });
|
||||||
if (showNotesPanel && Q('d2devNotes').value != '') { QV('notesPanel', true); } else { QV('notesPanel', false); }
|
if ((showNotesPanel === 'true') && Q('d2devNotes').value != '') { QV('notesPanel', true); } else { QV('notesPanel', false); }
|
||||||
}
|
}
|
||||||
|
|
||||||
function openIpKvmRemoteControl(nodeid) {
|
function openIpKvmRemoteControl(nodeid) {
|
||||||
|
|
@ -9321,7 +9387,7 @@
|
||||||
|
|
||||||
// Draw device power bars. The bars are 766px wide.
|
// Draw device power bars. The bars are 766px wide.
|
||||||
function drawDeviceTimeline() {
|
function drawDeviceTimeline() {
|
||||||
if ((currentNode == null) || (xxcurrentView < 10) || (xxcurrentView > 19) || (currentNode.mtype == 3) || (hidePowerTimeline)) return;
|
if ((currentNode == null) || (xxcurrentView < 10) || (xxcurrentView > 19) || (currentNode.mtype == 3) || (hidePowerTimeline === 'true')) return;
|
||||||
var timeline = null, now = Date.now();
|
var timeline = null, now = Date.now();
|
||||||
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
|
if (currentNode._id == powerTimelineNode) { timeline = powerTimeline; }
|
||||||
|
|
||||||
|
|
@ -10185,7 +10251,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function askRdpCredentialsEx() {
|
function askRdpCredentialsEx() {
|
||||||
xxdialogMode = 0;
|
|
||||||
var width = null, height = null;
|
var width = null, height = null;
|
||||||
if (desktopsettings.rdpsize) {
|
if (desktopsettings.rdpsize) {
|
||||||
if (desktopsettings.rdpsize == 'browser') {
|
if (desktopsettings.rdpsize == 'browser') {
|
||||||
|
|
@ -12096,7 +12161,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function p13openfilefolder() {
|
function p13openfilefolder() {
|
||||||
setModalContent('xxAddAgent', "Open File/Folder", 'Are you sure you want to open this file/folder on the remote devices desktop ?');
|
setModalContent('xxAddAgent', "Open File/Folder", "Are you sure you want to open this file/folder on the remote devices desktop?");
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13openfilefolderEx());
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13openfilefolderEx());
|
||||||
}
|
}
|
||||||
function p13openfilefolderEx() {
|
function p13openfilefolderEx() {
|
||||||
|
|
@ -12279,11 +12344,11 @@
|
||||||
function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
|
function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
|
||||||
function p13uploadFile() {
|
function p13uploadFile() {
|
||||||
setModalContent('xxAddAgent', "Upload File", '<input type=file name=files id=p13uploadinput class="form-control" multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />');
|
setModalContent('xxAddAgent', "Upload File", '<input type=file name=files id=p13uploadinput class="form-control" multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />');
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13uploadFileEx);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13uploadFileEx());
|
||||||
updateUploadDialogOk('p13uploadinput');
|
updateUploadDialogOk('p13uploadinput');
|
||||||
}
|
}
|
||||||
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q('p13uploadinput').files.length > 0); }
|
function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q('p13uploadinput').files.length > 0); }
|
||||||
function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
|
function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); return false; }
|
||||||
function p13viewfile() {
|
function p13viewfile() {
|
||||||
var checkboxes = document.getElementsByName('fd');
|
var checkboxes = document.getElementsByName('fd');
|
||||||
for (var i = 0; i < checkboxes.length; i++) {
|
for (var i = 0; i < checkboxes.length; i++) {
|
||||||
|
|
@ -12342,7 +12407,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setModalContent('xxAddAgent', "Paste", x);
|
setModalContent('xxAddAgent', "Paste", x);
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13pasteFileEx);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13pasteFileEx());
|
||||||
}
|
}
|
||||||
function p13pasteFileEx() { files.sendText({ action: (p13clipboardCut == 0 ? 'copy' : 'move'), reqid: 1, scpath: p13clipboardFolder, dspath: p13targetpath, names: p13clipboard }); p13folderup(999); if (p13clipboardCut == 1) { p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0; p13updateClipview(); } }
|
function p13pasteFileEx() { files.sendText({ action: (p13clipboardCut == 0 ? 'copy' : 'move'), reqid: 1, scpath: p13clipboardFolder, dspath: p13targetpath, names: p13clipboard }); p13folderup(999); if (p13clipboardCut == 1) { p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0; p13updateClipview(); } }
|
||||||
function p13updateClipview() {
|
function p13updateClipview() {
|
||||||
|
|
@ -12413,7 +12478,7 @@
|
||||||
//console.log('p13downloadFileCancel', gdownloadFile);
|
//console.log('p13downloadFileCancel', gdownloadFile);
|
||||||
files.sendText({ action: 'download', sub: 'start', id: gdownloadFile.id, path: gdownloadFile.path });
|
files.sendText({ action: 'download', sub: 'start', id: gdownloadFile.id, path: gdownloadFile.path });
|
||||||
setModalContent('xxAddAgent', "Download File", '<div>' + gdownloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
|
setModalContent('xxAddAgent', "Download File", '<div>' + gdownloadFile.file + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=' + z + ' />');
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13downloadFileCancel);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13downloadFileCancel());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by the html page to cancel the download
|
// Called by the html page to cancel the download
|
||||||
|
|
@ -12554,7 +12619,7 @@
|
||||||
p13uploadFileContinue(1, files);
|
p13uploadFileContinue(1, files);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, prompt for confirmation
|
// Otherwise, prompt for confirmation
|
||||||
setModalContent('xxAddAgent', "Upload File", p13uploadFileContinue, format((overWriteCount == 1) ? "Upload will overwrite 1 file. Continue?" : "Upload will overwrite {0} files. Continue?", overWriteCount));
|
setModalContent('xxAddAgent', "Upload File", format((overWriteCount == 1) ? "Upload will overwrite 1 file. Continue?" : "Upload will overwrite {0} files. Continue?", overWriteCount));
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13uploadFileContinue(3, files));
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13uploadFileContinue(3, files));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12565,8 +12630,10 @@
|
||||||
uploadFile.xfiles = files;
|
uploadFile.xfiles = files;
|
||||||
uploadFile.xfilePtr = -1;
|
uploadFile.xfilePtr = -1;
|
||||||
setModalContent('xxAddAgent', "Upload File", '<div id=p13dfileName>' + "Connecting..." + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=0 />');
|
setModalContent('xxAddAgent', "Upload File", '<div id=p13dfileName>' + "Connecting..." + '</div><br /><progress id=d2progressBar style=width:100% value=0 max=0 />');
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p13uploadFileCancel(10));
|
showModal('xxAddAgentModal', 'idx_dlgCancelButton', () => p13uploadFileCancel(10));
|
||||||
|
document.getElementById('idx_dlgOkButton').style.display = 'none'; // hide OK button
|
||||||
p13uploadNextFile();
|
p13uploadNextFile();
|
||||||
|
if (b == 3) return false; // if overwritten, dont close the dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform SHA-384 hashing
|
// Perform SHA-384 hashing
|
||||||
|
|
@ -13511,7 +13578,17 @@
|
||||||
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeids: [consoleNode._id], type: 'clear' }); } // Clear the core
|
else if (e.altKey == true) { meshserver.send({ action: 'uploadagentcore', nodeids: [consoleNode._id], type: 'clear' }); } // Clear the core
|
||||||
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
|
else if (e.ctrlKey == true) { p15uploadCore2(); } // Upload the core from a file
|
||||||
else {
|
else {
|
||||||
setModalContent('xxAddAgent', "Perform Agent Action", addHtmlFormFloating("Action", '<select id=d3coreMode class="form-select me-2"><option value=1>' + "Upload default server core" + '</option><option value=2>' + "Clear the core" + '</option><option value=6>' + "Upload recovery core" + '</option><option value=7>' + "Upload tiny core" + '</option><option value=3>' + "Upload a core file" + '</option><option value=4>' + "Soft disconnect agent" + '</option><option value=5>' + "Hard disconnect agent" + '</option><option value=8>' + "Restart agent service" + '</select>'));
|
var htmlValue = '<select id=d3coreMode class="form-select me-2">' +
|
||||||
|
'<option value=1>' + "Upload default server core" + '</option>' +
|
||||||
|
'<option value=2>' + "Clear the core" + '</option>' +
|
||||||
|
'<option value=3>' + "Upload a core file" + '</option>' +
|
||||||
|
'<option value=4>' + "Soft disconnect agent" + '</option>' +
|
||||||
|
'<option value=5>' + "Hard disconnect agent" + '</option>' +
|
||||||
|
'<option value=6>' + "Upload recovery core" + '</option>' +
|
||||||
|
'<option value=7>' + "Upload tiny core" + '</option>' +
|
||||||
|
'<option value=8>' + "Restart agent service" + '</option>' +
|
||||||
|
'<option value=9>' + "Force agent update" + '</option></select>';
|
||||||
|
setModalContent('xxAddAgent', "Perform Agent Action", addHtmlFormFloating("Action", htmlValue));
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', p15uploadCoreEx);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', p15uploadCoreEx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13541,6 +13618,9 @@
|
||||||
} else if (Q('d3coreMode').value == 8) {
|
} else if (Q('d3coreMode').value == 8) {
|
||||||
// Restart MeshAgent service
|
// Restart MeshAgent service
|
||||||
meshserver.send({ action: 'msg', type: 'console', nodeid: consoleNode._id, value:'service restart' });
|
meshserver.send({ action: 'msg', type: 'console', nodeid: consoleNode._id, value:'service restart' });
|
||||||
|
} else if (Q('d3coreMode').value == 9) {
|
||||||
|
// Update mesh agent
|
||||||
|
meshserver.send({ action: 'updateAgents', nodeids: [consoleNode._id] });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -13552,7 +13632,7 @@
|
||||||
Q('d3filter').value = '.js';
|
Q('d3filter').value = '.js';
|
||||||
Q('d3attrib').value = currentNode._id;
|
Q('d3attrib').value = currentNode._id;
|
||||||
setModalContent('xxAddAgent', "Upload Mesh Agent Core", '');
|
setModalContent('xxAddAgent', "Upload Mesh Agent Core", '');
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p15uploadCoreEx2);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => p15uploadCoreEx2());
|
||||||
d3init();
|
d3init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -13633,7 +13713,7 @@
|
||||||
x += '<td style=text-align:center><div style=padding:6px>' + "Verified phone number" + '</div><div style=font-size:20px>' + EscapeHtml(userinfo.phone) + '</div>';
|
x += '<td style=text-align:center><div style=padding:6px>' + "Verified phone number" + '</div><div style=font-size:20px>' + EscapeHtml(userinfo.phone) + '</div>';
|
||||||
x += '<div style=margin:10px><label><input id=d2delPhone type=checkbox class="form-check-input me-2" onclick=account_managePhoneRemoveValidate() />' + "Remove phone number" + '</label></div>';
|
x += '<div style=margin:10px><label><input id=d2delPhone type=checkbox class="form-check-input me-2" onclick=account_managePhoneRemoveValidate() />' + "Remove phone number" + '</label></div>';
|
||||||
setModalContent('xxAddAgent', "Phone Notifications", x);
|
setModalContent('xxAddAgent', "Phone Notifications", x);
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => account_managePhoneRemove);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => account_managePhoneRemove());
|
||||||
account_managePhoneRemoveValidate();
|
account_managePhoneRemoveValidate();
|
||||||
} else {
|
} else {
|
||||||
x = '<table style=width:100%><tr><td style=width:56px><img src="images/phone80.png" style=padding:8px>';
|
x = '<table style=width:100%><tr><td style=width:56px><img src="images/phone80.png" style=padding:8px>';
|
||||||
|
|
@ -13641,7 +13721,7 @@
|
||||||
x += '<br /><br /><div style=width:100%;text-align:center>' + "Phone number:" + ' <input type=tel pattern="[0-9]" autocomplete="tel" inputmode="tel" maxlength=18 id=d2phoneinput onKeyUp=account_managePhoneValidate() onkeypress="if (event.key==\'Enter\') account_managePhoneValidate(1)"></div></table>';
|
x += '<br /><br /><div style=width:100%;text-align:center>' + "Phone number:" + ' <input type=tel pattern="[0-9]" autocomplete="tel" inputmode="tel" maxlength=18 id=d2phoneinput onKeyUp=account_managePhoneValidate() onkeypress="if (event.key==\'Enter\') account_managePhoneValidate(1)"></div></table>';
|
||||||
xxdialogTag = 'verifyPhone';
|
xxdialogTag = 'verifyPhone';
|
||||||
setModalContent('xxAddAgent', "Phone Notifications", x);
|
setModalContent('xxAddAgent', "Phone Notifications", x);
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => account_managePhoneAdd);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => account_managePhoneAdd());
|
||||||
Q('d2phoneinput').focus();
|
Q('d2phoneinput').focus();
|
||||||
account_managePhoneValidate();
|
account_managePhoneValidate();
|
||||||
}
|
}
|
||||||
|
|
@ -13663,7 +13743,7 @@
|
||||||
x += '<td style=text-align:center><div style=padding:6px>' + "Verified handle" + '</div><div style=font-weight:bold>' + EscapeHtml(userinfo.msghandle) + '</div>';
|
x += '<td style=text-align:center><div style=padding:6px>' + "Verified handle" + '</div><div style=font-weight:bold>' + EscapeHtml(userinfo.msghandle) + '</div>';
|
||||||
x += '<div style=margin:10px><label><input id=d2delPhone type=checkbox class="form-check-input me-2" onclick=account_managePhoneRemoveValidate() />' + "Remove messaging" + '</label></div>';
|
x += '<div style=margin:10px><label><input id=d2delPhone type=checkbox class="form-check-input me-2" onclick=account_managePhoneRemoveValidate() />' + "Remove messaging" + '</label></div>';
|
||||||
setModalContent('xxAddAgent', "Messaging Notifications", x);
|
setModalContent('xxAddAgent', "Messaging Notifications", x);
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => account_manageMessagingRemove);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => account_manageMessagingRemove());
|
||||||
account_managePhoneRemoveValidate();
|
account_managePhoneRemoveValidate();
|
||||||
} else {
|
} else {
|
||||||
x = '<table style=width:100%><tr><td style=width:56px;vertical-align:top><img src="images/messaging40.png" style=padding:8px>';
|
x = '<table style=width:100%><tr><td style=width:56px;vertical-align:top><img src="images/messaging40.png" style=padding:8px>';
|
||||||
|
|
@ -13961,7 +14041,7 @@
|
||||||
if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return false;
|
if (xxdialogMode || (userinfo.emailVerified == true) || (serverinfo.emailcheck != true)) return false;
|
||||||
var x = "Click ok to send a verification mail to:" + '<br /><div style=padding:8px><b>' + EscapeHtml(userinfo.email) + '</b></div>' + "Please wait a few minute to receive the verification.";
|
var x = "Click ok to send a verification mail to:" + '<br /><div style=padding:8px><b>' + EscapeHtml(userinfo.email) + '</b></div>' + "Please wait a few minute to receive the verification.";
|
||||||
setModalContent('xxAddAgent', "Email Verification", x);
|
setModalContent('xxAddAgent', "Email Verification", x);
|
||||||
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => account_showVerifyEmailEx);
|
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => account_showVerifyEmailEx());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -14138,10 +14218,9 @@
|
||||||
function account_switchThemeEx() {
|
function account_switchThemeEx() {
|
||||||
var themeSwitcher = document.getElementById('theme-switcher');
|
var themeSwitcher = document.getElementById('theme-switcher');
|
||||||
const selectedTheme = themeSwitcher.value;
|
const selectedTheme = themeSwitcher.value;
|
||||||
const safeTheme = encodeURIComponent(selectedTheme);
|
const safeTheme = ((selectedTheme != 'default') ? encodeURIComponent(selectedTheme) : encodeURIComponent('..'));
|
||||||
var themeStylesheet = document.getElementById('theme-stylesheet');
|
var themeStylesheet = document.getElementById('theme-stylesheet');
|
||||||
var newThemeStylesheet = `styles/themes/${safeTheme}/bootstrap.min.css`;
|
themeStylesheet.href = `styles/themes/${safeTheme}/bootstrap-min.css`;
|
||||||
themeStylesheet.href = newThemeStylesheet;
|
|
||||||
// Save selected theme
|
// Save selected theme
|
||||||
putstore('theme', selectedTheme);
|
putstore('theme', selectedTheme);
|
||||||
// Update last 4 themes selected
|
// Update last 4 themes selected
|
||||||
|
|
@ -14880,7 +14959,7 @@
|
||||||
x += addHtmlFormFloating("Unknown password", '<select id=dp20amtbadpass class="form-select"><option value=0>' + "Do nothing" + '</option><option value=1>' + "If in CCM, reactivate Intel® AMT" + '</option></select>');
|
x += addHtmlFormFloating("Unknown password", '<select id=dp20amtbadpass class="form-select"><option value=0>' + "Do nothing" + '</option><option value=1>' + "If in CCM, reactivate Intel® AMT" + '</option></select>');
|
||||||
x += '</div>';
|
x += '</div>';
|
||||||
if ((features & 0x400) == 0) { x += addHtmlFormFloating("CIRA setup", '<select id=dp20amtcira class="form-select" title="' + "Client Initiated Remote Access" + '"><option value=0>' + "Do nothing" + '</option><option value=1>' + "Don't connect to server" + '</option><option value=2>' + "Connect to server" + '</option></select>'); }
|
if ((features & 0x400) == 0) { x += addHtmlFormFloating("CIRA setup", '<select id=dp20amtcira class="form-select" title="' + "Client Initiated Remote Access" + '"><option value=0>' + "Do nothing" + '</option><option value=1>' + "Don't connect to server" + '</option><option value=2>' + "Connect to server" + '</option></select>'); }
|
||||||
x += '<span id=dp10passNotify style="font-size:10px"> ' + "* 8 characters, 1 upper, 1 lower, 1 numeric, 1 non-alpha numeric." + '</span>';
|
x += '<span id=dp10passNotify style="font-size:10px"> ' + "* 8-16 characters, 1 upper, 1 lower, 1 numeric, 1 non-alpha numeric." + '</span>';
|
||||||
if ((currentMesh.mtype == 2) && (ptype == 2)) { x += '<span style="font-size:10px"> ' + "This policy will not impact devices with Intel® AMT in ACM mode." + '</span>'; }
|
if ((currentMesh.mtype == 2) && (ptype == 2)) { x += '<span style="font-size:10px"> ' + "This policy will not impact devices with Intel® AMT in ACM mode." + '</span>'; }
|
||||||
}
|
}
|
||||||
if (ptype == 0) { x = '<div class="row"><div class="col-2"><i class="fa-solid fa-times-circle text-danger" style="padding-right:8px; font-size:60px;"></i></div><div class="col-10">' + "When this policy is selected, Intel® AMT is not managed by this server. Intel AMT can still be used by manually activating and configuring it." + '</div></div>'; }
|
if (ptype == 0) { x = '<div class="row"><div class="col-2"><i class="fa-solid fa-times-circle text-danger" style="padding-right:8px; font-size:60px;"></i></div><div class="col-10">' + "When this policy is selected, Intel® AMT is not managed by this server. Intel AMT can still be used by manually activating and configuring it." + '</div></div>'; }
|
||||||
|
|
@ -17047,7 +17126,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function p4downloadUserInfoCSV() {
|
function p4downloadUserInfoCSV() {
|
||||||
var csv = "id, name, email, creation, lastlogin, groups, authfactors, siteadmin, useradmin, locked" + '\r\n';
|
var csv = "id,name,email,creation,lastlogin,groups,authfactors,siteadmin,useradmin,locked" + '\r\n';
|
||||||
for (var i in users) {
|
for (var i in users) {
|
||||||
var multiFactor = false, factors = [];
|
var multiFactor = false, factors = [];
|
||||||
if ((users[i].otpsecret > 0) || (users[i].otphkeys > 0)) {
|
if ((users[i].otpsecret > 0) || (users[i].otphkeys > 0)) {
|
||||||
|
|
@ -19839,6 +19918,7 @@
|
||||||
for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
|
for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
|
||||||
QV('dialog', x);
|
QV('dialog', x);
|
||||||
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
|
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
|
||||||
|
if (x == 0) { if (xxModal) xxModal.hide(); }
|
||||||
MoreToggle(false);
|
MoreToggle(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20456,7 +20536,7 @@
|
||||||
function addLink(x, f) { return '<span tabindex=0 role="button" onclick=\'' + f + '\' onkeypress="if (event.key==\'Enter\') {' + f + '} ">' + x + ' <i class="fa-solid fa-pencil fa-xs"></i></span>'; }
|
function addLink(x, f) { return '<span tabindex=0 role="button" onclick=\'' + f + '\' onkeypress="if (event.key==\'Enter\') {' + f + '} ">' + x + ' <i class="fa-solid fa-pencil fa-xs"></i></span>'; }
|
||||||
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
|
function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
|
||||||
function addKeyLink(x, f) { return '<span tabindex=0 role=button onclick=' + f + ' onkeypress="if (event.key==\'Enter\') { ' + f + ' } ">' + x + ' <i class="fa-solid fa-key"></i></span>'; }
|
function addKeyLink(x, f) { return '<span tabindex=0 role=button onclick=' + f + ' onkeypress="if (event.key==\'Enter\') { ' + f + ' } ">' + x + ' <i class="fa-solid fa-key"></i></span>'; }
|
||||||
function addKeyLinkConditional(x, f, c) { if (c) return addKeyLink(x, f); return x; }
|
function addKeyLinkConditional(x, t, c) { if (c) return '<span title=\'' + t + '\'>' + x + ' <i class="fa-solid fa-key"></i></span>'; return x }
|
||||||
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||||
function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
|
function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
|
||||||
function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
|
||||||
|
|
@ -20573,4 +20653,4 @@
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -460,7 +460,7 @@
|
||||||
// Show Language Select Box if needed
|
// Show Language Select Box if needed
|
||||||
if (showLanguageSelect === 'top' || showLanguageSelect === 'bottom') {
|
if (showLanguageSelect === 'top' || showLanguageSelect === 'bottom') {
|
||||||
var x = '<select id=d2langselect style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:8px" onChange="changeLanguage()">';
|
var x = '<select id=d2langselect style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:8px" onChange="changeLanguage()">';
|
||||||
x += '<option value="*">Use Browser Language</option>';
|
x += '<option value="*">' + "Use Browser Language" + '</option>';
|
||||||
for (var i in serverLangs) {
|
for (var i in serverLangs) {
|
||||||
var lang = serverLangs[i];
|
var lang = serverLangs[i];
|
||||||
x += '<option value="' + lang + '"' + ((urlargs.lang == lang)?' selected':'') + '>' + lang + ' - ' + (loclist[lang]?loclist[lang]:loclistex[lang]) + '</option>';
|
x += '<option value="' + lang + '"' + ((urlargs.lang == lang)?' selected':'') + '>' + lang + ' - ' + (loclist[lang]?loclist[lang]:loclistex[lang]) + '</option>';
|
||||||
|
|
|
||||||
|
|
@ -1097,7 +1097,6 @@
|
||||||
if (term != null) { term.dispose(); }
|
if (term != null) { term.dispose(); }
|
||||||
term = new Terminal();
|
term = new Terminal();
|
||||||
term.open(Q('XTermParent'));
|
term.open(Q('XTermParent'));
|
||||||
term.onData(function (data) { if (tunnel != null) { tunnel.sendText(data); } })
|
|
||||||
term.resize(80, 25);
|
term.resize(80, 25);
|
||||||
//term.setOption('convertEol', true); // Consider \n to be \r\n, this should be taken care of by "termios"
|
//term.setOption('convertEol', true); // Consider \n to be \r\n, this should be taken care of by "termios"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -746,7 +746,7 @@
|
||||||
var domainUrl = '{{{domainurl}}}';
|
var domainUrl = '{{{domainurl}}}';
|
||||||
var authCookie = '{{{authCookie}}}';
|
var authCookie = '{{{authCookie}}}';
|
||||||
var authRelayCookie = '{{{authRelayCookie}}}';
|
var authRelayCookie = '{{{authRelayCookie}}}';
|
||||||
var viewOnly = (parseInt('{{{viewOnly}}}') == 1);
|
var viewOnly = parseInt('{{{viewOnly}}}');
|
||||||
var authCookieRenewTimer = null;
|
var authCookieRenewTimer = null;
|
||||||
var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
|
var serverPublicNamePort = '{{{serverDnsName}}}:{{{serverPublicPort}}}';
|
||||||
var debugmode = false;
|
var debugmode = false;
|
||||||
|
|
@ -820,7 +820,26 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSessionActivity() { sessionActivity = Date.now(); }
|
function setSessionActivity() { sessionActivity = Date.now(); }
|
||||||
function checkIdleSessionTimeout() { var delta = (Date.now() - sessionActivity); if (delta > serverinfo.timeout) { window.location.href = 'logout'; } }
|
function checkIdleSessionTimeout() {
|
||||||
|
var delta = (Date.now() - sessionActivity);
|
||||||
|
if (delta > serverinfo.timeout) {
|
||||||
|
if (desktop != null) { // Disconnect remote desktop
|
||||||
|
desktop.Stop();
|
||||||
|
desktopNode = desktop = null;
|
||||||
|
}
|
||||||
|
if (terminal != null) { // Disconnect terminal
|
||||||
|
terminal.Stop();
|
||||||
|
terminal = null;
|
||||||
|
}
|
||||||
|
if (files != null) { // Disconnect files
|
||||||
|
files.Stop();
|
||||||
|
files = null;
|
||||||
|
}
|
||||||
|
if (serverinfo.logoutonidlesessiontimeout) {
|
||||||
|
window.location.href = 'logout';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Menu System
|
// Menu System
|
||||||
|
|
@ -845,7 +864,7 @@
|
||||||
gotKeyPressEvent = true;
|
gotKeyPressEvent = true;
|
||||||
Q('softKeyboard').value = '';
|
Q('softKeyboard').value = '';
|
||||||
// Check what keys we are allows to send
|
// Check what keys we are allows to send
|
||||||
if (viewOnly) return false;
|
if (viewOnly == 1) return false;
|
||||||
return desktop.m.handleKeys(e);
|
return desktop.m.handleKeys(e);
|
||||||
}
|
}
|
||||||
if (terminal && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 5) && (t !== 1)) {
|
if (terminal && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 5) && (t !== 1)) {
|
||||||
|
|
@ -873,7 +892,7 @@
|
||||||
gotKeyPressEvent = false;
|
gotKeyPressEvent = false;
|
||||||
Q('softKeyboard').value = '';
|
Q('softKeyboard').value = '';
|
||||||
// Check what keys we are allows to send
|
// Check what keys we are allows to send
|
||||||
if (viewOnly) return false;
|
if (viewOnly == 1) return false;
|
||||||
return desktop.m.handleKeyDown(e);
|
return desktop.m.handleKeyDown(e);
|
||||||
}
|
}
|
||||||
if (terminal && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 5) && (t !== 1)) {
|
if (terminal && !xxdialogMode && (xxcurrentView == 10) && (currentDevicePanel == 5) && (t !== 1)) {
|
||||||
|
|
@ -902,7 +921,7 @@
|
||||||
var inputStr = Q('softKeyboard').value;
|
var inputStr = Q('softKeyboard').value;
|
||||||
Q('softKeyboard').value = '';
|
Q('softKeyboard').value = '';
|
||||||
// Check what keys we are allows to send
|
// Check what keys we are allows to send
|
||||||
if (viewOnly) return;
|
if (viewOnly == 1) return;
|
||||||
if ((gotKeyPressEvent == false) && (inputStr.length > 0) && desktop.m.SendKeyUnicode) {
|
if ((gotKeyPressEvent == false) && (inputStr.length > 0) && desktop.m.SendKeyUnicode) {
|
||||||
// This is a mobile keyboard, we need to send that is in the input control.
|
// This is a mobile keyboard, we need to send that is in the input control.
|
||||||
var inputchar = inputStr[inputStr.length - 1].charCodeAt(0);
|
var inputchar = inputStr[inputStr.length - 1].charCodeAt(0);
|
||||||
|
|
@ -1062,6 +1081,7 @@
|
||||||
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
|
desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk'), authCookie);
|
||||||
desktop.debugmode = debugmode;
|
desktop.debugmode = debugmode;
|
||||||
desktop.onStateChanged = onDesktopStateChange;
|
desktop.onStateChanged = onDesktopStateChange;
|
||||||
|
desktop.m.stopInput = (viewOnly == 1);
|
||||||
desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
|
desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
|
||||||
desktop.m.useZRLE = (desktopsettings.encoding < 3);
|
desktop.m.useZRLE = (desktopsettings.encoding < 3);
|
||||||
desktop.m.showmouse = true;
|
desktop.m.showmouse = true;
|
||||||
|
|
@ -1071,6 +1091,8 @@
|
||||||
} else if ((contype == null) || (contype == 1) || ((contype == 3))) {
|
} else if ((contype == null) || (contype == 1) || ((contype == 3))) {
|
||||||
// Setup the Mesh Agent remote desktop
|
// Setup the Mesh Agent remote desktop
|
||||||
desktop = CreateAgentRedirect(null, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, null, domainUrl);
|
desktop = CreateAgentRedirect(null, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, null, domainUrl);
|
||||||
|
desktop.m.stopInput = (viewOnly == 1);
|
||||||
|
desktop.m.mouseCursorActive(true);
|
||||||
desktop.debugmode = debugmode;
|
desktop.debugmode = debugmode;
|
||||||
desktop.m.debugmode = debugmode;
|
desktop.m.debugmode = debugmode;
|
||||||
desktop.attemptWebRTC = attemptWebRTC;
|
desktop.attemptWebRTC = attemptWebRTC;
|
||||||
|
|
@ -1442,7 +1464,7 @@
|
||||||
QV('deskarea4', !fullscreen);
|
QV('deskarea4', !fullscreen);
|
||||||
QV('termarea1', !fullscreen);
|
QV('termarea1', !fullscreen);
|
||||||
QV('termarea4', !fullscreen);
|
QV('termarea4', !fullscreen);
|
||||||
var inputAllowed = !viewOnly;
|
var inputAllowed = (viewOnly == 0);
|
||||||
|
|
||||||
// Show full screen buttons if needed
|
// Show full screen buttons if needed
|
||||||
QV('deskkeybutton1', fullscreen);
|
QV('deskkeybutton1', fullscreen);
|
||||||
|
|
|
||||||
72
webserver.js
72
webserver.js
|
|
@ -2837,6 +2837,38 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
res.set('Content-Type', 'text/html');
|
res.set('Content-Type', 'text/html');
|
||||||
let url = domain.url;
|
let url = domain.url;
|
||||||
if (Object.keys(req.query).length > 0) { url += "?" + Object.keys(req.query).map(function(key) { return encodeURIComponent(key) + "=" + encodeURIComponent(req.query[key]); }).join("&"); }
|
if (Object.keys(req.query).length > 0) { url += "?" + Object.keys(req.query).map(function(key) { return encodeURIComponent(key) + "=" + encodeURIComponent(req.query[key]); }).join("&"); }
|
||||||
|
|
||||||
|
// check for relaystate is set, test against configured server name and accepted query params
|
||||||
|
if(req.body && req.body.RelayState !== undefined){
|
||||||
|
var relayState = decodeURIComponent(req.body.RelayState);
|
||||||
|
var serverName = (obj.getWebServerName(domain, req)).replaceAll('.','\\.');
|
||||||
|
|
||||||
|
var regexstr = `(?<=https:\\/\\/(?:.+?\\.)?${serverName}\\/?)` +
|
||||||
|
`.*((?<=([\\?&])gotodevicename=(.{64})|` +
|
||||||
|
`gotonode=(.{64})|` +
|
||||||
|
`gotodeviceip=(((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4})|` +
|
||||||
|
`gotodeviceip=(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::([0-9a-fA-F]{1,4}:){1,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:)` +
|
||||||
|
`lang=(.{5})|` +
|
||||||
|
`sitestyle=(\\d+)|` +
|
||||||
|
`user=(.{64})|` +
|
||||||
|
`pass=(.{256})|` +
|
||||||
|
`key=|` +
|
||||||
|
`locale=|` +
|
||||||
|
`gotomesh=(.{64})|` +
|
||||||
|
`gotouser=(.{0,64})|` +
|
||||||
|
`gotougrp=(.{64})|` +
|
||||||
|
`debug=|` +
|
||||||
|
`filter=|` +
|
||||||
|
`webrtc=|` +
|
||||||
|
`hide=|` +
|
||||||
|
`viewmode=(\\d+)(?=[\\&]|\\b)))`;
|
||||||
|
|
||||||
|
var regex = new RegExp(regexstr);
|
||||||
|
if(regex.test(relayState)){
|
||||||
|
url = relayState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.end('<html><head><meta http-equiv="refresh" content=0;url="' + url + '"></head><body></body></html>');
|
res.end('<html><head><meta http-equiv="refresh" content=0;url="' + url + '"></head><body></body></html>');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3116,12 +3148,12 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
// Fetch the web state
|
// Fetch the web state
|
||||||
parent.debug('web', 'handleRootRequestEx: success.');
|
parent.debug('web', 'handleRootRequestEx: success.');
|
||||||
|
|
||||||
var webstate = '';
|
var webstate = '{}';
|
||||||
if ((err == null) && (states != null) && (Array.isArray(states)) && (states.length == 1) && (states[0].state != null)) { webstate = obj.filterUserWebState(states[0].state); }
|
if ((err == null) && (states != null) && (Array.isArray(states)) && (states.length == 1) && (states[0].state != null)) { webstate = obj.filterUserWebState(states[0].state); }
|
||||||
if ((webstate == '') && (typeof domain.defaultuserwebstate == 'object')) { webstate = JSON.stringify(domain.defaultuserwebstate); } // User has no web state, use defaults.
|
if ((webstate == '{}') && (typeof domain.defaultuserwebstate == 'object')) { webstate = JSON.stringify(domain.defaultuserwebstate); } // User has no web state, use defaults.
|
||||||
if (typeof domain.forceduserwebstate == 'object') { // Forces initial user web state if present, use it.
|
if (typeof domain.forceduserwebstate == 'object') { // Forces initial user web state if present, use it.
|
||||||
var webstate2 = {};
|
var webstate2 = {};
|
||||||
try { if (webstate != '') { webstate2 = JSON.parse(webstate); } } catch (ex) { }
|
try { if (webstate != '{}') { webstate2 = JSON.parse(webstate); } } catch (ex) { }
|
||||||
for (var i in domain.forceduserwebstate) { webstate2[i] = domain.forceduserwebstate[i]; }
|
for (var i in domain.forceduserwebstate) { webstate2[i] = domain.forceduserwebstate[i]; }
|
||||||
webstate = JSON.stringify(webstate2);
|
webstate = JSON.stringify(webstate2);
|
||||||
}
|
}
|
||||||
|
|
@ -3152,8 +3184,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
if (obj.parent.config.settings && obj.parent.config.settings.webrtcconfig && (typeof obj.parent.config.settings.webrtcconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtcconfig)).replace(/'/g, '%27'); }
|
if (obj.parent.config.settings && obj.parent.config.settings.webrtcconfig && (typeof obj.parent.config.settings.webrtcconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtcconfig)).replace(/'/g, '%27'); }
|
||||||
else if (args.webrtcconfig && (typeof args.webrtcconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(args.webrtcconfig)).replace(/'/g, '%27'); }
|
else if (args.webrtcconfig && (typeof args.webrtcconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(args.webrtcconfig)).replace(/'/g, '%27'); }
|
||||||
|
|
||||||
|
// Load default page style or new modern ui
|
||||||
|
var uiViewMode = 'default';
|
||||||
|
var webstateJSON = JSON.parse(webstate);
|
||||||
|
if (webstateJSON && webstateJSON.uiViewMode == 3) { uiViewMode = 'default3'; }
|
||||||
|
if (domain.sitestyle == 3) { uiViewMode = 'default3'; }
|
||||||
|
if (req.query.sitestyle == 3) { uiViewMode = 'default3'; }
|
||||||
// Refresh the session
|
// Refresh the session
|
||||||
render(dbGetFunc.req, dbGetFunc.res, getRenderPage(((domain.sitestyle == 3) || (req.query.sitestyle == 3) ? 'default3' : 'default'), dbGetFunc.req, domain), getRenderArgs({
|
render(dbGetFunc.req, dbGetFunc.res, getRenderPage(uiViewMode, dbGetFunc.req, domain), getRenderArgs({
|
||||||
authCookie: authCookie,
|
authCookie: authCookie,
|
||||||
authRelayCookie: authRelayCookie,
|
authRelayCookie: authRelayCookie,
|
||||||
viewmode: viewmode,
|
viewmode: viewmode,
|
||||||
|
|
@ -3303,6 +3341,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
if (domain.scrolltotop == true) { features2 += 0x08000000; } // Show the "Scroll to top" button
|
if (domain.scrolltotop == true) { features2 += 0x08000000; } // Show the "Scroll to top" button
|
||||||
if (domain.devicesearchbargroupname === true) { features2 += 0x10000000; } // Search bar will find by group name too
|
if (domain.devicesearchbargroupname === true) { features2 += 0x10000000; } // Search bar will find by group name too
|
||||||
if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.duo2factor != false)) && (typeof domain.duo2factor == 'object') && (typeof domain.duo2factor.integrationkey == 'string') && (typeof domain.duo2factor.secretkey == 'string') && (typeof domain.duo2factor.apihostname == 'string')) { features2 += 0x20000000; } // using Duo for 2FA is allowed
|
if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.duo2factor != false)) && (typeof domain.duo2factor == 'object') && (typeof domain.duo2factor.integrationkey == 'string') && (typeof domain.duo2factor.secretkey == 'string') && (typeof domain.duo2factor.apihostname == 'string')) { features2 += 0x20000000; } // using Duo for 2FA is allowed
|
||||||
|
if (domain.showmodernuitoggle == true) { features2 += 0x40000000; } // Indicates that the new UI should be shown
|
||||||
return { features: features, features2: features2 };
|
return { features: features, features2: features2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4990,7 +5029,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
if (req.query.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
|
if (req.query.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
|
||||||
ws.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () {
|
ws.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () {
|
||||||
// The TLS connection method is the same as TCP, but located a bit differently.
|
// The TLS connection method is the same as TCP, but located a bit differently.
|
||||||
parent.debug('webrelay', 'TLS connected to ' + node.host + ':' + port + '.');
|
parent.debug('webrelay', user.name + ' - TLS connected to ' + node.host + ':' + port + '.');
|
||||||
ws.forwardclient.xstate = 1;
|
ws.forwardclient.xstate = 1;
|
||||||
ws._socket.resume();
|
ws._socket.resume();
|
||||||
});
|
});
|
||||||
|
|
@ -5003,7 +5042,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
ws.forwardclient.on('data', function (data) {
|
ws.forwardclient.on('data', function (data) {
|
||||||
if (typeof data == 'string') { data = Buffer.from(data, 'binary'); }
|
if (typeof data == 'string') { data = Buffer.from(data, 'binary'); }
|
||||||
if (obj.parent.debugLevel >= 1) { // DEBUG
|
if (obj.parent.debugLevel >= 1) { // DEBUG
|
||||||
parent.debug('webrelaydata', 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.');
|
parent.debug('webrelaydata', user.name + ' - TCP relay data from ' + node.host + ', ' + data.length + ' bytes.');
|
||||||
//if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + Buffer.from(data, 'binary').toString('hex')); }
|
//if (obj.parent.debugLevel >= 4) { Debug(4, ' ' + Buffer.from(data, 'binary').toString('hex')); }
|
||||||
}
|
}
|
||||||
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
|
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
|
||||||
|
|
@ -5018,13 +5057,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
|
|
||||||
// If the TCP connection closes, disconnect the associated web socket.
|
// If the TCP connection closes, disconnect the associated web socket.
|
||||||
ws.forwardclient.on('close', function () {
|
ws.forwardclient.on('close', function () {
|
||||||
parent.debug('webrelay', 'TCP relay disconnected from ' + node.host + ':' + port + '.');
|
parent.debug('webrelay', user.name + ' - TCP relay disconnected from ' + node.host + ':' + port + '.');
|
||||||
try { ws.close(); } catch (e) { }
|
try { ws.close(); } catch (e) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the TCP connection causes an error, disconnect the associated web socket.
|
// If the TCP connection causes an error, disconnect the associated web socket.
|
||||||
ws.forwardclient.on('error', function (err) {
|
ws.forwardclient.on('error', function (err) {
|
||||||
parent.debug('webrelay', 'TCP relay error from ' + node.host + ':' + port + ': ' + err);
|
parent.debug('webrelay', user.name + ' - TCP relay error from ' + node.host + ':' + port + ': ' + err);
|
||||||
try { ws.close(); } catch (e) { }
|
try { ws.close(); } catch (e) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -5035,7 +5074,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
if (node.intelamt.tls == 0) {
|
if (node.intelamt.tls == 0) {
|
||||||
// A TCP connection to Intel AMT just connected, start forwarding.
|
// A TCP connection to Intel AMT just connected, start forwarding.
|
||||||
ws.forwardclient.connect(port, node.host, function () {
|
ws.forwardclient.connect(port, node.host, function () {
|
||||||
parent.debug('webrelay', 'TCP relay connected to ' + node.host + ':' + port + '.');
|
parent.debug('webrelay', user.name + ' - TCP relay connected to ' + node.host + ':' + port + '.');
|
||||||
ws.forwardclient.xstate = 1;
|
ws.forwardclient.xstate = 1;
|
||||||
ws._socket.resume();
|
ws._socket.resume();
|
||||||
});
|
});
|
||||||
|
|
@ -6502,7 +6541,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
'Referrer-Policy': 'no-referrer',
|
'Referrer-Policy': 'no-referrer',
|
||||||
'X-XSS-Protection': '1; mode=block',
|
'X-XSS-Protection': '1; mode=block',
|
||||||
'X-Content-Type-Options': 'nosniff',
|
'X-Content-Type-Options': 'nosniff',
|
||||||
'Content-Security-Policy': "default-src 'none'; font-src 'self'; script-src 'self' 'unsafe-inline'" + extraScriptSrc + "; connect-src 'self'" + geourl + selfurl + "; img-src 'self' blob: data:" + geourl + " data:; style-src 'self' 'unsafe-inline'; frame-src 'self' blob: mcrouter:" + extraFrameSrc + "; media-src 'self'; form-action 'self'; manifest-src 'self'"
|
'Content-Security-Policy': "default-src 'none'; font-src 'self' fonts.gstatic.com data:; script-src 'self' 'unsafe-inline' " + extraScriptSrc + "; connect-src 'self'" + geourl + selfurl + "; img-src 'self' blob: data:" + geourl + " data:; style-src 'self' 'unsafe-inline' fonts.googleapis.com; frame-src 'self' blob: mcrouter:" + extraFrameSrc + "; media-src 'self'; form-action 'self'; manifest-src 'self'"
|
||||||
};
|
};
|
||||||
if (req.headers['user-agent'] && (req.headers['user-agent'].indexOf('Chrome') >= 0)) { headers['Permissions-Policy'] = 'interest-cohort=()'; } // Remove Google's FLoC Network, only send this if Chrome browser
|
if (req.headers['user-agent'] && (req.headers['user-agent'].indexOf('Chrome') >= 0)) { headers['Permissions-Policy'] = 'interest-cohort=()'; } // Remove Google's FLoC Network, only send this if Chrome browser
|
||||||
if ((parent.config.settings.allowframing !== true) && (typeof parent.config.settings.allowframing !== 'string')) { headers['X-Frame-Options'] = 'sameorigin'; }
|
if ((parent.config.settings.allowframing !== true) && (typeof parent.config.settings.allowframing !== 'string')) { headers['X-Frame-Options'] = 'sameorigin'; }
|
||||||
|
|
@ -6913,6 +6952,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
obj.app.get(url + 'auth-saml', function (req, res, next) {
|
obj.app.get(url + 'auth-saml', function (req, res, next) {
|
||||||
var domain = getDomain(req);
|
var domain = getDomain(req);
|
||||||
if (domain.passport == null) { next(); return; }
|
if (domain.passport == null) { next(); return; }
|
||||||
|
//set RelayState when queries are passed
|
||||||
|
if (Object.keys(req.query).length != 0){
|
||||||
|
req.query.RelayState = encodeURIComponent(`${req.protocol}://${req.hostname}${req.originalUrl}`.replace('auth-saml/',''))
|
||||||
|
}
|
||||||
domain.passport.authenticate('saml-' + domain.id, { failureRedirect: domain.url, failureFlash: true })(req, res, next);
|
domain.passport.authenticate('saml-' + domain.id, { failureRedirect: domain.url, failureFlash: true })(req, res, next);
|
||||||
});
|
});
|
||||||
obj.app.post(url + 'auth-saml-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) {
|
obj.app.post(url + 'auth-saml-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) {
|
||||||
|
|
@ -7049,7 +7092,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Login failed
|
// Login failed
|
||||||
handleRootRequestEx(req, res, domain, direct);
|
parent.debug('web', 'handleRootRequest: login authorization failed when returning from Duo 2FA.');
|
||||||
|
req.session.loginmode = 1;
|
||||||
|
res.redirect(domain.url + getQueryPortion(req)); // redirect back to main page
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -7804,7 +7850,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
|
|
||||||
async function getGroups(preset, tokenset) {
|
async function getGroups(preset, tokenset) {
|
||||||
let url = '';
|
let url = '';
|
||||||
if (preset == 'azure') { url = strategy.groups.recursive == true ? 'https://graph.microsoft.com/v1.0/me/transitiveMemberOf' : 'https://graph.microsoft.com/v1.0/me/memberOf'; }
|
if (preset == 'azure') { url = strategy.groups.recursive == true ? 'https://graph.microsoft.com/v1.0/me/transitiveMemberOf?$top=999' : 'https://graph.microsoft.com/v1.0/me/memberOf?$top=999'; }
|
||||||
if (preset == 'google') { url = strategy.custom.customer_id ? 'https://cloudidentity.googleapis.com/v1/groups?parent=customers/' + strategy.custom.customer_id : strategy.custom.identitysource ? 'https://cloudidentity.googleapis.com/v1/groups?parent=identitysources/' + strategy.custom.identitysource : null; }
|
if (preset == 'google') { url = strategy.custom.customer_id ? 'https://cloudidentity.googleapis.com/v1/groups?parent=customers/' + strategy.custom.customer_id : strategy.custom.identitysource ? 'https://cloudidentity.googleapis.com/v1/groups?parent=identitysources/' + strategy.custom.identitysource : null; }
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const options = {
|
const options = {
|
||||||
|
|
@ -9009,7 +9055,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter the user web site and only output state that we need to keep
|
// Filter the user web site and only output state that we need to keep
|
||||||
const acceptableUserWebStateStrings = ['webPageStackMenu', 'notifications', 'deviceView', 'nightMode', 'webPageFullScreen', 'search', 'showRealNames', 'sort', 'deskAspectRatio', 'viewsize', 'DeskControl', 'uiMode', 'footerBar','loctag','theme','lastThemes'];
|
const acceptableUserWebStateStrings = ['webPageStackMenu', 'notifications', 'deviceView', 'nightMode', 'webPageFullScreen', 'search', 'showRealNames', 'sort', 'deskAspectRatio', 'viewsize', 'DeskControl', 'uiMode', 'footerBar','loctag','theme','lastThemes','uiViewMode'];
|
||||||
const acceptableUserWebStateDesktopStrings = ['encoding', 'showfocus', 'showmouse', 'showcad', 'limitFrameRate', 'noMouseRotate', 'quality', 'scaling', 'agentencoding']
|
const acceptableUserWebStateDesktopStrings = ['encoding', 'showfocus', 'showmouse', 'showcad', 'limitFrameRate', 'noMouseRotate', 'quality', 'scaling', 'agentencoding']
|
||||||
obj.filterUserWebState = function (state) {
|
obj.filterUserWebState = function (state) {
|
||||||
if (typeof state == 'string') { try { state = JSON.parse(state); } catch (ex) { return null; } }
|
if (typeof state == 'string') { try { state = JSON.parse(state); } catch (ex) { return null; } }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue