Improved web user interface.

Ylian Saint-Hilaire committed Dec 14, 2017 at 14:57 UTC da4cade3a494841ce8ef4f07673173153cc6c8db
8 files changed +134 -63
agents/meshcore.js
+9 -1
@@ -362,11 +362,13 @@ function createMeshCore(agent) {
362 }
363
364 // Called when a file changed in the file system
365 + /*
366 function onFileWatcher(a, b) {
367 console.log('onFileWatcher', a, b, this.path);
368 var response = getDirectoryInfo(this.path);
369 if ((response != undefined) && (response != null)) { this.tunnel.s.write(JSON.stringify(response)); }
370 }
371 + */
372
373 // Get a formated response for a given directory path
374 function getDirectoryInfo(reqpath) {
@@ -447,12 +449,14 @@ function createMeshCore(agent) {
449 if (this.httprequest.protocol == 1) { this.httprequest.process.end(); delete this.httprequest.process; }
450 delete tunnels[this.httprequest.index];
451
452 + /*
453 // Close the watcher if required
454 if (this.httprequest.watcher != undefined) {
455 //console.log('Closing watcher: ' + this.httprequest.watcher.path);
456 //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
457 delete this.httprequest.watcher;
458 }
459 + */
460
461 // If there is a upload or download active on this connection, close the file
462 if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); this.httprequest.uploadFile = undefined; }
@@ -581,6 +585,7 @@ function createMeshCore(agent) {
585 console.log(objToString(cmd, 0, '.'));
586 switch (cmd.action) {
587 case 'ls': {
588 + /*
589 // Close the watcher if required
590 var samepath = ((this.httprequest.watcher != undefined) && (cmd.path == this.httprequest.watcher.path));
591 if ((this.httprequest.watcher != undefined) && (samepath == false)) {
@@ -588,12 +593,14 @@ function createMeshCore(agent) {
593 //this.httprequest.watcher.close(); // TODO: This line causes the agent to crash!!!!
594 delete this.httprequest.watcher;
595 }
596 + */
597
598 // Send the folder content to the browser
599 var response = getDirectoryInfo(cmd.path);
600 if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
601 this.write(JSON.stringify(response));
602
603 + /*
604 // Start the directory watcher
605 if ((cmd.path != '') && (samepath == false)) {
606 var watcher = fs.watch(cmd.path, onFileWatcher);
@@ -602,6 +609,7 @@ function createMeshCore(agent) {
609 this.httprequest.watcher = watcher;
610 //console.log('Starting watcher: ' + this.httprequest.watcher.path);
611 }
612 + */
613 break;
614 }
615 case 'mkdir': {
@@ -676,7 +684,7 @@ function createMeshCore(agent) {
684 var response = null;
685 switch (cmd) {
686 case 'help': { // Displays available commands
679 - response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi.';
687 + response = 'xxxxxxAvailable commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi.';
688 break;
689 }
690 case 'notify': { // Send a notification message to the mesh
meshcentral.js
+11 -9
@@ -72,7 +72,7 @@ function CreateMeshCentralServer() {
72 try { require('./pass').hash('test', function () { }); } catch (e) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
73
74 // Check for invalid arguments
75 - var validArguments = ['_', 'notls', 'user', 'port', 'mpsport', 'redirport', 'cert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey'];
75 + var validArguments = ['_', 'notls', 'user', 'port', 'mpsport', 'redirport', 'cert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'shownodes', 'showmeshes', 'showevents', 'showpower', 'showiplocations', 'help', 'exactports', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpsdebug', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbimport', 'selfupdate', 'tlsoffload', 'userallowedip', 'fastcert', 'swarmport', 'swarmdebug', 'logintoken', 'logintokenkey', 'logintokengen', 'logintokengen', 'mailtokengen'];
76 for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
77 if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
78
@@ -372,7 +372,7 @@ function CreateMeshCentralServer() {
372 // Load the login cookie encryption key from the database if allowed
373 if ((obj.config) && (obj.config.settings) && (obj.config.settings.loginTokenOk == true)) {
374 obj.db.Get('LoginCookieEncryptionKey', function (err, docs) {
375 - if ((docs.length > 0) && (docs[0].key != null)) {
375 + if ((docs.length > 0) && (docs[0].key != null) && (obj.args.logintokengen == null)) {
376 obj.loginCookieEncryptionKey = Buffer.from(docs[0].key, 'hex');
377 } else {
378 obj.loginCookieEncryptionKey = obj.generateCookieKey(); obj.db.Set({ _id: 'LoginCookieEncryptionKey', key: obj.loginCookieEncryptionKey.toString('hex'), time: Date.now() });
@@ -456,10 +456,12 @@ function CreateMeshCentralServer() {
456 if (!obj.db) return;
457
458 obj.debug(3, 'DispatchEvent', ids);
459 - event.type = 'event';
460 - event.time = Date.now();
461 - event.ids = ids;
462 - if (!event.nolog) { obj.db.StoreEvent(ids, source, event); }
459 + if (typeof event == 'object') {
460 + event.type = 'event';
461 + event.time = Date.now();
462 + event.ids = ids;
463 + if (!event.nolog) { obj.db.StoreEvent(ids, source, event); }
464 + }
465 var targets = []; // List of targets we dispatched the event to, we don't want to dispatch to the same target twice.
466 for (var j in ids) {
467 var id = ids[j];
@@ -472,7 +474,7 @@ function CreateMeshCentralServer() {
474 }
475 }
476 }
475 - if ((fromPeerServer == null) && (obj.multiServer != null) && (event.nopeers != 1)) { obj.multiServer.DispatchEvent(ids, source, event); }
477 + if ((fromPeerServer == null) && (obj.multiServer != null) && ((typeof event != 'object') || (event.nopeers != 1))) { obj.multiServer.DispatchEvent(ids, source, event); }
478 delete targets;
479 }
480
@@ -842,7 +844,7 @@ function CreateMeshCentralServer() {
844 } else {
845 // Load the login cookie encryption key from the database
846 obj.db.Get('LoginCookieEncryptionKey', function (err, docs) {
845 - if ((docs.length > 0) && (docs[0].key != null)) {
847 + if ((docs.length > 0) && (docs[0].key != null) && (obj.args.logintokengen == null)) {
848 // Key is present, use it.
849 obj.loginCookieEncryptionKey = Buffer.from(docs[0].key, 'hex');
850 func(obj.encodeCookie({ u: userid, a: 3 }, obj.loginCookieEncryptionKey));
@@ -860,7 +862,7 @@ function CreateMeshCentralServer() {
862 obj.showLoginTokenKey = function (func) {
863 // Load the login cookie encryption key from the database
864 obj.db.Get('LoginCookieEncryptionKey', function (err, docs) {
863 - if ((docs.length > 0) && (docs[0].key != null)) {
865 + if ((docs.length > 0) && (docs[0].key != null) && (obj.args.logintokengen == null)) {
866 // Key is present, use it.
867 func(docs[0].key);
868 } else {
meshmail.js
+1 -1
@@ -94,7 +94,7 @@ module.exports.CreateMeshMain = function (parent) {
94
95 // Load the cookie encryption key from the database
96 obj.parent.db.Get('MailCookieEncryptionKey', function (err, docs) {
97 - if ((docs.length > 0) && (docs[0].key != null)) {
97 + if ((docs.length > 0) && (docs[0].key != null) && (obj.parent.mailtokengen == null)) {
98 // Key is present, use it.
99 obj.mailCookieEncryptionKey = Buffer.from(docs[0].key, 'hex');
100 } else {
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.1.0-x",
3 + "version": "0.1.1-c",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/scripts/ol3-contextmenu.js
+1 -1
@@ -5,4 +5,4 @@
5 * Built: Fri Feb 24 2017 15:11:20 GMT-0300 (BRT)
6 */
7 !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.ContextMenu=e()}(this,function(){"use strict";var t="ol-ctx-menu",e="-container",n="-separator",i="-submenu",s="-hidden",o="-icon",a="-zoom-in",r="-zoom-out",l="ol-unselectable",c={BEFOREOPEN:"beforeopen",OPEN:"open",CLOSE:"close",ADD_MENU_ENTRY:"add-menu-entry",CONTEXTMENU:"contextmenu",HOVER:"mouseover"},h={container:t+e,separator:t+n,submenu:t+i,hidden:t+s,icon:t+o,zoomIn:t+a,zoomOut:t+r,OL_unselectable:l},u={width:150,scrollAt:4,eventType:c.CONTEXTMENU,defaultItems:!0},d=[{text:"Zoom In",classname:[h.zoomIn,h.icon].join(" "),callback:function(t,e){var n=e.getView();n.animate({zoom:+n.getZoom()+1,duration:700,center:t.coordinate})}},{text:"Zoom Out",classname:[h.zoomOut,h.icon].join(" "),callback:function(t,e){var n=e.getView();n.animate({zoom:+n.getZoom()-1,duration:700,center:t.coordinate})}}],p={isNumeric:function(t){return/^\d+$/.test(t)},classRegex:function(t){return new RegExp("(^|\\s+) "+t+" (\\s+|$)")},addClass:function(t,e,n){var i=this;if(Array.isArray(t))return void t.forEach(function(t){i.addClass(t,e)});for(var s=Array.isArray(e)?e:e.split(/\s+/),o=s.length;o--;)i.hasClass(t,s[o])||i._addClass(t,s[o],n)},_addClass:function(t,e,n){var i=this;t.classList?t.classList.add(e):t.className=(t.className+" "+e).trim(),n&&this.isNumeric(n)&&window.setTimeout(function(){i._removeClass(t,e)},n)},removeClass:function(t,e,n){var i=this;if(Array.isArray(t))return void t.forEach(function(t){i.removeClass(t,e,n)});for(var s=Array.isArray(e)?e:e.split(/\s+/),o=s.length;o--;)i.hasClass(t,s[o])&&i._removeClass(t,s[o],n)},_removeClass:function(t,e,n){var i=this;t.classList?t.classList.remove(e):t.className=t.className.replace(this.classRegex(e)," ").trim(),n&&this.isNumeric(n)&&window.setTimeout(function(){i._addClass(t,e)},n)},hasClass:function(t,e){return t.classList?t.classList.contains(e):this.classRegex(e).test(t.className)},toggleClass:function(t,e){var n=this;return Array.isArray(t)?void t.forEach(function(t){n.toggleClass(t,e)}):void(t.classList?t.classList.toggle(e):this.hasClass(t,e)?this._removeClass(t,e):this._addClass(t,e))},$:function(t){return t="#"===t[0]?t.substr(1,t.length):t,document.getElementById(t)},isElement:function(t){return"HTMLElement"in window?!!t&&t instanceof HTMLElement:!!t&&"object"==typeof t&&1===t.nodeType&&!!t.nodeName},find:function(t,e,n){void 0===e&&(e=window.document);var i=/^(#?[\w-]+|\.[\w-.]+)$/,s=/\./g,o=Array.prototype.slice,a=[];if(i.test(t))switch(t[0]){case"#":a=[this.$(t.substr(1))];break;case".":a=o.call(e.getElementsByClassName(t.substr(1).replace(s," ")));break;default:a=o.call(e.getElementsByTagName(t))}else a=o.call(e.querySelectorAll(t));return n?a:a[0]},offset:function(t){var e=t.getBoundingClientRect(),n=document.documentElement;return{left:e.left+window.pageXOffset-n.clientLeft,top:e.top+window.pageYOffset-n.clientTop,width:t.offsetWidth,height:t.offsetHeight}},getViewportSize:function(){return{w:window.innerWidth||document.documentElement.clientWidth,h:window.innerHeight||document.documentElement.clientHeight}},getAllChildren:function(t,e){return[].slice.call(t.getElementsByTagName(e))},isEmpty:function(t){return!t||0===t.length},emptyArray:function(t){for(;t.length;)t.pop()},removeAllChildren:function(t){for(;t.firstChild;)t.removeChild(t.firstChild)},mergeOptions:function(t,e){var n={};for(var i in t)n[i]=t[i];for(var s in e)n[s]=e[s];return n},createFragment:function(t){var e=document.createDocumentFragment(),n=document.createElement("div");for(n.innerHTML=t;n.firstChild;)e.appendChild(n.firstChild);return e},contains:function(t,e){return!!~e.indexOf(t)},getUniqueId:function(){return"_"+Math.random().toString(36).substr(2,9)},isDefAndNotNull:function(t){return null!=t},assertEqual:function(t,e,n){if(t!==e)throw new Error(n+" mismatch: "+t+" != "+e)},assert:function(t,e){if(void 0===e&&(e="Assertion failed"),!t){if("undefined"!=typeof Error)throw new Error(e);throw e}}},m=function(t){return this.Base=t,this.map=void 0,this.viewport=void 0,this.coordinateClicked=void 0,this.pixelClicked=void 0,this.lineHeight=0,this.items={},this.opened=!1,this.submenu={left:t.options.width-15+"px",lastLeft:""},this.eventHandler=this.handleEvent.bind(this),this};m.prototype.init=function(t){this.map=t,this.viewport=t.getViewport(),this.setListeners(),this.Base.Html.createMenu(),this.lineHeight=this.getItemsLength()>0?this.Base.container.offsetHeight/this.getItemsLength():this.Base.Html.cloneAndGetLineHeight()},m.prototype.getItemsLength=function(){var t=this,e=0;return Object.keys(this.items).forEach(function(n){t.items[n].submenu||t.items[n].separator||e++}),e},m.prototype.getPixelClicked=function(){return this.pixelClicked},m.prototype.getCoordinateClicked=function(){return this.coordinateClicked},m.prototype.positionContainer=function(t){var e=this,n=this.map.getSize(),i=n[0],s=n[1],o=s-t[1],a=i-t[0],r={w:this.Base.container.offsetWidth,h:Math.round(this.lineHeight*this.getItemsLength())},l=p.find("li."+h.submenu+"> div",this.Base.container,!0);a>=r.w?(this.Base.container.style.right="auto",this.Base.container.style.left=t[0]+5+"px"):(this.Base.container.style.left="auto",this.Base.container.style.right="15px"),o>=r.h?(this.Base.container.style.bottom="auto",this.Base.container.style.top=t[1]-10+"px"):(this.Base.container.style.top="auto",this.Base.container.style.bottom=0),p.removeClass(this.Base.container,h.hidden),l.length&&(a<2*r.w?this.submenu.lastLeft="-"+r.w+"px":this.submenu.lastLeft=this.submenu.left,l.forEach(function(t){var n=p.getViewportSize(),i=p.offset(t),s=i.height,a=o-s;a<0&&(a=s-(n.h-i.top),t.style.top="-"+a+"px"),t.style.left=e.submenu.lastLeft}))},m.prototype.openMenu=function(t,e){this.Base.dispatchEvent({type:c.OPEN,pixel:t,coordinate:e}),this.opened=!0,this.positionContainer(t)},m.prototype.closeMenu=function(){this.opened=!1,p.addClass(this.Base.container,h.hidden),this.Base.dispatchEvent({type:c.CLOSE})},m.prototype.setListeners=function(){this.viewport.addEventListener(this.Base.options.eventType,this.eventHandler,!1)},m.prototype.removeListeners=function(){this.viewport.removeEventListener(this.Base.options.eventType,this.eventHandler,!1)},m.prototype.handleEvent=function(t){var e=this;this.coordinateClicked=this.map.getEventCoordinate(t),this.pixelClicked=this.map.getEventPixel(t),this.Base.dispatchEvent({type:c.BEFOREOPEN,pixel:this.pixelClicked,coordinate:this.coordinateClicked}),this.Base.disabled||(this.Base.options.eventType===c.CONTEXTMENU&&(t.stopPropagation(),t.preventDefault()),this.openMenu(this.pixelClicked,this.coordinateClicked),t.target.addEventListener("mousedown",{handleEvent:function(n){e.closeMenu(),t.target.removeEventListener(n.type,this,!1)}},!1))},m.prototype.setItemListener=function(t,e){var n=this;t&&"function"==typeof this.items[e].callback&&!function(i){t.addEventListener("click",function(t){t.preventDefault();var s={coordinate:n.getCoordinateClicked(),data:n.items[e].data||null};n.closeMenu(),i(s,n.map)},!1)}(this.items[e].callback)};var f=function(t){return this.Base=t,this.Base.container=this.container=this.createContainer(),this};f.prototype.createContainer=function(t){var e=document.createElement("div"),n=document.createElement("ul"),i=[h.container,h.OL_unselectable];return t&&i.push(h.hidden),e.className=i.join(" "),e.style.width=parseInt(this.Base.options.width,10)+"px",e.appendChild(n),e},f.prototype.createMenu=function(){var t=[];return"items"in this.Base.options?t=this.Base.options.defaultItems?this.Base.options.items.concat(d):this.Base.options.items:this.Base.options.defaultItems&&(t=d),0!==t.length&&void t.forEach(this.addMenuEntry,this)},f.prototype.addMenuEntry=function(t){var e=this;if(t.items&&Array.isArray(t.items)){t.classname=t.classname||"",p.contains(h.submenu,t.classname)||(t.classname=t.classname.length?" "+h.submenu:h.submenu);var n=this.generateHtmlAndPublish(this.container,t),i=this.createContainer();i.style.left=this.Base.Internal.submenu.lastLeft||this.Base.Internal.submenu.left,n.appendChild(i),t.items.forEach(function(t){e.generateHtmlAndPublish(i,t,!0)})}else this.generateHtmlAndPublish(this.container,t)},f.prototype.generateHtmlAndPublish=function(t,e,n){var i,s,o,a=!1,r=p.getUniqueId();return"string"==typeof e&&"-"===e.trim()?(i=['<li id="',r,'" class="',h.separator,'">',"<hr></li>"].join(""),s=p.createFragment(i),o=[].slice.call(s.childNodes,0)[0],t.firstChild.appendChild(s),a=!0):(e.classname=e.classname||"",i="<span>"+e.text+"</span>",s=p.createFragment(i),o=document.createElement("li"),e.icon&&(""===e.classname?e.classname=h.icon:e.classname.indexOf(h.icon)===-1&&(e.classname+=" "+h.icon),o.setAttribute("style","background-image:url("+e.icon+")")),o.id=r,o.className=e.classname,o.appendChild(s),t.firstChild.appendChild(o)),this.Base.Internal.items[r]={id:r,submenu:n||0,separator:a,callback:e.callback,data:e.data||null},this.Base.Internal.setItemListener(o,r),o},f.prototype.removeMenuEntry=function(t){var e=p.find("#"+t,this.container.firstChild);e&&this.container.firstChild.removeChild(e),delete this.Base.Internal.items[t]},f.prototype.cloneAndGetLineHeight=function(){var t=this.container.cloneNode(),e=p.createFragment("<span>Foo</span>"),n=p.createFragment("<span>Foo</span>"),i=document.createElement("li"),s=document.createElement("li");i.appendChild(e),s.appendChild(n),t.appendChild(i),t.appendChild(s),this.container.parentNode.appendChild(t);var o=t.offsetHeight/2;return this.container.parentNode.removeChild(t),o};var y=function(t){function e(e){void 0===e&&(e={}),p.assert("object"==typeof e,"@param `opt_options` should be object type!"),"default_items"in e&&(u.defaultItems=e.default_items),this.options=p.mergeOptions(u,e),this.disabled=!1,this.Internal=new m(this),this.Html=new f(this),t.call(this,{element:this.container})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.clear=function(){var t=this;Object.keys(this.Internal.items).forEach(function(e){t.Html.removeMenuEntry(e)})},e.prototype.close=function(){this.Internal.closeMenu()},e.prototype.enable=function(){this.disabled=!1},e.prototype.disable=function(){this.disabled=!0},e.prototype.getDefaultItems=function(){return d},e.prototype.extend=function(t){p.assert(Array.isArray(t),"@param `arr` should be an Array."),t.forEach(this.push,this)},e.prototype.isOpened=function(){return this.isOpen()},e.prototype.isOpen=function(){return this.Internal.opened},e.prototype.updatePosition=function(t){p.assert(Array.isArray(t),"@param `pixel` should be an Array."),this.isOpen()&&this.Internal.positionContainer(t)},e.prototype.pop=function(){var t=Object.keys(this.Internal.items);this.Html.removeMenuEntry(t[t.length-1])},e.prototype.push=function(t){p.assert(p.isDefAndNotNull(t),"@param `item` must be informed."),this.Html.addMenuEntry(t)},e.prototype.shift=function(){this.Html.removeMenuEntry(Object.keys(this.Internal.items)[0])},e.prototype.setMap=function(t){ol.control.Control.prototype.setMap.call(this,t),t?this.Internal.init(t,this):this.Internal.removeListeners()},e}(ol.control.Control);return y});
8 -//# sourceMappingURL=ol3-contextmenu.js.map
\ No newline at end of file
8 +///# sourceMappingURL=ol3-contextmenu.js.map
\ No newline at end of file
views/default.handlebars
+58 -31
@@ -458,8 +458,8 @@
458 <tr>
459 <td style=background:#C0C0C0>
460 <div style=float:right;padding-right:4px>
461 - <span id=p15coreName title="Information about current core running on this agent"></span>
462 - <input type=button id=p15uploadCore value="Change Core" onclick=p15uploadCore(event) title="Change the agent Java Script code module" />
461 + <div style=padding:4px;display:inline-block id=p15coreName title="Information about current core running on this agent"></div>
462 + <input type=button id=p15uploadCore value="Agent Action" onclick=p15uploadCore(event) title="Change the agent Java Script code module" />
463 </div>
464 <div id="p15statetext" style=padding:4px></div>
465 </td>
@@ -782,6 +782,7 @@
782 QV('p2ServerActionsVersion', siteRights & 16);
783 QV('MainMenuMyFiles', siteRights & 8);
784 if (((siteRights & 8) == 0) && (xxcurrentView == 5)) { go(1); }
785 + if (currentNode != null) { gotoDevice(currentNode._id, xxcurrentView, true); }
786
787 // Update user management state
788 if ((userinfo.siteadmin & 2) != 0)
@@ -1264,6 +1265,7 @@
1265 if (!xxdialogMode && xxcurrentView == 11 && desktop && desktop.State == 3) return desktop.m.handleKeyUp(e);
1266 if (!xxdialogMode && xxcurrentView == 12 && terminal && terminal.State == 3) return terminal.m.TermHandleKeyUp(e);
1267 if (!xxdialogMode && xxcurrentView == 13 && e.keyCode == 116 && p13filetree != null) { p13folderup(9999); haltEvent(e); return false; } // F5 Refresh on files
1268 + if (xxdialogMode && e.keyCode == 27) { dialogclose(0); }
1269 if (xxdialogMode || xxcurrentView != 0 || e.ctrlKey == true || e.altKey == true || e.metaKey == true) return;
1270 if (Q('viewselect').value < 3) { if ((e.keyCode === 8 && searchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
1271 if (Q('viewselect').value == 3) { if ((e.keyCode === 8 && mapSearchFocus == 0) || e.keyCode === 27) { return haltEvent(e); } }
@@ -1432,17 +1434,23 @@
1434 x += addHtmlValue('Security', '<select id=dp1tls style=width:236px><option value=0>No TLS security</option><option value=1>TLS security required</option></select>');
1435 setDialogMode(2, "Add Intel&reg; AMT device", 3, addDeviceToMeshEx, x, meshid);
1436 validateDeviceToMesh();
1437 + Q('dp1devicename').focus();
1438 }
1439
1440 // Display the Intel AMT scanning dialog box
1441 function addAmtScanToMesh(meshid) {
1442 if (xxdialogMode) return;
1443 var x = "Enter a range of IP addresses to scan for Intel AMT devices.<br /><br />";
1441 - x += addHtmlValue('IP Range', '<input id=dp1range style=width:184px value="192.168.1.0/24" /><input id=dp1rangebutton type=button value=Scan onclick=addAmtScanToMeshButton()></input>');
1444 + x += addHtmlValue('IP Range', '<input id=dp1range style=width:184px value="192.168.1.0/24" onkeyup=addAmtScanToMeshKeyUp(event) /><input id=dp1rangebutton type=button value=Scan onclick=addAmtScanToMeshButton()></input>');
1445 x += '<div id=dp1results style="width:100%;height:200px;background-color:white;border:1px gray solid;overflow-y:scroll"></div>';
1446 setDialogMode(2, "Scan for Intel&reg; AMT devices", 3, addAmtScanToMeshEx, x, meshid);
1447 QE('idx_dlgOkButton', false);
1448 QH('dp1results', '<div style=width:100%;text-align:center;margin-top:12px;color:gray;line-height:1.5>Sample IP range values<br />192.168.0.100<br />192.168.1.0/24<br />192.167.0.1-192.168.0.100</div>');
1449 + focusTextBox('dp1range');
1450 + }
1451 +
1452 + function addAmtScanToMeshKeyUp(e) {
1453 + if (e.keyCode == 13) { haltEvent(e); addAmtScanToMeshButton(); }
1454 }
1455
1456 // Called when OK is pressed on the Intel AMT scanning box
@@ -1525,7 +1533,7 @@
1533 var meshidx = meshid.substring(5);
1534 if (meshidx[0] == '/') meshidx = meshidx.substring(1);
1535 var x = "";
1528 - x += addHtmlValue('Operating System', '<select id=aginsSelect onclick=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux</option><option value=2>Windows (UnInstall)</option><option value=3>Linux (UnInstall)</option></select>') + '<hr>';
1536 + x += addHtmlValue('Operating System', '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>Windows</option><option value=1>Linux</option><option value=2>Windows (UnInstall)</option><option value=3>Linux (UnInstall)</option></select>') + '<hr>';
1537
1538 // Windows agent install
1539 x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and configuration file and install the agent on the computer to manage.<br /><br />";
@@ -1548,7 +1556,7 @@
1556 x += '<textarea id=agins_linux_area_un rows=2 cols=20 readonly=readonly style=width:100%;resize:none;height:120px;overflow:scroll;font-size:12px readonly></textarea>';
1557 x += "</div>";
1558
1551 - setDialogMode(2, "Add Mesh Agent", 1, null, x);
1559 + setDialogMode(2, "Add Mesh Agent", 9, null, x);
1560
1561 if (serverinfo.https == true) {
1562 Q('agins_linux_area').value = "wget -q https://" + serverinfo.name + ":" + serverinfo.port + "/meshagents?script=1 --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://" + serverinfo.name + ":" + serverinfo.port + " " + meshid.split('/')[2].replace(/\$/g, '\\$') + "\r\n";
@@ -1557,6 +1565,7 @@
1565 Q('agins_linux_area').value = "wget -q http://" + serverinfo.name + ":" + serverinfo.port + "/meshagents?script=1 -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://" + serverinfo.name + ":" + serverinfo.port + " " + meshid.split('/')[2].replace(/\$/g, '\\$') + "\r\n";
1566 Q('agins_linux_area_un').value = "wget -q http://" + serverinfo.name + ":" + serverinfo.port + "/meshagents?script=1 -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
1567 }
1568 + Q('aginsSelect').focus();
1569 }
1570
1571 function addAgentToMeshClick() {
@@ -2513,7 +2522,7 @@
2522 QV('MainDevFiles', (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0)));
2523 QV('MainDevAmt', node.intelamt != null);
2524 QV('MainDevConsole', consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0)));
2516 - QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0));
2525 + QV('p15uploadCore', (node.agent != null) && (node.agent.caps != null) && ((node.agent.caps & 16) != 0) && (userinfo.siteadmin == 0xFFFFFFFF));
2526 QH('p15coreName', ((node.agent != null) && (node.agent.core != null))?node.agent.core:'');
2527
2528 // Setup/Refresh Intel AMT tab
@@ -2807,12 +2816,13 @@
2816 var showEditNodeValueDialog_modes2 = ['name', 'host', 'desc'];
2817 function showEditNodeValueDialog(mode) {
2818 if (xxdialogMode) return;
2810 - var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=32 onchange=p10editdevicevalueValidate(' + mode + ') onkeyup=p10editdevicevalueValidate(' + mode + ') />');
2819 + var x = addHtmlValue(showEditNodeValueDialog_modes[mode], '<input id=dp10devicevalue style=width:230px maxlength=32 onchange=p10editdevicevalueValidate(' + mode + ',event) onkeyup=p10editdevicevalueValidate(' + mode + ',event) />');
2820 setDialogMode(2, "Edit Device", 3, showEditNodeValueDialogEx, x, mode);
2821 var v = currentNode[showEditNodeValueDialog_modes2[mode]];
2822 if (v == null) v = '';
2823 Q('dp10devicevalue').value = v;
2824 p10editdevicevalueValidate();
2825 + Q('dp10devicevalue').focus();
2826 }
2827
2828 function showEditNodeValueDialogEx(button, mode) {
@@ -2821,8 +2831,10 @@
2831 meshserver.Send(x);
2832 }
2833
2824 - function p10editdevicevalueValidate(mode) {
2825 - QE('idx_dlgOkButton', (mode > 1) || (Q('dp10devicevalue').value.length > 0));
2834 + function p10editdevicevalueValidate(mode, e) {
2835 + var x = ((mode > 1) || (Q('dp10devicevalue').value.length > 0));
2836 + QE('idx_dlgOkButton', x);
2837 + if ((e != null) && (x == true) && (e.keyCode == 13)) { dialogclose(1); }
2838 }
2839
2840 //
@@ -3191,6 +3203,7 @@
3203 if (files != null) { files.Stop(); delete files; files = null; }
3204 break;
3205 case 3:
3206 + p13targetpath = '';
3207 files.Send(JSON.stringify({ action: 'ls', reqid: 1, path: '' }));
3208 break;
3209 }
@@ -3224,6 +3237,7 @@
3237 }
3238
3239 var p13filetree = null;
3240 + var p13targetpath = null;
3241 var p13filetreelocation = [];
3242
3243 function p13gotFiles(data) {
@@ -3235,9 +3249,11 @@
3249 p13filetree = data;
3250 p13updateFiles(checkedNames);
3251 } else {
3238 - // This is a different folder
3239 - p13filetree = data;
3240 - p13updateFiles();
3252 + if ((data.path.replace(/\//g, "\\") == p13targetpath.replace(/\//g, "\\")) || ((data.path == '\\') && (p13targetpath == ''))) {
3253 + // This is a different folder
3254 + p13filetree = data;
3255 + p13updateFiles();
3256 + }
3257 }
3258 }
3259
@@ -3318,12 +3334,14 @@
3334 }
3335
3336 function p13folderset(x) {
3321 - files.Send(JSON.stringify({ action: 'ls', reqid: 1, path: joinPaths(p13filetree.path, p13filetree.dir[x].n).split('\\').join('/') }));
3337 + p13targetpath = joinPaths(p13filetree.path, p13filetree.dir[x].n).split('\\').join('/');
3338 + files.Send(JSON.stringify({ action: 'ls', reqid: 1, path: p13targetpath }));
3339 }
3340
3341 function p13folderup(x) {
3342 if (x == null) { p13filetreelocation.pop(); } else { while (p13filetreelocation.length > x) { p13filetreelocation.pop(); } }
3326 - files.Send(JSON.stringify({ action: 'ls', reqid: 1, path: p13filetreelocation.join('/') }));
3343 + p13targetpath = p13filetreelocation.join('/');
3344 + files.Send(JSON.stringify({ action: 'ls', reqid: 1, path: p13targetpath }));
3345 }
3346
3347 var p13sortorder;
@@ -3367,13 +3385,13 @@
3385 function p13getFileSelCount() { var cc = 0; var checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) cc++; } return cc; }
3386 function p13getFileCount() { var cc = 0; var checkboxes = document.getElementsByName('fd'); return checkboxes.length; }
3387 function p13selectallfile() { var nv = (p13getFileSelCount() == 0), checkboxes = document.getElementsByName('fd'); for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = nv; } p13setActions(); }
3370 - function p13createfolder() { setDialogMode(2, "New Folder", 3, p13createfolderEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck() style=width:100% />'); Q('p13renameinput').focus(); }
3371 - function p13createfolderEx() { files.Send(JSON.stringify({ action: 'mkdir', reqid: 1, path: p13filetreelocation.join('/') + '/' + Q('p13renameinput').value })); }
3388 + function p13createfolder() { setDialogMode(2, "New Folder", 3, p13createfolderEx, '<input type=text id=p13renameinput maxlength=64 onkeyup=p13fileNameCheck(event) style=width:100% />'); focusTextBox('p13renameinput'); p13fileNameCheck(); }
3389 + function p13createfolderEx() { files.Send(JSON.stringify({ action: 'mkdir', reqid: 1, path: p13filetreelocation.join('/') + '/' + Q('p13renameinput').value })); p13folderup(999); }
3390 function p13deletefile() { var cc = getFileSelCount(); setDialogMode(2, "Delete", 3, p13deletefileEx, (cc > 1)?('Delete ' + cc + ' selected items?'):('Delete selected item?')); }
3373 - 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.Send(JSON.stringify({ action: 'rm', reqid: 1, path: p13filetreelocation.join('/'), delfiles: delfiles })); }
3374 - 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() style=width:100% value="' + renamefile + '" />', { action: 'rename', path: p13filetreelocation.join('/'), oldname: renamefile}); Q('p13renameinput').focus(); }
3375 - function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.Send(JSON.stringify(t)); }
3376 - function p13fileNameCheck() { QE('idx_dlgOkButton', isFilenameValid(Q('p13renameinput').value)); }
3391 + 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.Send(JSON.stringify({ action: 'rm', reqid: 1, path: p13filetreelocation.join('/'), delfiles: delfiles })); p13folderup(999); }
3392 + 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(); }
3393 + function p13renamefileEx(b, t) { t.newname = Q('p13renameinput').value; files.Send(JSON.stringify(t)); p13folderup(999); }
3394 + function p13fileNameCheck(e) { var x = isFilenameValid(Q('p13renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e.keyCode == 13)) { dialogclose(1); } }
3395 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'); }
3396 function p13uploadFileEx() { p13doUploadFiles(Q('p13uploadinput').files); }
3397
@@ -3481,6 +3499,7 @@
3499 function onFileUploadStateChange(xdownloadFile, state) {
3500 switch (state) {
3501 case 0:
3502 + p13folderup(9999);
3503 break;
3504 case 3:
3505 p13uploadNextFile();
@@ -3608,8 +3627,6 @@
3627 QE('p15consoleText', false);
3628 QE('p15uploadCore', false);
3629 }
3611 -
3612 - QV('p15uploadCore', (userinfo.siteadmin == 0xFFFFFFFF));
3630 }
3631
3632 // Clear the console for this node
@@ -3718,15 +3735,18 @@
3735 function account_showChangeEmail() {
3736 if (xxdialogMode) return;
3737 var x = "Change your account e-mail address here.<br /><br />";
3721 - x += addHtmlValue('Email', '<input id=dp2email style=width:230px maxlength=32 onchange=account_validateEmail() onkeyup=account_validateEmail() />');
3738 + x += addHtmlValue('Email', '<input id=dp2email style=width:230px maxlength=32 onchange=account_validateEmail() onkeyup=account_validateEmail(event) />');
3739 setDialogMode(2, "Email Address Change", 3, account_changeEmail, x);
3740 if (userinfo.email != null) { Q('dp2email').value = userinfo.email; }
3741 account_validateEmail();
3742 + Q('dp2email').focus();
3743 }
3744
3727 - function account_validateEmail() {
3745 + function account_validateEmail(e) {
3746 var x = Q('dp2email').value.split('@');
3729 - QE('idx_dlgOkButton', (x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2) && (Q('dp2email').value.length < 1024) && (Q('dp2email').value != userinfo.email));
3747 + x = (x.length == 2) && (x[0].length > 0) && (x[1].split('.').length > 1) && (x[1].length > 2) && (Q('dp2email').value.length < 1024) && (Q('dp2email').value != userinfo.email);
3748 + QE('idx_dlgOkButton', x);
3749 + if ((x == true) && (e != null) && (e.keyCode == 13)) { dialogclose(1); }
3750 }
3751
3752 function account_changeEmail() {
@@ -3746,6 +3766,7 @@
3766 x += '</div><br /></form>';
3767 setDialogMode(2, "Delete Account", 0, null, x);
3768 account_validateDeleteAccount();
3769 + Q('apassword1').focus();
3770 }
3771
3772 function account_showChangePassword() {
@@ -3763,6 +3784,7 @@
3784 x += '</div><br /></form>';
3785 setDialogMode(2, "Change Password", 0, null, x);
3786 account_validateDeleteAccount();
3787 + Q('apassword1').focus();
3788 }
3789
3790 function account_createMesh() {
@@ -3773,6 +3795,7 @@
3795 x += addHtmlValue('Description', '<div style=width:230px;margin:0;padding:0><textarea id=dp2meshdesc maxlength=1024 style=width:100%;resize:none></textarea></div>');
3796 setDialogMode(2, "Create Mesh", 3, account_createMeshEx, x);
3797 account_validateMeshCreate();
3798 + Q('dp2meshname').focus();
3799 }
3800
3801 function account_validateMeshCreate() {
@@ -3871,8 +3894,8 @@
3894 if (currentMesh.mtype == 2) meshtype = 'Mesh agent computer group';
3895
3896 var x = '';
3874 - x += addHtmlValue('Name', addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh()', (meshrights & 1) != 0));
3875 - x += addHtmlValue('Description', addLinkConditional(((currentMesh.desc && currentMesh.desc != '')?EscapeHtml(currentMesh.desc):'<i>None</i>'), 'p20editmesh()', (meshrights & 1) != 0));
3897 + x += addHtmlValue('Name', addLinkConditional(EscapeHtml(currentMesh.name), 'p20editmesh(1)', (meshrights & 1) != 0));
3898 + x += addHtmlValue('Description', addLinkConditional(((currentMesh.desc && currentMesh.desc != '')?EscapeHtml(currentMesh.desc):'<i>None</i>'), 'p20editmesh(2)', (meshrights & 1) != 0));
3899 x += addHtmlValue('Type', meshtype);
3900 x += addHtmlValue('Identifier', currentMesh._id.split('/')[2]);
3901
@@ -3941,7 +3964,7 @@
3964 meshserver.Send({ action: 'deletemesh', meshid: currentMesh._id, meshname: currentMesh.name });
3965 }
3966
3944 - function p20editmesh() {
3967 + function p20editmesh(focus) {
3968 if (xxdialogMode) return;
3969 x = "Create a new mesh computer group using the options below.<br /><br />";
3970 x += addHtmlValue('Mesh Name', '<input id=dp20meshname style=width:230px maxlength=32 onchange=p20editmeshValidate() onkeyup=p20editmeshValidate() />');
@@ -3950,6 +3973,7 @@
3973 Q('dp20meshname').value = currentMesh.name;
3974 if (currentMesh.desc) Q('dp20meshdesc').value = currentMesh.desc;
3975 p20editmeshValidate();
3976 + if (focus == 2) { Q('dp20meshdesc').focus(); } else { Q('dp20meshname').focus(); }
3977 }
3978
3979 function p20editmeshEx() {
@@ -3976,6 +4000,7 @@
4000 x += '</div>';
4001 setDialogMode(2, "Add User to Mesh", 3, p20showAddMeshUserDialogEx, x);
4002 p20validateAddMeshUserDialog();
4003 + Q('dp20username').focus();
4004 }
4005
4006 function p20validateAddMeshUserDialog() {
@@ -4175,13 +4200,13 @@
4200 function getFileSizeStr(size) { if (size == 1) return "1 byte"; return "" + size + " bytes"; }
4201 function p5folderup(x) { if (x == null) { filetreelocation.pop(); } else { while (filetreelocation.length > x) { filetreelocation.pop(); } } updateFiles(); }
4202 function p5folderset(x) { filetreelocation.push(decodeURIComponent(x)); updateFiles(); }
4178 - function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck() style=width:100% />'); Q('p5renameinput').focus(); }
4203 + function p5createfolder() { setDialogMode(2, "New Folder", 3, p5createfolderEx, '<input type=text id=p5renameinput maxlength=64 onkeyup=p5fileNameCheck(event) style=width:100% />'); focusTextBox('p5renameinput'); p5fileNameCheck(); }
4204 function p5createfolderEx() { meshserver.Send({ action: 'fileoperation', fileop: 'createfolder', path: filetreelocation, newfolder: Q('p5renameinput').value}); }
4205 function p5deletefile() { var cc = getFileSelCount(); setDialogMode(2, "Delete", 3, p5deletefileEx, (cc > 1)?('Delete ' + cc + ' selected items?'):('Delete selected item?')); }
4206 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}); }
4182 - 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() style=width:100% value="' + renamefile + '" />', { action: 'fileoperation', fileop: 'rename', path: filetreelocation, oldname: renamefile}); Q('p5renameinput').focus(); }
4207 + 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(); }
4208 function p5renamefileEx(b, t) { t.newname = Q('p5renameinput').value; meshserver.Send(t); }
4184 - function p5fileNameCheck() { QE('idx_dlgOkButton', isFilenameValid(Q('p5renameinput').value)); }
4209 + function p5fileNameCheck(e) { var x = isFilenameValid(Q('p5renameinput').value); QE('idx_dlgOkButton', x); if ((x == true) && (e.keyCode == 13)) { dialogclose(1); } }
4210 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] != '.'); } })();
4211 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'); }
4212 function p5uploadFileEx() { Q('p5loginSubmit').click(); }
@@ -4360,6 +4385,7 @@
4385 x += addHtmlValue('Password', '<input id=p4pass2 type=password style=width:230px maxlength=64 onchange=showCreateNewAccountDialogValidate() onkeyup=showCreateNewAccountDialogValidate() />');
4386 setDialogMode(2, "Create Account", 3, showCreateNewAccountDialogEx, x);
4387 showCreateNewAccountDialogValidate();
4388 + Q('p4name').focus();
4389 }
4390
4391 function showCreateNewAccountDialogValidate() {
@@ -4717,6 +4743,7 @@
4743 function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
4744 function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
4745 function parseUriArgs() { var name, r = {}, parsedUri = window.document.location.href.split(/[\?&|\=]/); parsedUri.splice(0, 1); for (x in parsedUri) { switch (x % 2) { case 0: { name = parsedUri[x]; break; } case 1: { r[name] = parsedUri[x]; var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } } } return r; }
4746 + function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
4747
4748 </script>
4749 </body>
views/login.handlebars
+46 -14
@@ -42,11 +42,11 @@
42 <table>
43 <tr>
44 <td align=right width=100>Username:</td>
45 - <td><input id=username type=text name=username onchange=validateLogin() onkeyup=validateLogin() /></td>
45 + <td><input id=username type=text name=username onchange=validateLogin(1) onkeyup=validateLogin(1,event) /></td>
46 </tr>
47 <tr>
48 <td align=right>Password:</td>
49 - <td><input id=password type=password name=password autocomplete=off onchange=validateLogin() onkeyup=validateLogin() /></td>
49 + <td><input id=password type=password name=password autocomplete=off onchange=validateLogin(2) onkeyup=validateLogin(2,event) /></td>
50 </tr>
51 <tr>
52 <td><div id=showPassHintLink style=display:none><a onclick=showPassHint() style="cursor:pointer">Show Hint</a></div></td>
@@ -73,27 +73,27 @@
73 <table>
74 <tr>
75 <td align=right width=100>Username:</td>
76 - <td><input id=ausername type=text name=username onchange=validateCreate() onkeyup=validateCreate() /></td>
76 + <td><input id=ausername type=text name=username onchange=validateCreate(1) onkeydown=haltReturn(event) onkeyup=validateCreate(1,event) /></td>
77 </tr>
78 <tr>
79 <td align=right width=100>Email:</td>
80 - <td><input id=aemail type=text name=email onchange=validateCreate() onkeyup=validateCreate() /></td>
80 + <td><input id=aemail type=text name=email onchange=validateCreate(2) onkeydown=haltReturn(event) onkeyup=validateCreate(2,event) /></td>
81 </tr>
82 <tr>
83 <td align=right>Password:</td>
84 - <td><input id=apassword1 type=password name=password1 autocomplete=off onchange=validateCreate() onkeyup=validateCreate() /></td>
84 + <td><input id=apassword1 type=password name=password1 autocomplete=off onkeydown=haltReturn(event) onchange=validateCreate(3) onkeyup=validateCreate(3,event) /></td>
85 </tr>
86 <tr>
87 <td align=right>Password:</td>
88 - <td><input id=apassword2 type=password name=password2 autocomplete=off onchange=validateCreate() onkeyup=validateCreate() /></td>
88 + <td><input id=apassword2 type=password name=password2 autocomplete=off onkeydown=haltReturn(event) onchange=validateCreate(4) onkeyup=validateCreate(4,event) /></td>
89 </tr>
90 <tr>
91 <td align=right>Password Hint:</td>
92 - <td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=250 /></td>
92 + <td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=250 onkeydown=haltReturn(event) onchange=validateCreate(5) onkeyup=validateCreate(5,event) /></td>
93 </tr>
94 <tr id=newAccountPass title="Enter the account creation token">
95 <td align=right>Creation Token:</td>
96 - <td><input id=anewaccountpass type=password name=anewaccountpass autocomplete=off maxlength=250 onchange=validateCreate() onkeyup=validateCreate() /></td>
96 + <td><input id=anewaccountpass type=password name=anewaccountpass autocomplete=off maxlength=250 onkeydown=haltReturn(event) onchange=validateCreate(6) onkeyup=validateCreate(6,event) /></td>
97 </tr>
98 <tr>
99 <td colspan=2>
@@ -116,7 +116,7 @@
116 <table>
117 <tr>
118 <td align=right width=100>Email:</td>
119 - <td><input id=remail type=text name=email onchange=validateReset() onkeyup=validateReset() /></td>
119 + <td><input id=remail type=text name=email onchange=validateReset() onkeyup=validateReset(event) /></td>
120 </tr>
121 <tr>
122 <td colspan=2>
@@ -180,7 +180,7 @@
180 if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); }
181 QV("newAccountPass", (newAccountPass == 1));
182 QV("resetAccountDiv", (emailCheck == true));
183 - QV("hrAccountDiv", (emailCheck == true) || (newAccountPass == 1))
183 + QV("hrAccountDiv", (emailCheck == true) || (newAccountPass == 1));
184 }
185
186 function showPassHint() {
@@ -199,15 +199,23 @@
199 QV('loginpanel', x == 1);
200 QV('createpanel', x == 2);
201 QV('resetpanel', x == 3);
202 + if (x == 1) { Q('username').focus(); }
203 + if (x == 2) { Q('ausername').focus(); }
204 + if (x == 3) { Q('remail').focus(); }
205 }
206
204 - function validateLogin() {
207 + function validateLogin(box, e) {
208 var ok = (Q('username').value.length > 0 && Q('password').value.length > 0);
209 QE('loginButton', ok);
210 setDialogMode(0);
211 + if ((e != null) && (e.keyCode == 13)) {
212 + if (box == 1) { Q('password').focus(); }
213 + if (box == 2) { Q('loginButton').click(); }
214 + }
215 + if (e != null) { haltEvent(e); }
216 }
217
210 - function validateCreate() {
218 + function validateCreate(box,e) {
219 setDialogMode(0);
220 var ok = ((Q('ausername').value.length > 0) && (checkEmail(Q('aemail').value) == true) && (Q('apassword1').value.length > 0) && (Q('apassword2').value == Q('apassword1').value));
221 if ((newAccountPass == 1) && (Q('anewaccountpass').value.length == 0)) { ok = false; }
@@ -220,11 +228,33 @@
228 else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>Good Password</b><span>'); }
229 else { QH('passWarning', '<span style=color:red><b>Weak Password</b><span>'); }
230 }
231 + if ((e != null) && (e.keyCode == 13)) {
232 + if (box == 1) { Q('aemail').focus(); }
233 + if (box == 2) { Q('apassword1').focus(); }
234 + if (box == 3) { Q('apassword2').focus(); }
235 + if (box == 4) { Q('apasswordhint').focus(); }
236 + if (box == 5) {
237 + if (newAccountPass == 1) {
238 + Q('anewaccountpass').focus();
239 + } else {
240 + Q('createButton').click();
241 + }
242 + }
243 + if (box == 6) {
244 + Q('createButton').click();
245 + }
246 + }
247 + if (e != null) { haltEvent(e); }
248 }
249
225 - function validateReset() {
250 + function validateReset(e) {
251 setDialogMode(0);
227 - QE('eresetButton', checkEmail(Q('remail').value));
252 + var x = checkEmail(Q('remail').value);
253 + QE('eresetButton', x);
254 + if ((e != null) && (e.keyCode == 13) && (x == true)) {
255 + Q('eresetButton').click();
256 + }
257 + if (e != null) { haltEvent(e); }
258 }
259
260 // Return true is the input string looks like an email address
@@ -286,6 +316,8 @@
316 function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
317 function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
318 function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
319 + function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
320 + function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
321
322 </script>
323 </body>
webserver.js
+7 -5
@@ -447,10 +447,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
447 obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Verified email of user ' + EscapeHtml(user.name) + ' (' + EscapeHtml(userinfo.email) + ')', domain: domain.id })
448
449 // Send the confirmation page
450 - res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Verified e-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' });
450 + res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' });
451
452 // Send a notification
453 - obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified: <b>' + EscapeHtml(userinfo.email) + '</b>.' , nolog: 1 })
453 + obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(userinfo.email) + '</b>.' , nolog: 1 })
454 }
455 });
456 }
@@ -485,7 +485,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
485 obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, { etype: 'user', username: userinfo.name, account: userinfo, action: 'accountchange', msg: 'Password reset for user ' + EscapeHtml(user.name), domain: domain.id })
486
487 // Send the new password
488 - res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Password for \"' + EscapeHtml(user.name) + '\" has been reset to \"<b>' + EscapeHtml(newpass) + '</b>\", login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' });
488 + res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: '<div>Password for account <b>' + EscapeHtml(user.name) + '</b> has been reset to:</div><div style=padding:14px;font-size:18px><b>' + EscapeHtml(newpass) + '</b></div>Login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' });
489 });
490 });
491 }
@@ -617,7 +617,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
617 res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.certificates.CommonName, serverRedirPort: args.redirport, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass, webcerthash: obj.webCertificateHashBase64 });
618 } else {
619 // Send back the login application
620 - res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port, emailcheck: obj.parent.mailserver != null });
620 + var loginmode = req.session.loginmode;
621 + delete req.session.loginmode; // Clear this state, if the user hits refresh, we want to go back to the login page.
622 + res.render(obj.path.join(__dirname, 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port, emailcheck: obj.parent.mailserver != null });
623 }
624 }
625
@@ -636,7 +638,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
638 if (req.session && req.session.userid) {
639 if (req.session.domainid != domain.id) { req.session.destroy(function () { res.redirect(domain.url); }); return; } // Check is the session is for the correct domain
640 var user = obj.users[req.session.userid];
639 - res.render(obj.path.join(__dirname, 'views/terms'), { logoutControl: 'Welcome ' + user.name + '. <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>' });
641 + res.render(obj.path.join(__dirname, 'views/terms'), { title: domain.title, title2: domain.title2, logoutControl: 'Welcome ' + user.name + '. <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>' });
642 } else {
643 res.render(obj.path.join(__dirname, 'views/terms'), { title: domain.title, title2: domain.title2 });
644 }