Started work on agent self-sharing.
Ylian Saint-Hilaire committed
Nov 9, 2021 at 22:51 UTC
f4b9372dd295f0aeb02c6f87496d5aaf455cf549
2 files changed
+111
-3
meshagent.js
+107
-2
@@ -61,6 +61,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
61
if (arg == 2) { try { ws._socket._parent.end(); if (obj.nodeid != null) { parent.parent.debug('agent', 'Hard disconnect ' + obj.nodeid + ' (' + obj.remoteaddrport + ')'); } } catch (e) { console.log(e); } } // Hard close, close the TCP socket
62
// If arg == 3, don't communicate with this agent anymore, but don't disconnect (Duplicate agent).
63
64
+ // Stop any current self-share
65
+ if (obj.guestSharing === true) { removeGuestSharing(); }
66
+
67
// Remove this agent from the webserver list
68
if (parent.wsagents[obj.dbNodeKey] == obj) {
69
delete parent.wsagents[obj.dbNodeKey];
@@ -126,8 +129,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
129
delete obj.remoteaddr;
130
delete obj.remoteaddrport;
131
delete obj.meshid;
129
- delete obj.dbNodeKey;
130
- delete obj.dbMeshKey;
132
delete obj.connectTime;
133
delete obj.agentInfo;
134
delete obj.agentExeInfo;
@@ -1088,6 +1089,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1089
if (typeof domain.terminal.launchcommand.darwin == 'string') { serverInfo.termlaunchcommand.darwin = domain.terminal.launchcommand.darwin; }
1090
if (typeof domain.terminal.launchcommand.freebsd == 'string') { serverInfo.termlaunchcommand.freebsd = domain.terminal.launchcommand.freebsd; }
1091
}
1092
+ // Enable agent self guest sharing if allowed
1093
+ if (domain.agentselfguestsharing === true) { serverInfo.agentSelfGuestSharing = true; }
1094
obj.send(JSON.stringify(serverInfo));
1095
1096
// Plug in handler
@@ -1666,6 +1669,24 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1669
}
1670
break;
1671
}
1672
+ case 'guestShare': {
1673
+ if ((domain.agentselfguestsharing !== true) || (typeof command.flags != 'number')) return; // Check if agent self-sharing is allowed, this is off by default.
1674
+ if (command.flags == 0) {
1675
+ // Stop any current self-share
1676
+ removeGuestSharing(function () {
1677
+ delete obj.guestSharing;
1678
+ obj.send(JSON.stringify({ action: 'guestShare', flags: command.flags, url: null, viewOnly: false }));
1679
+ });
1680
+ } else {
1681
+ // Add a new self-share, this will replace any share for this device
1682
+ if ((command.flags & 1) == 0) { command.viewOnly = false; } // Only allow "view only" if desktop is shared.
1683
+ addGuestSharing(command.flags, command.viewOnly, function (share) {
1684
+ obj.guestSharing = true;
1685
+ obj.send(JSON.stringify({ action: 'guestShare', url: share.url, flags: share.flags, viewOnly: share.viewOnly }));
1686
+ })
1687
+ }
1688
+ break;
1689
+ }
1690
case 'scriptTask': {
1691
// TODO
1692
break;
@@ -1683,6 +1704,90 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1704
}
1705
}
1706
1707
+ function addGuestSharing(flags, viewOnly, func) {
1708
+ // Create cookie
1709
+ var publicid = 'AS:' + obj.dbNodeKey;
1710
+ var cookie = { a: 6, pid: publicid }; // New style sharing cookie
1711
+ const inviteCookie = parent.parent.encodeCookie(cookie, parent.parent.invitationLinkEncryptionKey);
1712
+ if (inviteCookie == null) return;
1713
+
1714
+ // Create the server url
1715
+ var serverName = parent.getWebServerName(domain);
1716
+ var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
1717
+ var xdomain = (domain.dns == null) ? domain.id : '';
1718
+ if (xdomain != '') xdomain += '/';
1719
+ var url = 'https://' + serverName + ':' + httpsPort + '/' + xdomain + 'sharing?c=' + inviteCookie;
1720
+ if (serverName.split('.') == 1) { url = '/' + xdomain + page + '?c=' + inviteCookie; }
1721
+
1722
+ // Create a device sharing database entry
1723
+ var shareEntry = { _id: 'deviceshare-' + publicid, type: 'deviceshare', nodeid: obj.dbNodeKey, p: flags, domain: domain.id, publicid: publicid, guestName: '*Agent', consent: true, url: url };
1724
+ if (viewOnly === true) { shareEntry.viewOnly = true; }
1725
+ parent.db.Set(shareEntry);
1726
+
1727
+ // Send out an event that we added a device share
1728
+ var targets = parent.CreateNodeDispatchTargets(obj.dbMeshKey, obj.dbNodeKey);
1729
+ var event = { etype: 'node', nodeid: obj.dbNodeKey, action: 'addedDeviceShare', msg: 'Added Device Share', msgid: 101, msgArgs: ['*Agent', 'DATETIME:' + null, 'DATETIME:' + null], domain: domain.id };
1730
+ parent.parent.DispatchEvent(targets, obj, event);
1731
+
1732
+ // Send device share update
1733
+ parent.db.GetAllTypeNodeFiltered([obj.dbNodeKey], domain.id, 'deviceshare', null, function (err, docs) {
1734
+ if (err != null) return;
1735
+
1736
+ // Check device sharing
1737
+ var now = Date.now();
1738
+ for (var i = 0; i < docs.length; i++) {
1739
+ const doc = docs[i];
1740
+ if (doc.expireTime < now) { parent.db.Remove(doc._id, function () { }); delete docs[i]; } else {
1741
+ // This share is ok, remove extra data we don't need to send.
1742
+ delete doc._id; delete doc.domain; delete doc.nodeid; delete doc.type;
1743
+ }
1744
+ }
1745
+
1746
+ // Send device share update
1747
+ var targets = parent.CreateNodeDispatchTargets(obj.dbMeshKey, obj.dbNodeKey, []);
1748
+ parent.parent.DispatchEvent(targets, obj, { etype: 'node', nodeid: obj.dbNodeKey, action: 'deviceShareUpdate', domain: domain.id, deviceShares: docs, nolog: 1 });
1749
+
1750
+ // Callback
1751
+ if (func) { func({ url: url, flags: flags, viewOnly: viewOnly }); }
1752
+ });
1753
+ }
1754
+
1755
+ function removeGuestSharing(func) {
1756
+ var publicid = 'AS:' + obj.dbNodeKey;
1757
+ parent.db.GetAllTypeNodeFiltered([obj.dbNodeKey], domain.id, 'deviceshare', null, function (err, docs) {
1758
+ if (err != null) return;
1759
+
1760
+ // Remove device sharing
1761
+ var now = Date.now(), removedExact = null, removed = false, okDocs = [];
1762
+ for (var i = 0; i < docs.length; i++) {
1763
+ const doc = docs[i];
1764
+ if (doc.publicid == publicid) { parent.db.Remove(doc._id, function () { }); removedExact = doc; removed = true; }
1765
+ else if (doc.expireTime < now) { parent.db.Remove(doc._id, function () { }); removed = true; } else {
1766
+ // This share is ok, remove extra data we don't need to send.
1767
+ delete doc._id; delete doc.domain; delete doc.nodeid; delete doc.type;
1768
+ okDocs.push(doc);
1769
+ }
1770
+ }
1771
+
1772
+ // Event device share removal
1773
+ if (removedExact != null) {
1774
+ // Send out an event that we removed a device share
1775
+ var targets = parent.CreateNodeDispatchTargets(obj.dbMeshKey, obj.dbNodeKey, []);
1776
+ var event = { etype: 'node', nodeid: obj.dbNodeKey, action: 'removedDeviceShare', msg: 'Removed Device Share', msgid: 102, msgArgs: ['*Agent'], domain: domain.id, publicid: publicid };
1777
+ parent.parent.DispatchEvent(targets, obj, event);
1778
+ }
1779
+
1780
+ // If we removed any shares, send device share update
1781
+ if (removed == true) {
1782
+ var targets = parent.CreateNodeDispatchTargets(obj.dbMeshKey, obj.dbNodeKey, []);
1783
+ parent.parent.DispatchEvent(targets, obj, { etype: 'node', nodeid: obj.dbNodeKey, action: 'deviceShareUpdate', domain: domain.id, deviceShares: okDocs, nolog: 1 });
1784
+ }
1785
+
1786
+ // Call back when done
1787
+ if (func) func(removed);
1788
+ });
1789
+ }
1790
+
1791
// Notify update of sessions
1792
obj.updateSessions = function () {
1793
// Perform some clean up
meshuser.js
+4
-1
@@ -4677,7 +4677,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4677
}
4678
4679
// Confirm removal if requested
4680
- if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'removeDeviceShare', responseid: command.responseid, nodeid: command.nodeid, publicid: doc.publicid, removed: removedExact })); } catch (ex) { } }
4680
+ if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'removeDeviceShare', responseid: command.responseid, nodeid: command.nodeid, publicid: command.publicid, removed: removedExact })); } catch (ex) { } }
4681
4682
// Event device share removal
4683
if (removedExact != null) {
@@ -4685,6 +4685,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4685
var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
4686
var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'removedDeviceShare', msg: 'Removed Device Share', msgid: 102, msgArgs: [removedExact.guestName], domain: domain.id, publicid: command.publicid };
4687
parent.parent.DispatchEvent(targets, obj, event);
4688
+
4689
+ // If this is an agent self-sharing link, notify the agent
4690
+ if (command.publicid.startsWith('AS:node/')) { routeCommandToNode({ action: 'msg', type: 'guestShare', nodeid: command.publicid.substring(3), flags: 0, url: null, viewOnly: false }); }
4691
}
4692
4693
// If we removed any shares, send device share update