Greenlock being deprecated, added NODESKTOP device group permission.

This commit is contained in:
Ylian Saint-Hilaire 2020-03-06 14:06:33 -08:00
parent 16e679d49a
commit 67a3b001e1
7 changed files with 435 additions and 403 deletions

View File

@ -36,6 +36,10 @@ var MESHRIGHT_NOTERMINAL = 512;
var MESHRIGHT_NOFILES = 1024; var MESHRIGHT_NOFILES = 1024;
var MESHRIGHT_NOAMT = 2048; var MESHRIGHT_NOAMT = 2048;
var MESHRIGHT_LIMITEDINPUT = 4096; var MESHRIGHT_LIMITEDINPUT = 4096;
var MESHRIGHT_LIMITEVENTS = 8192;
var MESHRIGHT_CHATNOTIFY = 16384;
var MESHRIGHT_UNINSTALL = 32768;
var MESHRIGHT_NODESKTOP = 65536;
function createMeshCore(agent) { function createMeshCore(agent) {
var obj = {}; var obj = {};
@ -1328,7 +1332,7 @@ function createMeshCore(agent) {
//this.write('MeshCore Terminal Hello'); //this.write('MeshCore Terminal Hello');
} else if (this.httprequest.protocol == 2) { } else if (this.httprequest.protocol == 2) {
// Check user access rights for desktop // Check user access rights for desktop
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) { if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0))) {
// Disengage this tunnel, user does not have the rights to do this!! // Disengage this tunnel, user does not have the rights to do this!!
this.httprequest.protocol = 999999; this.httprequest.protocol = 999999;
this.httprequest.s.end(); this.httprequest.s.end();
@ -1396,8 +1400,7 @@ function createMeshCore(agent) {
if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) { if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) {
this.httprequest.desktop.kvm.connectionCount++; this.httprequest.desktop.kvm.connectionCount++;
this.httprequest.desktop.kvm.users.push(this.httprequest.username); this.httprequest.desktop.kvm.users.push(this.httprequest.username);
} } else {
else {
this.httprequest.desktop.kvm.connectionCount = 1; this.httprequest.desktop.kvm.connectionCount = 1;
this.httprequest.desktop.kvm.users = [this.httprequest.username]; this.httprequest.desktop.kvm.users = [this.httprequest.username];
} }
@ -1505,7 +1508,6 @@ function createMeshCore(agent) {
//this.write('MeshCore KVM Hello!1'); //this.write('MeshCore KVM Hello!1');
} else if (this.httprequest.protocol == 5) { } else if (this.httprequest.protocol == 5) {
// Check user access rights for files // Check user access rights for files
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) { if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) {
// Disengage this tunnel, user does not have the rights to do this!! // Disengage this tunnel, user does not have the rights to do this!!

View File

@ -343,6 +343,7 @@ module.exports.CreateLetsEncrypt2 = function (parent) {
obj.redirWebServerHooked = false; obj.redirWebServerHooked = false;
obj.configErr = null; obj.configErr = null;
obj.configOk = false; obj.configOk = false;
obj.pendingRequest = false;
// Let's Encrypt debug logging // Let's Encrypt debug logging
obj.log = function (str) { obj.log = function (str) {
@ -364,7 +365,7 @@ module.exports.CreateLetsEncrypt2 = function (parent) {
// Deal with HTTP challenges // Deal with HTTP challenges
function challengeCreateFn(authz, challenge, keyAuthorization) { if (challenge.type === 'http-01') { obj.challenges[challenge.token] = keyAuthorization; } } function challengeCreateFn(authz, challenge, keyAuthorization) { if (challenge.type === 'http-01') { obj.challenges[challenge.token] = keyAuthorization; } }
function challengeRemoveFn(authz, challenge, keyAuthorization) { if (challenge.type === 'http-01') { delete obj.challenges[challenge.token]; } } function challengeRemoveFn(authz, challenge, keyAuthorization) { if (challenge.type === 'http-01') { delete obj.challenges[challenge.token]; } }
obj.challenge = function (token, hostname, func) { obj.log((obj.challenges[token] != null)?"Succesful response to challenge.":"Failed to respond to challenge."); func(obj.challenges[token]); } obj.challenge = function (token, hostname, func) { if (obj.challenges[token] != null) { obj.log("Succesful response to challenge."); } else { obj.log("Failed to respond to challenge, token: " + token + ", table: " + JSON.stringify(obj.challenges) + "."); } func(obj.challenges[token]); }
// Get the current certificate // Get the current certificate
obj.getCertificate = function(certs, func) { obj.getCertificate = function(certs, func) {
@ -433,6 +434,7 @@ module.exports.CreateLetsEncrypt2 = function (parent) {
// Check if we need to get a new certificate // Check if we need to get a new certificate
// Return 0 = CertOK, 1 = Request:NoCert, 2 = Request:Expire, 3 = Request:MissingNames // Return 0 = CertOK, 1 = Request:NoCert, 2 = Request:Expire, 3 = Request:MissingNames
obj.checkRenewCertificate = function () { obj.checkRenewCertificate = function () {
if (obj.pendingRequest == true) { obj.log("Request for certificate is in process."); return 4; }
if (obj.certNames == null) { if (obj.certNames == null) {
obj.log("Got no certificates, asking for one now."); obj.log("Got no certificates, asking for one now.");
obj.requestCertificate(); obj.requestCertificate();
@ -466,7 +468,9 @@ module.exports.CreateLetsEncrypt2 = function (parent) {
} }
obj.requestCertificate = function () { obj.requestCertificate = function () {
if (obj.pendingRequest == true) return;
if (obj.configOk == false) { obj.log("Can't request cert, invalid configuration.");return; } if (obj.configOk == false) { obj.log("Can't request cert, invalid configuration.");return; }
obj.pendingRequest = true;
// Create a private key // Create a private key
obj.log("Generating private key..."); obj.log("Generating private key...");
@ -508,12 +512,18 @@ module.exports.CreateLetsEncrypt2 = function (parent) {
obj.parent.performServerCertUpdate(); obj.parent.performServerCertUpdate();
}, function (err) { }, function (err) {
obj.log("Failed to obtain certificate: " + err.message); obj.log("Failed to obtain certificate: " + err.message);
obj.pendingRequest = false;
delete obj.client;
}); });
}, function (err) { }, function (err) {
obj.log("Failed to generate certificate request: " + err.message); obj.log("Failed to generate certificate request: " + err.message);
obj.pendingRequest = false;
delete obj.client;
}); });
}, function (err) { }, function (err) {
obj.log("Failed to generate private key: " + err.message); obj.log("Failed to generate private key: " + err.message);
obj.pendingRequest = false;
delete obj.client;
}); });
} }

