Many server improvements, wildcard certs, local keyboard map, improved object cleanup, limited input mode.

This commit is contained in:
Ylian Saint-Hilaire 2019-03-09 14:28:08 -08:00
parent eb3977ee72
commit 92b9a9d5be
14 changed files with 707 additions and 593 deletions

View File

@ -34,6 +34,7 @@ var MESHRIGHT_REMOTEVIEW = 256;
var MESHRIGHT_NOTERMINAL = 512;
var MESHRIGHT_NOFILES = 1024;
var MESHRIGHT_NOAMT = 2048;
var MESHRIGHT_LIMITEDINPUT = 4096;
function createMeshCore(agent) {
var obj = {};
@ -772,12 +773,12 @@ function createMeshCore(agent) {
};
if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
//sendConsoleText('KVM Rights: ' + this.httprequest.rights);
if ((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) {
if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0))) {
// If we have remote control rights, pipe the KVM input
this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. Pipe the Browser --> KVM input.
} else {
// We need to only pipe non-mouse & non-keyboard inputs.
//sendConsoleText('Warning: No Remote Desktop Input Rights.');
// TODO!!!
}

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@
# Description: <DESCRIPTION>
### END INIT INFO
SCRIPT=/usr/local/mesh_services/meshagent/meshagent
SCRIPT=/usr/local/mesh/meshagent
RUNAS=root
PIDFILE=/var/run/meshagent.pid

View File

