Added chat to device support, more fixes.

Ylian Saint-Hilaire committed Dec 7, 2018 at 16:36 UTC e236fae42e767be65a85c0abf7c25044b4b70ad5
16 files changed +157 -68
agents/MeshCmd-signed.exe
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
agents/MeshCmd64-signed.exe
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
agents/MeshService-signed.exe
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64-signed.exe
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshcore.js
+44 -5
@@ -436,14 +436,23 @@ function createMeshCore(agent) {
436 break;
437 }
438 case 'ps': {
439 + // Return the list of running processes
440 if (data.sessionid) {
441 processManager.getProcesses(function (plist) { mesh.SendCommand({ "action": "msg", "type": "ps", "value": JSON.stringify(plist), "sessionid": data.sessionid }); });
442 }
443 break;
444 }
445 case 'pskill': {
445 - //sendConsoleText(JSON.stringify(data));
446 - try { process.kill(data.value); } catch (e) { sendConsoleText(JSON.stringify(e)); }
446 + // Kill a process
447 + if (data.value) {
448 + try { process.kill(data.value); } catch (e) { sendConsoleText(JSON.stringify(e)); }
449 + }
450 + break;
451 + }
452 + case 'openUrl': {
453 + // Open a local web browser and return success/fail
454 + sendConsoleText('OpenURL: ' + data.url);
455 + if (data.url) { mesh.SendCommand({ "action": "msg", "type":"openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
456 break;
457 }
458 }
@@ -477,6 +486,12 @@ function createMeshCore(agent) {
486 if (data.title && data.msg) { require('toaster').Toast(data.title, data.msg); }
487 break;
488 }
489 + case 'openUrl': {
490 + // Open a local web browser and return success/fail
491 + sendConsoleText('OpenURL: ' + data.url);
492 + if (data.url) { mesh.SendCommand({ "action": "openUrl", "url": data.url, "sessionid": data.sessionid, "success": (openUserDesktopUrl(data.url) != null) }); }
493 + break;
494 + }
495 }
496 }
497 }
@@ -964,13 +979,32 @@ function createMeshCore(agent) {
979 response.close = function () { sendConsoleText('httprequest.response.close', this.sessionid); consoleHttpRequest = null; }
980 };
981
982 + // Open a web browser to a specified URL on current user's desktop
983 + function openUserDesktopUrl(url) {
984 + var child = null;
985 + try {
986 + switch (process.platform) {
987 + case 'win32':
988 + child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ["/c", "start", url], { type: childProcess.SpawnTypes.USER });
989 + break;
990 + case 'linux':
991 + child = require('child_process').execFile('/usr/bin/xdg-open', ['xdg-open', url], { type: require('child_process').SpawnTypes.DETACHED, uid: require('user-sessions').consoleUid() });
992 + break;
993 + case 'darwin':
994 + child = require('child_process').execFile('/usr/bin/open', ['open', url], { uid: require('user-sessions').consoleUid() });
995 + break;
996 + }
997 + } catch (ex) { }
998 + return child;
999 + }
1000 +
1001 // Process a mesh agent console command
1002 function processConsoleCommand(cmd, args, rights, sessionid) {
1003 try {
1004 var response = null;
1005 switch (cmd) {
1006 case 'help': { // Displays available commands
973 - response = 'Available commands: help, info, osinfo, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios, toast, lock, users, sendcaps.';
1007 + response = 'Available commands: help, info, osinfo,args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios, toast, lock, users, sendcaps, openurl.';
1008 break;
1009 }
1010 /*
@@ -992,6 +1026,11 @@ function createMeshCore(agent) {
1026 }
1027 break;
1028 */
1029 + case 'openurl': {
1030 + if (args['_'].length != 1) { response = 'Proper usage: openurl (url)'; } // Display usage
1031 + else { if (openUserDesktopUrl(args['_'][0]) == null) { response = 'Failed.'; } else { response = 'Success.'; } }
1032 + break;
1033 + }
1034 case 'users': {
1035 if (meshCoreObj.users == null) { response = 'Active users are unknown.'; } else { response = 'Active Users: ' + meshCoreObj.users.join(', ') + '.'; }
1036 break;
@@ -1520,7 +1559,7 @@ function createMeshCore(agent) {
1559 //amtLms.on('bind', function (map) { });
1560 amtLms.on('notify', function (data, options, str, code) {
1561 if (code == 'iAMT0052-3') {
1523 - kvmGetData();
1562 + obj.kvmGetData();
1563 } else {
1564 //if (str != null) { sendConsoleText('Intel AMT LMS: ' + str); }
1565 handleAmtNotification(data);
@@ -1597,7 +1636,7 @@ function createMeshCore(agent) {
1636 });
1637 }
1638
1600 - obj.kvmGetData = function(tag) {
1639 + obj.kvmGetData = function (tag) {
1640 obj.osamtstack.IPS_KVMRedirectionSettingData_DataChannelRead(obj.kvmDataGetResponse, tag);
1641 }
1642
agents/modules_meshcore/amt-wsman-duk.js
+3
@@ -88,8 +88,10 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
88 obj.digest.http = require('http');
89 }
90 var request = { protocol: (obj.tls == 1 ? 'https:' : 'http:'), method: 'POST', host: obj.host, path: '/wsman', port: obj.port, rejectUnauthorized: false, checkServerIdentity: function (cert) { console.log('checkServerIdentity', JSON.stringify(cert)); } };
91 +
92 var req = obj.digest.request(request);
93 //console.log('Request ' + (obj.RequestCount++));
94 +
95 req.on('error', function (e) { obj.gotNextMessagesError({ status: 600 }, 'error', null, [postdata, callback, tag]); });
96 req.on('response', function (response) {
97 //console.log('Response: ' + response.statusCode);
@@ -105,6 +107,7 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
107
108 // Send POST body, this work with binary.
109 req.end(postdata);
110 +
111 obj.ActiveAjaxCount++;
112 return req;
113 }
meshrelay.js
+8 -1
@@ -98,7 +98,14 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
98 if (obj.id.startsWith('meshmessenger/')) {
99 if (obj.user == null) { try { obj.close(); } catch (e) { } return null; }
100 var x = obj.id.split('/'), user1 = x[1] + '/' + x[2] + '/' + x[3], user2 = x[4] + '/' + x[5] + '/' + x[6];
101 - if ((obj.user._id != user1) && (obj.user._id != user2)) { try { obj.close(); } catch (e) { } return null; }
101 + if ((x[1] != 'user') && (x[4] != 'user')) { try { obj.close(); } catch (e) { } return null; } // MeshMessenger session must have at least one authenticated user
102 + if ((x[1] == 'user') && (x[4] == 'user')) {
103 + // If this is a user-to-user session, you must be authenticated to join.
104 + if ((obj.user._id != user1) && (obj.user._id != user2)) { try { obj.close(); } catch (e) { } return null; }
105 + } else {
106 + // If only one side of the session is a user
107 + // !!!!! TODO: Need to make sure that one of the two sides is the correct user. !!!!!
108 + }
109 }
110
111 // Validate that the id is valid, we only need to do this on non-authenticated sessions.
meshuser.js
+64 -40
@@ -76,6 +76,40 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
76 ds.on('close', function () { /*delete this.ss.fs._copyStreams[this.ss.id];*/ func(tag); });
77 }
78
79 + // Route a command to a target node
80 + function routeCommandToNode(command) {
81 + if (obj.common.validateString(command.nodeid, 8, 128) == false) return false;
82 + var splitnodeid = command.nodeid.split('/');
83 + // Check that we are in the same domain and the user has rights over this node.
84 + if ((splitnodeid[0] == 'node') && (splitnodeid[1] == domain.id)) {
85 + // See if the node is connected
86 + var agent = obj.parent.wsagents[command.nodeid];
87 + if (agent != null) {
88 + // Check if we have permission to send a message to that node
89 + var rights = user.links[agent.dbMeshKey];
90 + if ((rights != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission, 256 is desktop read only
91 + command.sessionid = ws.sessionId; // Set the session id, required for responses.
92 + command.rights = rights.rights; // Add user rights flags to the message
93 + delete command.nodeid; // Remove the nodeid since it's implyed.
94 + try { agent.send(JSON.stringify(command)); } catch (ex) { }
95 + }
96 + } else {
97 + // Check if a peer server is connected to this agent
98 + var routing = obj.parent.parent.GetRoutingServerId(command.nodeid, 1); // 1 = MeshAgent routing type
99 + if (routing != null) {
100 + // Check if we have permission to send a message to that node
101 + var rights = user.links[routing.meshid];
102 + if ((rights != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission
103 + command.fromSessionid = ws.sessionId; // Set the session id, required for responses.
104 + command.rights = rights.rights; // Add user rights flags to the message
105 + obj.parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
106 + }
107 + }
108 + }
109 + }
110 + return true;
111 + }
112 +
113 try {
114 // Check if the user is logged in
115 if (user == null) { try { obj.ws.close(); } catch (e) { } return; }
@@ -303,37 +337,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
337 }
338 case 'msg':
339 {
306 - // Route a message.
307 - // This this command has a nodeid, that is the target.
308 - if (obj.common.validateString(command.nodeid, 8, 128) == false) return;
309 - var splitnodeid = command.nodeid.split('/');
310 - // Check that we are in the same domain and the user has rights over this node.
311 - if ((splitnodeid[0] == 'node') && (splitnodeid[1] == domain.id)) {
312 - // See if the node is connected
313 - var agent = obj.parent.wsagents[command.nodeid];
314 - if (agent != null) {
315 - // Check if we have permission to send a message to that node
316 - var rights = user.links[agent.dbMeshKey];
317 - if ((rights != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission, 256 is desktop read only
318 - command.sessionid = ws.sessionId; // Set the session id, required for responses.
319 - command.rights = rights.rights; // Add user rights flags to the message
320 - delete command.nodeid; // Remove the nodeid since it's implyed.
321 - try { agent.send(JSON.stringify(command)); } catch (ex) { }
322 - }
323 - } else {
324 - // Check if a peer server is connected to this agent
325 - var routing = obj.parent.parent.GetRoutingServerId(command.nodeid, 1); // 1 = MeshAgent routing type
326 - if (routing != null) {
327 - // Check if we have permission to send a message to that node
328 - var rights = user.links[routing.meshid];
329 - if ((rights != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission
330 - command.fromSessionid = ws.sessionId; // Set the session id, required for responses.
331 - command.rights = rights.rights; // Add user rights flags to the message
332 - obj.parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
333 - }
334 - }
335 - }
336 - }
340 + // Route this command to a target node
341 + routeCommandToNode(command);
342 break;
343 }
344 case 'events':
@@ -601,19 +606,38 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
606 {
607 // Send a notification message to a user
608 if ((user.siteadmin & 2) == 0) break;
604 - if (obj.common.validateString(command.userid, 1, 2048) == false) break;
609
606 - // Create the notification message
607 - var notification = {
608 - "action": "msg", "type": "notify", "value": "<b>" + user.name + "</b>: Chat Request, Click here to accept.", "userid": user._id, "username": user.name, "tag": 'meshmessenger/' + encodeURIComponent(command.userid) + '/' + encodeURIComponent(user._id) };
610 + // Setup a user-to-user session
611 + if (obj.common.validateString(command.userid, 1, 2048)) {
612
610 - // Get the list of sessions for this user
611 - var sessions = obj.parent.wssessions[command.userid];
612 - if (sessions != null) { for (i in sessions) { try { sessions[i].send(JSON.stringify(notification)); } catch (ex) { } } }
613 + // Create the notification message
614 + var notification = {
615 + "action": "msg", "type": "notify", "value": "<b>" + user.name + "</b>: Chat Request, Click here to accept.", "userid": user._id, "username": user.name, "tag": 'meshmessenger/' + encodeURIComponent(command.userid) + '/' + encodeURIComponent(user._id)
616 + };
617
614 - if (obj.parent.parent.multiServer != null) {
615 - // TODO: Add multi-server support
618 + // Get the list of sessions for this user
619 + var sessions = obj.parent.wssessions[command.userid];
620 + if (sessions != null) { for (i in sessions) { try { sessions[i].send(JSON.stringify(notification)); } catch (ex) { } } }
621 +
622 + if (obj.parent.parent.multiServer != null) {
623 + // TODO: Add multi-server support
624 + }
625 + }
626 +
627 + // Setup a user-to-node session
628 + if (obj.common.validateString(command.nodeid, 1, 2048)) {
629 + if (obj.args.lanonly == true) { return; } // User-to-device chat is not support in LAN-only mode yet. We need the agent to replace the IP address of the server??
630 +
631 + // Create the server url
632 + var httpsPort = ((obj.parent.args.aliasport == null) ? obj.parent.args.port : obj.parent.args.aliasport); // Use HTTPS alias port is specified
633 + var xdomain = (domain.dns == null) ? domain.id : '';
634 + if (xdomain != '') xdomain += "/";
635 + var url = "http" + (obj.args.notls ? '' : 's') + "://" + obj.parent.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "messenger.htm?id=meshmessenger/" + encodeURIComponent(command.nodeid) + "/" + encodeURIComponent(user._id) + "&title=" + encodeURIComponent(user.name);
636 +
637 + // Create the notification message
638 + routeCommandToNode({ "action": "openUrl", "nodeid": command.nodeid, "userid": user._id, "username": user.name, "url": url });
639 }
640 +
641 break;
642 }
643 case 'serverversion':
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.2.4-b",
3 + "version": "0.2.4-e",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/images/icon-notify.png
Binary files /dev/null and b/public/images/icon-notify.png differ
public/images/icon-url.png
Binary files /dev/null and b/public/images/icon-url.png differ
public/images/icon-url2.png
Binary files /dev/null and b/public/images/icon-url2.png differ
views/default.handlebars
+22 -6
@@ -447,8 +447,11 @@
447 <td style=padding-top:2px;padding-bottom:2px;background:#C0C0C0>
448 <div style=float:right;text-align:right>
449 <select id=termdisplays style=display:none onchange=deskSetDisplay(event) onclick=deskGetDisplayNumbers(event)></select>&nbsp;
450 - <input id=DeskToastButton type=button value=Toast title="Display a notification message on the remote computer" onkeypress="return false" onkeydown="return false" onclick="deviceToastFunction()">&nbsp;
450 + <!--<input id=DeskToastButton type=button value=Toast title="Display a notification message on the remote computer" onkeypress="return false" onkeydown="return false" onclick="deviceToastFunction()">&nbsp;-->
451 <input id=DeskToolsButton type=button value=Tools title="Toggle tools view" onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()">&nbsp;
452 + <span style="float:right;margin-top:1px;margin-right:4px;cursor:pointer" title="Open chat window to this computer"><a onclick=deviceChat()><img src='images/icon-chat.png' height=16 width=16 style=padding-top:2px /></a></span>
453 + <span style="float:right;margin-top:1px;margin-right:4px;cursor:pointer" title="Display a notification on the remote computer"><a onclick=deviceToastFunction()><img src='images/icon-notify.png' height=16 width=16 style=padding-top:2px /></a></span>
454 + <span style="float:right;margin-top:1px;margin-right:4px;cursor:pointer" title="Open a web address on remote computer"><a onclick=deviceUrlFunction()><img src='images/icon-url2.png' height=16 width=16 style=padding-top:2px /></a></span>
455 </div>
456 <div>
457 <select style="margin-left:6px" id="deskkeys">
@@ -3229,7 +3232,6 @@
3232 if (((meshrights & 8) != 0) && (mesh.mtype == 2)) x += '<a style=cursor:pointer onclick=p10showMeshCmdDialog(1,"' + node._id + '") title="Traffic router used to connect to a device thru this server.">Router</a>&nbsp;';
3233
3234 // RDP link, show this link only of the remote machine is Windows.
3232 - console.log(((connectivity & 1) != 0), (clickOnce == true), (mesh.mtype == 2), ((meshrights & 8) != 0));
3235 if (((connectivity & 1) != 0) && (clickOnce == true) && (mesh.mtype == 2) && ((meshrights & 8) != 0)) {
3236 if ((node.agent.id > 0) && (node.agent.id < 5)) { x += '<a style=cursor:pointer onclick=p10clickOnce("' + node._id + '","RDP2",3389) title="Requires Microsoft ClickOnce support in your browser.">RDP</a>&nbsp;'; }
3237 if (node.agent.id > 4) {
@@ -3312,9 +3314,24 @@
3314
3315 function showNotesEx(buttons, tag) { meshserver.send({ action: 'setNotes', id: decodeURIComponent(tag), notes: encodeURIComponent(Q('d2devNotes').value) }); }
3316
3317 + function deviceChat() {
3318 + if (xxdialogMode) return;
3319 + window.open('/messenger.htm?id=meshmessenger/' + encodeURIComponent(currentNode._id) + '/' + encodeURIComponent(userinfo._id) + '&title=' + currentNode.name, 'meshmessenger:' + currentNode._id);
3320 + meshserver.send({ action: 'meshmessenger', nodeid: decodeURIComponent(currentNode._id) });
3321 + }
3322 +
3323 + function deviceUrlFunction() {
3324 + if (xxdialogMode) return;
3325 + setDialogMode(2, "Open Page on Device", 3, deviceUrlFunctionEx, '<input id=d2devurl placeholder="http://server.com" style=width:100%;overflow-y:scroll></input>');
3326 + }
3327 +
3328 + function deviceUrlFunctionEx() {
3329 + meshserver.send({ action: 'msg', type: 'openUrl', nodeid: currentNode._id, url: Q('d2devurl').value });
3330 + }
3331 +
3332 function deviceToastFunction() {
3333 if (xxdialogMode) return;
3317 - setDialogMode(2, "Device Toast", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
3334 + setDialogMode(2, "Device Notification", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
3335 }
3336
3337 function deviceToastFunctionEx() {
@@ -5727,11 +5744,10 @@
5744 if (sessions != null) {
5745 gray = '';
5746 if (self) {
5730 - msg2 = "<span style=float:right;margin-top:1px;margin-left:4px;margin-right:4px title=Chat><a onclick=userChat(event,\"" + encodeURIComponent(user._id) + "\",\"" + encodeURIComponent(user.name) + "\")><img src='images/icon-chat.png' height=16 width=16 style=padding-top:2px /></a></span>";
5731 - msg += "<a onclick=showUserAlertDialog(event,\"" + encodeURIComponent(user._id) + "\")>";
5747 + msg2 = "<span style=float:right;margin-top:1px;margin-right:4px title=Chat><a onclick=userChat(event,\"" + encodeURIComponent(user._id) + "\",\"" + encodeURIComponent(user.name) + "\")><img src='images/icon-chat.png' height=16 width=16 style=padding-top:2px /></a></span>";
5748 + msg2 += "<span style=float:right;margin-top:1px;margin-left:4px;margin-right:4px title=Notify><a onclick=showUserAlertDialog(event,\"" + encodeURIComponent(user._id) + "\")><img src='images/icon-notify.png' height=16 width=16 style=padding-top:2px /></a></span>";
5749 }
5750 if (sessions == 1) { msg += '1 active session'; } else { msg += sessions + ' active sessions'; }
5734 - if (self) { msg += "</a>"; }
5751 } else {
5752 if (user.login) { msg += '<span title="Last login: ' + new Date(user.login).toLocaleString() + '">' + new Date(user.login).toLocaleDateString() + '</span>'; }
5753 }
webserver.js
+15 -15
@@ -755,14 +755,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
755 if (obj.args.minify && !req.query.nominify) {
756 // Try to server the minified version if we can.
757 try {
758 - res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile-min' : 'views/default-min'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
758 + res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile-min' : 'views/default-min'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
759 } catch (ex) {
760 // In case of an exception, serve the non-minified version.
761 - res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
761 + res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : '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.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
762 }
763 } else {
764 // Serve non-minified version of web pages.
765 - res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
765 + res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/default-mobile' : '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.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, webcerthash: new Buffer(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer });
766 }
767 } else {
768 // Send back the login application
@@ -775,18 +775,18 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
775 if (obj.args.minify && !req.query.nominify) {
776 // Try to server the minified version if we can.
777 try {
778 - res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile-min' : 'views/login-min'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
778 + res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile-min' : 'views/login-min'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
779 } catch (ex) {
780 // In case of an exception, serve the non-minified version.
781 - res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
781 + res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : '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.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
782 }
783 } else {
784 // Serve non-minified version of web pages.
785 - res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
785 + res.render(obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : '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.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, sessiontime: args.sessiontime, footer: (domain.footer == null) ? '' : domain.footer });
786 }
787
788 /*
789 - var xoptions = { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, footer: (domain.footer == null) ? '' : domain.footer };
789 + var xoptions = { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, footer: (domain.footer == null) ? '' : domain.footer };
790 var xpath = obj.path.join(__dirname, isMobileBrowser(req) ? 'views/login-mobile' : 'views/login');
791 console.log('Render...');
792 res.render(xpath, xoptions, function (err, html) {
@@ -1272,8 +1272,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1272 ws.on('error', function (err) { console.log('WEBSERVER WSERR2: ' + err); });
1273
1274 // If the web socket is closed, close the associated TCP connection.
1275 - ws.on('close', function (req) {
1276 - Debug(1, 'Closing relay web socket connection to ' + ws.upgradeReq.query.host + '.');
1275 + ws.on('close', function () {
1276 + Debug(1, 'Closing relay web socket connection to ' + req.query.host + '.');
1277 if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
1278 });
1279
@@ -1550,7 +1550,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1550 var xdomain = (domain.dns == null) ? domain.id : '';
1551 if (xdomain != '') xdomain += "/";
1552 var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
1553 - if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
1553 + if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + obj.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
1554 if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
1555 if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += "InstallFlags=" + req.query.installflags + "\r\n"; }
1556
@@ -1612,7 +1612,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1612 };
1613 if (user != null) { meshaction.username = user.name; }
1614 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
1615 - if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
1615 + if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + obj.getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
1616 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename=meshaction.txt' });
1617 res.send(JSON.stringify(meshaction, null, ' '));
1618 });
@@ -1627,7 +1627,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1627 };
1628 if (user != null) { meshaction.username = user.name; }
1629 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
1630 - if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
1630 + if (obj.args.lanonly != true) { meshaction.serverUrl = ((obj.args.notls == true) ? 'ws://' : 'wss://') + obj.getWebServerName(domain) + ':' + httpsPort + '/' + ((domain.id == '') ? '' : ('/' + domain.id)) + 'meshrelay.ashx'; }
1631 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename=meshaction.txt' });
1632 res.send(JSON.stringify(meshaction, null, ' '));
1633 } else {
@@ -1650,7 +1650,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1650 };
1651
1652 // Get the web server hostname. This may change if using a domain with a DNS name.
1653 - function getWebServerName(domain) {
1653 + obj.getWebServerName = function(domain) {
1654 if (domain.dns != null) return domain.dns;
1655 return obj.certificates.CommonName;
1656 }
@@ -1688,7 +1688,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1688 var xdomain = (domain.dns == null) ? domain.id : '';
1689 if (xdomain != '') xdomain += "/";
1690 var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
1691 - if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
1691 + if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + obj.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
1692 if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
1693 if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += "InstallFlags=" + req.query.installflags + "\r\n"; }
1694
@@ -1769,7 +1769,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1769 if (xdomain != '') xdomain += "/";
1770 var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
1771 var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
1772 - if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
1772 + if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + obj.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
1773 if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
1774 if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += "InstallFlags=" + req.query.installflags + "\r\n"; }
1775