Fixed guest web relay session revocation (#4667)

Ylian Saint-Hilaire committed Oct 25, 2022 at 11:14 UTC 41fb7d4f42f78b5c28709d38f2a741d5723257c7
4 files changed +32 -6
meshagent.js
+1 -1
@@ -1842,7 +1842,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1842 // Event device share removal
1843 if (removedExact != null) {
1844 // Send out an event that we removed a device share
1845 - var targets = parent.CreateNodeDispatchTargets(obj.dbMeshKey, obj.dbNodeKey, []);
1845 + var targets = parent.CreateNodeDispatchTargets(obj.dbMeshKey, obj.dbNodeKey, ['server-shareremove']);
1846 var event = { etype: 'node', nodeid: obj.dbNodeKey, action: 'removedDeviceShare', msg: 'Removed Device Share', msgid: 102, msgArgs: ['Agent'], domain: domain.id, publicid: publicid };
1847 parent.parent.DispatchEvent(targets, obj, event);
1848 }
meshuser.js
+1 -1
@@ -4160,7 +4160,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
4160 // Event device share removal
4161 if (removedExact != null) {
4162 // Send out an event that we removed a device share
4163 - var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', user._id]);
4163 + var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['server-users', 'server-shareremove', user._id]);
4164 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 };
4165 parent.parent.DispatchEvent(targets, obj, event);
4166
webrelayserver.js
+15 -2
@@ -65,6 +65,17 @@ module.exports.CreateWebRelayServer = function (parent, db, args, certificates,
65 // If args.sessionkey is a string, use it as a single key, but args.sessionkey can also be used as an array of keys.
66 const keygrip = require('keygrip')((typeof args.sessionkey == 'string') ? [args.sessionkey] : args.sessionkey, 'sha384', 'base64');
67
68 + // Watch for device share removal
69 + parent.AddEventDispatch(['server-shareremove'], obj);
70 + obj.HandleEvent = function (source, event, ids, id) {
71 + if (event.action == 'removedDeviceShare') {
72 + for (var relaySessionId in relaySessions) {
73 + // A share was removed that matches an active session, close the session.
74 + if (relaySessions[relaySessionId].xpublicid === event.publicid) { relaySessions[relaySessionId].close(); }
75 + }
76 + }
77 + }
78 +
79 // Setup cookie session
80 const sessionOptions = {
81 name: 'xid', // Recommended security practice to not use the default cookie name
@@ -187,11 +198,11 @@ module.exports.CreateWebRelayServer = function (parent, db, args, certificates,
198 if (req.query.c == null) { res.sendStatus(404); return; }
199
200 // Decode and check if this relay cookie is valid
190 - var userid, domainid, domain, nodeid, addr, port, appid, webSessionId, expire;
201 + var userid, domainid, domain, nodeid, addr, port, appid, webSessionId, expire, publicid;
202 const urlCookie = obj.parent.decodeCookie(req.query.c, parent.loginCookieEncryptionKey, 32); // Allow cookies up to 32 minutes old. The web page will renew this cookie every 30 minutes.
203 if (urlCookie == null) { res.sendStatus(404); return; }
204
194 - // Decode the incomign cookie
205 + // Decode the incoming cookie
206 if ((urlCookie.ruserid != null) && (urlCookie.x != null)) {
207 if (parent.webserver.destroyedSessions[urlCookie.ruserid + '/' + urlCookie.x] != null) { res.sendStatus(404); return; }
208
@@ -220,6 +231,7 @@ module.exports.CreateWebRelayServer = function (parent, db, args, certificates,
231 port = urlCookie.port;
232 appid = (urlCookie.p == 16) ? 2 : 1; // appid: 1 = HTTP, 2 = HTTPS
233 webSessionId = userid + '/' + urlCookie.pid;
234 + publicid = urlCookie.pid;
235 if (req.session.x) { delete req.session.x; } // Clear the web relay sessionid
236 if (req.session.userid) { delete req.session.userid; } // Clear the web relay userid
237 if (req.session.z != webSessionId) { req.session.z = webSessionId; } // Set the web relay guest session
@@ -248,6 +260,7 @@ module.exports.CreateWebRelayServer = function (parent, db, args, certificates,
260
261 // Create a web relay session
262 const relaySession = require('./apprelays.js').CreateWebRelaySession(obj, db, req, args, domain, userid, nodeid, addr, port, appid, webSessionId, expire);
263 + relaySession.xpublicid = publicid;
264 relaySession.onclose = function (sessionId) {
265 // Remove the relay session
266 delete relaySessions[sessionId];
webserver.js
+15 -2
@@ -87,9 +87,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
87
88 // Web relay sessions
89 var webRelayNextSessionId = 1;
90 - var webRelaySessions = {} // UserId/SessionId/Host --> Web Relay Session
90 + var webRelaySessions = {} // UserId/SessionId/Host --> Web Relay Session
91 var webRelayCleanupTimer = null;
92
93 + // Monitor web relay session removals
94 + parent.AddEventDispatch(['server-shareremove'], obj);
95 + obj.HandleEvent = function (source, event, ids, id) {
96 + if (event.action == 'removedDeviceShare') {
97 + for (var relaySessionId in webRelaySessions) {
98 + // A share was removed that matches an active session, close the web relay session.
99 + if (webRelaySessions[relaySessionId].xpublicid === event.publicid) { webRelaySessions[relaySessionId].close(); }
100 + }
101 + }
102 + }
103 +
104 // Mesh Rights
105 const MESHRIGHT_EDITMESH = 0x00000001;
106 const MESHRIGHT_MANAGEUSERS = 0x00000002;
@@ -6749,7 +6760,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6760 if (req.query.c == null) { res.sendStatus(404); return; }
6761
6762 // Decode and check if this relay cookie is valid
6752 - var userid, domainid, domain, nodeid, addr, port, appid, webSessionId, expire;
6763 + var userid, domainid, domain, nodeid, addr, port, appid, webSessionId, expire, publicid;
6764 const urlCookie = obj.parent.decodeCookie(req.query.c, parent.loginCookieEncryptionKey, 32); // Allow cookies up to 32 minutes old. The web page will renew this cookie every 30 minutes.
6765 if (urlCookie == null) { res.sendStatus(404); return; }
6766
@@ -6782,6 +6793,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6793 port = urlCookie.port;
6794 appid = (urlCookie.p == 16) ? 2 : 1; // appid: 1 = HTTP, 2 = HTTPS
6795 webSessionId = userid + '/' + urlCookie.pid;
6796 + publicid = urlCookie.pid;
6797 if (req.session.x) { delete req.session.x; } // Clear the web relay sessionid
6798 if (req.session.userid) { delete req.session.userid; } // Clear the web relay userid
6799 if (req.session.z != webSessionId) { req.session.z = webSessionId; } // Set the web relay guest session
@@ -6854,6 +6866,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6866
6867 // Create a web relay session
6868 const relaySession = require('./apprelays.js').CreateWebRelaySession(obj, db, req, args, domain, userid, nodeid, addr, port, appid, xrelaySessionId, expire);
6869 + relaySession.xpublicid = publicid;
6870 relaySession.onclose = function (sessionId) {
6871 // Remove the relay session
6872 delete webRelaySessions[sessionId];