diff --git a/agents/MeshService.exe b/agents/MeshService.exe index 5244b404..9dca89fc 100644 Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ diff --git a/agents/MeshService64.exe b/agents/MeshService64.exe index 9867e40e..e39bb68e 100644 Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ diff --git a/agents/meshagent_arm b/agents/meshagent_arm index 6355f325..ef5f3019 100644 Binary files a/agents/meshagent_arm and b/agents/meshagent_arm differ diff --git a/agents/meshagent_pi b/agents/meshagent_pi index 8843cc13..f8907239 100644 Binary files a/agents/meshagent_pi and b/agents/meshagent_pi differ diff --git a/agents/meshagent_pogo b/agents/meshagent_pogo index ae542daa..ed0e7a6a 100644 Binary files a/agents/meshagent_pogo and b/agents/meshagent_pogo differ diff --git a/agents/meshagent_poky b/agents/meshagent_poky index 95207afa..01c7938b 100644 Binary files a/agents/meshagent_poky and b/agents/meshagent_poky differ diff --git a/agents/meshagent_poky64 b/agents/meshagent_poky64 index 173261a1..1a732442 100644 Binary files a/agents/meshagent_poky64 and b/agents/meshagent_poky64 differ diff --git a/agents/meshagent_x86 b/agents/meshagent_x86 index c5b99e4e..3c8e1acf 100644 Binary files a/agents/meshagent_x86 and b/agents/meshagent_x86 differ diff --git a/agents/meshagent_x86-64 b/agents/meshagent_x86-64 index 55a6ca92..e2ae3de6 100644 Binary files a/agents/meshagent_x86-64 and b/agents/meshagent_x86-64 differ diff --git a/agents/meshagent_x86-64_nokvm b/agents/meshagent_x86-64_nokvm index 21ae8439..705cfa47 100644 Binary files a/agents/meshagent_x86-64_nokvm and b/agents/meshagent_x86-64_nokvm differ diff --git a/agents/meshagent_x86_nokvm b/agents/meshagent_x86_nokvm index 3aaf9785..cddf5bd5 100644 Binary files a/agents/meshagent_x86_nokvm and b/agents/meshagent_x86_nokvm differ diff --git a/agents/meshcore.js b/agents/meshcore.js index 9e04ef37..c59c18dc 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -26,7 +26,7 @@ function createMeshCore(agent) { var lastNetworkInfo = null; var lastPublicLocationInfo = null; var selfInfoUpdateTimer = null; - obj.useNativePipes = (process.platform == 'win32'); + obj.useNativePipes = true; //(process.platform == 'win32'); var http = require('http'); var fs = require('fs'); @@ -158,7 +158,7 @@ function createMeshCore(agent) { }; // Replace a string with a number if the string is an exact number - function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) == x)) { x = parseInt(x); } return x; } + function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; } // Convert decimal to hex function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); } @@ -218,16 +218,48 @@ function createMeshCore(agent) { return results; } - // Parge a URL string into an options object - function parseUrl(url) { - var x = url.split('/'); - if (x.length < 4) return null; - var y = x[2].split(':'); - var options = {}; - var options = { protocol: x[0], hostname: y[0], path: '/' + x.splice(3).join('/') }; - if (y.length == 1) { options.port = ((x[0] == 'https:') || (x[0] == 'wss:')) ? 443 : 80; } else { options.port = parseInt(y[1]); } - if (isNaN(options.port) == true) return null; - return options; + // Get server target url with a custom path + function getServerTargetUrl(path) { + var x = mesh.ServerUrl; + //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl); + if (x == null) { return null; } + if (path == null) { path = ''; } + x = http.parseUri(x); + if (x == null) return null; + return x.protocol + '//' + x.host + ':' + x.port + '/' + path; + } + + // Get server url. If the url starts with "*/..." change it, it not use the url as is. + function getServerTargetUrlEx(url) { + if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); } + return url; + } + + // Send a wake-on-lan packet + function sendWakeOnLan(hexMac) { + var count = 0; + try { + var interfaces = require('os').networkInterfaces(); + var magic = 'FFFFFFFFFFFF'; + for (var x = 1; x <= 16; ++x) { magic += hexMac; } + var magicbin = Buffer.from(magic, 'hex'); + + for (var adapter in interfaces) { + if (interfaces.hasOwnProperty(adapter)) { + for (var i = 0; i < interfaces[adapter].length; ++i) { + var addr = interfaces[adapter][i]; + if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) { + var socket = require('dgram').createSocket({ type: "udp4" }); + socket.bind({ address: addr.address }); + socket.setBroadcast(true); + socket.send(magicbin, 7, "255.255.255.255"); + count++; + } + } + } + } + } catch (e) { } + return count; } // Handle a mesh agent command @@ -245,21 +277,26 @@ function createMeshCore(agent) { else if (data.type == 'tunnel') { // Process a new tunnel connection request if (data.value && data.sessionid) { // Create a new tunnel object - var tunnel = http.request(parseUrl(data.value)); - tunnel.upgrade = onTunnelUpgrade; - tunnel.sessionid = data.sessionid; - tunnel.rights = data.rights; - tunnel.state = 0; - tunnel.url = data.value; - tunnel.protocol = 0; + //sendConsoleText(data.value); + var xurl = getServerTargetUrlEx(data.value); + //sendConsoleText(xurl); + if (xurl != null) { + var tunnel = http.request(http.parseUri(xurl)); + tunnel.upgrade = onTunnelUpgrade; + tunnel.sessionid = data.sessionid; + tunnel.rights = data.rights; + tunnel.state = 0; + tunnel.url = xurl; + tunnel.protocol = 0; - // Put the tunnel in the tunnels list - var index = 1; - while (tunnels[index]) { index++; } - tunnel.index = index; - tunnels[index] = tunnel; + // Put the tunnel in the tunnels list + var index = 1; + while (tunnels[index]) { index++; } + tunnel.index = index; + tunnels[index] = tunnel; - sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid); + sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid); + } } } break; @@ -267,7 +304,7 @@ function createMeshCore(agent) { case 'wakeonlan': { // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses. sendConsoleText('Server requesting wake-on-lan for: ' + data.macs.join(', ')); - // TODO!!!! + for (var i in data.macs) { sendWakeOnLan(data.macs[i]); } break; } case 'poweraction': { @@ -554,7 +591,7 @@ function createMeshCore(agent) { var response = null; switch (cmd) { case 'help': { // Displays available commands - response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseurl, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power.'; + response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan.'; break; } case 'notify': { // Send a notification message to the mesh @@ -569,7 +606,7 @@ function createMeshCore(agent) { break; } case 'info': { // Return information about the agent and agent core module - response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.'; + response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.\r\nServer URL: ' + mesh.ServerUrl + '.'; break; } case 'selfinfo': { // Return self information block @@ -628,10 +665,6 @@ function createMeshCore(agent) { response = 'Database compacted: ' + r; break; } - case 'parseurl': { - response = objToString(parseUrl(args['_'][0])); - break; - } case 'httpget': { if (consoleHttpRequest != null) { response = 'HTTP operation already in progress.'; @@ -639,7 +672,7 @@ function createMeshCore(agent) { if (args['_'].length != 1) { response = 'Proper usage: httpget (url)'; } else { - var options = parseUrl(args['_'][0]); + var options = http.parseUri(args['_'][0]); options.method = 'GET'; if (options == null) { response = 'Invalid url.'; @@ -648,7 +681,7 @@ function createMeshCore(agent) { consoleHttpRequest.sessionid = sessionid; if (consoleHttpRequest != null) { consoleHttpRequest.end(); - response = 'HTTPGET ' + options.protocol + '//' + options.hostname + ':' + options.port + options.path; + response = 'HTTPGET ' + options.protocol + '//' + options.host + ':' + options.port + options.path; } } } @@ -670,7 +703,7 @@ function createMeshCore(agent) { } else { var httprequest = null; try { - httprequest = http.request(parseUrl(args['_'][0])); + httprequest = http.request(http.parseUri(args['_'][0])); } catch (e) { response = 'Invalid HTTP websocket request'; } if (httprequest != null) { httprequest.upgrade = onWebSocketUpgrade; @@ -756,7 +789,18 @@ function createMeshCore(agent) { break; } case 'netinfo': { // Show network interface information - response = objToString(mesh.NetInfo, 0, '.'); + //response = objToString(mesh.NetInfo, 0, '.'); + var interfaces = require('os').networkInterfaces(); + response = objToString(interfaces, 0, '.'); + break; + } + case 'wakeonlan': { // Send wake-on-lan + if ((args['_'].length != 1) || (args['_'][0].length != 12)) { + response = 'Proper usage: wakeonlan [mac], for example "wakeonlan 010203040506".'; + } else { + var count = sendWakeOnLan(args['_'][0]); + response = 'Sent wake-on-lan on ' + count + ' interface(s).'; + } break; } case 'sendall': { // Send a message to all consoles on this mesh @@ -782,6 +826,10 @@ function createMeshCore(agent) { }); break; } + case 'parseuri': { + response = JSON.stringify(http.parseUri(args['_'][0])); + break; + } default: { // This is an unknown command, return an error message response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.'; break; diff --git a/meshagent.js b/meshagent.js index fc421427..bc47544a 100644 --- a/meshagent.js +++ b/meshagent.js @@ -378,9 +378,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { delete command.sessionid; // Remove the sessionid, since we are sending to that sessionid, so it's implyed. ws.send(JSON.stringify(command)); } else if (obj.parent.parent.multiServer != null) { - // We need to send this message to other servers - command.fromNodeid = obj.dbNodeKey; - obj.parent.parent.multiServer.DispatchMessage(command); + // See if we can send this to a peer server + var serverid = obj.parent.wsPeerSessions2[command.sessionid]; + if (serverid != null) { + command.fromNodeid = obj.dbNodeKey; + obj.parent.parent.multiServer.DispatchMessageSingleServer(command, serverid); + } } } } else if (command.userid != null) { // If this command has a userid, that is the target. diff --git a/mesherrors.txt b/mesherrors.txt index bccabb7d..f762e5b2 100644 --- a/mesherrors.txt +++ b/mesherrors.txt @@ -2017,3 +2017,60 @@ Error: not opened at Receiver.opcodes.2.finish (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:633:12) +-------- 9/20/2017, 11:40:47 AM -------- + +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522 + obj.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId + ^ + +TypeError: Cannot set property 'AmtMachine7' of undefined + at Object.obj.ProcessPeerServerMessage (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522:51) + at processServerData (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:377:32) + at WebSocket. (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:262:49) + at emitTwo (events.js:106:13) + at WebSocket.emit (events.js:191:7) + at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10) + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18 + at Receiver.applyExtensions (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:371:5) + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:508:14 + at Receiver.flush (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:347:3) + + +-------- 9/20/2017, 11:40:51 AM -------- + +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522 + obj.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId + ^ + +TypeError: Cannot set property 'AmtMachine7' of undefined + at Object.obj.ProcessPeerServerMessage (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522:51) + at processServerData (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:377:32) + at WebSocket. (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:262:49) + at emitTwo (events.js:106:13) + at WebSocket.emit (events.js:191:7) + at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10) + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18 + at Receiver.applyExtensions (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:371:5) + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:508:14 + at Receiver.flush (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:347:3) + + +-------- 9/20/2017, 1:55:44 PM -------- + +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1155 + for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } } + ^ + +TypeError: Cannot read property 'domainid' of undefined + at WebSocket. (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1155:89) + at emitTwo (events.js:106:13) + at WebSocket.emit (events.js:191:7) + at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10) + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:368:7 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\PerMessageDeflate.js:249:5 + at afterWrite (_stream_writable.js:360:3) + at onwrite (_stream_writable.js:351:7) + at WritableState.onwrite (_stream_writable.js:89:5) + + diff --git a/multiserver.js b/multiserver.js index 619766ae..21d49746 100644 --- a/multiserver.js +++ b/multiserver.js @@ -472,17 +472,29 @@ module.exports.CreateMultiServer = function (parent, args) { obj.SetupPeerServer = function (server, peerServerId) { console.log('Connected to peer server ' + peerServerId + '.'); obj.peerServers[peerServerId] = server; + + // Send the list of connections to the peer server.send(JSON.stringify({ action: 'connectivityTable', connectivityTable: obj.parent.peerConnectivityByNode[obj.parent.serverId] })); + + // Send a list of user sessions to the peer + server.send(JSON.stringify({ action: 'sessionsTable', sessionsTable: Object.keys(obj.parent.webserver.wssessions2) })); } // We disconnected to a peer server, clean up everything obj.ClearPeerServer = function (server, peerServerId) { console.log('Disconnected from peer server ' + peerServerId + '.'); + + // Clean up the connectivity state delete obj.peerServers[peerServerId]; - //delete obj.parent.peerConnectivityByMesh[peerServerId]; // TODO: We will need to re-adjust all of the node power states. var oldList = obj.parent.peerConnectivityByNode[peerServerId]; obj.parent.peerConnectivityByNode[peerServerId] = {}; obj.parent.UpdateConnectivityState(oldList); + + // Clean up the sessions list + for (var i in obj.parent.webserver.wsPeerSessions[peerServerId]) { delete obj.parent.webserver.wsPeerSessions2[obj.parent.webserver.wsPeerSessions[peerServerId][i]]; } + delete obj.parent.webserver.wsPeerSessions[peerServerId]; + delete obj.parent.webserver.wsPeerSessions3[peerServerId]; + obj.parent.webserver.recountSessions(); // Recount all sessions } // Process a message coming from a peer server @@ -498,6 +510,43 @@ module.exports.CreateMultiServer = function (parent, args) { obj.parent.UpdateConnectivityState(msg.connectivityTable); break; } + case 'sessionsTable': { + obj.parent.webserver.wsPeerSessions[peerServerId] = msg.sessionsTable; + var userToSession = {}; + for (var i in msg.sessionsTable) { + var sessionid = msg.sessionsTable[i]; + obj.parent.webserver.wsPeerSessions2[sessionid] = peerServerId; + var userid = sessionid.split('/').slice(0, 3).join('/'); // Take the sessionid and keep only the userid partion + if (userToSession[userid] == null) { userToSession[userid] = [sessionid]; } else { userToSession[userid].push(sessionid); } // UserId -> [ SessionId ] + } + obj.parent.webserver.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId + obj.parent.webserver.recountSessions(); // Recount all sessions + break; + } + case 'sessionStart': { + obj.parent.webserver.wsPeerSessions[peerServerId].push(msg.sessionid); + obj.parent.webserver.wsPeerSessions2[msg.sessionid] = peerServerId; + var userid = msg.sessionid.split('/').slice(0, 3).join('/'); + if (obj.parent.webserver.wsPeerSessions3[peerServerId] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId] = {}; } + if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId][userid] = [ msg.sessionid ]; } else { obj.parent.webserver.wsPeerSessions3[peerServerId][userid].push(msg.sessionid); } + obj.parent.webserver.recountSessions(msg.sessionid); // Recount a specific user + break; + } + case 'sessionEnd': { + var i = obj.parent.webserver.wsPeerSessions[peerServerId].indexOf(msg.sessionid); + if (i >= 0) { obj.parent.webserver.wsPeerSessions[peerServerId].splice(i, 1); } + delete obj.parent.webserver.wsPeerSessions2[msg.sessionid]; + var userid = msg.sessionid.split('/').slice(0, 3).join('/'); + if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] != null) { + i = obj.parent.webserver.wsPeerSessions3[peerServerId][userid].indexOf(msg.sessionid); + if (i >= 0) { + obj.parent.webserver.wsPeerSessions3[peerServerId][userid].splice(i, 1); + if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid].length == 0) { delete obj.parent.webserver.wsPeerSessions3[peerServerId][userid]; } + } + } + obj.parent.webserver.recountSessions(msg.sessionid); // Recount a specific user + break; + } case 'SetConnectivityState': { obj.parent.SetConnectivityState(msg.meshid, msg.nodeid, msg.connectTime, msg.connectType, msg.powerState, peerServerId); break; diff --git a/package.json b/package.json index 8aaf3ee7..474311f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.0.7-y", + "version": "0.0.8-b", "keywords": [ "Remote Management", "Intel AMT", diff --git a/public/scripts/agent-redir-ws-0.1.0.js b/public/scripts/agent-redir-ws-0.1.0.js index 7dd6513e..75a3901f 100644 --- a/public/scripts/agent-redir-ws-0.1.0.js +++ b/public/scripts/agent-redir-ws-0.1.0.js @@ -24,7 +24,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) { obj.Start = function (nodeid) { var url2, url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/meshrelay.ashx?id=" + obj.tunnelid; - if (serverPublicNamePort) { url2 = window.location.protocol.replace("http", "ws") + "//" + serverPublicNamePort + "/meshrelay.ashx?id=" + obj.tunnelid; } else { url2 = url; } + //if (serverPublicNamePort) { url2 = window.location.protocol.replace("http", "ws") + "//" + serverPublicNamePort + "/meshrelay.ashx?id=" + obj.tunnelid; } else { url2 = url; } obj.nodeid = nodeid; obj.connectstate = 0; obj.socket = new WebSocket(url); @@ -33,7 +33,8 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) { obj.socket.onerror = function (e) { console.error(e); } obj.socket.onclose = obj.xxOnSocketClosed; obj.xxStateChange(1); - obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 }); + //obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 }); + obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: "*/meshrelay.ashx?id=" + obj.tunnelid }); //obj.debug("Agent Redir Start: " + url); } diff --git a/views/login.handlebars b/views/login.handlebars index b5fb7ef1..24f7a8e0 100644 --- a/views/login.handlebars +++ b/views/login.handlebars @@ -150,7 +150,7 @@ if ('{{loginmode}}' != '') { go({{loginmode}}); } else { go(1); } QV('newAccountDiv', '{{{newAccount}}}' != '0' ); if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); } - QV("anewaccountpass", (newAccountPass == 1)); + QV("newAccountPass", (newAccountPass == 1)); } function showPassHint() { diff --git a/webserver.js b/webserver.js index 89939733..713855dc 100644 --- a/webserver.js +++ b/webserver.js @@ -74,10 +74,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate // Main lists obj.wsagents = {}; - obj.wssessions = {}; // UserId --> Array Of Sessions - obj.wssessions2 = {}; // UserId + SessionId --> Session - obj.wsrelays = {}; // Id -> Relay - obj.wsPeerRelays = {}; // Id -> { ServerId, Time } + obj.wssessions = {}; // UserId --> Array Of Sessions + obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd) + obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd" + obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId + obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ] + obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount + obj.wsrelays = {}; // Id -> Relay + obj.wsPeerRelays = {}; // Id -> { ServerId, Time } // Setup randoms obj.crypto.randomBytes(32, function (err, buf) { obj.httpAuthRandom = buf; }); @@ -383,7 +387,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate 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, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass }); } else { // Send back the login application - 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)?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port }); + 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 }); } } @@ -941,8 +945,15 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate ws.sessionId = user._id + '/' + ('' + Math.random()).substring(2); obj.wssessions2[ws.sessionId] = ws; if (!obj.wssessions[user._id]) { obj.wssessions[user._id] = [ws]; } else { obj.wssessions[user._id].push(ws); } - obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[user._id].length, nolog: 1, domain: domain.id }) - + if (obj.parent.multiServer == null) { + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[user._id].length, nolog: 1, domain: domain.id }) + } else { + obj.recountSessions(ws.sessionId); // Recount sessions + } + + // If we have peer servers, inform them of the new session + if (obj.parent.multiServer != null) { obj.parent.multiServer.DispatchMessage({ action: 'sessionStart', sessionid: ws.sessionId }); } + // Handle events ws.HandleEvent = function (source, event) { if (!event.domain || event.domain == domain.id) { @@ -1136,11 +1147,17 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate } case 'wssessioncount': { - // Request a list of all web socket session count - if ((user.siteadmin & 2) == 0) break; + // Request a list of all web socket user session count var wssessions = {}; - for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } } - ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions })); + if ((user.siteadmin & 2) == 0) break; + if (obj.parent.multiServer == null) { + // No peering, use simple session counting + for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } } + } else { + // We have peer servers, use more complex session counting + for (var userid in obj.sessionsCount) { if (userid.split('/')[1] == domain.id) { wssessions[userid] = obj.sessionsCount[userid]; } } + } + ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions })); // wssessions is: userid --> count break; } case 'deleteuser': @@ -1664,10 +1681,19 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate if (i >= 0) { obj.wssessions[ws.userid].splice(i, 1); var user = obj.users[ws.userid]; - if (user) { obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[ws.userid].length, nolog: 1, domain: domain.id }) } + if (user) { + if (obj.parent.multiServer == null) { + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[ws.userid].length, nolog: 1, domain: domain.id }) + } else { + obj.recountSessions(ws.sessionId); // Recount sessions + } + } if (obj.wssessions[ws.userid].length == 0) { delete obj.wssessions[ws.userid]; } } } + + // If we have peer servers, inform them of the disconnected session + if (obj.parent.multiServer != null) { obj.parent.multiServer.DispatchMessage({ action: 'sessionEnd', sessionid: ws.sessionId }); } }); // Send user information to web socket, this is the first thing we send @@ -2126,5 +2152,70 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate // Start server on a free port CheckListenPort(obj.args.port, StartWebServer); +/* + obj.wssessions = {}; // UserId --> Array Of Sessions + obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd) + obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd" + obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId + obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ] +*/ + + // Count sessions and event any changes + obj.recountSessions = function (changedSessionId) { + if (changedSessionId == null) { + // Recount all sessions + + // Calculate the session count for all userid's + var newSessionsCount = {}; + for (var userid in obj.wssessions) { newSessionsCount[userid] = obj.wssessions[userid].length; } + for (var serverid in obj.wsPeerSessions3) { + for (var userid in obj.wsPeerSessions3[serverid]) { + var c = obj.wsPeerSessions3[serverid][userid].length; + if (newSessionsCount[userid] == null) { newSessionsCount[userid] = c; } else { newSessionsCount[userid] += c; } + } + } + + // See what session counts have changed, event any changes + for (var userid in newSessionsCount) { + var newcount = newSessionsCount[userid]; + var oldcount = obj.sessionsCount[userid]; + if (oldcount == null) { oldcount = 0; } else { delete obj.sessionsCount[userid]; } + if (newcount != oldcount) { + var x = userid.split('/'); + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 }) + } + } + + // If there are any counts left in the old counts, event to zero + for (var userid in obj.sessionsCount) { + var oldcount = obj.sessionsCount[userid]; + if ((oldcount != null) && (oldcount != 0)) { + var x = userid.split('/'); + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 }) + } + } + + // Set the new session counts + obj.sessionsCount = newSessionsCount; + } else { + // Figure out the userid + var userid = changedSessionId.split('/').slice(0, 3).join('/'); + + // Recount only changedSessionId + var newcount = 0; + if (obj.wssessions[userid] != null) { newcount = obj.wssessions[userid].length; } + for (var serverid in obj.wsPeerSessions3) { if (obj.wsPeerSessions3[serverid][userid] != null) { newcount += obj.wsPeerSessions3[serverid][userid].length; } } + var oldcount = obj.sessionsCount[userid]; + if (oldcount == null) { oldcount = 0; } + + // If the count changed, update and event + if (newcount != oldcount) { + var x = userid.split('/'); + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 }) + obj.sessionsCount[userid] = newcount; + } + } + } + return obj; }