View File

@ -263,23 +263,25 @@ function readNextBlock(state, func) {
var r = {}, buf = Buffer.alloc(16); var r = {}, buf = Buffer.alloc(16);
fs.read(state.recFile, buf, 0, 16, state.recFilePtr, function (err, bytesRead, buf) { fs.read(state.recFile, buf, 0, 16, state.recFilePtr, function (err, bytesRead, buf) {
if (bytesRead != 16) { func(state, null, true); return; } // Error if (bytesRead != 16) { func(state, null, true); return; } // Error
r.type = buf.readUInt16BE(0); try {
r.flags = buf.readUInt16BE(2); r.type = buf.readUInt16BE(0);
r.size = buf.readUInt32BE(4); r.flags = buf.readUInt16BE(2);
r.time = buf.readUIntBE(8, 8); r.size = buf.readUInt32BE(4);
r.date = new Date(r.time); r.time = buf.readUIntBE(8, 8);
r.ptr = state.recFilePtr; r.date = new Date(r.time);
if ((state.recFilePtr + 16 + r.size) > state.recFileSize) { func(state, null, true); return; } // Error r.ptr = state.recFilePtr;
if (r.size == 0) { if ((state.recFilePtr + 16 + r.size) > state.recFileSize) { func(state, null, true); return; } // Error
r.data = null; if (r.size == 0) {
func(state, r); r.data = null;
} else {
r.data = Buffer.alloc(r.size);
fs.read(state.recFile, r.data, 0, r.size, state.recFilePtr + 16, function (err, bytesRead, buf) {
state.recFilePtr += (16 + r.size);
func(state, r); func(state, r);
}); } else {
} r.data = Buffer.alloc(r.size);
fs.read(state.recFile, r.data, 0, r.size, state.recFilePtr + 16, function (err, bytesRead, buf) {
state.recFilePtr += (16 + r.size);
func(state, r);
});
}
} catch (ex) { func(state, null, true); return; } // Error
}); });
} }

