Added session termination feature except for desktop multiplexor.
Ylian Saint-Hilaire committed
Oct 19, 2021 at 11:47 UTC
bd2e4f4d2bbbd32312b32fdde5580491fc3b3bfd
3 files changed
+85
-7
agents/meshcore.js
+22
-1
@@ -1015,6 +1015,22 @@ function handleServerCommand(data) {
1015
}
1016
break;
1017
}
1018
+ case 'endtunnel': {
1019
+ // Terminate one or more tunnels
1020
+ if ((data.rights != 4294967295) && (data.xuserid != data.userid)) return; // This command requires full admin rights on the device or user self-closes it's own sessions
1021
+ for (var i in tunnels) {
1022
+ if ((tunnels[i].userid == data.xuserid) && (tunnels[i].guestname == data.guestname)) {
1023
+ var disconnect = false;
1024
+ if ((data.protocol == 'kvm') && (tunnels[i].protocol == 2)) { disconnect = true; }
1025
+ else if ((data.protocol == 'terminal') && (tunnels[i].protocol == 1)) { disconnect = true; }
1026
+ else if ((data.protocol == 'files') && (tunnels[i].protocol == 5)) { disconnect = true; }
1027
+ else if ((data.protocol == 'tcp') && (tunnels[i].tcpport != null)) { disconnect = true; }
1028
+ else if ((data.protocol == 'udp') && (tunnels[i].udpport != null)) { disconnect = true; }
1029
+ if (disconnect) { if (tunnels[i].s != null) { tunnels[i].s.end(); } else { tunnels[i].end(); } }
1030
+ }
1031
+ }
1032
+ break;
1033
+ }
1034
case 'messagebox': {
1035
// Display a message box
1036
if (data.title && data.msg) {
@@ -3988,7 +4004,12 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
4004
}
4005
case 'tunnels': { // Show the list of current tunnels
4006
response = '';
3991
- for (var i in tunnels) { response += 'Tunnel #' + i + ', ' + tunnels[i].url + '\r\n'; }
4007
+ for (var i in tunnels) {
4008
+ response += 'Tunnel #' + i + ', ' + tunnels[i].protocol; //tunnels[i].url
4009
+ if (tunnels[i].userid) { response += ', ' + tunnels[i].userid; }
4010
+ if (tunnels[i].guestname) { response += '/' + tunnels[i].guestname; }
4011
+ response += '\r\n'
4012
+ }
4013
if (response == '') { response = 'No websocket sessions.'; }
4014
break;
4015
}
meshuser.js
+23
@@ -5660,6 +5660,29 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5660
5661
break;
5662
}
5663
+ case 'endDesktopMultiplex': {
5664
+ var err = null, xuser = null;
5665
+ try {
5666
+ if (command.xuserid.indexOf('/') < 0) { command.xuserid = 'user/' + domain.id + '/' + command.xuserid; }
5667
+ if (common.validateString(command.nodeid, 1, 1024) == false) { err = 'Invalid device identifier'; } // Check the meshid
5668
+ else if (command.nodeid.indexOf('/') == -1) { command.nodeid = 'node/' + domain.id + '/' + command.nodeid; }
5669
+ const xusersplit = command.xuserid.split('/');
5670
+ xuser = parent.users[command.xuserid];
5671
+ if (xuser == null) { err = 'User does not exists'; }
5672
+ else if ((obj.crossDomain !== true) && ((xusersplit.length != 3) || (xusersplit[1] != domain.id))) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain
5673
+ } catch (ex) { err = 'Validation exception: ' + ex; }
5674
+
5675
+ // Handle any errors
5676
+ if (err != null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changeusernotify', responseid: command.responseid, result: err })); } catch (ex) { } } break; }
5677
+
5678
+ // Get the node and the rights for this node
5679
+ parent.GetNodeWithRights(domain, xuser, command.nodeid, function (node, rights, visible) {
5680
+ if ((rights != 0xFFFFFFFF) && (xuser._id != command.xuserid)) return;
5681
+ //console.log('TODO');
5682
+ });
5683
+
5684
+ break;
5685
+ }
5686
default: {
5687
// Unknown user action
5688
console.log('Unknown action from user ' + user.name + ': ' + command.action + '.');
views/default.handlebars
+40
-6
@@ -4461,28 +4461,62 @@
4461
for (var i in node.sessions) {
4462
if ((i == 'kvm') && (node.sessions.multidesk == null)) {
4463
x += '<u>' + "Remote Desktop" + '</u>';
4464
- for (var j in node.sessions.kvm) { x += addHtmlValue2(getUserName(j), (node.sessions.kvm[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.kvm[j]))); }
4464
+ for (var j in node.sessions.kvm) {
4465
+ var trash = '';
4466
+ if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("kvm", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4467
+ x += addHtmlValue2(getUserName(j), ((node.sessions.kvm[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.kvm[j]))) + trash);
4468
+ }
4469
} else if (i == 'multidesk') {
4470
x += '<u>' + "Remote Desktop" + '</u>';
4467
- for (var j in node.sessions.multidesk) { x += addHtmlValue2(getUserName(j), ((node.sessions.multidesk[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.multidesk[j])))); }
4471
+ for (var j in node.sessions.multidesk) {
4472
+ var trash = '';
4473
+ if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("multidesk", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4474
+ x += addHtmlValue2(getUserName(j), ((node.sessions.multidesk[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.multidesk[j]))) + trash);
4475
+ }
4476
} else if (i == 'terminal') {
4477
x += '<u>' + "Terminal" + '</u>';
4470
- for (var j in node.sessions.terminal) { x += addHtmlValue2(getUserName(j), ((node.sessions.terminal[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.terminal[j])))); }
4478
+ for (var j in node.sessions.terminal) {
4479
+ var trash = '';
4480
+ if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("terminal", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4481
+ x += addHtmlValue2(getUserName(j), ((node.sessions.terminal[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.terminal[j]))) + trash);
4482
+ }
4483
} else if (i == 'files') {
4484
x += '<u>' + "Files" + '</u>';
4473
- for (var j in node.sessions.files) { x += addHtmlValue2(getUserName(j), ((node.sessions.files[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.files[j])))); }
4485
+ for (var j in node.sessions.files) {
4486
+ var trash = '';
4487
+ if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("files", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4488
+ x += addHtmlValue2(getUserName(j), ((node.sessions.files[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.files[j]))) + trash);
4489
+ }
4490
} else if (i == 'tcp') {
4491
x += '<u>' + "TCP Routing" + '</u>';
4476
- for (var j in node.sessions.tcp) { x += addHtmlValue2(getUserName(j), ((node.sessions.tcp[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.tcp[j])))); }
4492
+ for (var j in node.sessions.tcp) {
4493
+ var trash = '';
4494
+ if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("tcp", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4495
+ x += addHtmlValue2(getUserName(j), ((node.sessions.tcp[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.tcp[j]))) + trash);
4496
+ }
4497
} else if (i == 'udp') {
4498
x += '<u>' + "UDP Routing" + '</u>';
4479
- for (var j in node.sessions.udp) { x += addHtmlValue2(getUserName(j), ((node.sessions.udp[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.udp[j])))); }
4499
+ for (var j in node.sessions.udp) {
4500
+ var trash = '';
4501
+ if ((j == userinfo._id) || (GetNodeRights(node) == 0xFFFFFFFF)) { trash = ' <a href=# onclick=\'return endDeviceSession("udp", "' + encodeURIComponentEx(node._id) + '", "' + encodeURIComponentEx(j) + '")\' title="' + "Disconnect this session" + '" style=cursor:pointer><img src=images/trash.png border=0 height=10 width=10></a>'; }
4502
+ x += addHtmlValue2(getUserName(j), ((node.sessions.udp[j] == 1)?"1 session":nobreak(format("{0} sessions", node.sessions.udp[j]))) + trash);
4503
+ }
4504
}
4505
}
4506
if (x != '') { setDialogMode(2, "Sessions" + ' - ' + EscapeHtml(node.name), 1, null, x, 'SESSIONS-' + node._id); } else { setDialogMode(0); }
4507
return false;
4508
}
4509
4510
+ function endDeviceSession(protocol, nodeid, userid) {
4511
+ var userIdSplit = decodeURIComponent(userid).split('/'), uid = userIdSplit[0] + '/' + userIdSplit[1] + '/' + userIdSplit[2], guestname = null;
4512
+ if ((userIdSplit.length == 4) && (userIdSplit[3].startsWith('guest:'))) { guestname = atob(userIdSplit[3].substring(6)); }
4513
+ if (protocol == 'multidesk') {
4514
+ meshserver.send({ action: 'endDesktopMultiplex', nodeid: decodeURIComponent(nodeid), xuserid: uid, guestname, guestname });
4515
+ } else {
4516
+ meshserver.send({ action: 'msg', type: 'endtunnel', nodeid: decodeURIComponent(nodeid), xuserid: uid, guestname, guestname, protocol: protocol });
4517
+ }
4518
+ }
4519
+
4520
// Show currently active sessions on this device
4521
function showDeviceMessages(nodeid, force, e) {
4522
if (e) haltEvent(e);