mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
More work on device self-sharing.
This commit is contained in:
parent
d001699c8c
commit
ecd25f3eb2
@ -1720,13 +1720,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
if (serverName.split('.') == 1) { url = '/' + xdomain + page + '?c=' + inviteCookie; }
|
||||
|
||||
// Create a device sharing database entry
|
||||
var shareEntry = { _id: 'deviceshare-' + publicid, type: 'deviceshare', nodeid: obj.dbNodeKey, p: flags, domain: domain.id, publicid: publicid, guestName: '*Agent', consent: true, url: url };
|
||||
var shareEntry = { _id: 'deviceshare-' + publicid, type: 'deviceshare', nodeid: obj.dbNodeKey, p: flags, domain: domain.id, publicid: publicid, guestName: 'Agent', consent: 0x7F, url: url };
|
||||
if (viewOnly === true) { shareEntry.viewOnly = true; }
|
||||
parent.db.Set(shareEntry);
|
||||
|
||||
// Send out an event that we added a device share
|
||||
var targets = parent.CreateNodeDispatchTargets(obj.dbMeshKey, obj.dbNodeKey);
|
||||
var event = { etype: 'node', nodeid: obj.dbNodeKey, action: 'addedDeviceShare', msg: 'Added Device Share', msgid: 101, msgArgs: ['*Agent', 'DATETIME:' + null, 'DATETIME:' + null], domain: domain.id };
|
||||
var event = { etype: 'node', nodeid: obj.dbNodeKey, action: 'addedDeviceShare', msg: 'Added device share with unlimited time', msgid: 131, msgArgs: ['Agent'], domain: domain.id };
|
||||
parent.parent.DispatchEvent(targets, obj, event);
|
||||
|
||||
// Send device share update
|
||||
@ -1773,7 +1773,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
|
||||
if (removedExact != null) {
|
||||
// Send out an event that we removed a device share
|
||||
var targets = parent.CreateNodeDispatchTargets(obj.dbMeshKey, obj.dbNodeKey, []);
|
||||
var event = { etype: 'node', nodeid: obj.dbNodeKey, action: 'removedDeviceShare', msg: 'Removed Device Share', msgid: 102, msgArgs: ['*Agent'], domain: domain.id, publicid: publicid };
|
||||
var event = { etype: 'node', nodeid: obj.dbNodeKey, action: 'removedDeviceShare', msg: 'Removed Device Share', msgid: 102, msgArgs: ['Agent'], domain: domain.id, publicid: publicid };
|
||||
parent.parent.DispatchEvent(targets, obj, event);
|
||||
}
|
||||
|
||||
|
31
meshrelay.js
31
meshrelay.js
@ -84,6 +84,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
obj.user = user;
|
||||
obj.ruserid = null;
|
||||
obj.req = req; // Used in multi-server.js
|
||||
if ((cookie != null) && (cookie.nouser == 1)) { obj.nouser = true; } // This is a relay without user authentication
|
||||
|
||||
// Setup subscription for desktop sharing public identifier
|
||||
// If the identifier is removed, drop the connection
|
||||
@ -96,11 +97,11 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
// Check relay authentication
|
||||
if ((user == null) && (obj.req.query != null) && (obj.req.query.rauth != null)) {
|
||||
const rcookie = parent.parent.decodeCookie(obj.req.query.rauth, parent.parent.loginCookieEncryptionKey, 240); // Cookie with 4 hour timeout
|
||||
if (rcookie.ruserid != null) { obj.ruserid = rcookie.ruserid; }
|
||||
if (rcookie.ruserid != null) { obj.ruserid = rcookie.ruserid; } else if (rcookie.nouser === 1) { obj.rnouser = true; }
|
||||
}
|
||||
|
||||
// If there is no authentication, drop this connection
|
||||
if ((obj.id != null) && (obj.id.startsWith('meshmessenger/') == false) && (obj.user == null) && (obj.ruserid == null)) { try { ws.close(); parent.parent.debug('relay', 'Relay: Connection with no authentication (' + obj.req.clientIp + ')'); } catch (e) { console.log(e); } return; }
|
||||
if ((obj.id != null) && (obj.id.startsWith('meshmessenger/') == false) && (obj.user == null) && (obj.ruserid == null) && (obj.nouser !== true) && (obj.rnouser !== true)) { try { ws.close(); parent.parent.debug('relay', 'Relay: Connection with no authentication (' + obj.req.clientIp + ')'); } catch (e) { console.log(e); } return; }
|
||||
|
||||
// Relay session count (we may remove this in the future)
|
||||
obj.relaySessionCounted = true;
|
||||
@ -153,8 +154,8 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
obj.sendAgentMessage = function (command, userid, domainid) {
|
||||
var rights, mesh;
|
||||
if (command.nodeid == null) return false;
|
||||
var user = parent.users[userid];
|
||||
if (user == null) return false;
|
||||
var user = null;
|
||||
if (userid != null) { user = parent.users[userid]; if (user == null) return false; }
|
||||
var splitnodeid = command.nodeid.split('/');
|
||||
// Check that we are in the same domain and the user has rights over this node.
|
||||
if ((splitnodeid[0] == 'node') && (splitnodeid[1] == domainid)) {
|
||||
@ -163,15 +164,17 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
var agent = parent.wsagents[command.nodeid];
|
||||
if (agent != null) {
|
||||
// Check if we have permission to send a message to that node
|
||||
rights = parent.GetNodeRights(user, agent.dbMeshKey, agent.dbNodeKey);
|
||||
if (userid == null) { rights = MESHRIGHT_REMOTECONTROL; } else { rights = parent.GetNodeRights(user, agent.dbMeshKey, agent.dbNodeKey); }
|
||||
mesh = parent.meshes[agent.dbMeshKey];
|
||||
if ((rights != null) && (mesh != null) || ((rights & MESHRIGHT_REMOTECONTROL) != 0)) {
|
||||
if (ws.sessionId) { command.sessionid = ws.sessionId; } // Set the session id, required for responses.
|
||||
command.rights = rights; // Add user rights flags to the message
|
||||
if (typeof command.consent == 'number') { command.consent = command.consent | mesh.consent; } else { command.consent = mesh.consent; } // Add user consent
|
||||
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
|
||||
if (user != null) {
|
||||
command.username = user.name; // Add user name
|
||||
command.realname = user.realname; // Add real name
|
||||
}
|
||||
if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
|
||||
delete command.nodeid; // Remove the nodeid since it's implyed.
|
||||
agent.send(JSON.stringify(command));
|
||||
@ -182,15 +185,17 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
var routing = parent.parent.GetRoutingServerIdNotSelf(command.nodeid, 1); // 1 = MeshAgent routing type
|
||||
if (routing != null) {
|
||||
// Check if we have permission to send a message to that node
|
||||
rights = parent.GetNodeRights(user, routing.meshid, command.nodeid);
|
||||
if (userid == null) { rights = MESHRIGHT_REMOTECONTROL; } else { rights = parent.GetNodeRights(user, routing.meshid, command.nodeid); }
|
||||
mesh = parent.meshes[routing.meshid];
|
||||
if (rights != null || ((rights & MESHRIGHT_REMOTECONTROL) != 0)) {
|
||||
if (ws.sessionId) { command.fromSessionid = ws.sessionId; } // Set the session id, required for responses.
|
||||
command.rights = rights; // Add user rights flags to the message
|
||||
if (typeof command.consent == 'number') { command.consent = command.consent | mesh.consent; } else { command.consent = mesh.consent; } // Add user consent
|
||||
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
|
||||
if (user != null) {
|
||||
command.username = user.name; // Add user name
|
||||
command.realname = user.realname; // Add real name
|
||||
}
|
||||
if (typeof domain.desktopprivacybartext == 'string') { command.privacybartext = domain.desktopprivacybartext; } // Privacy bar text
|
||||
parent.parent.multiServer.DispatchMessageSingleServer(command, routing.serverid);
|
||||
return true;
|
||||
@ -285,7 +290,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
if (u1 != null) { u1 = 'user/' + domain.id + '/' + parent.args.user.toLowerCase(); }
|
||||
if (u2 != null) { u2 = 'user/' + domain.id + '/' + parent.args.user.toLowerCase(); }
|
||||
}
|
||||
if (u1 != u2) {
|
||||
if ((u1 != u2) && (obj.nouser !== true) && (relayinfo.peer1.nouser !== true)) {
|
||||
ws.close();
|
||||
parent.parent.debug('relay', 'Relay auth mismatch (' + u1 + ' != ' + u2 + '): ' + obj.id + ' (' + obj.req.clientIp + ')');
|
||||
delete obj.id;
|
||||
@ -829,7 +834,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
setExpireTimer();
|
||||
|
||||
// Mark this relay session as authenticated if this is the user end.
|
||||
obj.authenticated = (user != null);
|
||||
obj.authenticated = ((user != null) || (obj.nouser === true));
|
||||
if (obj.authenticated) {
|
||||
// To build the connection URL, if we are using a sub-domain or one with a DNS, we need to craft the URL correctly.
|
||||
var xdomain = (domain.dns == null) ? domain.id : '';
|
||||
@ -931,7 +936,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
const node = docs[0];
|
||||
|
||||
// Check if this user has permission to manage this computer
|
||||
if ((parent.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0) { console.log('ERR: Access denied (2)'); try { obj.close(); } catch (e) { } return; }
|
||||
if ((obj.nouser !== true) && ((parent.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (2)'); try { obj.close(); } catch (e) { } return; }
|
||||
|
||||
// Set nodeid and meshid
|
||||
obj.nodeid = node._id;
|
||||
@ -939,8 +944,10 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
|
||||
// Send connection request to agent
|
||||
if (obj.id == null) { obj.id = ('' + Math.random()).substring(2); }
|
||||
const rcookie = parent.parent.encodeCookie({ ruserid: user._id, nodeid: node._id }, parent.parent.loginCookieEncryptionKey);
|
||||
const command = { nodeid: node._id, action: 'msg', type: 'tunnel', userid: user._id, value: '*/' + xdomain + 'meshrelay.ashx?p=' + obj.req.query.p + '&id=' + obj.id + '&rauth=' + rcookie + '&nodeid=' + node._id, soptions: {}, rights: cookie.r, guestname: cookie.gn, consent: cookie.cf, remoteaddr: cleanRemoteAddr(obj.req.clientIp) };
|
||||
const rcookieData = { nodeid: node._id };
|
||||
if (user != null) { rcookieData.ruserid = user._id; } else if (obj.nouser === true) { rcookieData.nouser = 1; }
|
||||
const rcookie = parent.parent.encodeCookie(rcookieData, parent.parent.loginCookieEncryptionKey);
|
||||
const command = { nodeid: node._id, action: 'msg', type: 'tunnel', value: '*/' + xdomain + 'meshrelay.ashx?p=' + obj.req.query.p + '&id=' + obj.id + '&rauth=' + rcookie + '&nodeid=' + node._id, soptions: {}, rights: cookie.r, guestname: cookie.gn, consent: cookie.cf, remoteaddr: cleanRemoteAddr(obj.req.clientIp) };
|
||||
obj.guestname = cookie.gn;
|
||||
|
||||
// Limit what this relay connection can do
|
||||
@ -966,7 +973,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
|
||||
if (typeof domain.notificationmessages.files == 'string') { command.soptions.notifyMsgFiles = domain.notificationmessages.files; }
|
||||
}
|
||||
parent.parent.debug('relay', 'Relay: Sending agent tunnel command: ' + JSON.stringify(command));
|
||||
if (obj.sendAgentMessage(command, user._id, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
|
||||
if (obj.sendAgentMessage(command, user?user._id:null, domain.id) == false) { delete obj.id; parent.parent.debug('relay', 'Relay: Unable to contact this agent (' + obj.req.clientIp + ')'); }
|
||||
|
||||
performRelay(0);
|
||||
});
|
||||
|
@ -403,7 +403,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
||||
else if (event == 'updatefiles') { updateUserFiles(user, ws, domain); }
|
||||
else {
|
||||
// If updating guest device shares, if we are updating a user that is not creator of the share, remove the URL.
|
||||
if (event.action == 'deviceShareUpdate') {
|
||||
if ((event.action == 'deviceShareUpdate') && (Array.isArray(event.deviceShares))) {
|
||||
event = common.Clone(event);
|
||||
for (var i in event.deviceShares) { if (event.deviceShares[i].userid != user._id) { delete event.deviceShares[i].url; } }
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort, au
|
||||
obj.xxOnControlCommand = function (msg) {
|
||||
var controlMsg;
|
||||
try { controlMsg = JSON.parse(msg); } catch (e) { return; }
|
||||
if (controlMsg.ctrlChannel != '102938') { obj.m.ProcessData(msg); return; }
|
||||
if (controlMsg.ctrlChannel != '102938') { if (obj.m.ProcessData) { obj.m.ProcessData(msg); } else { console.log(msg); } return; }
|
||||
if ((typeof args != 'undefined') && args.redirtrace) { console.log('RedirRecv', controlMsg); }
|
||||
if (controlMsg.type == 'console') {
|
||||
obj.setConsoleMessage(controlMsg.msg, controlMsg.msgid, controlMsg.msgargs, controlMsg.timeout);
|
||||
|
@ -3584,6 +3584,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
const doc = docs[0];
|
||||
// Generate an old style cookie from the information in the database
|
||||
var cookie = { a: 5, p: doc.p, uid: doc.userid, gn: doc.guestName, nid: doc.nodeid, cf: doc.consent, pid: doc.publicid };
|
||||
if ((cookie.userid == null) && (cookie.pid.startsWith('AS:node/'))) { cookie.nouser = 1; }
|
||||
if ((doc.startTime != null) && (doc.expireTime != null)) { cookie.start = doc.startTime; cookie.expire = doc.expireTime; }
|
||||
if (doc.viewOnly === true) { cookie.vo = 1; }
|
||||
handleSharingRequestEx(req, res, domain, cookie);
|
||||
@ -3618,7 +3619,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
|
||||
// Looks good, let's create the outbound session cookies.
|
||||
// Consent flags are 1 = Notify, 8 = Prompt, 64 = Privacy Bar.
|
||||
const authCookie = obj.parent.encodeCookie({ userid: c.uid, domainid: domain.id, nid: c.nid, ip: req.clientIp, p: c.p, gn: c.gn, cf: c.cf, r: 8, expire: c.expire, pid: c.pid, vo: c.vo }, obj.parent.loginCookieEncryptionKey);
|
||||
const authCookieData = { userid: c.uid, domainid: domain.id, nid: c.nid, ip: req.clientIp, p: c.p, gn: c.gn, cf: c.cf, r: 8, expire: c.expire, pid: c.pid, vo: c.vo };
|
||||
if ((authCookieData.userid == null) && (authCookieData.pid.startsWith('AS:node/'))) { authCookieData.nouser = 1; }
|
||||
const authCookie = obj.parent.encodeCookie(authCookieData, obj.parent.loginCookieEncryptionKey);
|
||||
|
||||
// Server features
|
||||
var features2 = 0;
|
||||
@ -3633,7 +3636,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Handle domain redirection
|
||||
obj.handleDomainRedirect = function (req, res) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
@ -6595,6 +6597,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
} else if ((cookie != null) && (cookie.a === 3) && (typeof cookie.u == 'string') && (obj.users[cookie.u]) && (cookie.u.split('/')[1] == domain.id)) {
|
||||
// Valid cookie, we are authenticated. Cookie of format { u: 'user//name', a: 3 }
|
||||
func(ws, req, domain, obj.users[cookie.u], cookie);
|
||||
} else if ((cookie != null) && (cookie.nouser === 1)) {
|
||||
// This is a valid cookie, but no user. This is used for agent self-sharing.
|
||||
func(ws, req, domain, null, cookie);
|
||||
} else {
|
||||
// This is a bad cookie, keep going anyway, maybe we have a active session that will save us.
|
||||
if ((cookie != null) && (cookie.domainid != domain.id)) { parent.debug('web', 'ERR: Invalid domain, got \"' + cookie.domainid + '\", expected \"' + domain.id + '\".'); }
|
||||
|
Loading…
Reference in New Issue
Block a user