View File

@ -1068,14 +1068,14 @@ function CreateMeshCentralServer(config, args) {
obj.certificateOperations.GetMeshServerCertificate(obj.args, obj.config, function (certs) { obj.certificateOperations.GetMeshServerCertificate(obj.args, obj.config, function (certs) {
// Get the current node version // Get the current node version
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]); const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
if ((obj.config.letsencrypt == null) || (obj.redirserver == null) || (nodeVersion < 8) || ((obj.config.letsencrypt.lib != 'acme-client') && (require('crypto').generateKeyPair == null))) { if ((obj.config.letsencrypt == null) || (obj.redirserver == null) || (nodeVersion < 8) || ((obj.config.letsencrypt.lib == 'greenlock') && (require('crypto').generateKeyPair == null))) {
obj.StartEx3(certs); // Just use the configured certificates obj.StartEx3(certs); // Just use the configured certificates
} else if ((obj.config.letsencrypt != null) && (obj.config.letsencrypt.nochecks == true)) { } else if ((obj.config.letsencrypt != null) && (obj.config.letsencrypt.nochecks == true)) {
// Use Let's Encrypt with no checking // Use Let's Encrypt with no checking
if (obj.config.letsencrypt.lib == 'acme-client') { if (obj.config.letsencrypt.lib == 'greenlock') {
obj.letsencrypt = require('./letsencrypt.js').CreateLetsEncrypt2(obj);
} else {
obj.letsencrypt = require('./letsencrypt.js').CreateLetsEncrypt(obj); obj.letsencrypt = require('./letsencrypt.js').CreateLetsEncrypt(obj);
} else {
obj.letsencrypt = require('./letsencrypt.js').CreateLetsEncrypt2(obj);
} }
obj.letsencrypt.getCertificate(certs, obj.StartEx3); // Use Let's Encrypt with no checking, use at your own risk. obj.letsencrypt.getCertificate(certs, obj.StartEx3); // Use Let's Encrypt with no checking, use at your own risk.
} else { } else {
@ -1089,10 +1089,10 @@ function CreateMeshCentralServer(config, args) {
else { else {
var le = require('./letsencrypt.js'); var le = require('./letsencrypt.js');
try { try {
if (obj.config.letsencrypt.lib == 'acme-client') { if (obj.config.letsencrypt.lib == 'greenlock') {
obj.letsencrypt = le.CreateLetsEncrypt2(obj);
} else {
obj.letsencrypt = le.CreateLetsEncrypt(obj); obj.letsencrypt = le.CreateLetsEncrypt(obj);
} else {
obj.letsencrypt = le.CreateLetsEncrypt2(obj);
} }
} catch (ex) { console.log(ex); } } catch (ex) { console.log(ex); }
if (obj.letsencrypt == null) { addServerWarning("Unable to setup GreenLock module."); leok = false; } if (obj.letsencrypt == null) { addServerWarning("Unable to setup GreenLock module."); leok = false; }
@ -2390,10 +2390,10 @@ function mainStart() {
if (ldap == true) { modules.push('ldapauth-fork'); } if (ldap == true) { modules.push('ldapauth-fork'); }
if (recordingIndex == true) { modules.push('image-size'); } // Need to get the remote desktop JPEG sizes to index the recodring file. if (recordingIndex == true) { modules.push('image-size'); } // Need to get the remote desktop JPEG sizes to index the recodring file.
if (config.letsencrypt != null) { if (config.letsencrypt != null) {
if (config.letsencrypt.lib == 'acme-client') { if (config.letsencrypt.lib == 'greenlock') {
if (nodeVersion < 8) { addServerWarning("Let's Encrypt support requires Node v8.x or higher.", !args.launch); } else { modules.push('acme-client'); }
} else {
if ((nodeVersion < 10) || (require('crypto').generateKeyPair == null)) { addServerWarning("Let's Encrypt support requires Node v10.12 or higher.", !args.launch); } else { modules.push('greenlock@4.0.4'); } if ((nodeVersion < 10) || (require('crypto').generateKeyPair == null)) { addServerWarning("Let's Encrypt support requires Node v10.12 or higher.", !args.launch); } else { modules.push('greenlock@4.0.4'); }
} else {
if (nodeVersion < 8) { addServerWarning("Let's Encrypt support requires Node v8.x or higher.", !args.launch); } else { modules.push('acme-client'); }
} }
} // Add Greenlock Module or acme-client module } // Add Greenlock Module or acme-client module
if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules

View File

@ -55,8 +55,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
obj.onDisplayinfo = null; obj.onDisplayinfo = null;
obj.accumulator = null; obj.accumulator = null;
var mouseCursors = ['default', 'progress', 'crosshair', 'pointer', 'help', 'text', 'no-drop', 'move', 'nesw-resize', 'ns-resize', 'nwse-resize', 'w-resize', 'alias', 'wait', 'none']; var mouseCursors = ['default', 'progress', 'crosshair', 'pointer', 'help', 'text', 'no-drop', 'move', 'nesw-resize', 'ns-resize', 'nwse-resize', 'w-resize', 'alias', 'wait', 'none', 'not-allowed', 'col-resize', 'row-resize', 'copy', 'zoom-in', 'zoom-out'];
obj.Start = function () { obj.Start = function () {
obj.State = 0; obj.State = 0;
obj.accumulator = null; obj.accumulator = null;

File diff suppressed because it is too large Load Diff

View File

@ -3981,11 +3981,12 @@
var rights = GetNodeRights(node); var rights = GetNodeRights(node);
var consoleRights = ((rights & 16) != 0); var consoleRights = ((rights & 16) != 0);
// Check if we have terminal and file access // Check if we have desktop, terminal and file access
var desktopAccess = ((rights == 0xFFFFFFFF) || ((rights & 65536) == 0));
var terminalAccess = ((rights == 0xFFFFFFFF) || ((rights & 512) == 0)); var terminalAccess = ((rights == 0xFFFFFFFF) || ((rights & 512) == 0));
var fileAccess = ((rights == 0xFFFFFFFF) || ((rights & 1024) == 0)); var fileAccess = ((rights == 0xFFFFFFFF) || ((rights & 1024) == 0));
QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((rights & 8) || (rights & 256))); QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((rights & 8) || (rights & 256)) && desktopAccess);
QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (rights & 8) && terminalAccess); QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (rights & 8) && terminalAccess);
QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (rights & 8) && fileAccess); QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (rights & 8) && fileAccess);
QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (rights & 8)); QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (rights & 8));
@ -4915,6 +4916,7 @@
masterUpdate(256); masterUpdate(256);
// Check if we have terminal and file access // Check if we have terminal and file access
var desktopAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 65536) == 0));
var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0)); var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0)); var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
var amtAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 2048) == 0)); var amtAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 2048) == 0));
@ -4970,9 +4972,9 @@
// Show or hide the tabs // Show or hide the tabs
// mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent // mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
// node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console // node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
QV('MainDevDesktop', (((mesh.mtype == 1) && ((typeof node.intelamt.sku !== 'number') || ((node.intelamt.sku & 8) != 0))) QV('MainDevDesktop', desktopAccess && ((((mesh.mtype == 1) && ((typeof node.intelamt.sku !== 'number') || ((node.intelamt.sku & 8) != 0)))
|| ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))))) || ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2)))))
&& ((meshrights & 8) || (meshrights & 256)) && ((meshrights & 8) || (meshrights & 256)))
); );
QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess); QV('MainDevTerminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess);
QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess); QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
@ -8415,6 +8417,7 @@
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotecontrol>' + "Remote Control" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotecontrol>' + "Remote Control" + '</label><br>';
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remoteview style=margin-left:12px>' + "Remote View Only" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remoteview style=margin-left:12px>' + "Remote View Only" + '</label><br>';
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotelimitedinput style=margin-left:12px>' + "Limited Input Only" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remotelimitedinput style=margin-left:12px>' + "Limited Input Only" + '</label><br>';
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20nodesktop style=margin-left:12px>' + "No Desktop Access" + '</label><br>';
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noterminal style=margin-left:12px>' + "No Terminal Access" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noterminal style=margin-left:12px>' + "No Terminal Access" + '</label><br>';
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20nofiles style=margin-left:12px>' + "No File Access" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20nofiles style=margin-left:12px>' + "No File Access" + '</label><br>';
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noamt style=margin-left:12px>' + "No Intel&reg; AMT" + '</label><br>'; x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20noamt style=margin-left:12px>' + "No Intel&reg; AMT" + '</label><br>';
@ -8450,6 +8453,7 @@
if (meshrights & 4) { Q('p20managecomputers').checked = true; } if (meshrights & 4) { Q('p20managecomputers').checked = true; }
if (meshrights & 8) { if (meshrights & 8) {
Q('p20remotecontrol').checked = true; Q('p20remotecontrol').checked = true;
if (meshrights & 65536) { Q('p20nodesktop').checked = true; }
if (meshrights & 256) { Q('p20remoteview').checked = true; } if (meshrights & 256) { Q('p20remoteview').checked = true; }
if (meshrights & 512) { Q('p20noterminal').checked = true; } if (meshrights & 512) { Q('p20noterminal').checked = true; }
if (meshrights & 1024) { Q('p20nofiles').checked = true; } if (meshrights & 1024) { Q('p20nofiles').checked = true; }
@ -8528,6 +8532,7 @@
QE('p20limitevents', nc); QE('p20limitevents', nc);
QE('p20remoteview', nc && Q('p20remotecontrol').checked); QE('p20remoteview', nc && Q('p20remotecontrol').checked);
QE('p20remotelimitedinput', nc && Q('p20remotecontrol').checked && !Q('p20remoteview').checked); QE('p20remotelimitedinput', nc && Q('p20remotecontrol').checked && !Q('p20remoteview').checked);
QE('p20nodesktop', nc && Q('p20remotecontrol').checked);
QE('p20noterminal', nc && Q('p20remotecontrol').checked); QE('p20noterminal', nc && Q('p20remotecontrol').checked);
QE('p20nofiles', nc && Q('p20remotecontrol').checked); QE('p20nofiles', nc && Q('p20remotecontrol').checked);
QE('p20noamt', nc && Q('p20remotecontrol').checked); QE('p20noamt', nc && Q('p20remotecontrol').checked);
@ -8550,6 +8555,7 @@
if (Q('p20wakedevices').checked == true) meshadmin += 64; if (Q('p20wakedevices').checked == true) meshadmin += 64;
if (Q('p20editnotes').checked == true) meshadmin += 128; if (Q('p20editnotes').checked == true) meshadmin += 128;
if (Q('p20remoteview').checked == true) meshadmin += 256; if (Q('p20remoteview').checked == true) meshadmin += 256;
if (Q('p20nodesktop').checked == true) meshadmin += 65536;
if (Q('p20noterminal').checked == true) meshadmin += 512; if (Q('p20noterminal').checked == true) meshadmin += 512;
if (Q('p20nofiles').checked == true) meshadmin += 1024; if (Q('p20nofiles').checked == true) meshadmin += 1024;
if (Q('p20noamt').checked == true) meshadmin += 2048; if (Q('p20noamt').checked == true) meshadmin += 2048;
@ -8598,6 +8604,7 @@
if ((meshrights & 64) != 0) r.push("Wake Devices"); if ((meshrights & 64) != 0) r.push("Wake Devices");
if ((meshrights & 128) != 0) r.push("Edit Notes"); if ((meshrights & 128) != 0) r.push("Edit Notes");
if (((meshrights & 8) != 0) && (meshrights & 256) != 0) r.push("Remote View Only"); if (((meshrights & 8) != 0) && (meshrights & 256) != 0) r.push("Remote View Only");
if (((meshrights & 8) != 0) && (meshrights & 65536) != 0) r.push("No Desktop");
if (((meshrights & 8) != 0) && (meshrights & 512) != 0) r.push("No Terminal"); if (((meshrights & 8) != 0) && (meshrights & 512) != 0) r.push("No Terminal");
if (((meshrights & 8) != 0) && (meshrights & 1024) != 0) r.push("No Files"); if (((meshrights & 8) != 0) && (meshrights & 1024) != 0) r.push("No Files");
if (((meshrights & 8) != 0) && (meshrights & 2048) != 0) r.push("No Intel&reg; AMT"); if (((meshrights & 8) != 0) && (meshrights & 2048) != 0) r.push("No Intel&reg; AMT");