diff --git a/meshrelay.js b/meshrelay.js
index 7798807b..33ec69b9 100644
--- a/meshrelay.js
+++ b/meshrelay.js
@@ -18,8 +18,18 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
obj.ws = ws;
obj.id = req.query.id;
obj.user = user;
+ obj.ruserid = null;
obj.req = req; // Used in multi-server.js
+ // Check relay authentication
+ if ((user == null) && (req.query.rauth != null)) {
+ var rcookie = parent.parent.decodeCookie(req.query.rauth, parent.parent.loginCookieEncryptionKey, 240); // Cookie with 4 hour timeout
+ if (rcookie.ruserid != null) { obj.ruserid = rcookie.ruserid; }
+ }
+
+ // If there is no authentication, drop this connection
+ if ((obj.id.startsWith('meshmessenger/') == false) && (obj.user == null) && (obj.ruserid == null)) { try { ws.close(); parent.parent.debug('relay', 'Relay: Connection with no authentication (' + cleanRemoteAddr(req.ip) + ')'); } catch (e) { console.log(e); } return; }
+
// Relay session count (we may remove this in the future)
obj.relaySessionCounted = true;
parent.relaySessionCount++;
@@ -150,6 +160,20 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
return null;
}
+ // Check that both connection are for the same user
+ if (!obj.id.startsWith('meshmessenger/')) {
+ var u1 = obj.user ? obj.user._id : obj.ruserid;
+ var u2 = relayinfo.peer1.user ? relayinfo.peer1.user._id : relayinfo.peer1.ruserid;
+ if (u1 != u2) {
+ ws.close();
+ parent.parent.debug('relay', 'Relay auth mismatch: ' + obj.id + ' (' + cleanRemoteAddr(req.ip) + ')');
+ delete obj.id;
+ delete obj.ws;
+ delete obj.peer;
+ return null;
+ }
+ }
+
// Connect to peer
obj.peer = relayinfo.peer1;
obj.peer.peer = obj;
diff --git a/meshuser.js b/meshuser.js
index 0b6277e3..b2dee2d8 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -361,7 +361,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
case 'authcookie':
{
// Renew the authentication cookie
- try { ws.send(JSON.stringify({ action: 'authcookie', cookie: parent.parent.encodeCookie({ userid: user._id, domainid: domain.id }, parent.parent.loginCookieEncryptionKey) })); } catch (ex) { }
+ try {
+ console.log(req.ip);
+ ws.send(JSON.stringify({
+ action: 'authcookie',
+ cookie: parent.parent.encodeCookie({ userid: user._id, domainid: domain.id, ip: cleanRemoteAddr(req.ip) }, parent.parent.loginCookieEncryptionKey),
+ rcookie: parent.parent.encodeCookie({ ruserid: user._id }, parent.parent.loginCookieEncryptionKey)
+ }));
+ } catch (ex) { }
break;
}
case 'logincookie':
diff --git a/package.json b/package.json
index 55ac63b3..3658eb99 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "meshcentral",
- "version": "0.4.2-k",
+ "version": "0.4.2-l",
"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 ccec91de..531d627f 100644
--- a/public/scripts/agent-redir-ws-0.1.0.js
+++ b/public/scripts/agent-redir-ws-0.1.0.js
@@ -5,12 +5,13 @@
*/
// Construct a MeshServer agent direction object
-var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, authCookie, domainUrl) {
+var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, authCookie, rauthCookie, domainUrl) {
var obj = {};
obj.m = module; // This is the inner module (Terminal or Desktop)
module.parent = obj;
obj.meshserver = meshserver;
obj.authCookie = authCookie;
+ obj.rauthCookie = rauthCookie;
obj.State = 0;
obj.nodeid = null;
obj.socket = null;
@@ -49,7 +50,9 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
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: "*" + domainUrl + "meshrelay.ashx?p=" + obj.protocol + "&nodeid=" + nodeid + "&id=" + obj.tunnelid, usage: obj.protocol });
+ var rurl = "*" + domainUrl + "meshrelay.ashx?p=" + obj.protocol + "&nodeid=" + nodeid + "&id=" + obj.tunnelid;
+ if ((rauthCookie != null) && (rauthCookie != '')) { rurl += '&rauth=' + rauthCookie; }
+ obj.meshserver.send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: rurl, usage: obj.protocol });
//obj.debug("Agent Redir Start: " + url);
}
diff --git a/views/default-min.handlebars b/views/default-min.handlebars
index 66e162b5..426bf0b9 100644
--- a/views/default-min.handlebars
+++ b/views/default-min.handlebars
@@ -1,4 +1,4 @@
-
{{{title}}} My Devices | My Account | My Events | My Files | My Users | My Server | |
General | Desktop | Terminal | Files | Events | Details | Intel® AMT | Console | Plugins | |
Server disconnected, click to reconnect.
My Devices
| No device groups. |
My Account
Device Groups ( New ) My Events
| Show | |
My Files
These files are shared publicly, click "link" to get public url.
✓
✗
My Server
Server Statistics
Intel® AMT Redirection port or KVM feature is disabled, click here to enable it.
Remote computer is not powered on, click here to issue a power command.
Intel® AMT Redirection port or KVM feature is disabled, click here to enable it.
Remote computer is not powered on, click here to issue a power command.
| Show | |
General -
Events -
| Show | |
File Selection
Agent Remote Desktop
Scaling
Frame rate
Intel® AMT Hardware KVM
Image Encoding
{{{title}}} My Devices | My Account | My Events | My Files | My Users | My Server | |
General | Desktop | Terminal | Files | Events | Details | Intel® AMT | Console | Plugins | |
Server disconnected, click to reconnect.
My Devices
| No device groups. |
My Account
Device Groups ( New ) My Events
| Show | |
My Files
These files are shared publicly, click "link" to get public url.
✓
✗
My Server
Server Statistics
Intel® AMT Redirection port or KVM feature is disabled, click here to enable it.
Remote computer is not powered on, click here to issue a power command.
Intel® AMT Redirection port or KVM feature is disabled, click here to enable it.
Remote computer is not powered on, click here to issue a power command.
| Show | |
General -
Events -
| Show | |
File Selection
Agent Remote Desktop
Scaling
Frame rate
Intel® AMT Hardware KVM
Image Encoding
{{{title}}} Server disconnected, click to reconnect.
◀ | | |
Account Security
Account Actions
Device Groups ( New ) ◀ | | My Files |
◀ | | |
\ No newline at end of file
+ {{{title}}} Server disconnected, click to reconnect.
◀ | | |
Account Security
Account Actions
Device Groups ( New ) ◀ | | My Files |
◀ | | |
\ No newline at end of file
diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars
index 4e5fdfaf..552f7f87 100644
--- a/views/default-mobile.handlebars
+++ b/views/default-mobile.handlebars
@@ -603,6 +603,8 @@
var domain = "{{{domain}}}";
var domainUrl = "{{{domainurl}}}";
var authCookie = "{{{authCookie}}}";
+ var authRelayCookie = "{{{authRelayCookie}}}";
+ var authCookieRenewTimer = null;
var meshserver = null;
var xdr = null;
var serverinfo = null;
@@ -658,13 +660,14 @@
if (errorCode == 'noauth') { QH('p0span', 'Unable to perform authentication'); return; }
if (prevState == 2) { setTimeout(serverPoll, 5000); } else { QH('p0span', 'Unable to connect web socket'); }
// Clean up here
-
+ if (authCookieRenewTimer != null) { clearInterval(authCookieRenewTimer); authCookieRenewTimer = null; }
} else if (state == 2) {
// Fetch list of meshes, nodes, files
meshserver.send({ action: 'meshes' });
meshserver.send({ action: 'nodes' });
meshserver.send({ action: 'files' });
if (xxcurrentView < 2) { go(2); }
+ authCookieRenewTimer = setInterval(function () { meshserver.send({ action: 'authcookie' }); }, 1800000); // Request a cookie refresh every 30 minutes.
}
QV('topMenuIcon', state == 2);
}
@@ -715,6 +718,12 @@
QV('logoutMenuOption', ((features & 4) == 0) && (serverinfo.domainauth == false)); // Hide logout if in single user mode or domain authentication
break;
}
+ case 'authcookie': {
+ // Got an authentication cookie refresh
+ authCookie = message.cookie;
+ authRelayCookie = message.rcookie;
+ break;
+ }
case 'userinfo': {
userinfo = message.userinfo;
QH('p3userName', userinfo.name);
@@ -2312,7 +2321,7 @@
desktop.contype = 2;
} else {
// Setup the Mesh Agent remote desktop
- desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, domainUrl);
+ desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
desktop.debugmode = debugmode;
desktop.m.debugmode = debugmode;
desktop.attemptWebRTC = attemptWebRTC;
@@ -2670,7 +2679,7 @@
function connectFiles(e) {
if (!files) {
// Setup a mesh agent files
- files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, domainUrl);
+ files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
files.attemptWebRTC = attemptWebRTC;
files.onStateChanged = onFilesStateChange;
files.Start(filesNode._id);
@@ -2896,7 +2905,7 @@
// Called by the html page to start a download, arguments are: path, file name and file size.
function p13downloadfile(x, y, z) {
if (xxdialogMode) return;
- downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort, authCookie, domainUrl); // Create our websocket file transport
+ downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl); // Create our websocket file transport
downloadFile.ctrlMsgAllowed = false;
downloadFile.onStateChanged = onFileDownloadStateChange;
downloadFile.xpath = decodeURIComponent(x);
@@ -2983,7 +2992,7 @@
// Connect again
function p13uploadReconnect() {
- uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie, domainUrl);
+ uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
uploadFile.ws.attemptWebRTC = false;
uploadFile.ws.ctrlMsgAllowed = false;
uploadFile.ws.onStateChanged = onFileUploadStateChange;
diff --git a/views/default.handlebars b/views/default.handlebars
index b30d7fd7..c84e196c 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -184,9 +184,9 @@
-
+
-
+
|
@@ -1017,6 +1017,7 @@
var domain = "{{{domain}}}";
var domainUrl = "{{{domainurl}}}";
var authCookie = "{{{authCookie}}}";
+ var authRelayCookie = "{{{authRelayCookie}}}";
var authCookieRenewTimer = null;
var multiDesktop = {};
var multiDesktopFilter = null;
@@ -1466,6 +1467,7 @@
case 'authcookie': {
// Got an authentication cookie refresh
authCookie = message.cookie;
+ authRelayCookie = message.rcookie;
break;
}
case 'serverinfo': {
@@ -2664,6 +2666,10 @@
if (typeof deviceHeaderCount[node.state] == 'undefined') { deviceHeaderCount[node.state] = 1; } else { deviceHeaderCount[node.state]++; }
}
+ // Display "connect all" and "auto"
+ QV('kvmMultiConnectButtonSpan', (kvmDivs.length < 16));
+ QV('kvmAutoConnectButtonSpan', (kvmDivs.length < 16));
+
// If displaying devices by groups, sort the group names and display the devices.
if (sort == 3) {
if (view == 2) { r = ' | User | Address | Connectivity'; }
@@ -2877,7 +2883,7 @@
multiDesktop[nodeid] = desk;
} else if (contype == 1) {
// Setup the Mesh Agent remote desktop
- desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + shortid), serverPublicNamePort, authCookie, domainUrl);
+ desk = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('kvmid_' + shortid), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
desk.shortid = shortid;
desk.attemptWebRTC = attemptWebRTC;
desk.onStateChanged = onMultiDesktopStateChange;
@@ -5038,7 +5044,7 @@
desktop.contype = 2;
} else {
// Setup the Mesh Agent remote desktop
- desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, domainUrl);
+ desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
desktop.debugmode = debugmode;
desktop.m.debugmode = debugmode;
desktop.attemptWebRTC = attemptWebRTC;
@@ -5755,7 +5761,7 @@
}
}
if ((e && (e.shiftKey == true)) || (options && (options.powershell))) { termoptions.protocol = 6; }
- terminal = CreateAgentRedirect(meshserver, CreateAmtRemoteTerminal('Term', termoptions), serverPublicNamePort, authCookie, domainUrl);
+ terminal = CreateAgentRedirect(meshserver, CreateAmtRemoteTerminal('Term', termoptions), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
terminal.debugmode = debugmode;
terminal.m.debugmode = debugmode;
terminal.m.onTitleChange = function (sender, title) { QH('termtitle', ' - ' + EscapeHtml(title)); }
@@ -5891,7 +5897,7 @@
p13clearConsoleMsg();
if (!files) {
// Setup a mesh agent files
- files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, domainUrl);
+ files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
files.attemptWebRTC = attemptWebRTC;
files.onStateChanged = onFilesStateChange;
files.onConsoleMessageChange = function () {
@@ -6188,7 +6194,7 @@
// Called by the html page to start a download, arguments are: path, file name and file size.
function p13downloadfile(x, y, z) {
if (xxdialogMode) return;
- downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort, authCookie, domainUrl); // Create our websocket file transport
+ downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl); // Create our websocket file transport
downloadFile.ctrlMsgAllowed = false;
downloadFile.onStateChanged = onFileDownloadStateChange;
downloadFile.xpath = decodeURIComponent(x);
@@ -6297,7 +6303,7 @@
// Connect again
function p13uploadReconnect() {
- uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie, domainUrl);
+ uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort, authCookie, authRelayCookie, domainUrl);
uploadFile.ws.attemptWebRTC = false;
uploadFile.ws.ctrlMsgAllowed = false;
uploadFile.ws.onStateChanged = onFileUploadStateChange;
diff --git a/webserver.js b/webserver.js
index ed7ddc27..2e0ad5c0 100644
--- a/webserver.js
+++ b/webserver.js
@@ -1510,6 +1510,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// Create a authentication cookie
const authCookie = obj.parent.encodeCookie({ userid: user._id, domainid: domain.id, ip: cleanRemoteAddr(req.ip) }, obj.parent.loginCookieEncryptionKey);
+ const authRelayCookie = obj.parent.encodeCookie({ ruserid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey);
// Send the master web application
if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' Logout'; } // If a default user is in use or no user mode, don't display the logout button
@@ -1522,7 +1523,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
parent.debug('web', 'handleRootRequestEx: success.');
obj.db.Get('ws' + user._id, function (err, states) {
var webstate = (states.length == 1) ? states[0].state : '';
- res.render(getRenderPage('default', req), { authCookie: authCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(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, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate), pluginHandler: (parent.pluginHandler == null)?'null':parent.pluginHandler.prepExports() });
+ res.render(getRenderPage('default', req), { authCookie: authCookie, authRelayCookie: authRelayCookie, viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, extitle: encodeURIComponent(domain.title), extitle2: encodeURIComponent(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, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate), pluginHandler: (parent.pluginHandler == null)?'null':parent.pluginHandler.prepExports() });
});
} else {
// Send back the login application
@@ -3460,7 +3461,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
// This is a encrypted cookie authentication
var cookie = obj.parent.decodeCookie(req.query.auth, obj.parent.loginCookieEncryptionKey, 240); // Cookie with 4 hour timeout
if ((cookie == null) && (obj.parent.multiServer != null)) { cookie = obj.parent.decodeCookie(req.query.auth, obj.parent.serverKey, 240); } // Try the server key
- //if ((cookie != null) && (cookie.ip != null) && (cookie.ip != cleanRemoteAddr(req.ip))) { cookie = null; } // If the cookie if binded to an IP address, check here.
+ if ((cookie != null) && (cookie.ip != null) && (cookie.ip != cleanRemoteAddr(req.ip) && (cookie.ip != req.ip))) { cookie = null; } // If the cookie if binded to an IP address, check here.
if ((cookie != null) && (obj.users[cookie.userid]) && (cookie.domainid == domain.id)) {
// Valid cookie, we are authenticated
func(ws, req, domain, obj.users[cookie.userid], cookie);
|
|