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