Fixed ClickOnce support & improved websocket authentication

This commit is contained in:
Ylian Saint-Hilaire 2018-10-15 17:21:37 -07:00
parent 564646fcdf
commit fc03f1ce1d
12 changed files with 87 additions and 123 deletions

View File

@ -1055,7 +1055,8 @@ function CreateMeshCentralServer(config, args) {
o.time = Math.floor(Date.now() / 1000); // Add the cookie creation time o.time = Math.floor(Date.now() / 1000); // Add the cookie creation time
var iv = new Buffer(obj.crypto.randomBytes(12), 'binary'), cipher = obj.crypto.createCipheriv('aes-256-gcm', key, iv); var iv = new Buffer(obj.crypto.randomBytes(12), 'binary'), cipher = obj.crypto.createCipheriv('aes-256-gcm', key, iv);
var crypted = Buffer.concat([cipher.update(JSON.stringify(o), 'utf8'), cipher.final()]); var crypted = Buffer.concat([cipher.update(JSON.stringify(o), 'utf8'), cipher.final()]);
return Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); var cookie = Buffer.concat([iv, cipher.getAuthTag(), crypted]).toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
return cookie;
} catch (e) { return null; } } catch (e) { return null; }
}; };
@ -1067,11 +1068,11 @@ function CreateMeshCentralServer(config, args) {
var decipher = obj.crypto.createDecipheriv('aes-256-gcm', key, cookie.slice(0, 12)); var decipher = obj.crypto.createDecipheriv('aes-256-gcm', key, cookie.slice(0, 12));
decipher.setAuthTag(cookie.slice(12, 16)); decipher.setAuthTag(cookie.slice(12, 16));
var o = JSON.parse(decipher.update(cookie.slice(28), 'binary', 'utf8') + decipher.final('utf8')); var o = JSON.parse(decipher.update(cookie.slice(28), 'binary', 'utf8') + decipher.final('utf8'));
if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { return null; } if ((o.time == null) || (o.time == null) || (typeof o.time != 'number')) { Debug(1, 'ERR: Bad cookie due to invalid time'); return null; }
o.time = o.time * 1000; // Decode the cookie creation time o.time = o.time * 1000; // Decode the cookie creation time
o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds) o.dtime = Date.now() - o.time; // Decode how long ago the cookie was created (in milliseconds)
if (timeout == null) { timeout = 2; } if (timeout == null) { timeout = 2; }
if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) return null; // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right) if ((o.dtime > (timeout * 60000)) || (o.dtime < -30000)) { Debug(1, 'ERR: Bad cookie due to timeout'); return null; } // The cookie is only valid 120 seconds, or 30 seconds back in time (in case other server's clock is not quite right)
return o; return o;
} catch (e) { return null; } } catch (e) { return null; }
}; };

View File