@ -171,6 +171,20 @@ module.exports.CertificateOperations = function (parent) {
return str.split('\r').join('\n'); // If there is no \n, replace all \r with \n.
}
// Return true if the name is found in the certificates names, we support wildcard certificates
function compareCertificateNames(certNames, name) {
if (certNames == null) return false;
if (certNames.indexOf(name.toLowerCase()) >= 0) return true;
for (var i in certNames) {
if ((certNames[i].startsWith('*.') == true) && (name.endsWith(certNames[i].substring(1)) == true)) { return true; }
if (certNames[i].startsWith('http://*.') == true) {
if (name.endsWith(certNames[i].substring(8)) == true) { return true; }
if ((certNames[i].endsWith('/') == true) && (name.endsWith(certNames[i].substring(8, certNames[i].length - 1)) == true)) { return true; }
}
}
return false;
}
// Returns the web server TLS certificate and private key, if not present, create demonstration ones.
obj.GetMeshServerCertificate = function (args, config, func) {
var i = 0;
@ -268,55 +282,66 @@ module.exports.CertificateOperations = function (parent) {
if (xxargs.length > 2) { mpsOrganization = xxargs[2]; }
}
if (rcount === rcountmax) {
// Fetch the certificates names for the main certificate
r.AmtMpsName = obj.pki.certificateFromPem(r.mps.cert).subject.getField("CN").value;
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
r.WebIssuer = webCertificate.issuer.getField("CN").value;
r.CommonName = webCertificate.subject.getField("CN").value;
if (r.CommonName.startsWith('*.')) {
if (commonName.indexOf('.') == -1) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
if (commonName.startsWith('*.')) { console.log("ERROR: Server can't use a wildcard name: " + commonName); process.exit(0); return; }
r.CommonName = commonName;
}
r.CommonNames = [r.CommonName.toLowerCase()];
var altNames = webCertificate.getExtension("subjectAltName");
if (altNames) { for (i = 0; i < altNames.altNames.length; i++) { r.CommonNames.push(altNames.altNames[i].value.toLowerCase()); } }
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
r.RootName = rootCertificate.subject.getField("CN").value;
}
// Look for domains that have DNS names and load their certificates
r.dns = {};
for (i in config.domains) {
if ((i != "") && (config.domains[i] != null) && (config.domains[i].dns != null)) {
dnsname = config.domains[i].dns;
if (args.tlsoffload) {
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
if (obj.fileExists("webserver-" + i + "-cert-public.crt")) {
r.dns[i] = { cert: obj.fileLoad("webserver-" + i + "-cert-public.crt", "utf8") };
config.domains[i].certs = r.dns[i];
} else {
console.log("WARNING: File \"webserver-" + i + "-cert-public.crt\" missing, domain \"" + i + "\" will not work correctly.");
}
// Check if this domain matches a parent wildcard cert, if so, use the parent cert.
if (compareCertificateNames(r.CommonNames, dnsname) == true) {
r.dns[i] = { cert: obj.fileLoad("webserver-cert-public.crt", "utf8"), key: obj.fileLoad("webserver-cert-private.key", "utf8") };
} else {
// If the web certificate already exist, load it. Load both certificate and private key
if (obj.fileExists("webserver-" + i + "-cert-public.crt") && obj.fileExists("webserver-" + i + "-cert-private.key")) {
r.dns[i] = { cert: obj.fileLoad("webserver-" + i + "-cert-public.crt", "utf8"), key: obj.fileLoad("webserver-" + i + "-cert-private.key", "utf8") };
config.domains[i].certs = r.dns[i];
// If CA certificates are present, load them
caindex = 1;
r.dns[i].ca = [];
do {
caok = false;
if (obj.fileExists("webserver-" + i + "-cert-chain" + caindex + ".crt")) {
r.dns[i].ca.push(obj.fileLoad("webserver-" + i + "-cert-chain" + caindex + ".crt", "utf8"));
caok = true;
}
caindex++;
} while (caok === true);
if (args.tlsoffload) {
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
if (obj.fileExists("webserver-" + i + "-cert-public.crt")) {
r.dns[i] = { cert: obj.fileLoad("webserver-" + i + "-cert-public.crt", "utf8") };
config.domains[i].certs = r.dns[i];
} else {
console.log("WARNING: File \"webserver-" + i + "-cert-public.crt\" missing, domain \"" + i + "\" will not work correctly.");
}
} else {
rcountmax++; // This certificate must be generated
// If the web certificate already exist, load it. Load both certificate and private key
if (obj.fileExists("webserver-" + i + "-cert-public.crt") && obj.fileExists("webserver-" + i + "-cert-private.key")) {
r.dns[i] = { cert: obj.fileLoad("webserver-" + i + "-cert-public.crt", "utf8"), key: obj.fileLoad("webserver-" + i + "-cert-private.key", "utf8") };
config.domains[i].certs = r.dns[i];
// If CA certificates are present, load them
caindex = 1;
r.dns[i].ca = [];
do {
caok = false;
if (obj.fileExists("webserver-" + i + "-cert-chain" + caindex + ".crt")) {
r.dns[i].ca.push(obj.fileLoad("webserver-" + i + "-cert-chain" + caindex + ".crt", "utf8"));
caok = true;
}
caindex++;
} while (caok === true);
} else {
rcountmax++; // This certificate must be generated
}
}
}
}
}
if (rcount === rcountmax) {
// Fetch the Intel AMT MPS common name
r.AmtMpsName = obj.pki.certificateFromPem(r.mps.cert).subject.getField("CN").value;
// Fetch the name of the server
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
r.WebIssuer = webCertificate.issuer.getField("CN").value;
r.CommonName = webCertificate.subject.getField("CN").value;
r.CommonNames = [r.CommonName.toLowerCase()];
var altNames = webCertificate.getExtension("subjectAltName");
if (altNames) { for (i = 0; i < altNames.altNames.length; i++) { r.CommonNames.push(altNames.altNames[i].value.toLowerCase()); } }
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
r.RootName = rootCertificate.subject.getField("CN").value;
if ((certargs == null) && (mpscertargs == null)) { if (func != undefined) { func(r); } return r; } // If no certificate arguments are given, keep the certificate
var xcountry, xcountryField = webCertificate.subject.getField("C");
if (xcountryField != null) { xcountry = xcountryField.value; }
@ -325,14 +350,13 @@ module.exports.CertificateOperations = function (parent) {
if (certargs == null) { commonName = r.CommonName; country = xcountry; organization = xorganization; }
// Check if we have correct certificates
if ((r.CommonNames.indexOf(commonName.toLowerCase()) >= 0) && (r.AmtMpsName == mpsCommonName)) {
// Certificate matches what we want, keep it.
if (compareCertificateNames(r.CommonNames, commonName) == false) { forceWebCertGen = 1; }
if (r.AmtMpsName != mpsCommonName) { forceMpsCertGen = 1; }
// If the certificates matches what we want, use them.
if ((forceWebCertGen == 0) && (forceMpsCertGen == 0)) {
if (func !== undefined) { func(r); }
return r;
} else {
// Check what certificates we really need to re-generate.
if ((r.CommonNames.indexOf(commonName.toLowerCase()) < 0)) { forceWebCertGen = 1; }
if (r.AmtMpsName != mpsCommonName) { forceMpsCertGen = 1; }
}
}
if (parent.configurationFiles != null) { console.log("Error: Database missing some certificates."); process.exit(0); return null; }
@ -418,33 +442,53 @@ module.exports.CertificateOperations = function (parent) {
r = { root: { cert: rootCertificate, key: rootPrivateKey }, web: { cert: webCertificate, key: webPrivateKey, ca: [] }, mps: { cert: mpsCertificate, key: mpsPrivateKey }, agent: { cert: agentCertificate, key: agentPrivateKey }, ca: calist, CommonName: commonName, RootName: rootName, AmtMpsName: mpsCommonName, dns: {}, WebIssuer: webIssuer };
// Fetch the certificates names for the main certificate
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
r.WebIssuer = webCertificate.issuer.getField("CN").value;
r.CommonName = webCertificate.subject.getField("CN").value;
if (r.CommonName.startsWith('*.')) {
if (commonName.indexOf('.') == -1) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
if (commonName.startsWith('*.')) { console.log("ERROR: Server can't use a wildcard name: " + commonName); process.exit(0); return; }
r.CommonName = commonName;
}
r.CommonNames = [r.CommonName.toLowerCase()];
var altNames = webCertificate.getExtension("subjectAltName");
if (altNames) { for (i = 0; i < altNames.altNames.length; i++) { r.CommonNames.push(altNames.altNames[i].value.toLowerCase()); } }
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
r.RootName = rootCertificate.subject.getField("CN").value;
// Look for domains with DNS names that have no certificates and generated them.
for (i in config.domains) {
if ((i != "") && (config.domains[i] != null) && (config.domains[i].dns != null)) {
dnsname = config.domains[i].dns;
if (!args.tlsoffload) {
// If the web certificate does not exist, create it
if ((obj.fileExists("webserver-" + i + "-cert-public.crt") === false) || (obj.fileExists("webserver-" + i + "-cert-private.key") === false)) {
console.log("Generating HTTPS certificate for " + i + "...");
var xwebCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, dnsname, country, organization, null, strongCertificate);
var xwebCertificate = obj.pki.certificateToPem(xwebCertAndKey.cert);
var xwebPrivateKey = obj.pki.privateKeyToPem(xwebCertAndKey.key);
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt"), xwebCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-private.key"), xwebPrivateKey);
r.dns[i] = { cert: xwebCertificate, key: xwebPrivateKey };
config.domains[i].certs = r.dns[i];
// Check if this domain matches a parent wildcard cert, if so, use the parent cert.
if (compareCertificateNames(r.CommonNames, dnsname) == true) {
r.dns[i] = { cert: obj.fileLoad("webserver-cert-public.crt", "utf8"), key: obj.fileLoad("webserver-cert-private.key", "utf8") };
} else {
if (!args.tlsoffload) {
// If the web certificate does not exist, create it
if ((obj.fileExists("webserver-" + i + "-cert-public.crt") === false) || (obj.fileExists("webserver-" + i + "-cert-private.key") === false)) {
console.log("Generating HTTPS certificate for " + i + "...");
var xwebCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, dnsname, country, organization, null, strongCertificate);
var xwebCertificate = obj.pki.certificateToPem(xwebCertAndKey.cert);
var xwebPrivateKey = obj.pki.privateKeyToPem(xwebCertAndKey.key);
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt"), xwebCertificate);
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-private.key"), xwebPrivateKey);
r.dns[i] = { cert: xwebCertificate, key: xwebPrivateKey };
config.domains[i].certs = r.dns[i];
// If CA certificates are present, load them
caindex = 1;
r.dns[i].ca = [];
do {
caok = false;
if (obj.fileExists("webserver-" + i + "-cert-chain" + caindex + ".crt")) {
r.dns[i].ca.push(fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-chain" + caindex + ".crt"), "utf8")));
caok = true;
}
caindex++;
} while (caok === true);
// If CA certificates are present, load them
caindex = 1;
r.dns[i].ca = [];
do {
caok = false;
if (obj.fileExists("webserver-" + i + "-cert-chain" + caindex + ".crt")) {
r.dns[i].ca.push(fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-chain" + caindex + ".crt"), "utf8")));
caok = true;
}
caindex++;
} while (caok === true);
}
}
}
}

View File

@ -18,7 +18,7 @@
module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
const forge = parent.parent.certificateOperations.forge;
const common = parent.parent.common;
const agentUpdateBlockSize = 65520;
const agentUpdateBlockSize = 65531;
var obj = {};
obj.domain = domain;
@ -45,6 +45,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if ((arg == 1) || (arg == null)) { try { ws.close(); if (obj.nodeid != null) { parent.parent.debug(1, 'Soft disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } // Soft close, close the websocket
if (arg == 2) { try { ws._socket._parent.end(); if (obj.nodeid != null) { parent.parent.debug(1, 'Hard disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } // Hard close, close the TCP socket
// If arg == 3, don't communicate with this agent anymore, but don't disconnect (Duplicate agent).
// Remove this agent from the webserver list
if (parent.wsagents[obj.dbNodeKey] == obj) {
delete parent.wsagents[obj.dbNodeKey];
parent.parent.ClearConnectivityState(obj.dbMeshKey, obj.dbNodeKey, 1);
@ -53,14 +55,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Get the current mesh
const mesh = parent.meshes[obj.dbMeshKey];
// Other clean up may be needed here
if (obj.unauth) { delete obj.unauth; }
if (obj.agentUpdate != null) {
if (obj.agentUpdate.fd) { try { parent.fs.close(obj.agentUpdate.fd); } catch (ex) { } }
parent.parent.taskLimiter.completed(obj.agentUpdate.taskid); // Indicate this task complete
delete obj.agentUpdate;
}
// If this is a temporary or recovery agent, or all devices in this group are temporary, remove the agent (0x20 = Temporary, 0x40 = Recovery)
if (((obj.agentInfo) && (obj.agentInfo.capabilities) && ((obj.agentInfo.capabilities & 0x20) || (obj.agentInfo.capabilities & 0x40))) || ((mesh) && (mesh.flags) && (mesh.flags & 1))) {
// Delete this node including network interface information and events
@ -85,7 +79,26 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Update the last connect time
if (obj.authenticated == 2) { db.Set({ _id: 'lc' + obj.dbNodeKey, type: 'lastconnect', domain: domain.id, time: obj.connectTime, addr: obj.remoteaddrport }); }
}
delete obj.nodeid;
// If we where updating the agent, clean that up.
if (obj.agentUpdate != null) {
if (obj.agentUpdate.fd) { try { parent.fs.close(obj.agentUpdate.fd); } catch (ex) { } }
parent.parent.taskLimiter.completed(obj.agentUpdate.taskid); // Indicate this task complete
delete obj.agentUpdate;
}
// Perform aggressive cleanup
if (obj.nonce) { delete obj.nonce; }
if (obj.nodeid) { delete obj.nodeid; }
if (obj.unauth) { delete obj.unauth; }
if (obj.remoteaddr) { delete obj.remoteaddr; }
if (obj.remoteaddrport) { delete obj.remoteaddrport; }
if (obj.meshid) { delete obj.meshid; }
if (obj.dbNodeKey) { delete obj.dbNodeKey; }
if (obj.dbMeshKey) { delete obj.dbMeshKey; }
if (obj.connectTime) { delete obj.connectTime; }
if (obj.agentInfo) { delete obj.agentInfo; }
ws.removeAllListeners(["message", "close", "error"]);
};
// When data is received from the mesh agent web socket
@ -112,7 +125,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
const agentMeshCoreHash = (msg.length == 52) ? msg.substring(4, 52) : null;
// If the agent indicates this is a custom core, we are done.
if ((agentMeshCoreHash != null) && (agentMeshCoreHash == '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0')) {
if ((agentMeshCoreHash != null) && (agentMeshCoreHash == '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0')) {
obj.agentCoreCheck = 0;
obj.send(common.ShortToStr(16) + common.ShortToStr(0)); // MeshCommand_CoreOk. Indicates to the agent that the core is ok. Start it if it's not already started.
agentCoreIsStable();
@ -197,7 +210,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
else if (cmdid == 12) { // MeshCommand_AgentHash
if ((msg.length == 52) && (obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) {
const agenthash = msg.substring(4);
if ((agenthash != obj.agentExeInfo.hash) && (agenthash != '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0')) {
if ((agenthash != obj.agentExeInfo.hash) && (agenthash != '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0')) {
// Mesh agent update required, do it using task limiter so not to flood the network. Medium priority task.
parent.parent.taskLimiter.launch(function (argument, taskid, taskLimiterQueue) {
if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; } // If agent disconnection, complete and exit now.
@ -353,13 +366,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Perform the hash signature using older swarm server certificate
parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, obj, function (obj2, signature) {
// Send back our certificate + signature
obj2.send(common.ShortToStr(2) + common.ShortToStr(obj2.parent.swarmCertificateAsn1.length) + obj2.parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature
obj2.send(common.ShortToStr(2) + common.ShortToStr(parent.swarmCertificateAsn1.length) + parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature
});
} else {
// Perform the hash signature using the server agent certificate
parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, obj, function (obj2, signature) {
// Send back our certificate + signature
obj2.send(common.ShortToStr(2) + common.ShortToStr(obj2.parent.agentCertificateAsn1.length) + obj2.parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature
obj2.send(common.ShortToStr(2) + common.ShortToStr(parent.agentCertificateAsn1.length) + parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature
});
}
}
@ -419,7 +432,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
});
// If error, do nothing
ws.on('error', function (err) { console.log('AGENT WSERR: ' + err); });
ws.on('error', function (err) { console.log('AGENT WSERR: ' + err); obj.close(0); });
// If the mesh agent web socket is closed, clean up.
ws.on('close', function (req) {
@ -703,7 +716,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
console.log('recoveryAgentCoreIsStable()');
// Close the recovery agent connection when done.
obj.close(1);
//obj.close(1);
}
obj.sendUpdatedIntelAmtPolicy = function() {

View File

@ -60,7 +60,7 @@ function CreateMeshCentralServer(config, args) {
obj.serverKey = Buffer.from(obj.crypto.randomBytes(48), 'binary');
obj.loginCookieEncryptionKey = null;
obj.serverSelfWriteAllowed = true;
obj.taskLimiter = obj.common.createTaskLimiterQueue(20, 20, 60); // This is a task limiter queue to smooth out server work.
obj.taskLimiter = obj.common.createTaskLimiterQueue(50, 20, 60); // (maxTasks, maxTaskTime, cleaningInterval) This is a task limiter queue to smooth out server work.
try { obj.currentVer = JSON.parse(obj.fs.readFileSync(obj.path.join(__dirname, 'package.json'), 'utf8')).version; } catch (e) { } // Fetch server version
// Setup the default configuration and files paths
@ -877,7 +877,7 @@ function CreateMeshCentralServer(config, args) {
};
obj.RemoveEventDispatch = function (ids, target) {
obj.debug(3, 'RemoveEventDispatch', id);
for (var i in ids) { var id = ids[i]; if (obj.eventsDispatch[id]) { var j = obj.eventsDispatch[id].indexOf(target); if (j >= 0) { obj.eventsDispatch[id].splice(j, 1); } } }
for (var i in ids) { var id = ids[i]; if (obj.eventsDispatch[id]) { var j = obj.eventsDispatch[id].indexOf(target); if (j >= 0) { if (obj.eventsDispatch[id].length == 1) { delete obj.eventsDispatch[id]; } else { obj.eventsDispatch[id].splice(j, 1); } } } }
};
obj.RemoveEventDispatchId = function (id) {
obj.debug(3, 'RemoveEventDispatchId', id);
@ -885,7 +885,7 @@ function CreateMeshCentralServer(config, args) {
};
obj.RemoveAllEventDispatch = function (target) {
obj.debug(3, 'RemoveAllEventDispatch');
for (var i in obj.eventsDispatch) { var j = obj.eventsDispatch[i].indexOf(target); if (j >= 0) { obj.eventsDispatch[i].splice(j, 1); } }
for (var i in obj.eventsDispatch) { var j = obj.eventsDispatch[i].indexOf(target); if (j >= 0) { if (obj.eventsDispatch[i].length == 1) { delete obj.eventsDispatch[i]; } else { obj.eventsDispatch[i].splice(j, 1); } } }
};
obj.DispatchEvent = function (ids, source, event, fromPeerServer) {
// If the database is not setup, exit now.
@ -1148,9 +1148,9 @@ function CreateMeshCentralServer(config, args) {
// Read meshcore.js and all .js files in the modules folder.
var meshCore = null, modulesDir = null;
const modulesAdd = {
'windows-amt': 'var addedModules = [];\r\n',
'linux-amt': 'var addedModules = [];\r\n',
'linux-noamt': 'var addedModules = [];\r\n'
'windows-amt': ['var addedModules = [];\r\n'],
'linux-amt': ['var addedModules = [];\r\n'],
'linux-noamt': ['var addedModules = [];\r\n']
};
// Read the recovery core if present
@ -1158,8 +1158,8 @@ function CreateMeshCentralServer(config, args) {
if (obj.fs.existsSync(obj.path.join(__dirname, 'agents', 'recoverycore.js')) == true) {
try { meshRecoveryCore = obj.fs.readFileSync(obj.path.join(__dirname, 'agents', 'recoverycore.js')).toString(); } catch (ex) { }
if (meshRecoveryCore != null) {
modulesAdd['windows-recovery'] = 'var addedModules = [];\r\n';
modulesAdd['linux-recovery'] = 'var addedModules = [];\r\n';
modulesAdd['windows-recovery'] = ['var addedModules = [];\r\n'];
modulesAdd['linux-recovery'] = ['var addedModules = [];\r\n'];
}
}
@ -1168,8 +1168,8 @@ function CreateMeshCentralServer(config, args) {
if (obj.fs.existsSync(obj.path.join(__dirname, 'agents', 'agentrecoverycore.js')) == true) {
try { meshAgentRecoveryCore = obj.fs.readFileSync(obj.path.join(__dirname, 'agents', 'agentrecoverycore.js')).toString(); } catch (ex) { }
if (meshAgentRecoveryCore != null) {
modulesAdd['windows-agentrecovery'] = 'var addedModules = [];\r\n';
modulesAdd['linux-agentrecovery'] = 'var addedModules = [];\r\n';
modulesAdd['windows-agentrecovery'] = ['var addedModules = [];\r\n'];
modulesAdd['linux-agentrecovery'] = ['var addedModules = [];\r\n'];
}
}
@ -1184,39 +1184,39 @@ function CreateMeshCentralServer(config, args) {
if (modulesDir[i].toLowerCase().endsWith('.js')) {
var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3);
if (moduleName.endsWith('.min')) { moduleName = moduleName.substring(0, moduleName.length - 4); } // Remove the ".min" for ".min.js" files.
var moduleData = 'try { addModule("' + moduleName + '", "' + obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')) + '"); addedModules.push("' + moduleName + '"); } catch (e) { }\r\n';
var moduleData = [ 'try { addModule("', moduleName, '", "', obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')), '"); addedModules.push("', moduleName, '"); } catch (e) { }\r\n' ];
// Merge this module
// NOTE: "smbios" module makes some non-AI Linux segfault, only include for IA platforms.
if (moduleName.startsWith('amt-') || (moduleName == 'smbios')) {
// Add to IA / Intel AMT cores only
modulesAdd['windows-amt'] += moduleData;
modulesAdd['linux-amt'] += moduleData;
modulesAdd['windows-amt'].push(...moduleData);
modulesAdd['linux-amt'].push(...moduleData);
} else if (moduleName.startsWith('win-')) {
// Add to Windows cores only
modulesAdd['windows-amt'] += moduleData;
modulesAdd['windows-amt'].push(...moduleData);
} else if (moduleName.startsWith('linux-')) {
// Add to Linux cores only
modulesAdd['linux-amt'] += moduleData;
modulesAdd['linux-noamt'] += moduleData;
modulesAdd['linux-amt'].push(...moduleData);
modulesAdd['linux-noamt'].push(...moduleData);
} else {
// Add to all cores
modulesAdd['windows-amt'] += moduleData;
modulesAdd['linux-amt'] += moduleData;
modulesAdd['linux-noamt'] += moduleData;
modulesAdd['windows-amt'].push(...moduleData);
modulesAdd['linux-amt'].push(...moduleData);
modulesAdd['linux-noamt'].push(...moduleData);
}
// Merge this module to recovery modules if needed
if (modulesAdd['windows-recovery'] != null) {
if ((moduleName == 'win-console') || (moduleName == 'win-message-pump') || (moduleName == 'win-terminal')) {
modulesAdd['windows-recovery'] += moduleData;
modulesAdd['windows-recovery'].push(...moduleData);
}
}
// Merge this module to agent recovery modules if needed
if (modulesAdd['windows-agentrecovery'] != null) {
if ((moduleName == 'win-console') || (moduleName == 'win-message-pump') || (moduleName == 'win-terminal')) {
modulesAdd['windows-agentrecovery'] += moduleData;
modulesAdd['windows-agentrecovery'].push(...moduleData);
}
}
}
@ -1226,11 +1226,11 @@ function CreateMeshCentralServer(config, args) {
// Merge the cores and compute the hashes
for (var i in modulesAdd) {
if ((i == 'windows-recovery') || (i == 'linux-recovery')) {
obj.defaultMeshCores[i] = obj.common.IntToStr(0) + modulesAdd[i] + meshRecoveryCore;
obj.defaultMeshCores[i] = [obj.common.IntToStr(0), ...modulesAdd[i], meshRecoveryCore].join('');
} else if ((i == 'windows-agentrecovery') || (i == 'linux-agentrecovery')) {
obj.defaultMeshCores[i] = obj.common.IntToStr(0) + modulesAdd[i] + meshAgentRecoveryCore;
obj.defaultMeshCores[i] = [obj.common.IntToStr(0), ...modulesAdd[i], meshAgentRecoveryCore].join('');
} else {
obj.defaultMeshCores[i] = obj.common.IntToStr(0) + modulesAdd[i] + meshCore;
obj.defaultMeshCores[i] = [obj.common.IntToStr(0), ...modulesAdd[i], meshCore].join('');
}
obj.defaultMeshCoresHash[i] = obj.crypto.createHash('sha384').update(obj.defaultMeshCores[i]).digest("binary");
obj.debug(1, 'Core module ' + i + ' is ' + obj.defaultMeshCores[i].length + ' bytes.');
@ -1247,7 +1247,7 @@ function CreateMeshCentralServer(config, args) {
obj.updateMeshCmdTimer = 'notset';
obj.updateMeshCmd = function (func) {
// Figure out where meshcmd.js is and read it.
var meshCmd = null, meshcmdPath, moduleAdditions = 'var addedModules = [];\r\n', moduleDirPath, modulesDir = null;
var meshCmd = null, meshcmdPath, moduleAdditions = ['var addedModules = [];\r\n'], moduleDirPath, modulesDir = null;
if ((obj.args.minifycore !== false) && (obj.fs.existsSync(obj.path.join(obj.datapath, 'meshcmd.min.js')))) { meshcmdPath = obj.path.join(obj.datapath, 'meshcmd.min.js'); meshCmd = obj.fs.readFileSync(meshcmdPath).toString(); }
else if (obj.fs.existsSync(obj.path.join(obj.datapath, 'meshcmd.js'))) { meshcmdPath = obj.path.join(obj.datapath, 'meshcmd.js'); meshCmd = obj.fs.readFileSync(meshcmdPath).toString(); }
else if ((obj.args.minifycore !== false) && (obj.fs.existsSync(obj.path.join(__dirname, 'agents', 'meshcmd.min.js')))) { meshcmdPath = obj.path.join(__dirname, 'agents', 'meshcmd.min.js'); meshCmd = obj.fs.readFileSync(meshcmdPath).toString(); }
@ -1268,13 +1268,14 @@ function CreateMeshCentralServer(config, args) {
// Merge this module
var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3);
if (moduleName.endsWith('.min')) { moduleName = moduleName.substring(0, moduleName.length - 4); } // Remove the ".min" for ".min.js" files.
moduleAdditions += 'try { addModule("' + moduleName + '", "' + obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')) + '"); addedModules.push("' + moduleName + '"); } catch (e) { }\r\n';
moduleAdditions.push('try { addModule("', moduleName, '", "', obj.escapeCodeString(obj.fs.readFileSync(obj.path.join(moduleDirPath, modulesDir[i])).toString('binary')), '"); addedModules.push("', moduleName, '"); } catch (e) { }\r\n');
}
}
}
// Set the new default meshcmd.js
obj.defaultMeshCmd = moduleAdditions + meshCmd;
moduleAdditions.push(meshCmd);
obj.defaultMeshCmd = moduleAdditions.join('');
//console.log('MeshCmd is ' + obj.defaultMeshCmd.length + ' bytes.'); // DEBUG, Print the merged meshcmd.js size
//obj.fs.writeFile("C:\\temp\\meshcmd.js", obj.defaultMeshCmd.substring(4)); // DEBUG, Write merged meshcmd.js to file
if (func != null) { func(true); }
@ -1284,7 +1285,7 @@ function CreateMeshCentralServer(config, args) {
obj.updateMeshCmdTimer = null;
obj.fs.watch(meshcmdPath, function (eventType, filename) {
if (obj.updateMeshCmdTimer != null) { clearTimeout(obj.updateMeshCmdTimer); obj.updateMeshCmdTimer = null; }
obj.updateMeshCmdTimer = setTimeout(function () { obj.updateMeshCmd(); /*console.log('Updated meshcmd.js.');*/ }, 5000);
obj.updateMeshCmdTimer = setTimeout(function () { obj.updateMeshCmd(); }, 5000);
});
}
};

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.2.9-w",
"version": "0.2.9-z",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -31,6 +31,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
obj.debugmode = 0;
obj.firstUpKeys = [];
obj.stopInput = false;
obj.localKeyMap = true;
obj.sessionid = 0;
obj.username;
@ -377,7 +378,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
obj.SendKeyMsg = function (action, event) {
if (action == null) return;
if (!event) { event = window.event; }
if (event.code) {
if (event.code && (obj.localKeyMap == false)) {
// Convert "event.code" into a scancode. This works the same regardless of the keyboard language.
// Older browsers will not support this.
var kc = convertKeyCode(event);

View File

@ -24,6 +24,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.useZRLE = true;
obj.showmouse = true;
obj.buttonmask = 0;
obj.localKeyMap = true;
//obj.inbytes = 0;
//obj.outbytes = 0;
obj.spare = null;
@ -634,7 +635,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
function _keyevent(d, e) {
if (!e) { e = window.event; }
if (e.code) {
if (e.code && (obj.localKeyMap == false)) {
// For new browsers, this mapping is keyboard language independent
var k = convertAmtKeyCode(e);
if (k != null) { obj.sendkey(k, d); }

View File

@ -311,8 +311,7 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
if (checkSwarmIpAddress(socket, obj.args.swarmallowedip) == false) { obj.stats.blockedConnect++; Debug(1, "SWARM:New blocked agent connection"); return; }
obj.stats.connectCount++;
socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", socket: socket };
//socket.pingTimer = setInterval(function () { obj.SendCommand(socket, LegacyMeshProtocol.PING); }, 20000);
socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "" };
Debug(1, 'SWARM:New legacy agent connection');
if ((socket.tag.clientCert == null) || (socket.tag.clientCert.subject == null)) { obj.stats.noCertConnectCount++; } else { obj.stats.clientCertConnectCount++; }
@ -321,12 +320,20 @@ module.exports.CreateSwarmServer = function (parent, db, args, certificates) {
socket.addListener("close", function () {
obj.stats.onclose++;
Debug(1, 'Swarm:Connection closed');
if (this.relaySocket) { try { this.relaySocket.end(); delete this.relaySocket; } catch (ex) { } }
// Perform aggressive cleanup
if (this.relaySocket) { try { this.relaySocket.end(); this.relaySocket.removeAllListeners(["data", "end", "error"]); delete this.relaySocket; } catch (ex) { } }
if (this.pingTimer != null) { clearInterval(this.pingTimer); delete this.pingTimer; }
if (this.tag && (typeof this.tag.taskid == 'number')) {
obj.parent.taskLimiter.completed(this.tag.taskid); // Indicate this task complete
delete this.tag.taskid;
}
if (this.tag) {
if (this.tag.accumulator) { delete this.tag.accumulator; }
if (this.tag.clientCert) { delete this.tag.clientCert; }
delete this.tag;
}
this.removeAllListeners([ "data", "close", "error" ]);
});
socket.addListener("error", function () {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -795,6 +795,7 @@
</div>
</div>
<div id=dialog7 style="margin:auto;margin:3px">
<div id="d7meshkvm">
<h4 style="width:100%;border-bottom:1px solid gray">Agent Remote Desktop</h4>
<div style="margin:3px 0 3px 0">
@ -839,6 +840,7 @@
<div style="float:right;border:1px solid #666;width:200px;height:60px;overflow-y:scroll;background-color:white">
<label><input type="checkbox" id='d7showfocus'>Show Focus Tool<br></label>
<label><input type="checkbox" id='d7showcursor'>Show Local Mouse Cursor<br></label>
<label><input type="checkbox" id='d7localKeyMap'>Local Keyboard Map<br></label>
</div>
<div>Other Settings</div>
</div>
@ -881,7 +883,7 @@
var wssessions = null;
var nodeShortIdent = 0;
var desktop;
var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50 };
var desktopsettings = { encoding: 2, showfocus: false, showmouse: true, showcad: true, quality: 40, scaling: 1024, framerate: 50, localkeymap: false };
var multidesktopsettings = { quality: 20, scaling: 128, framerate: 1000 };
var terminal;
var files;
@ -1860,7 +1862,18 @@
}
function ondockeypress(e) {
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) return desktop.m.handleKeys(e);
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
// Check what keys we are allows to send
if (currentNode != null) {
var mesh = meshes[currentNode.meshid];
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
if (inputAllowed == false) return false;
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || (e.keyCode < 32) || (e.keyCode > 90)) return false; }
}
return desktop.m.handleKeys(e);
}
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeys(e);
if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) return agentConsoleHandleKeys(e);
if (!xxdialogMode && xxcurrentView == 4) {
@ -1908,7 +1921,18 @@
}
function ondockeydown(e) {
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) { return desktop.m.handleKeyDown(e); }
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
// Check what keys we are allows to send
if (currentNode != null) {
var mesh = meshes[currentNode.meshid];
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
if (inputAllowed == false) return false;
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || (e.keyCode < 32) || (e.keyCode > 90)) return false; }
}
return desktop.m.handleKeyDown(e);
}
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) { return terminal.m.TermHandleKeyDown(e); }
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { haltEvent(e); return false; } // F5 Refresh on files
if (!xxdialogMode && ((xxcurrentView == 15) || (xxcurrentView == 115))) { return agentConsoleHandleKeys(e); }
@ -1931,7 +1955,18 @@
}
function ondockeyup(e) {
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) return desktop.m.handleKeyUp(e);
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q("DeskControl").checked) {
// Check what keys we are allows to send
if (currentNode != null) {
var mesh = meshes[currentNode.meshid];
var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
if (inputAllowed == false) return false;
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
if (limitedInputAllowed == true) { if ((e.altKey == true) || (e.ctrlKey == true) || (e.keyCode < 32) || (e.keyCode > 90)) return false; }
}
return desktop.m.handleKeyUp(e);
}
if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyUp(e);
if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
if (!xxdialogMode && xxcurrentView == 4) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
@ -4080,26 +4115,27 @@
QV('d7meshkvm', (webRtcDesktop) || ((mesh.mtype == 2) && (currentNode.agent.caps & 1) && ((deskState == false) || (desktop.contype == 1))));
// Enable buttons
var inputAllowed = (meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) == 0));
var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
QE('connectbutton1', online);
var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
QE('connectbutton1h', hwonline);
QE('deskSaveBtn', deskState == 3);
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
QV('DeskCAD', meshrights & 8);
QV('DeskCAD', inputAllowed);
QE('DeskCAD', deskState == 3);
QE('DeskClip', deskState == 3);
QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5) && inputAllowed);
QE('DeskWD', deskState == 3);
QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5) && inputAllowed);
QE('deskkeys', deskState == 3);
QV('DeskToolsButton', (meshrights & 8) && (mesh.mtype == 2) && online);
QV('DeskChatButton', (browserfullscreen == false) && (meshrights & 8) && (mesh.mtype == 2) && online);
QV('DeskNotifyButton', (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8) && (mesh.mtype == 2) && online);
QV('DeskOpenWebButton', (browserfullscreen == false) && (meshrights & 8) && (mesh.mtype == 2) && online);
QV('DeskToolsButton', (inputAllowed) && (mesh.mtype == 2) && online);
QV('DeskChatButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
QV('DeskNotifyButton', (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (mesh.mtype == 2) && online);
QV('DeskOpenWebButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
QV('DeskControlSpan', meshrights & 8)
QV('DeskControlSpan', inputAllowed)
QV('deskActionsBtn', (browserfullscreen == false));
QV('deskActionsSettings', (browserfullscreen == false));
if (meshrights & 8) { Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); } else { Q('DeskControl').checked = false; }
@ -4121,6 +4157,7 @@
desktop.onStateChanged = onDesktopStateChange;
desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2;
desktop.m.useZRLE = (desktopsettings.encoding < 3);
desktop.m.localKeyMap = desktopsettings.localkeymap;
desktop.m.showmouse = desktopsettings.showmouse;
desktop.m.onScreenSizeChange = deskAdjust;
desktop.m.onKvmData = function (x) {
@ -4285,11 +4322,14 @@
desktopsettings.quality = d7bitmapquality.value;
desktopsettings.scaling = d7bitmapscaling.value;
desktopsettings.framerate = d7framelimiter.value;
desktopsettings.localkeymap = d7localKeyMap.checked;
localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
applyDesktopSettings();
if (desktop) {
if (desktop.contype == 1) {
if (desktop.State != 0) { desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate); }
if (desktop.State != 0) {
desktop.m.SendCompressionLevel(1, desktopsettings.quality, desktopsettings.scaling, desktopsettings.framerate);
}
}
if (desktop.contype == 2) {
if (desktopsettings.showfocus == false) { desktop.m.focusmode = 0; deskFocusBtn.value = 'All Focus'; }
@ -4309,6 +4349,7 @@
if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
d7bitmapscaling.value = desktopsettings.scaling;
if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; }
if (desktopsettings.localkeymap) { d7localKeyMap.checked = desktopsettings.localkeymap; }
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (desktop.state != 0) && (desktopsettings.showfocus));
}
@ -5958,6 +5999,7 @@
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20managecomputers>Manage Device Group Computers<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotecontrol>Remote Control<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remoteview style=margin-left:12px>Remote View Only<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotelimitedinput style=margin-left:12px>Limited Input Only<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noterminal style=margin-left:12px>No Terminal Access<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20nofiles style=margin-left:12px>No File Access<br>';
x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noamt style=margin-left:12px>No Intel&reg; AMT<br>';
@ -5984,6 +6026,7 @@
QE('p20wakedevices', !Q('p20fulladmin').checked);
QE('p20editnotes', !Q('p20fulladmin').checked);
QE('p20remoteview', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
QE('p20remotelimitedinput', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked && !Q('p20remoteview').checked);
QE('p20noterminal', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
QE('p20nofiles', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
QE('p20noamt', !Q('p20fulladmin').checked && Q('p20remotecontrol').checked);
@ -6004,6 +6047,7 @@
if (Q('p20noterminal').checked == true) meshadmin += 512;
if (Q('p20nofiles').checked == true) meshadmin += 1024;
if (Q('p20noamt').checked == true) meshadmin += 2048;
if (Q('p20remotelimitedinput').checked == true) meshadmin += 4096;
}
meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value , meshadmin: meshadmin});
}
@ -6021,10 +6065,11 @@
if ((meshrights & 32) != 0) r += ', Server Files';
if ((meshrights & 64) != 0) r += ', Wake Devices';
if ((meshrights & 128) != 0) r += ', Edit Notes';
if ((meshrights & 256) != 0) r += ', Remote View Only';
if ((meshrights & 512) != 0) r += ', No Terminal';
if ((meshrights & 1024) != 0) r += ', No Files';
if ((meshrights & 2048) != 0) r += ', No Intel&reg; AMT';
if (((meshrights & 8) != 0) && (meshrights & 256) != 0) r += ', Remote View Only';
if (((meshrights & 8) != 0) && (meshrights & 512) != 0) r += ', No Terminal';
if (((meshrights & 8) != 0) && (meshrights & 1024) != 0) r += ', No Files';
if (((meshrights & 8) != 0) && (meshrights & 2048) != 0) r += ', No Intel&reg; AMT';
if (((meshrights & 8) != 0) && ((meshrights & 4096) != 0) && ((meshrights & 256) == 0)) r += ', Limited Input';
}
r = r.substring(2);
if (r == '') { r = 'No Rights'; }