Added View Only Desktop, Optimized Images

Ylian Saint-Hilaire committed Nov 2, 2018 at 18:13 UTC dfeab93cc90dc8e113ac39b2706401ec892cb9d9
36 files changed +198 -109
meshcentral.js
+12 -4
@@ -407,6 +407,9 @@ function CreateMeshCentralServer(config, args) {
407 // Load any domain web certificates
408 for (i in obj.config.domains) {
409 if (obj.config.domains[i].certurl != null) {
410 + // Fix the URL and add 'https://' if needed
411 + if (obj.config.domains[i].certurl.indexOf('://') < 0) { obj.config.domains[i].certurl = 'https://' + obj.config.domains[i].certurl; }
412 +
413 // Load web certs
414 webCertLoadCount++;
415 obj.certificateOperations.loadCertificate(obj.config.domains[i].certurl, obj.config.domains[i], function (url, cert, xdomain) {
@@ -415,12 +418,17 @@ function CreateMeshCentralServer(config, args) {
418 // Decode a RSA certificate and hash the public key
419 var forgeCert = obj.certificateOperations.forge.pki.certificateFromAsn1(obj.certificateOperations.forge.asn1.fromDer(cert.raw.toString('binary')));
420 var hash = obj.certificateOperations.forge.pki.getPublicKeyFingerprint(forgeCert.publicKey, { md: obj.certificateOperations.forge.md.sha384.create(), encoding: 'hex' });
418 - xdomain.certhash = hash;
419 - console.log('Loaded RSA web certificate at ' + url + ', SHA384: ' + xdomain.certhash + '.');
421 + if (xdomain.certhash != hash) {
422 + xdomain.certhash = hash;
423 + console.log('Loaded RSA web certificate at ' + url + ', SHA384: ' + xdomain.certhash + '.');
424 + }
425 } catch (ex) {
426 // This may be a ECDSA certificate, hash the entire cert
422 - xdomain.certhash = obj.crypto.createHash('sha384').update(cert.raw).digest('hex');
423 - console.log('Loaded non-RSA web certificate at ' + url + ', SHA384: ' + xdomain.certhash + '.');
427 + var hash = obj.crypto.createHash('sha384').update(cert.raw).digest('hex');
428 + if (xdomain.certhash != hash) {
429 + xdomain.certhash = hash;
430 + console.log('Loaded non-RSA web certificate at ' + url + ', SHA384: ' + xdomain.certhash + '.');
431 + }
432 }
433 } else {
434 console.log('Failed to load web certificate at: ' + url);
meshuser.js
+4 -4
@@ -315,7 +315,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
315 if (agent != null) {
316 // Check if we have permission to send a message to that node
317 var rights = user.links[agent.dbMeshKey];
318 - if ((rights != null) && ((rights.rights & 8) != 0)) { // 8 is remote control permission
318 + if ((rights != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission, 256 is desktop read only
319 command.sessionid = ws.sessionId; // Set the session id, required for responses.
320 command.rights = rights.rights; // Add user rights flags to the message
321 delete command.nodeid; // Remove the nodeid since it's implyed.
@@ -327,7 +327,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
327 if (routing != null) {
328 // Check if we have permission to send a message to that node
329 var rights = user.links[routing.meshid];
330 - if ((rights != null) && ((rights.rights & 8) != 0)) { // 8 is remote control permission
330 + if ((rights != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission
331 command.fromSessionid = ws.sessionId; // Set the session id, required for responses.
332 command.rights = rights.rights; // Add user rights flags to the message
333 obj.parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
@@ -1210,7 +1210,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1210 mesh = obj.parent.meshes[command.id];
1211 if (mesh) {
1212 // Check if this user has rights to do this
1213 - if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { return; }
1213 + if ((mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) { return; } // Must have rights to edit the mesh
1214
1215 // Set the id's notes
1216 if (obj.common.validateString(command.notes, 1) == false) {
@@ -1265,7 +1265,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1265 mesh = obj.parent.meshes[command.id];
1266 if (mesh) {
1267 // Check if this user has rights to do this
1268 - if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { return; }
1268 + if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 1) == 0)) { return; } // Must have rights to edit the mesh
1269
1270 // Get the notes about this node
1271 obj.db.Get('nt' + command.id, function (err, notes) {
public/images/User-200.png
Binary files a/public/images/User-200.png and /dev/null differ
public/images/icons200-1-1.jpg
Binary files /dev/null and b/public/images/icons200-1-1.jpg differ
public/images/icons200-1-1.png
Binary files a/public/images/icons200-1-1.png and /dev/null differ
public/images/icons200-2-1.jpg
Binary files /dev/null and b/public/images/icons200-2-1.jpg differ
public/images/icons200-2-1.png
Binary files a/public/images/icons200-2-1.png and /dev/null differ
public/images/icons200-3-1.jpg
Binary files /dev/null and b/public/images/icons200-3-1.jpg differ
public/images/icons200-3-1.png
Binary files a/public/images/icons200-3-1.png and /dev/null differ
public/images/icons200-4-1.jpg
Binary files /dev/null and b/public/images/icons200-4-1.jpg differ
public/images/icons200-4-1.png
Binary files a/public/images/icons200-4-1.png and /dev/null differ
public/images/icons200-5-1.jpg
Binary files /dev/null and b/public/images/icons200-5-1.jpg differ
public/images/icons200-5-1.png
Binary files a/public/images/icons200-5-1.png and /dev/null differ
public/images/icons200-6-1.jpg
Binary files /dev/null and b/public/images/icons200-6-1.jpg differ
public/images/icons200-6-1.png
Binary files a/public/images/icons200-6-1.png and /dev/null differ
public/images/leftbar-62.jpg
Binary files /dev/null and b/public/images/leftbar-62.jpg differ
public/images/leftbar-62.png
Binary files a/public/images/leftbar-62.png and /dev/null differ
public/images/leftbar-90.png
Binary files a/public/images/leftbar-90.png and /dev/null differ
public/images/mainaccount.jpg
Binary files /dev/null and b/public/images/mainaccount.jpg differ
public/images/mainaccount.png
Binary files a/public/images/mainaccount.png and /dev/null differ
public/images/mainwelcome-90.png
Binary files a/public/images/mainwelcome-90.png and /dev/null differ
public/images/mainwelcome.jpg
Binary files /dev/null and b/public/images/mainwelcome.jpg differ
public/images/mainwelcome.png
Binary files a/public/images/mainwelcome.png and /dev/null differ
public/images/mesh-200.jpg
Binary files /dev/null and b/public/images/mesh-200.jpg differ
public/images/mesh-200.png
Binary files a/public/images/mesh-200.png and /dev/null differ
public/images/server-200.jpg
Binary files /dev/null and b/public/images/server-200.jpg differ
public/images/server-200.png
Binary files a/public/images/server-200.png and /dev/null differ
public/images/user-200.jpg
Binary files /dev/null and b/public/images/user-200.jpg differ
public/images/webp/mainwelcome.webp
Binary files /dev/null and b/public/images/webp/mainwelcome.webp differ
public/images/webp/mesh-200.webp
Binary files /dev/null and b/public/images/webp/mesh-200.webp differ
public/images/webp/user-200.webp
Binary files /dev/null and b/public/images/webp/user-200.webp differ
public/styles/style.css
+6 -6
@@ -197,7 +197,7 @@ a {
197 }
198
199 .lb1 {
200 - background: url(../images/leftbar-62.png) -0px 0px;
200 + background: url(../images/leftbar-62.jpg) -0px 0px;
201 height: 62px;
202 width: 62px;
203 cursor: pointer;
@@ -205,7 +205,7 @@ a {
205 }
206
207 .lb2 {
208 - background: url(../images/leftbar-62.png) -75px 0px;
208 + background: url(../images/leftbar-62.jpg) -75px 0px;
209 height: 62px;
210 width: 62px;
211 cursor: pointer;
@@ -213,7 +213,7 @@ a {
213 }
214
215 .lb3 {
216 - background: url(../images/leftbar-62.png) -150px 0px;
216 + background: url(../images/leftbar-62.jpg) -150px 0px;
217 height: 62px;
218 width: 62px;
219 cursor: pointer;
@@ -221,7 +221,7 @@ a {
221 }
222
223 .lb4 {
224 - background: url(../images/leftbar-62.png) -225px 0px;
224 + background: url(../images/leftbar-62.jpg) -225px 0px;
225 height: 62px;
226 width: 62px;
227 cursor: pointer;
@@ -229,7 +229,7 @@ a {
229 }
230
231 .lb5 {
232 - background: url(../images/leftbar-62.png) -294px 0px;
232 + background: url(../images/leftbar-62.jpg) -294px 0px;
233 height: 62px;
234 width: 62px;
235 cursor: pointer;
@@ -237,7 +237,7 @@ a {
237 }
238
239 .lb6 {
240 - background: url(../images/leftbar-62.png) -360px 0px;
240 + background: url(../images/leftbar-62.jpg) -360px 0px;
241 height: 62px;
242 width: 62px;
243 cursor: pointer;
views/default-mobile.handlebars
+139 -77
@@ -389,9 +389,10 @@
389 </div>
390 <div>
391 <input id="deskActionsBtn" type=button style="margin-left:3px" title="Perform power actions on the device" onkeypress="return false" onkeydown="return false" value=Actions onclick=deviceActionFunction() />
392 - <input type="button" value="Settings..." title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()">
393 - <input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="display:none">
394 - <input id="DeskCAD" type="button" value="Ctrl-Alt-Del" onkeypress="return false" onkeydown="return false" onclick="sendCAD()">
392 + <input type="button" value="Settings..." style="margin-left:3px" title="Edit remote desktop settings" onkeypress="return false" onkeydown="return false" onclick="showDesktopSettings()">
393 + <input type="button" title="Change the power state of the remote machine" onkeypress="return false" onkeydown="return false" value="Power Actions..." onclick="showPowerActionDlg()" style="display:none;margin-left:3px">
394 + <!--<input id="DeskCAD" type="button" value="Ctrl-Alt-Del" onkeypress="return false" onkeydown="return false" onclick="sendCAD()">-->
395 + <span id="DeskControlSpan" style="margin-left:3px;display:none" title="Toggle mouse and keyboard input"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false">Input</span>
396 </div>
397 </div>
398 </div>
@@ -500,6 +501,56 @@
501 <div id=dialog2 style="margin:auto;margin:3px">
502 <div id=id_dialogOptions></div>
503 </div>
504 + <div id=dialog7 style="margin:auto;margin:3px">
505 + <div id="d7meshkvm">
506 + <h4 style="width:100%;border-bottom:1px solid gray">Agent Remote Desktop</h4>
507 + <div style="margin:3px 0 3px 0">
508 + <select id="d7bitmapquality" style="float:right;width:200px;height:20px" dir="rtl"></select>
509 + <div style="height:20px">Quality</div>
510 + </div>
511 + <div style="margin:3px 0 3px 0">
512 + <select id="d7bitmapscaling" style="float:right;width:200px;height:20px" dir="rtl">
513 + <option selected=selected value=1024>100%</option>
514 + <option value=896>87.5%</option>
515 + <option value=768>75%</option>
516 + <option value=640>62.5%</option>
517 + <option value=512>50%</option>
518 + <option value=384>37.5%</option>
519 + <option value=256>25%</option>
520 + <option value=128>12.5%</option>
521 + </select>
522 + <div style="height:20px">Scaling</div>
523 + </div>
524 + <div style="margin:3px 0 3px 0">
525 + <select id="d7framelimiter" style="float:right;width:200px;height:20px" dir="rtl">
526 + <option selected=selected value=50>Fast</option>
527 + <option value=100>Medium</option>
528 + <option value=400>Slow</option>
529 + <option value=1000>Very slow</option>
530 + </select>
531 + <div style="height:20px">Rate</div>
532 + </div>
533 + </div>
534 + <div id="d7amtkvm">
535 + <h4 style="width:100%;border-bottom:1px solid gray">Intel&reg; AMT Hardware KVM</h4>
536 + <div style='height:26px'>
537 + <select id="d7desktopmode" style="float:right;width:200px">
538 + <option value="1">RLE8, Fastest</option>
539 + <option value="2">RLE16, Recommended</option>
540 + <option value="3">RAW8, Slow</option>
541 + <option value="4">RAW16, Very Slow</option>
542 + </select>
543 + <div>Encoding</div>
544 + </div>
545 + <div style="height:60px">
546 + <div style="float:right;border:1px solid #666;width:200px;height:60px;overflow-y:scroll;background-color:white">
547 + <input type="checkbox" id='d7showfocus'>Show Focus Tool<br>
548 + <input type="checkbox" id='d7showcursor'>Show Local Mouse Cursor<br>
549 + </div>
550 + <div>Other</div>
551 + </div>
552 + </div>
553 + </div>
554 </div>
555 <div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:20px">
556 <input id="idx_dlgCancelButton" type="button" value="Cancel" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
@@ -637,7 +688,7 @@
688 if (message.nodes[m][n].rname) { message.nodes[m][n].rnamel = message.nodes[m][n].rname.toLowerCase(); } else { message.nodes[m][n].rnamel = message.nodes[m][n].namel; }
689 message.nodes[m][n].meshnamel = meshes[m].name.toLowerCase();
690 message.nodes[m][n].meshid = m;
640 - message.nodes[m][n].state = (message.nodes[m][n].state)?(message.nodes[m][n].state):0;
691 + message.nodes[m][n].state = (message.nodes[m][n].state) ? (message.nodes[m][n].state) : 0;
692 message.nodes[m][n].desc = message.nodes[m][n].desc;
693 if (!message.nodes[m][n].icon) message.nodes[m][n].icon = 1;
694 message.nodes[m][n].ident = ++nodeShortIdent;
@@ -883,9 +934,9 @@
934 }
935
936 function updateFooterMenu(options) {
886 - while (options != null && options.length < 3) { options.push( { n:'' } ); }
937 + while (options != null && options.length < 3) { options.push({ n: '' }); }
938 var x = '', prev = '';
888 - if (options != null) { for (var i in options) { x += '<td style="cursor:pointer' + ((prev == '')?'':';border-left:solid 1px white') + '" onclick="' + options[i].f + '">' + options[i].n; prev = options[i].n; } }
939 + if (options != null) { for (var i in options) { x += '<td style="cursor:pointer' + ((prev == '') ? '' : ';border-left:solid 1px white') + '" onclick="' + options[i].f + '">' + options[i].n; prev = options[i].n; } }
940 QH('footerMenu', '<tr>' + x);
941 }
942
@@ -986,7 +1037,7 @@
1037 function checkPasswordStrength(password) {
1038 var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) }
1039 if (!password) return 0;
989 - for (var i = 0; i< password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
1040 + for (var i = 0; i < password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
1041 for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; }
1042 return parseInt(r + (varCount - 1) * 10);
1043 }
@@ -1078,7 +1129,7 @@
1129 if (filetreelinkpath != '') { filetreelinkpath += '/' + filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + filetreelocation[i]; } }
1130 }
1131 filetreex = filetreex.f[filetreelocation[i]];
1081 - displayPath += ' / <a style=cursor:pointer onclick=p5folderup(' + folderdepth + ')>' + (filetreex.n != null?filetreex.n:filetreelocation[i]) + '</a>';
1132 + displayPath += ' / <a style=cursor:pointer onclick=p5folderup(' + folderdepth + ')>' + (filetreex.n != null ? filetreex.n : filetreelocation[i]) + '</a>';
1133 folderdepth++;
1134 } else {
1135 break;
@@ -1108,7 +1159,7 @@
1159
1160 var h = '';
1161 if (f.t < 3 || f.t == 4) {
1111 - var right = (f.t == 1 || f.t == 4)?p5getQuotabar(f):'', title = '';
1162 + var right = (f.t == 1 || f.t == 4) ? p5getQuotabar(f) : '', title = '';
1163 h = "<div class=filelist file=999><input file=999 style=float:left name=fc class=fcb type=checkbox onchange=p5setActions() value='" + name + "'>&nbsp;<span style=float:right;padding-right:4px title=\"" + title + "\">" + right + "</span><span><div class=fileIcon" + f.t + "></div><a style=cursor:pointer onclick=p5folderset(\"" + encodeURIComponent(f.nx) + "\")>" + shortname + "</a></span></div>";
1164 } else {
1165 var link = shortname;
@@ -1144,7 +1195,7 @@
1195 while (f.t > 1 && f.t != 4) { f = f.parent; }
1196 if ((f.t != 1 && f.t != 4) || (f.maxbytes == null)) return '';
1197 var tf = Math.floor(f.s / 1024), tq = Math.floor((f.maxbytes - f.s) / 1024);
1147 - return '<span title="' + tf + "k in " + f.c + " file" + (f.c > 1?'s':'') + ". " + (Math.floor(f.maxbytes / 1024)) + 'k maxinum">' + ((tq < 0)?('Storage limit exceed'):(tq + 'k remaining')) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' /></span>';
1198 + return '<span title="' + tf + "k in " + f.c + " file" + (f.c > 1 ? 's' : '') + ". " + (Math.floor(f.maxbytes / 1024)) + 'k maxinum">' + ((tq < 0) ? ('Storage limit exceed') : (tq + 'k remaining')) + ' <progress style=height:10px;width:100px value=' + f.s + ' max=' + f.maxbytes + ' /></span>';
1199 }
1200
1201 function p5showPublicLink(u) { setDialogMode(2, "Public Link", 1, null, '<input type=text style=width:100% value="' + u + '" readonly />'); }
@@ -1186,22 +1237,22 @@
1237 function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); }
1238 function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); }
1239 function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% />'); focusTextBox('p5renameinput'); p5fileNameCheck(); }
1189 - function p5createfolderEx() { meshserver.send({ action: 'fileoperation', fileop: 'createfolder', path: filetreelocation, newfolder: Q('p5renameinput').value}); }
1190 - function p5deletefile() { var cc = getFileSelCount(); setDialogMode(2, "Delete", 3, p5deletefileEx, (cc > 1)?('Delete ' + cc + ' selected items?'):('Delete selected item?')); }
1191 - function p5deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(checkboxes[i].value); } } meshserver.send({ action: 'fileoperation', fileop: 'delete', path: filetreelocation, delfiles: delfiles}); }
1192 - function p5renamefile() { var renamefile, checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { renamefile = checkboxes[i].value; } } setDialogMode(2, "Rename", 3, p5renamefileEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'fileoperation', fileop: 'rename', path: filetreelocation, oldname: renamefile}); focusTextBox('p5renameinput'); p5fileNameCheck(); }
1240 + function p5createfolderEx() { meshserver.send({ action: 'fileoperation', fileop: 'createfolder', path: filetreelocation, newfolder: Q('p5renameinput').value }); }
1241 + function p5deletefile() { var cc = getFileSelCount(); setDialogMode(2, "Delete", 3, p5deletefileEx, (cc > 1) ? ('Delete ' + cc + ' selected items?') : ('Delete selected item?')); }
1242 + function p5deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(checkboxes[i].value); } } meshserver.send({ action: 'fileoperation', fileop: 'delete', path: filetreelocation, delfiles: delfiles }); }
1243 + function p5renamefile() { var renamefile, checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { renamefile = checkboxes[i].value; } } setDialogMode(2, "Rename", 3, p5renamefileEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'fileoperation', fileop: 'rename', path: filetreelocation, oldname: renamefile }); focusTextBox('p5renameinput'); p5fileNameCheck(); }
1244 function p5renamefileEx(b, t) { t.newname = Q('p5renameinput').value; meshserver.send(t); }
1245 function p5fileNameCheck(e) { var x = isFilenameValid(Q('p5renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e.keyCode == 13)) { dialogclose(1); } }
1195 - var isFilenameValid = (function(){ var x1=/^[^\\/:\*\?"<>\|]+$/, x2=/^\./, x3=/^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname){ return x1.test(fname)&&!x2.test(fname)&&!x3.test(fname)&&(fname[0] != '.'); } })();
1246 + var isFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
1247 function p5uploadFile() { setDialogMode(2, "Upload File", 3, p5uploadFileEx, '<form method=post enctype=multipart/form-data action=uploadfile.ashx target=fileUploadFrame><input type=text name=link style=display:none id=p5uploadpath value=\"' + encodeURIComponent(filetreelinkpath) + '\" /><input type=file name=files id=p5uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p5uploadinput\')" /><input type=submit id=p5loginSubmit style=display:none /></form>'); updateUploadDialogOk('p5uploadinput'); }
1248 function p5uploadFileEx() { Q('p5loginSubmit').click(); }
1249 function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
1250
1251 var p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0;
1252 function p5copyFile(cut) { var checkboxes = document.getElementsByName('fc'); p5clipboard = []; p5clipboardCut = cut, p5clipboardFolder = Clone(filetreelocation); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == "3")) { p5clipboard.push(checkboxes[i].value); } } p5updateClipview(); }
1202 - function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Confim ' + (p5clipboardCut == 0?'copy':'move') + ' of ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' to this location?' } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
1203 - function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0?'copy':'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
1204 - function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Holding ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1)?'s':'') + ' for ' + (p5clipboardCut == 0?'copy':'move') + ', <a onclick=p5clearClip() style=cursor:pointer>Clear</a>.' } QH('p5bottomstatus', x); p5setActions(); }
1253 + function p5pasteFile() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Confim ' + (p5clipboardCut == 0 ? 'copy' : 'move') + ' of ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1) ? 's' : '') + ' to this location?' } setDialogMode(2, "Paste", 3, p5pasteFileEx, x); }
1254 + function p5pasteFileEx() { meshserver.send({ action: 'fileoperation', fileop: (p5clipboardCut == 0 ? 'copy' : 'move'), scpath: p5clipboardFolder, path: filetreelocation, names: p5clipboard }); p5folderup(999); if (p5clipboardCut == 1) { p5clipboard = null, p5clipboardFolder = null, p5clipboardCut = 0; p5updateClipview(); } }
1255 + function p5updateClipview() { var x = ''; if ((p5clipboard != null) && (p5clipboard.length > 0)) { x = 'Holding ' + p5clipboard.length + ' entrie' + ((p5clipboard.length > 1) ? 's' : '') + ' for ' + (p5clipboardCut == 0 ? 'copy' : 'move') + ', <a onclick=p5clearClip() style=cursor:pointer>Clear</a>.' } QH('p5bottomstatus', x); p5setActions(); }
1256 function p5clearClip() { p5clipboard = null; p5clipboardFolder = null; p5clipboardCut = 0; p5updateClipview(); }
1257
1258 function p5fileDragDrop(e) {
@@ -1216,7 +1267,7 @@
1267 names.push(file.name);
1268 sizes.push(file.size);
1269 types.push(file.type);
1219 - reader.onload = function(event) {
1270 + reader.onload = function (event) {
1271 datas.push(event.target.result);
1272 if (--readercount == 0) {
1273 Q('p5fileDragName').value = names.join('*');
@@ -1428,7 +1479,7 @@
1479 }
1480
1481 function meshSort(a, b) { if (a.meshnamel > b.meshnamel) return 1; if (a.meshnamel < b.meshnamel) return -1; if (a.meshid == b.meshid) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } return 0; }
1431 - function powerSort(a, b) { var ap = a.pwr?a.pwr:0; var bp = b.pwr?b.pwr:0; if (ap == bp) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } if (ap > bp) return 1; if (ap < bp) return -1; return 0; }
1482 + function powerSort(a, b) { var ap = a.pwr ? a.pwr : 0; var bp = b.pwr ? b.pwr : 0; if (ap == bp) { if (showRealNames == true) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; } else { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; } } if (ap > bp) return 1; if (ap < bp) return -1; return 0; }
1483 function deviceSort(a, b) { if (a.namel > b.namel) return 1; if (a.namel < b.namel) return -1; return 0; }
1484 function deviceHostSort(a, b) { if (a.rnamel > b.rnamel) return 1; if (a.rnamel < b.rnamel) return -1; return 0; }
1485
@@ -1491,7 +1542,7 @@
1542 }
1543
1544 // Attribute: Description
1494 - var description = node.desc?EscapeHtml(node.desc):"<i>None</i>";
1545 + var description = node.desc ? EscapeHtml(node.desc) : "<i>None</i>";
1546 if ((meshrights & 4) != 0) {
1547 x += addDeviceAttribute('Description', '<span onclick=showEditNodeValueDialog(2) style=cursor:pointer>' + description + '</span>');
1548 } else {
@@ -1499,7 +1550,7 @@
1550 }
1551
1552 // Attribute: Mesh Agent
1502 - var agentsStr = ['Unknown', 'Windows 32bit console', 'Windows 64bit console', 'Windows 32bit service', 'Windows 64bit service', 'Linux 32bit', 'Linux 64bit', 'MIPS', 'XENx86', 'Android ARM', 'Linux ARM', 'OSX 32bit', 'Android x86', 'PogoPlug ARM', 'Android APK', 'Linux Poky x86-32bit', 'OSX 64bit', 'ChromeOS', 'Linux Poky x86-64bit', 'Linux NoKVM x86-32bit', 'Linux NoKVM x86-64bit', 'Windows MinCore console', 'Windows MinCore service', 'NodeJS', 'ARM-Linaro', 'ARMv6l / ARMv7l' ];
1553 + var agentsStr = ['Unknown', 'Windows 32bit console', 'Windows 64bit console', 'Windows 32bit service', 'Windows 64bit service', 'Linux 32bit', 'Linux 64bit', 'MIPS', 'XENx86', 'Android ARM', 'Linux ARM', 'OSX 32bit', 'Android x86', 'PogoPlug ARM', 'Android APK', 'Linux Poky x86-32bit', 'OSX 64bit', 'ChromeOS', 'Linux Poky x86-64bit', 'Linux NoKVM x86-32bit', 'Linux NoKVM x86-64bit', 'Windows MinCore console', 'Windows MinCore service', 'NodeJS', 'ARM-Linaro', 'ARMv6l / ARMv7l'];
1554 if ((node.agent != null) && (node.agent.id != null) && (node.agent.ver != null)) {
1555 var str = '';
1556 if (node.agent.id <= agentsStr.length) { str = agentsStr[node.agent.id]; } else { str = agentsStr[0]; }
@@ -1590,7 +1641,7 @@
1641 //if (node.state == 0) { powerstate = 'Unknown State'; }
1642 if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px title="Agent connected">Mesh Agent</span>'; }
1643 if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px title="Intel&reg; AMT connected">Intel&reg; AMT connected</span>'; } else
1593 - if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px title="Intel&reg; AMT detected">Intel&reg; AMT detected</span>'; }
1644 + if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += '<span style=font-size:10px title="Intel&reg; AMT detected">Intel&reg; AMT detected</span>'; }
1645 QH('MainComputerState', powerstate);
1646
1647 // Set the node icon
@@ -1613,18 +1664,20 @@
1664 }
1665
1666 function deviceToastFunctionEx() {
1616 - meshserver.send({ action: 'toast', nodeids: [ currentNode._id ], title: 'MeshCentral', msg: Q('d2devToast').value });
1667 + meshserver.send({ action: 'toast', nodeids: [currentNode._id], title: 'MeshCentral', msg: Q('d2devToast').value });
1668 }
1669
1670 function setupDeviceMenu(op, obj) {
1671 + var meshrights = 0;
1672 + if (currentNode) { meshrights = meshes[currentNode.meshid].links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights; }
1673 if (op != null) { currentDevicePanel = op; }
1674 QV('p10general', currentDevicePanel == 0);
1622 - QV('p10desktop', currentDevicePanel == 1);
1675 + QV('p10desktop', currentDevicePanel == 1); // Show if we have remote control rights or desktop view only rights
1676 QV('p10files', currentDevicePanel == 2);
1677 var menus = [];
1678 if (currentDevicePanel != 0) { menus.push({ n: 'General', f: 'setupDeviceMenu(0)' }); }
1626 - if ((currentDevicePanel != 1) && (currentNode != null) && ((currentNode.mtype == 1) || (currentNode.agent.caps & 1))) { menus.push({ n: 'Desktop', f: 'setupDeviceMenu(1)' }); }
1627 - if ((currentDevicePanel != 2) && (currentNode != null) && ((currentNode.mtype == 2) && (currentNode.agent.caps & 4))) { menus.push({ n: 'Files', f: 'setupDeviceMenu(2)' }); }
1679 + if ((currentDevicePanel != 1) && (currentNode != null) && ((meshrights & 8) || (meshrights & 256)) && ((currentNode.mtype == 1) || (currentNode.agent.caps & 1))) { menus.push({ n: 'Desktop', f: 'setupDeviceMenu(1)' }); }
1680 + if ((currentDevicePanel != 2) && (currentNode != null) && (meshrights & 8) && ((currentNode.mtype == 2) && (currentNode.agent.caps & 4))) { menus.push({ n: 'Files', f: 'setupDeviceMenu(2)' }); }
1681 updateFooterMenu(menus);
1682 }
1683
@@ -1644,10 +1697,10 @@
1697 var op = Q('d2deviceop').value;
1698 if (op == 100) {
1699 // Device wake
1647 - meshserver.send({ action: 'wakedevices', nodeids: [ currentNode._id ] });
1700 + meshserver.send({ action: 'wakedevices', nodeids: [currentNode._id] });
1701 } else {
1702 // Power operation
1650 - meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: op });
1703 + meshserver.send({ action: 'poweraction', nodeids: [currentNode._id], actiontype: op });
1704 }
1705 }
1706
@@ -1671,12 +1724,12 @@
1724 // De-compact the timeline
1725 var timeline2 = [];
1726 if (timeline != null && timeline.length > 1) {
1674 - timeline2.push([ 0, timeline[1], timeline[0] ]); // Start, End, Power
1727 + timeline2.push([0, timeline[1], timeline[0]]); // Start, End, Power
1728 var ct = timeline[1];
1729 for (var i = 2; i < timeline.length; i += 2) {
1730 var power = timeline[i], dt = now;
1731 if (timeline.length > (i + 1)) { dt = timeline[i + 1]; }
1679 - timeline2.push([ ct, ct + dt, power ]); // Start, End, Power
1732 + timeline2.push([ct, ct + dt, power]); // Start, End, Power
1733 ct = ct + dt;
1734 }
1735 }
@@ -1699,7 +1752,7 @@
1752 }
1753 }
1754 }
1702 - x += '<tr style=' + (((count % 2) == 0)?'background-color:#DDD':'') + '><td><div>&nbsp;' + date.toLocaleDateString() + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
1755 + x += '<tr style=' + (((count % 2) == 0) ? 'background-color:#DDD' : '') + '><td><div>&nbsp;' + date.toLocaleDateString() + '<div></div></div></td><td><div>' + datavalue + '</div></td></tr>';
1756 ++count;
1757 date = new Date(date.getTime() - (1000 * 60 * 60 * 24)); // Substract one day
1758 }
@@ -1767,7 +1820,7 @@
1820 }
1821
1822 function p10showDeleteNodeDialogEx(buttons, nodeid) {
1770 - meshserver.send({ action: 'removedevices', nodeids: [ nodeid ] });
1823 + meshserver.send({ action: 'removedevices', nodeids: [nodeid] });
1824 }
1825
1826 function p10showiconselector() {
@@ -1851,11 +1904,12 @@
1904 var mesh = meshes[currentNode.meshid];
1905 var deskState = 0;
1906 if (desktop != null) { deskState = desktop.State; }
1907 + var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
1908
1909 // Show the right buttons
1910 QV('disconnectbutton1', (deskState != 0));
1857 - QV('connectbutton1', (deskState == 0) && (mesh.mtype == 2));
1858 - QV('connectbutton1h', (deskState == 0) && ((currentNode.intelamt != null) && (mesh.mtype == 1 || currentNode.intelamt.state == 2) && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
1911 + QV('connectbutton1', (deskState == 0) && (mesh.mtype == 2) && ((meshrights & 8) || (meshrights & 256)));
1912 + QV('connectbutton1h', (deskState == 0) && ((currentNode.intelamt != null) && (meshrights & 8) && (mesh.mtype == 1 || currentNode.intelamt.state == 2) && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
1913
1914 // Show the right settings
1915 QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
@@ -1867,14 +1921,17 @@
1921 var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
1922 QE('connectbutton1h', hwonline);
1923 //QE('deskSaveBtn', deskState == 3);
1870 - QE('DeskCAD', deskState == 3);
1871 - QE('DeskWD', deskState == 3);
1872 - QE('deskkeys', deskState == 3);
1873 - QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5));
1874 - QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5));
1875 - QE('DeskToolsButton', online);
1876 - QV('DeskToastButton', (currentNode.agent) && (currentNode.agent.id < 5));
1924 + //QV('DeskCAD', meshrights & 8);
1925 + //QE('DeskCAD', deskState == 3);
1926 + //QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5));
1927 + //QE('DeskWD', deskState == 3);
1928 + //QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5));
1929 + //QE('deskkeys', deskState == 3);
1930 + //QE('DeskToolsButton', online);
1931 + QV('DeskToastButton', (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
1932 QE('DeskToastButton', online);
1933 + QV('deskActionsBtn', meshrights & 8);
1934 + Q('DeskControl').checked = ((meshrights & 8) != 0);
1935 if (online == false) QV('DeskTools', false);
1936 }
1937
@@ -1965,8 +2022,7 @@
2022 }
2023
2024 function applyDesktopSettings() {
1968 - /*
1969 - var r = '', ops = (features & 512)?[90,70,50,40,30,20,10,5,1]:[50,40,30,20,10,5,1];
2025 + var r = '', ops = (features & 512) ? [90, 70, 50, 40, 30, 20, 10, 5, 1] : [50, 40, 30, 20, 10, 5, 1];
2026 for (var i in ops) { r += '<option value=' + ops[i] + '>' + ops[i] + '%</option>'; }
2027 QH('d7bitmapquality', r);
2028 d7desktopmode.value = desktopsettings.encoding;
@@ -1976,7 +2032,6 @@
2032 if (ops.indexOf(parseInt(desktopsettings.quality)) >= 0) { d7bitmapquality.value = desktopsettings.quality; }
2033 d7bitmapscaling.value = desktopsettings.scaling;
2034 if (desktopsettings.framerate) { d7framelimiter.value = desktopsettings.framerate; }
1979 - */
2035 }
2036
2037 var fullscreen = false;
@@ -2025,6 +2080,7 @@
2080 QS('Desk')['margin-bottom'] = x + 'px';
2081 }
2082
2083 + /*
2084 // Remote desktop special key combos for Windows
2085 function deskSendKeys() {
2086 if (xxdialogMode || desktop == null || desktop.State != 3) return;
@@ -2061,12 +2117,15 @@
2117 }
2118 }
2119 }
2120 + */
2121
2122 + /*
2123 // Send CTRL-ALT-DEL
2124 function sendCAD() {
2125 if (xxdialogMode || desktop == null || desktop.State != 3) return;
2126 desktop.m.sendcad();
2127 }
2128 + */
2129
2130 // Show process dialogs
2131 function toggleDeskTools() {
@@ -2084,7 +2143,7 @@
2143 function refreshDeskTools() {
2144 QV('DeskToolsRefreshButton', false);
2145 setTimeout(refreshDeskToolsEx, 500);
2087 - meshserver.send({ action: 'msg', type:'ps', nodeid: currentNode._id });
2146 + meshserver.send({ action: 'msg', type: 'ps', nodeid: currentNode._id });
2147 }
2148 function refreshDeskToolsEx() { QV('DeskToolsRefreshButton', true); }
2149 var deskTools = { sort: 1, msg: null };
@@ -2099,10 +2158,10 @@
2158 try { processes = JSON.parse(message.value); } catch (e) { }
2159 console.log(processes);
2160 if (processes != null) {
2102 - for (var pid in processes) { p.push( { p:parseInt(pid), c:processes[pid].cmd, d:processes[pid].cmd.toLowerCase(), u: processes[pid].user } ); }
2161 + for (var pid in processes) { p.push({ p: parseInt(pid), c: processes[pid].cmd, d: processes[pid].cmd.toLowerCase(), u: processes[pid].user }); }
2162 if (deskTools.sort == 0) { p.sort(sortProcessPid); } else if (deskTools.sort == 1) { p.sort(sortProcessName); }
2163 var x = '';
2105 - for (var i in p) { if (p[i].p != 0) { x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a style=float:right;padding-right:5px;cursor:pointer title="Stop process" onclick=stopProcess(' + p[i].p + ',"' + p[i].c + '")><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u?p[i].u:'') + '</div><div>' + p[i].c + '</div></div>'; } }
2164 + for (var i in p) { if (p[i].p != 0) { x += '<div class=deskToolsBar><div style=width:50px;float:left;text-align:right;padding-right:5px>' + p[i].p + '</div><a style=float:right;padding-right:5px;cursor:pointer title="Stop process" onclick=stopProcess(' + p[i].p + ',"' + p[i].c + '")><img width=10 height=10 src="images/trash.png"></a><div style=float:right;padding-right:5px>' + (p[i].u ? p[i].u : '') + '</div><div>' + p[i].c + '</div></div>'; } }
2165 QH('DeskToolsProcesses', x);
2166 }
2167 }
@@ -2116,7 +2175,7 @@
2175
2176 function deskDisplayInfo(sender, info, selDisplay, selItem) {
2177 var txt = Q('termdisplays').value;
2119 - if (info.length > 0) { var options = ''; for (var x in info) { options += '<option' + ((txt == info[x])?' selected':'') + '>' + info[x] + '</option>'; } QH('termdisplays', options); }
2178 + if (info.length > 0) { var options = ''; for (var x in info) { options += '<option' + ((txt == info[x]) ? ' selected' : '') + '>' + info[x] + '</option>'; } QH('termdisplays', options); }
2179 QV('termdisplays', info.length > 0);
2180 }
2181
@@ -2128,13 +2187,13 @@
2187 desktop.m.SetDisplay(display);
2188 }
2189
2131 - function dmousedown(e) { if (!xxdialogMode && desktop != null) desktop.m.mousedown(e) }
2132 - function dmouseup(e) { if (!xxdialogMode && desktop != null) desktop.m.mouseup(e) }
2133 - function dmousemove(e) { if (!xxdialogMode && desktop != null) desktop.m.mousemove(e) }
2134 - function dmousewheel(e) { if (!xxdialogMode && desktop != null && desktop.m.mousewheel) { desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
2190 + function dmousedown(e) { if ((!xxdialogMode && desktop != null) && Q('DeskControl').checked) desktop.m.mousedown(e) }
2191 + function dmouseup(e) { if ((!xxdialogMode && desktop != null) && Q('DeskControl').checked) desktop.m.mouseup(e) }
2192 + function dmousemove(e) { if ((!xxdialogMode && desktop != null) && Q('DeskControl').checked) desktop.m.mousemove(e) }
2193 + function dmousewheel(e) { if ((!xxdialogMode && desktop != null) && Q('DeskControl').checked && desktop.m.mousewheel) { desktop.m.mousewheel(e); haltEvent(e); return true; } return false; }
2194 function drotate(x) { if (!xxdialogMode && desktop != null) { desktop.m.setRotation(desktop.m.rotation + x); deskAdjust(); deskAdjust(); } }
2195 function stopProcess(id, name) { setDialogMode(2, "Process Control", 3, stopProcessEx, 'Stop process #' + id + ' "' + name + '"?', id); }
2137 - function stopProcessEx(buttons, tag) { meshserver.send({ action: 'msg', type:'pskill', nodeid: currentNode._id, value: tag }); setTimeout(refreshDeskTools, 300); }
2196 + function stopProcessEx(buttons, tag) { meshserver.send({ action: 'msg', type: 'pskill', nodeid: currentNode._id, value: tag }); setTimeout(refreshDeskTools, 300); }
2197
2198 //
2199 // FILES
@@ -2145,7 +2204,7 @@
2204 // Setup the files tab
2205 var samenode = (filesNode == currentNode);
2206 filesNode = currentNode;
2148 - var online = ((filesNode.conn & 1) != 0)?true:false; // If Agent (1) connected, enable Terminal
2207 + var online = ((filesNode.conn & 1) != 0) ? true : false; // If Agent (1) connected, enable Terminal
2208 QE('p13Connect', online);
2209 if (((samenode == false) || (online == false)) && files) { files.Stop(); files = null; }
2210 }
@@ -2176,8 +2235,8 @@
2235 function CreateRemoteFiles(onFileUpdate) {
2236 var obj = { protocol: 5 };
2237 obj.onFileUpdate = onFileUpdate;
2179 - obj.xxStateChange = function(state) { }
2180 - obj.ProcessData = function(data) { obj.onFileUpdate(data); }
2238 + obj.xxStateChange = function (state) { }
2239 + obj.ProcessData = function (data) { obj.onFileUpdate(data); }
2240 return obj;
2241 }
2242
@@ -2348,9 +2407,9 @@
2407 function p13selectallfile() { var nv = (p13getFileSelCount() == 0), checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p13setActions(); }
2408 function p13createfolder() { setDialogMode(2, "New Folder", 3, p13createfolderEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% />'); focusTextBox('p13renameinput'); p13fileNameCheck(); }
2409 function p13createfolderEx() { files.sendText({ action: 'mkdir', reqid: 1, path: p13filetreelocation.join('/') + '/' + Q('p13renameinput').value }); p13folderup(999); }
2351 - function p13deletefile() { var cc = getFileSelCount(); setDialogMode(2, "Delete", 3, p13deletefileEx, (cc > 1)?('Delete ' + cc + ' selected items?'):('Delete selected item?')); }
2410 + function p13deletefile() { var cc = getFileSelCount(); setDialogMode(2, "Delete", 3, p13deletefileEx, (cc > 1) ? ('Delete ' + cc + ' selected items?') : ('Delete selected item?')); }
2411 function p13deletefileEx() { var delfiles = [], checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { delfiles.push(p13filetree.dir[checkboxes[i].value].n); } } files.sendText({ action: 'rm', reqid: 1, path: p13filetreelocation.join('/'), delfiles: delfiles }); p13folderup(999); }
2353 - function p13renamefile() { var renamefile, checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { renamefile = p13filetree.dir[checkboxes[i].value].n; } } setDialogMode(2, "Rename", 3, p13renamefileEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'rename', path: p13filetreelocation.join('/'), oldname: renamefile}); focusTextBox('p13renameinput'); p13fileNameCheck(); }
2412 + function p13renamefile() { var renamefile, checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { renamefile = p13filetree.dir[checkboxes[i].value].n; } } setDialogMode(2, "Rename", 3, p13renamefileEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% value="' + renamefile + '" />', { action: 'rename', path: p13filetreelocation.join('/'), oldname: renamefile }); focusTextBox('p13renameinput'); p13fileNameCheck(); }
2413 function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.sendText(t); p13folderup(999); }
2414 function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); } }
2415 function p13uploadFile() { setDialogMode(2, "Upload File", 3, p13uploadFileEx, '<input type=file name=files id=p13uploadinput style=width:100% multiple=multiple onchange="updateUploadDialogOk(\'p13uploadinput\')" />'); updateUploadDialogOk('p13uploadinput'); }
@@ -2358,9 +2417,9 @@
2417
2418 var p13clipboard = null, p13clipboardFolder = null, p13clipboardCut = 0;
2419 function p13copyFile(cut) { var checkboxes = document.getElementsByName('fd'); p13clipboard = []; p13clipboardCut = cut, p13clipboardFolder = p13targetpath; for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && (checkboxes[i].attributes.file.value == "3")) { p13clipboard.push(p13filetree.dir[checkboxes[i].value].n); } } p13updateClipview(); }
2361 - function p13pasteFile() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Confim ' + (p13clipboardCut == 0?'copy':'move') + ' of ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' to this location?' } setDialogMode(2, "Paste", 3, p13pasteFileEx, x); }
2362 - 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(); } }
2363 - function p13updateClipview() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Holding ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1)?'s':'') + ' for ' + (p13clipboardCut == 0?'copy':'move') + ', <a onclick=p13clearClip() style=cursor:pointer>Clear</a>.' } QH('p13bottomstatus', x); p13setActions(); }
2420 + function p13pasteFile() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Confim ' + (p13clipboardCut == 0 ? 'copy' : 'move') + ' of ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1) ? 's' : '') + ' to this location?' } setDialogMode(2, "Paste", 3, p13pasteFileEx, x); }
2421 + 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(); } }
2422 + function p13updateClipview() { var x = ''; if ((p13clipboard != null) && (p13clipboard.length > 0)) { x = 'Holding ' + p13clipboard.length + ' entrie' + ((p13clipboard.length > 1) ? 's' : '') + ' for ' + (p13clipboardCut == 0 ? 'copy' : 'move') + ', <a onclick=p13clearClip() style=cursor:pointer>Clear</a>.' } QH('p13bottomstatus', x); p13setActions(); }
2423 function p13clearClip() { p13clipboard = null; p13clipboardFolder = null; p13clipboardCut = 0; p13updateClipview(); }
2424 function updateUploadDialogOk(x) { QE('idx_dlgOkButton', Q(x).value != ''); }
2425 function getFileSelCount(includeDirs) { var cc = 0; var checkboxes = document.getElementsByName('fc'); for (var i = 0; i < checkboxes.length; i++) { if ((checkboxes[i].checked) && ((includeDirs != false) || (checkboxes[i].attributes.file.value == "3"))) cc++; } return cc; }
@@ -2512,7 +2571,7 @@
2571 Q('d2progressBar').value = 0;
2572
2573 uploadFile.xreader = new FileReader();
2515 - uploadFile.xreader.onload = function() {
2574 + uploadFile.xreader.onload = function () {
2575 uploadFile.xdata = uploadFile.xreader.result;
2576 uploadFile.ws.sendText({ action: 'upload', reqid: uploadFile.xfilePtr, path: uploadFile.xpath, name: file.name, size: uploadFile.xdata.byteLength });
2577 };
@@ -2581,7 +2640,7 @@
2640
2641 var x = '';
2642 x += addHtmlValue('Name', addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
2584 - x += addHtmlValue('Description', addLinkConditional(((currentMesh.desc && currentMesh.desc != '')?EscapeHtml(currentMesh.desc):'<i>None</i>'), 'p20editmesh(2)', (meshrights & 1) != 0));
2643 + x += addHtmlValue('Description', addLinkConditional(((currentMesh.desc && currentMesh.desc != '') ? EscapeHtml(currentMesh.desc) : '<i>None</i>'), 'p20editmesh(2)', (meshrights & 1) != 0));
2644 x += addHtmlValue('Type', meshtype);
2645 //x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
2646
@@ -2623,14 +2682,14 @@
2682 // Sort the users for this mesh
2683 var count = 1, sortedusers = [];
2684 for (var i in currentMesh.links) { sortedusers.push({ id: i, name: i.split('/')[2], rights: currentMesh.links[i].rights }); }
2626 - sortedusers.sort(function(a, b) { if (a.name > b.name) return 1; if (a.name < b.name) return -1; return 0; });
2685 + sortedusers.sort(function (a, b) { if (a.name > b.name) return 1; if (a.name < b.name) return -1; return 0; });
2686
2687 // Display all users for this mesh
2688 for (var i in sortedusers) {
2689 var trash = '', rights = 'Partial&nbsp;Rights', r = sortedusers[i].rights;
2690 if (r == 0xFFFFFFFF) rights = 'Full&nbsp;Administrator'; else if (r == 0) rights = 'No&nbsp;Rights';
2691 if ((i != userinfo._id) && (meshrights == 0xFFFFFFFF || (((meshrights & 2) != 0)))) { trash = '<a onclick=p20deleteUser(event,"' + encodeURIComponent(sortedusers[i].id) + '") title="Remote user rights to this mesh" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
2633 - x += '<tr onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") style=height:32px;cursor:pointer' + (((count % 2) == 0)?';background-color:#DDD':'') + '><td>';
2692 + x += '<tr onclick=p20viewuser("' + encodeURIComponent(sortedusers[i].id) + '") style=height:32px;cursor:pointer' + (((count % 2) == 0) ? ';background-color:#DDD' : '') + '><td>';
2693 x += '<div style=float:right>' + trash + '</div><div style=float:right;padding-right:4px>' + rights + '</div><div class=m2></div><div>&nbsp;' + sortedusers[i].name + '<div></div></div>';
2694 x += '</td></tr>';
2695 ++count;
@@ -2693,6 +2752,7 @@
2752 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshserverfiles>Server Files<br>';
2753 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>Wake Devices<br>';
2754 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>Edit Device Notes<br>';
2755 + x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remoteview>Remote View Only<br>';
2756 x += '</div>';
2757 setDialogMode(2, "Add User to Mesh", 3, p20showAddMeshUserDialogEx, x);
2758 p20validateAddMeshUserDialog();
@@ -2711,6 +2771,7 @@
2771 QE('p20meshserverfiles', !Q('p20fulladmin').checked);
2772 QE('p20wakedevices', !Q('p20fulladmin').checked);
2773 QE('p20editnotes', !Q('p20fulladmin').checked);
2774 + QE('p20remoteview', !Q('p20fulladmin').checked);
2775 }
2776
2777 function p20showAddMeshUserDialogEx() {
@@ -2724,8 +2785,9 @@
2785 if (Q('p20meshserverfiles').checked == true) meshadmin += 32;
2786 if (Q('p20wakedevices').checked == true) meshadmin += 64;
2787 if (Q('p20editnotes').checked == true) meshadmin += 128;
2788 + if (Q('p20remoteview').checked == true) meshadmin += 256;
2789 }
2728 - meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value , meshadmin: meshadmin});
2790 + meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value, meshadmin: meshadmin });
2791 }
2792
2793 function p20viewuser(userid) {
@@ -2733,13 +2795,13 @@
2795 userid = decodeURIComponent(userid);
2796 var r = '', cmeshrights = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights, meshrights = currentMesh.links[userid].rights;
2797 if (meshrights == 0xFFFFFFFF) r = ', Full Administrator'; else {
2736 - if ((meshrights & 1) != 0) r += ', Edit Device Group';
2737 - if ((meshrights & 2) != 0) r += ', Manage Device Group Users';
2738 - if ((meshrights & 4) != 0) r += ', Manage Device Group Computers';
2739 - if ((meshrights & 8) != 0) r += ', Remote Control';
2740 - if ((meshrights & 16) != 0) r += ', Agent Console';
2741 - if ((meshrights & 32) != 0) r += ', Server Files';
2742 - if ((meshrights & 64) != 0) r += ', Wake Devices';
2798 + if ((meshrights & 1) != 0) r += ', Edit Device Group';
2799 + if ((meshrights & 2) != 0) r += ', Manage Device Group Users';
2800 + if ((meshrights & 4) != 0) r += ', Manage Device Group Computers';
2801 + if ((meshrights & 8) != 0) r += ', Remote Control';
2802 + if ((meshrights & 16) != 0) r += ', Agent Console';
2803 + if ((meshrights & 32) != 0) r += ', Server Files';
2804 + if ((meshrights & 64) != 0) r += ', Wake Devices';
2805 if ((meshrights & 128) != 0) r += ', Edit Notes';
2806 }
2807 r = r.substring(2);
@@ -2752,7 +2814,7 @@
2814
2815 function p20viewuserEx(button, userid) { if (button != 2) return; setDialogMode(2, "Remote Mesh User", 3, p20viewuserEx2, "Confirm removal of user " + userid.split('/')[2] + "?", userid); }
2816 function p20deleteUser(e, userid) { haltEvent(e); p20viewuserEx(2, decodeURIComponent(userid)); }
2755 - function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid}); }
2817 + function p20viewuserEx2(button, userid) { meshserver.send({ action: 'removemeshuser', meshid: currentMesh._id, meshname: currentMesh.name, userid: userid }); }
2818
2819 //
2820 // PANELS
@@ -2820,8 +2882,8 @@
2882 function passwordcheck(p) { var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()]).{8,}/; return re.test(p); }
2883 function getFileSizeStr(size) { if (size == 1) return "1 byte"; return "" + size + " bytes"; }
2884 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('/'); }
2823 - function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
2824 - var isFilenameValid = (function(){ var x1=/^[^\\/:\*\?"<>\|]+$/, x2=/^\./, x3=/^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname){ return x1.test(fname)&&!x2.test(fname)&&!x3.test(fname)&&(fname[0] != '.'); } })();
2885 + function focusTextBox(x) { setTimeout(function () { Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
2886 + var isFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); } })();
2887
2888 </script>
2889 </body>
views/default.handlebars
+31 -15
@@ -236,7 +236,7 @@
236 <div id=p2 style="display:none">
237 <h1>My Account</h1>
238 <div id="p2AccountActions">
239 - <p><strong><img alt="" width=150 height=103 src=images/mainaccount.png style=margin-bottom:10px;margin-right:20px;float:right />Account actions</strong></p>
239 + <p><strong><img alt="" width=150 height=103 src=images/mainaccount.jpg style=margin-bottom:10px;margin-right:20px;float:right />Account actions</strong></p>
240 <p style="margin-left:40px">
241 <span id="verifyEmailId" style="display:none"><a onclick="account_showVerifyEmail()" style="cursor:pointer">Verify email</a><br /></span>
242 <a onclick="account_showChangeEmail()" style="cursor:pointer">Change email address</a><br />
@@ -462,7 +462,7 @@
462 </select>
463 <input id="DeskWD" type=button value="Send" onkeypress="return false" onkeydown="return false" onclick="deskSendKeys()">
464 <input id="DeskCAD" style="margin-left:6px" type="button" value="Ctrl-Alt-Del" onkeypress="return false" onkeydown="return false" onclick="sendCAD()">
465 - <span style="margin-left:6px" title="Toggle mouse and keyboard input"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()">Input</span>&nbsp;
465 + <span id="DeskControlSpan" style="margin-left:6px" title="Toggle mouse and keyboard input"><input id="DeskControl" type="checkbox" onkeypress="return false" onkeydown="return false" onclick="toggleKvmControl()">Input</span>&nbsp;
466 </div>
467 </td>
468 </tr>
@@ -662,7 +662,10 @@
662 <div id=p16events style="max-height:calc(100vh - 267px);overflow-y:auto"></div>
663 </div>
664 <div id=p20 style="display:none">
665 - <img id=MainMeshImage src="images/mesh-200.png" style=border-width:0px;height:200px;width:200px;float:right>
665 + <picture id=MainMeshImage style=border-width:0px;height:200px;width:200px;float:right>
666 + <source type="image/webp" width=200 height=200 srcset="images/webp/mesh-200.webp">
667 + <img alt="" width=200 height=200 src=images/mesh-200.jpg />
668 + </picture>
669 <div style="float:left"><div class="backButton" onclick=goBack() title="Back"><div class="backButtonEx"></div></div></div>
670 <h1>General - <span id=p20meshName></span></h1>
671 <p id=p20info></p>
@@ -679,7 +682,10 @@
682 </td>
683 <td style=width:20px></td>
684 <td style=width:200px>
682 - <img id=MainUserImage src="images/user-200.png" style=border-width:0px;height:200px;width:200px>
685 + <picture id=MainUserImage style=border-width:0px;height:200px;width:200px;float:right>
686 + <source type="image/webp" width=200 height=200 srcset="images/webp/user-200.webp">
687 + <img alt="" width=200 height=200 src=images/user-200.jpg />
688 + </picture>
689 <div style="width:100%;text-align:center"><strong><span id=MainUserState></span></strong></div>
690 </td>
691 </tr>
@@ -890,6 +896,7 @@
896 var hide = parseInt(args.hide);
897 QV('masthead', !(hide & 1));
898 QV('topbarmaster', !(hide & 2));
899 + QV('page_leftbar', !(hide & 2));
900 QV('footer', !(hide & 4));
901 QV('p10title', !(hide & 8));
902 QV('p11title', !(hide & 8));
@@ -1068,6 +1075,7 @@
1075 QV('p2ServerActionsRestore', siteRights & 4);
1076 QV('p2ServerActionsVersion', siteRights & 16);
1077 QV('MainMenuMyFiles', siteRights & 8);
1078 + QV('LeftMenuMyFiles', siteRights & 8);
1079 if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { setDialogMode(0); go(1); }
1080 if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
1081
@@ -1753,7 +1761,7 @@
1761 r += '<div style=float:left;height:18px;width:18px;background-color:white onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class=j' + icon + ' style=width:16px;margin-top:1px;margin-left:2px;height:16px></div></div>';
1762 r += '<div class=g1 style=height:18px;float:left></div><div class=g2 style=height:18px;float:right></div>';
1763 r += '<div style=cursor:pointer;font-size:14px title="' + title + '" onclick=gotoDevice(\'' + nodes[i]._id + '\')><span style=float:right>' + nodestate + '</span><span style=width:300px>' + name + '</span></div></div></td></tr>';
1756 - } else if ((view == 3) && (nodes[i].conn & 1) && ((meshrights & 8) != 0) && ((nodes[i].agent.caps & 1) != 0)) { // Check if we have rights and agent is capable of KVM.
1764 + } else if ((view == 3) && (nodes[i].conn & 1) && (((meshrights & 8) || (meshrights & 256)) != 0) && ((nodes[i].agent.caps & 1) != 0)) { // Check if we have rights and agent is capable of KVM.
1765 if ((multiDesktopFilter.length == 0) || (multiDesktopFilter.indexOf('devid_' + nodes[i]._id) >= 0)) {
1766 r += '<div id=devs style=display:inline-block;margin:1px;background-color:lightgray;border-radius:5px;position:relative><div style=padding:3px;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\',11)>';
1767 //r += '<input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox style=float:left>';
@@ -1914,7 +1922,7 @@
1922
1923 function toggleKvmDevice(nodeid) {
1924 var node = getNodeFromId(nodeid), mesh = meshes[node.meshid], meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
1917 - if ((meshrights & 8) != 0) { // Requires remote control rights
1925 + if ((meshrights & 8) || (meshrights & 256)) { // Requires remote control rights or desktop view only rights
1926 //var conn = 0;
1927 //if ((node.conn & 1) != 0) { conn = 1; } else if ((node.conn & 6) != 0) { conn = 2; } // Check what type of connect we can do (Agent vs AMT)
1928 if (node.conn & 1) { connectMultiDesktop(node, 1); }
@@ -2375,7 +2383,7 @@
2383 var meshlinks = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
2384 var meshrights = meshlinks.rights;
2385 var consoleRights = ((meshrights & 16) != 0);
2378 - QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8));
2386 + QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((meshrights & 8) || (meshrights & 256)));
2387 QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8));
2388 QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8));
2389 QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
@@ -3199,7 +3207,7 @@
3207 QH('MainComputerState', powerstate);
3208
3209 // Set the node icon
3202 - Q('MainComputerImage').setAttribute("src", "images/icons200-" + node.icon + "-1.png");
3210 + Q('MainComputerImage').setAttribute("src", "images/icons200-" + node.icon + "-1.jpg");
3211 Q('MainComputerImage').className = ((!node.conn) || (node.conn == 0)?'gray':'');
3212
3213 // Setup/Refresh the desktop tab
@@ -3211,7 +3219,7 @@
3219 // Show or hide the tabs
3220 // mesh.mtype: 1 = Intel AMT only, 2 = Mesh Agent
3221 // node.agent.caps (bitmask): 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console
3214 - QV('MainDevDesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8));
3222 + QV('MainDevDesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((meshrights & 8) || (meshrights & 256)));
3223 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));
3224 QV('MainDevFiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8));
3225 QV('MainDevAmt', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
@@ -3623,11 +3631,12 @@
3631 var mesh = meshes[currentNode.meshid];
3632 var deskState = 0;
3633 if (desktop != null) { deskState = desktop.State; }
3634 + var meshrights = mesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()].rights;
3635
3636 // Show the right buttons
3637 QV('disconnectbutton1span', (deskState != 0));
3629 - QV('connectbutton1span', (deskState == 0) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
3630 - QV('connectbutton1hspan', (deskState == 0) && ((currentNode.intelamt != null) && (mesh.mtype == 1 || currentNode.intelamt.state == 2) && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
3638 + QV('connectbutton1span', (deskState == 0) && ((meshrights & 8) || (meshrights & 256)) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
3639 + QV('connectbutton1hspan', (deskState == 0) && (meshrights & 8) && ((currentNode.intelamt != null) && (mesh.mtype == 1 || currentNode.intelamt.state == 2) && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))));
3640
3641 // Show the right settings
3642 QV('d7amtkvm', (currentNode.intelamt != null && ((currentNode.intelamt.ver != null) || (mesh.mtype == 1))) && ((deskState == 0) || (desktop.contype == 2)));
@@ -3640,14 +3649,18 @@
3649 QE('connectbutton1h', hwonline);
3650 QE('deskSaveBtn', deskState == 3);
3651 QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (deskState != 0) && (desktopsettings.showfocus));
3652 + QV('DeskCAD', meshrights & 8);
3653 QE('DeskCAD', deskState == 3);
3654 + QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
3655 QE('DeskWD', deskState == 3);
3656 + QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
3657 QE('deskkeys', deskState == 3);
3646 - QV('DeskWD', (currentNode.agent) && (currentNode.agent.id < 5));
3647 - QV('deskkeys', (currentNode.agent) && (currentNode.agent.id < 5));
3658 + QV('DeskToolsButton', meshrights & 8);
3659 QE('DeskToolsButton', online);
3649 - QV('DeskToastButton', (currentNode.agent) && (currentNode.agent.id < 5));
3660 + QV('DeskToastButton', (currentNode.agent) && (currentNode.agent.id < 5) && (meshrights & 8));
3661 QE('DeskToastButton', online);
3662 + QV('DeskControlSpan', meshrights & 8)
3663 + if (meshrights & 8) { Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); } else { Q('DeskControl').checked = false; }
3664 if (online == false) QV('DeskTools', false);
3665 }
3666
@@ -5072,7 +5085,7 @@
5085 //x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
5086
5087 // Display group note support
5075 - x += '<br><input type=button value=Notes title="View notes about this device group" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
5088 + if (meshrights & 1) { x += '<br><input type=button value=Notes title="View notes about this device group" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />'; }
5089
5090 x += '<br style=clear:both><br>';
5091 var currentMeshLinks = currentMesh.links['user/' + domain + '/' + userinfo.name.toLowerCase()];
@@ -5192,6 +5205,7 @@
5205 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20meshserverfiles>Server Files<br>';
5206 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20wakedevices>Wake Devices<br>';
5207 x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editnotes>Edit Device Notes<br>';
5208 + x += '<input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20remoteview>Remote View Only<br>';
5209 x += '</div>';
5210 setDialogMode(2, "Add User to Device Group", 3, p20showAddMeshUserDialogEx, x);
5211 p20validateAddMeshUserDialog();
@@ -5210,6 +5224,7 @@
5224 QE('p20meshserverfiles', !Q('p20fulladmin').checked);
5225 QE('p20wakedevices', !Q('p20fulladmin').checked);
5226 QE('p20editnotes', !Q('p20fulladmin').checked);
5227 + QE('p20remoteview', !Q('p20fulladmin').checked);
5228 }
5229
5230 function p20showAddMeshUserDialogEx() {
@@ -5223,6 +5238,7 @@
5238 if (Q('p20meshserverfiles').checked == true) meshadmin += 32;
5239 if (Q('p20wakedevices').checked == true) meshadmin += 64;
5240 if (Q('p20editnotes').checked == true) meshadmin += 128;
5241 + if (Q('p20remoteview').checked == true) meshadmin += 256;
5242 }
5243 meshserver.send({ action: 'addmeshuser', meshid: currentMesh._id, meshname: currentMesh.name, username: Q('dp20username').value , meshadmin: meshadmin});
5244 }
views/login.handlebars
+4 -1
@@ -110,7 +110,10 @@
110 <table id="centralTable" style=width:100%>
111 <tr>
112 <td id="welcomeimage" align="right">
113 - <img alt="" height=310 src=images/mainwelcome.png width=359 />
113 + <picture>
114 + <source type="image/webp" width=359 height=310 srcset="images/webp/mainwelcome.webp">
115 + <img alt="" width=359 height=310 src=images/mainwelcome.jpg />
116 + </picture>
117 </td>
118 <td id="logincell" align="left">
119 <div id=loginpanel style="background-color: #979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
webserver.js
+2 -2
@@ -1817,13 +1817,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1817 // Server picture
1818 obj.app.get(url + 'serverpic.ashx', function (req, res) {
1819 // Check if we have "server.png" in the data folder, if so, use that.
1820 - var p = obj.path.join(obj.parent.datapath, 'server.png');
1820 + var p = obj.path.join(obj.parent.datapath, 'server.jpg');
1821 if (obj.fs.existsSync(p)) {
1822 // Use the data folder server picture
1823 try { res.sendFile(p); } catch (e) { res.sendStatus(404); }
1824 } else {
1825 // Use the default server picture
1826 - try { res.sendFile(obj.path.join(__dirname, 'public/images/server-200.png')); } catch (e) { res.sendStatus(404); }
1826 + try { res.sendFile(obj.path.join(__dirname, 'public/images/server-200.jpg')); } catch (e) { res.sendStatus(404); }
1827 }
1828 });
1829