@ -13,11 +13,13 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
"use strict"; "use strict";
module.exports.CreateMeshRelay = function (parent, ws, req, domain) { module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie) {
var obj = {}; var obj = {};
obj.ws = ws; obj.ws = ws;
obj.req = req; obj.req = req;
obj.peer = null; obj.peer = null;
obj.user = user;
obj.cookie = cookie;
obj.parent = parent; obj.parent = parent;
obj.id = req.query.id; obj.id = req.query.id;
obj.remoteaddr = obj.ws._socket.remoteAddress; obj.remoteaddr = obj.ws._socket.remoteAddress;
@ -69,48 +71,24 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
return false; return false;
}; };
if (req.query.auth == null) { // Mark this relay session as authenticated if this is the user end.
// Use ExpressJS session, check if this session is a logged in user, at least one of the two connections will need to be authenticated. obj.authenticated = (obj.user != null);
try { if ((req.session) && (req.session.userid) || (req.session.domainid == obj.domain.id)) { obj.authenticated = true; } } catch (e) { }
if ((obj.authenticated != true) && (req.query.user != null) && (req.query.pass != null)) { // Kick off the routing, if we have agent routing instructions, process them here.
// Check user authentication if ((obj.cookie != null) && (obj.cookie.nodeid != null) && (obj.cookie.tcpport != null) && (obj.cookie.domainid != null)) {
obj.parent.authenticate(req.query.user, req.query.pass, obj.domain, function (err, userid, passhint) { // We have routing instructions in the cookie, Send connection request to agent
if (userid != null) { if (obj.id == undefined) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one.
obj.authenticated = true; var command = { nodeid: obj.cookie.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: obj.cookie.tcpport, tcpaddr: obj.cookie.tcpaddr };
// Check if we have agent routing instructions, process this here. obj.parent.parent.debug(1, 'Relay: Sending agent tunnel command: ' + JSON.stringify(command));
if ((req.query.nodeid != null) && (req.query.tcpport != null)) { if (obj.sendAgentMessage(command, obj.cookie.userid, obj.cookie.domainid) == false) { obj.id = null; obj.parent.parent.debug(1, 'Relay: Unable to contact this agent (' + obj.remoteaddr + ')'); }
if (obj.id == undefined) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one. } else if ((req.query.nodeid != null) && (req.query.tcpport != null)) {
var command = { nodeid: req.query.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: req.query.tcpport, tcpaddr: ((req.query.tcpaddr == null) ? '127.0.0.1' : req.query.tcpaddr) }; // We have routing instructions in the URL arguments, Send connection request to agent
if (obj.sendAgentMessage(command, userid, obj.domain.id) == false) { obj.id = null; obj.parent.parent.debug(1, 'Relay: Unable to contact this agent (' + obj.remoteaddr + ')'); } if (obj.id == null) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one.
} var command = { nodeid: req.query.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: req.query.tcpport, tcpaddr: ((req.query.tcpaddr == null) ? '127.0.0.1' : req.query.tcpaddr) };
} else { obj.parent.parent.debug(1, 'Relay: Sending agent tunnel command: ' + JSON.stringify(command));
obj.parent.parent.debug(1, 'Relay: User authentication failed (' + obj.remoteaddr + ')'); if (obj.sendAgentMessage(command, userid, obj.domain.id) == false) { obj.id = null; obj.parent.parent.debug(1, 'Relay: Unable to contact this agent (' + obj.remoteaddr + ')'); }
obj.ws.send('error:Authentication failed');
}
performRelay();
});
} else {
performRelay();
}
} else {
// Get the session from the cookie
var cookie = obj.parent.parent.decodeCookie(req.query.auth);
if (cookie != null) {
obj.authenticated = true;
if (cookie.tcpport != null) {
// This cookie has agent routing instructions, process this here.
if (obj.id == undefined) { obj.id = ('' + Math.random()).substring(2); } // If there is no connection id, generate one.
// Send connection request to agent
var command = { nodeid: cookie.nodeid, action: 'msg', type: 'tunnel', value: '*/meshrelay.ashx?id=' + obj.id, tcpport: cookie.tcpport, tcpaddr: cookie.tcpaddr };
if (obj.sendAgentMessage(command, cookie.userid, cookie.domainid) == false) { obj.id = null; obj.parent.parent.debug(1, 'Relay: Unable to contact this agent (' + obj.remoteaddr + ')'); }
}
} else {
obj.id = null;
obj.parent.parent.debug(1, 'Relay: invalid cookie (' + obj.remoteaddr + ')');
obj.ws.send('error:Invalid cookie');
}
performRelay();
} }
performRelay();
function performRelay() { function performRelay() {
if (obj.id == null) { try { obj.close(); } catch (e) { } return null; } // Attempt to connect without id, drop this. if (obj.id == null) { try { obj.close(); } catch (e) { } return null; } // Attempt to connect without id, drop this.

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.2.2-e", "version": "0.2.2-f",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",

View File

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2"> <asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
<assemblyIdentity name="MeshMiniRouter.application" version="2.0.0.16" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /> <assemblyIdentity name="MeshMiniRouter.application" version="2.0.0.17" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
<description asmv2:publisher="Meshcentral.com" asmv2:product="MeshCentral Mini-Router" asmv2:supportUrl="https://meshcentral.com/" xmlns="urn:schemas-microsoft-com:asm.v1" /> <description asmv2:publisher="Meshcentral.com" asmv2:product="MeshCentral Mini-Router" asmv2:supportUrl="https://meshcentral.com/" xmlns="urn:schemas-microsoft-com:asm.v1" />
<deployment install="false" mapFileExtensions="true" trustURLParameters="true" /> <deployment install="false" mapFileExtensions="true" trustURLParameters="true" />
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2"> <compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
<framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" /> <framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" />
</compatibleFrameworks> </compatibleFrameworks>
<dependency> <dependency>
<dependentAssembly dependencyType="install" codebase="Application Files\MeshMiniRouter_2_0_0_16\MeshMiniRouter.exe.manifest" size="4712"> <dependentAssembly dependencyType="install" codebase="Application Files\MeshMiniRouter_2_0_0_17\MeshMiniRouter.exe.manifest" size="4712">
<assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.16" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" /> <assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.17" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
<hash> <hash>
<dsig:Transforms> <dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" /> <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms> </dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /> <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>uaxqCrqKPjDkZMXMlJ9pIvARsSxYXXLci7n8z3Q8hUU=</dsig:DigestValue> <dsig:DigestValue>nyBHr6mVUVhjU6l4Bmrfa0juzDDrPD6BiiYzVMhKKVA=</dsig:DigestValue>
</hash> </hash>
</dependentAssembly> </dependentAssembly>
</dependency> </dependency>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2"> <asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
<asmv1:assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.16" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" /> <asmv1:assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.17" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
<description asmv2:iconFile="MeshMiniRouter.ico" xmlns="urn:schemas-microsoft-com:asm.v1" /> <description asmv2:iconFile="MeshMiniRouter.ico" xmlns="urn:schemas-microsoft-com:asm.v1" />
<application /> <application />
<entryPoint> <entryPoint>
<assemblyIdentity name="MeshMiniRouter" version="1.0.6667.26398" language="neutral" processorArchitecture="msil" /> <assemblyIdentity name="MeshMiniRouter" version="1.0.6862.31040" language="neutral" processorArchitecture="msil" />
<commandLine file="MeshMiniRouter.exe" parameters="" /> <commandLine file="MeshMiniRouter.exe" parameters="" />
</entryPoint> </entryPoint>
<trustInfo> <trustInfo>
@ -43,14 +43,14 @@
</dependentAssembly> </dependentAssembly>
</dependency> </dependency>
<dependency> <dependency>
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="MeshMiniRouter.exe" size="193536"> <dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="MeshMiniRouter.exe" size="186368">
<assemblyIdentity name="MeshMiniRouter" version="1.0.6667.26398" language="neutral" processorArchitecture="msil" /> <assemblyIdentity name="MeshMiniRouter" version="1.0.6862.31040" language="neutral" processorArchitecture="msil" />
<hash> <hash>
<dsig:Transforms> <dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" /> <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms> </dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /> <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>2K6tEre6rIjqc6bZn7uhWlXLgAnZ82UP3jYzxNJ7WIk=</dsig:DigestValue> <dsig:DigestValue>H+qrBKAsVVx/APIHP2Tq2cK3/FUh4SIShsjM6eo0fUw=</dsig:DigestValue>
</hash> </hash>
</dependentAssembly> </dependentAssembly>
</dependency> </dependency>

View File

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2"> <asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
<assemblyIdentity name="MeshMiniRouter.application" version="2.0.0.16" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /> <assemblyIdentity name="MeshMiniRouter.application" version="2.0.0.17" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
<description asmv2:publisher="Meshcentral.com" asmv2:product="MeshCentral Mini-Router" asmv2:supportUrl="https://meshcentral.com/" xmlns="urn:schemas-microsoft-com:asm.v1" /> <description asmv2:publisher="Meshcentral.com" asmv2:product="MeshCentral Mini-Router" asmv2:supportUrl="https://meshcentral.com/" xmlns="urn:schemas-microsoft-com:asm.v1" />
<deployment install="false" mapFileExtensions="true" trustURLParameters="true" /> <deployment install="false" mapFileExtensions="true" trustURLParameters="true" />
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2"> <compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
<framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" /> <framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" />
</compatibleFrameworks> </compatibleFrameworks>
<dependency> <dependency>
<dependentAssembly dependencyType="install" codebase="Application Files\MeshMiniRouter_2_0_0_16\MeshMiniRouter.exe.manifest" size="4712"> <dependentAssembly dependencyType="install" codebase="Application Files\MeshMiniRouter_2_0_0_17\MeshMiniRouter.exe.manifest" size="4712">
<assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.16" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" /> <assemblyIdentity name="MeshMiniRouter.exe" version="2.0.0.17" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="msil" type="win32" />
<hash> <hash>
<dsig:Transforms> <dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" /> <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms> </dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /> <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>uaxqCrqKPjDkZMXMlJ9pIvARsSxYXXLci7n8z3Q8hUU=</dsig:DigestValue> <dsig:DigestValue>nyBHr6mVUVhjU6l4Bmrfa0juzDDrPD6BiiYzVMhKKVA=</dsig:DigestValue>
</hash> </hash>
</dependentAssembly> </dependentAssembly>
</dependency> </dependency>

View File

@ -59,7 +59,7 @@ FONT.key {font-weight: bold; color: darkgreen}
<TR><TD ALIGN="LEFT"><TABLE CELLPADDING="2" CELLSPACING="0" BORDER="0" WIDTH="540"><TR><TD WIDTH="496"> <TR><TD ALIGN="LEFT"><TABLE CELLPADDING="2" CELLSPACING="0" BORDER="0" WIDTH="540"><TR><TD WIDTH="496">
<!-- Begin AppInfo --> <!-- Begin AppInfo -->
<TABLE><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Name:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>MeshCentral Mini-Router</TD></TR><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Version:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>2.0.0.16</TD></TR><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Publisher:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>Meshcentral.com</TD></TR><tr><td colspan="3">&nbsp;</td></tr></TABLE> <TABLE><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Name:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>MeshCentral Mini-Router</TD></TR><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Version:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>2.0.0.17</TD></TR><TR><TD COLSPAN="3">&nbsp;</TD></TR><TR><TD><B>Publisher:</B></TD><TD WIDTH="5"><SPACER TYPE="block" WIDTH="10" /></TD><TD>Meshcentral.com</TD></TR><tr><td colspan="3">&nbsp;</td></tr></TABLE>
<!-- End AppInfo --> <!-- End AppInfo -->

View File

@ -1271,7 +1271,7 @@
case 'getcookie': { case 'getcookie': {
if (message.tag == 'clickonce') { if (message.tag == 'clickonce') {
var basicPort = "{{{serverRedirPort}}}"==""?"{{{serverPublicPort}}}":"{{{serverRedirPort}}}"; var basicPort = "{{{serverRedirPort}}}"==""?"{{{serverPublicPort}}}":"{{{serverRedirPort}}}";
rdpurl = "http://" + window.location.hostname + ":" + basicPort + "/clickonce/minirouter/MeshMiniRouter.application?WS=wss%3A%2F%2F" + window.location.hostname + "%2Fmeshrelay.ashx%3Fauth=" + message.cookie + "&CH={{{webcerthash}}}&AP=" + message.protocol + "&HOL=1"; var rdpurl = "http://" + window.location.hostname + ":" + basicPort + "/clickonce/minirouter/MeshMiniRouter.application?WS=wss%3A%2F%2F" + window.location.hostname + "%2Fmeshrelay.ashx%3Fauth=" + message.cookie + "&CH={{{webcerthash}}}&AP=" + message.protocol + "&HOL=1";
window.open(rdpurl, '_blank'); window.open(rdpurl, '_blank');
} }
break; break;

View File

@ -1059,26 +1059,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
}; };
// Handle a web socket relay request // Handle a web socket relay request
function handleRelayWebSocket(ws, req) { function handleRelayWebSocket(ws, req, domain, user, cookie) {
var domain = checkUserIpAddress(ws, req); if (!(req.query.host)) { console.log('ERR: No host target specified'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
if (domain == null) return;
// Check if this is a logged in user
var user, peering = true;
if (req.query.auth == null) {
// Use ExpressJS session
if (!req.session || !req.session.userid) { return; } // Web socket attempt without login, disconnect.
if (req.session.domainid != domain.id) { console.log('ERR: Invalid domain'); return; }
user = obj.users[req.session.userid];
} else {
// Get the session from the cookie
if (obj.parent.multiServer == null) { return; }
var session = obj.parent.decodeCookie(req.query.auth);
if (session == null) { console.log('ERR: Invalid cookie'); return; }
if (session.domainid != domain.id) { console.log('ERR: Invalid domain'); return; }
user = obj.users[session.userid];
peering = false; // Don't allow the connection to jump again to a different server
}
if (!user) { console.log('ERR: Not a user'); return; }
Debug(1, 'Websocket relay connected from ' + user.name + ' for ' + req.query.host + '.'); Debug(1, 'Websocket relay connected from ' + user.name + ' for ' + req.query.host + '.');
ws.pause(); // Hold this socket until we are ready. ws.pause(); // Hold this socket until we are ready.
@ -1086,13 +1068,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Fetch information about the target // Fetch information about the target
obj.db.Get(req.query.host, function (err, docs) { obj.db.Get(req.query.host, function (err, docs) {
if (docs.length == 0) { console.log('ERR: Node not found'); return; } if (docs.length == 0) { console.log('ERR: Node not found'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
var node = docs[0]; var node = docs[0];
if (!node.intelamt) { console.log('ERR: Not AMT node'); return; } if (!node.intelamt) { console.log('ERR: Not AMT node'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
// Check if this user has permission to manage this computer // Check if this user has permission to manage this computer
var meshlinks = user.links[node.meshid]; var meshlinks = user.links[node.meshid];
if ((!meshlinks) || (!meshlinks.rights) || ((meshlinks.rights & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (2)'); return; } if ((!meshlinks) || (!meshlinks.rights) || ((meshlinks.rights & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (2)'); try { ws.close(); } catch (e) { } return; }
// Check what connectivity is available for this node // Check what connectivity is available for this node
var state = parent.GetConnectivityState(req.query.host); var state = parent.GetConnectivityState(req.query.host);
@ -1100,7 +1082,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (!state || state.connectivity == 0) { Debug(1, 'ERR: No routing possible (1)'); try { ws.close(); } catch (e) { } return; } else { conn = state.connectivity; } if (!state || state.connectivity == 0) { Debug(1, 'ERR: No routing possible (1)'); try { ws.close(); } catch (e) { } return; } else { conn = state.connectivity; }
// Check what server needs to handle this connection // Check what server needs to handle this connection
if ((obj.parent.multiServer != null) && (peering == true)) { if ((obj.parent.multiServer != null) && (cookie == null)) { // If a cookie is provided, don't allow the connection to jump again to a different server
var server = obj.parent.GetRoutingServerId(req.query.host, 2); // Check for Intel CIRA connection var server = obj.parent.GetRoutingServerId(req.query.host, 2); // Check for Intel CIRA connection
if (server != null) { if (server != null) {
if (server.serverid != obj.parent.serverId) { if (server.serverid != obj.parent.serverId) {
@ -1810,10 +1792,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.app.post(url + 'uploadmeshcorefile.ashx', handleUploadMeshCoreFile); obj.app.post(url + 'uploadmeshcorefile.ashx', handleUploadMeshCoreFile);
obj.app.get(url + 'userfiles/*', handleDownloadUserFiles); obj.app.get(url + 'userfiles/*', handleDownloadUserFiles);
obj.app.ws(url + 'echo.ashx', handleEchoWebSocket); obj.app.ws(url + 'echo.ashx', handleEchoWebSocket);
obj.app.ws(url + 'meshrelay.ashx', function (ws, req) { try { obj.meshRelayHandler.CreateMeshRelay(obj, ws, req, getDomain(req)); } catch (e) { console.log(e); } }); obj.app.ws(url + 'meshrelay.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, function (ws1, req1, domain, user, cookie) { obj.meshRelayHandler.CreateMeshRelay(obj, ws1, req1, domain, user, cookie); }); });
obj.app.get(url + 'webrelay.ashx', function (req, res) { res.send('Websocket connection expected'); }); obj.app.get(url + 'webrelay.ashx', function (req, res) { res.send('Websocket connection expected'); });
obj.app.ws(url + 'webrelay.ashx', function (ws, req) { PerformSessionAuth(ws, req, handleRelayWebSocket); }); obj.app.ws(url + 'webrelay.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, handleRelayWebSocket); });
obj.app.ws(url + 'control.ashx', function (ws, req) { PerformSessionAuth(ws, req, function (ws1, req1, domain) { obj.meshUserHandler.CreateMeshUser(obj, obj.db, ws1, req1, obj.args, domain); }); }); obj.app.ws(url + 'control.ashx', function (ws, req) { PerformWSSessionAuth(ws, req, function (ws1, req1, domain, user, cookie) { obj.meshUserHandler.CreateMeshUser(obj, obj.db, ws1, req1, obj.args, domain); }); });
// Server picture // Server picture
obj.app.get(url + 'serverpic.ashx', function (req, res) { obj.app.get(url + 'serverpic.ashx', function (req, res) {
@ -1847,47 +1829,50 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
} }
// Authenticates a session and forwards // Authenticates a session and forwards
function PerformSessionAuth(ws, req, func) { function PerformWSSessionAuth(ws, req, func) {
try { try {
// Check IP filtering and domain
var domain = checkUserIpAddress(ws, req); var domain = checkUserIpAddress(ws, req);
if (domain != null) { if (domain == null) { try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth' })); ws.close(); return; } catch (e) { return; } }
var loginok = false;
// Check if the user is logged in // A web socket session can be authenticated in many ways (Default user, session, user/pass and cookie). Check authentication here.
if ((!req.session) || (!req.session.userid) || (req.session.domainid != domain.id)) { if ((req.query.user != null) && (req.query.pass != null)) {
// If a default user is active, setup the session here. // A user/pass is provided in URL arguments
if (obj.args.user && obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]) { obj.authenticate(req.query.user, req.query.pass, domain, function (err, userid) {
if (req.session && req.session.loginmode) { delete req.session.loginmode; } if ((err == null) && (obj.users[userid])) {
req.session.userid = 'user/' + domain.id + '/' + obj.args.user.toLowerCase(); // We are authenticated
req.session.domainid = domain.id; func(ws, req, domain, obj.users[userid]);
func(ws, req, domain);
loginok = true;
} else { } else {
// See the the user/pass is provided in URL arguments // If not authenticated, close the websocket connection
if ((req.query.user != null) && (req.query.pass != null)) { Debug(1, 'ERR: Websocket bad user/pass auth');
loginok = true; try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth' })); ws.close(); } catch (e) { }
obj.authenticate(req.query.user, req.query.pass, domain, function (err, userid) {
var loginok2 = false;
if (err == null) {
var user = obj.users[userid];
if (user) {
req.session.userid = userid;
req.session.domainid = domain.id;
func(ws, req, domain);
loginok2 = true;
}
}
// If not authenticated, close the websocket connection
if (loginok2 == false) { try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth' })); ws.close(); } catch (e) { } }
});
}
} }
});
return;
} else if (req.query.auth != null) {
// This is a encrypted cookie authentication
var cookie = obj.parent.decodeCookie(req.query.auth, null, 60); // Cookie with 60 minute timeout
if ((cookie != null) && (obj.users[cookie.userid])) {
// Valid cookie, we are authenticated
func(ws, req, domain, obj.users[cookie.userid], cookie);
} else { } else {
func(ws, req, domain); // This is a bad cookie
loginok = true; Debug(1, 'ERR: Websocket bad cookie auth: ' + req.query.auth);
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth' })); ws.close(); } catch (e) { }
} }
// If not authenticated, close the websocket connection return;
if (loginok == false) { try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth' })); ws.close(); } catch (e) { } } } else if (obj.args.user && obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]) {
// A default user is active
func(ws, req, domain, obj.users['user/' + domain.id + '/' + obj.args.user.toLowerCase()]);
return;
} else if (req.session && (req.session.userid != null) && (req.session.domainid == obj.domain.id)) {
// This user is logged in using the ExpressJS session
func(ws, req, domain, req.session.userid);
return;
} }
// If not authenticated, close the websocket connection
Debug(1, 'ERR: Websocket no auth');
try { ws.send(JSON.stringify({ action: 'close', cause: 'noauth' })); ws.close(); } catch (e) { }
} catch (e) { console.log(e); } } catch (e) { console.log(e); }
} }