Centralization of user access control.
Ylian Saint-Hilaire committed
Dec 26, 2019 at 22:53 UTC
c9b4c3441826367d1dea910c104fdefb9dcd6c36
2 files changed
+145
-123
meshuser.js
+58
-76
@@ -113,10 +113,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
113
if (meshpath[0] != user._id) return null; // Only allow own user folder
114
} else if (splitid[0] == 'mesh') {
115
// Check mesh access
116
- var meshrights = user.links[meshpath[0]];
117
- if (meshrights == null) return null; // No meth rights for this user
118
- meshrights = meshrights.rights; // Get the rights bit mask
119
- if ((meshrights == null) || ((meshrights & 32) == 0)) return null; // This user must have mesh rights to "server files"
116
+ if ((parent.GetMeshRights(user, meshpath[0]) & MESHRIGHT_SERVERFILES) == 0) return null; // This user must have mesh rights to "server files"
117
} else return null;
118
var rootfolder = meshpath[0], rootfoldersplit = rootfolder.split('/'), domainx = 'domain';
119
if (rootfoldersplit[1].length > 0) domainx = 'domain-' + rootfoldersplit[1];
@@ -155,11 +152,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
152
var agent = parent.wsagents[command.nodeid];
153
if (agent != null) {
154
// Check if we have permission to send a message to that node
158
- var rights = user.links[agent.dbMeshKey];
155
+ var meshrights = parent.GetMeshRights(user, agent.dbMeshKey);
156
var mesh = parent.meshes[agent.dbMeshKey];
160
- if ((rights != null) && (mesh != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission, 256 is desktop read only
157
+ if ((mesh != null) && ((meshrights & MESHRIGHT_REMOTECONTROL) || (meshrights & MESHRIGHT_REMOTEVIEWONLY))) { // 8 is remote control permission, 256 is desktop read only
158
command.sessionid = ws.sessionId; // Set the session id, required for responses
162
- command.rights = rights.rights; // Add user rights flags to the message
159
+ command.rights = meshrights; // Add user rights flags to the message
160
command.consent = mesh.consent; // Add user consent
161
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
162
command.username = user.name; // Add user name
@@ -174,11 +171,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
171
var routing = parent.parent.GetRoutingServerId(command.nodeid, 1); // 1 = MeshAgent routing type
172
if (routing != null) {
173
// Check if we have permission to send a message to that node
177
- var rights = user.links[routing.meshid];
174
+ var meshrights = parent.GetMeshRights(user, routing.meshid);
175
var mesh = parent.meshes[routing.meshid];
179
- if ((rights != null) && (mesh != null) && ((rights.rights & 8) || (rights.rights & 256))) { // 8 is remote control permission
176
+ if ((mesh != null) && ((meshrights & MESHRIGHT_REMOTECONTROL) || (meshrights & MESHRIGHT_REMOTEVIEWONLY))) { // 8 is remote control permission
177
command.fromSessionid = ws.sessionId; // Set the session id, required for responses
181
- command.rights = rights.rights; // Add user rights flags to the message
178
+ command.rights = meshrights; // Add user rights flags to the message
179
command.consent = mesh.consent; // Add user consent
180
if (typeof domain.userconsentflags == 'number') { command.consent |= domain.userconsentflags; } // Add server required consent flags
181
command.username = user.name; // Add user name
@@ -261,8 +258,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
258
// Because of the device group "Show Self Events Only", we need to do more checks here.
259
if (id.startsWith('mesh/')) {
260
// Check if we have rights to get this message. If we have limited events on this mesh, don't send the event to the user.
264
- var meshlink = obj.user.links[id];
265
- if ((meshlink != null) && ((meshlink.rights == 0xFFFFFFFF) || ((meshlink.rights & 8192) == 0) || (ids.indexOf(user._id) >= 0))) {
261
+ var meshrights = parent.GetMeshRights(user, id);
262
+ if ((meshrights == 0xFFFFFFFF) || ((meshrights & MESHRIGHT_LIMITEVENTS) == 0) || (ids.indexOf(user._id) >= 0)) {
263
// We have the device group rights to see this event or we are directly targetted by the event
264
ws.send(JSON.stringify({ action: 'event', event: event }));
265
} else {
@@ -435,14 +432,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
432
case 'meshes':
433
{
434
// Request a list of all meshes this user as rights to
438
- var docs = [];
439
- for (i in user.links) {
440
- if ((parent.meshes[i]) && (parent.meshes[i].deleted == null)) {
441
- // Remove the Intel AMT password if present
442
- docs.push(parent.CloneSafeMesh(parent.meshes[i]));
443
- }
444
- }
445
- try { ws.send(JSON.stringify({ action: 'meshes', meshes: docs, tag: command.tag })); } catch (ex) { }
435
+ try { ws.send(JSON.stringify({ action: 'meshes', meshes: parent.GetAllMeshWithRights(user).map(parent.CloneSafeMesh), tag: command.tag })); } catch (ex) { }
436
break;
437
}
438
case 'nodes':
@@ -451,13 +441,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
441
try {
442
if (command.meshid == null) {
443
// Request a list of all meshes this user as rights to
454
- for (i in user.links) { links.push(i); }
444
+ links = parent.GetAllMeshIdWithRights(user);
445
} else {
446
// Request list of all nodes for one specific meshid
447
meshid = command.meshid;
448
if (common.validateString(meshid, 0, 128) == false) { err = 'Invalid group id'; } else {
449
if (meshid.split('/').length == 1) { meshid = 'mesh/' + domain.id + '/' + command.meshid; }
460
- if (user.links[meshid] != null) { links.push(meshid); } else { err = 'Invalid group id'; }
450
+ if (obj.IsMeshViewable(user, meshid)) { links.push(meshid); } else { err = 'Invalid group id'; }
451
}
452
}
453
} catch (ex) { err = 'Validation exception: ' + ex; }
@@ -519,13 +509,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
509
if ((snode.length != 3) || (snode[1] != domain.id)) break;
510
511
// Check that we have permissions for this node.
522
- if (obj.user.links == null) return;
512
db.Get(command.nodeid, function (err, nodes) {
513
if (nodes == null || nodes.length != 1) return;
514
const node = nodes[0];
515
527
- var meshlink = obj.user.links[node.meshid];
528
- if ((meshlink != null) && (meshlink.rights != 0)) {
516
+ if (parent.GetMeshRights(user, node.meshid) != 0) {
517
// Query the database for the power timeline for a given node
518
// The result is a compacted array: [ startPowerState, startTimeUTC, powerState ] + many[ deltaTime, powerState ]
519
db.getPowerTimeline(command.nodeid, function (err, docs) {
@@ -566,13 +554,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
554
if ((snode.length != 3) || (snode[1] != domain.id)) break;
555
556
// Check that we have permissions for this node.
569
- if (obj.user.links == null) return;
557
db.Get(command.nodeid, function (err, nodes) {
558
if (nodes == null || nodes.length != 1) return;
559
const node = nodes[0];
560
574
- var meshlink = obj.user.links[node.meshid];
575
- if ((meshlink != null) && (meshlink.rights != 0)) {
561
+ if (parent.GetMeshRights(user, node.meshid) != 0) {
562
// Query the database system information
563
db.Get('si' + command.nodeid, function (err, docs) {
564
if ((docs != null) && (docs.length > 0)) {
@@ -600,13 +586,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
586
if ((snode.length != 3) || (snode[1] != domain.id)) break;
587
588
// Check that we have permissions for this node.
603
- if (obj.user.links == null) return;
589
db.Get(command.nodeid, function (err, nodes) {
590
if (nodes == null || nodes.length != 1) return;
591
const node = nodes[0];
592
608
- var meshlink = obj.user.links[node.meshid];
609
- if ((meshlink != null) && (meshlink.rights != 0)) {
593
+ if (parent.GetMeshRights(user, node.meshid) != 0) {
594
// Query the database for the last time this node connected
595
db.Get('lc' + command.nodeid, function (err, docs) {
596
if ((docs != null) && (docs.length > 0)) {
@@ -981,18 +965,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
965
}
966
} else if (common.validateString(command.nodeid, 0, 128) == true) { // Device filtered events
967
// Check that the user has access to this nodeid
984
- if (obj.user.links == null) return;
968
db.Get(command.nodeid, function (err, nodes) {
969
if ((nodes == null) || (nodes.length != 1)) return;
970
const node = nodes[0];
971
989
- var meshlink = obj.user.links[node.meshid];
990
- if ((meshlink != null) && (meshlink.rights != 0)) {
972
+ var meshrights = parent.GetMeshRights(user, node.meshid);
973
+ if (meshrights != 0) {
974
// Put a limit on the number of returned entries if present
975
var limit = 10000;
976
if (common.validateInt(command.limit, 1, 60000) == true) { limit = command.limit; }
977
995
- if ((meshlink.rights & 8192) != 0) {
978
+ if ((meshrights & MESHRIGHT_LIMITEVENTS) != 0) {
979
// Send the list of most recent events for this nodeid that only apply to us, up to 'limit' count
980
db.GetNodeEventsSelfWithLimit(command.nodeid, domain.id, user._id, limit, function (err, docs) {
981
if (err != null) return;
@@ -1014,8 +997,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
997
// All events
998
var exGroupFilter2 = [], filter = [], filter2 = user.subscriptions;
999
1017
- // Remove MeshID's that we do not have rights to see events for
1018
- for (var link in obj.user.links) { if (((obj.user.links[link].rights & 8192) != 0) && ((obj.user.links[link].rights != 0xFFFFFFFF))) { exGroupFilter2.push(link); } }
1000
+ // Remove MeshID's that we do not have rights to see events for (TODO: user groups)
1001
+ for (var link in obj.user.links) { if (((obj.user.links[link].rights & MESHRIGHT_LIMITEVENTS) != 0) && ((obj.user.links[link].rights != 0xFFFFFFFF))) { exGroupFilter2.push(link); } }
1002
for (var i in filter2) { if (exGroupFilter2.indexOf(filter2[i]) == -1) { filter.push(filter2[i]); } }
1003
1004
if ((command.limit == null) || (typeof command.limit != 'number')) {
@@ -1215,6 +1198,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1198
}
1199
}
1200
1201
+ // TODO: Remove user groups??
1202
+
1203
db.Remove('ws' + deluser._id); // Remove user web state
1204
db.Remove('nt' + deluser._id); // Remove notes for this user
1205
@@ -1522,13 +1507,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1507
if (common.validateString(command.meshid, 1, 1024) == false) { err = 'Invalid group identifier'; } // Check the meshid
1508
else if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; }
1509
if (common.validateInt(command.notify) == false) { err = 'Invalid notification flags'; }
1525
- if ((user.links == null) || (user.links[command.meshid] == null)) { err = 'Incorrect group identifier'; }
1510
+ if (parent.GetMeshRights(user, command.meshid) == 0) err = 'Access denied';
1511
} catch (ex) { err = 'Validation exception: ' + ex; }
1512
1513
// Handle any errors
1514
if (err != null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changemeshnotify', responseid: command.responseid, result: err })); } catch (ex) { } } break; }
1515
1531
- // Change the notification
1516
+ // Change the notification (TODO: Add user group support, not sure how to do this here)
1517
if (command.notify == 0) {
1518
delete user.links[command.meshid].notify;
1519
} else {
@@ -1702,7 +1687,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1687
mesh = parent.meshes[node.meshid];
1688
if (mesh) {
1689
// Check if this user has rights to do this
1705
- if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & MESHRIGHT_CHATNOTIFY) == 0)) return;
1690
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_CHATNOTIFY) == 0) return;
1691
1692
// Create the server url
1693
var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
@@ -1820,7 +1805,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1805
1806
// Check if this user has rights to do this
1807
var err = null;
1823
- if (mesh.links[user._id] == null || mesh.links[user._id].rights != 0xFFFFFFFF) { err = 'Access denied'; }
1808
+ if (parent.GetMeshRights(user, mesh) != 0xFFFFFFFF) { err = 'Access denied'; }
1809
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = 'Invalid group'; } // Invalid domain, operation only valid for current domain
1810
1811
// Handle any errors
@@ -1867,7 +1852,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1852
1853
if (mesh) {
1854
// Check if this user has rights to do this
1870
- if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 1) == 0)) return;
1855
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_EDITMESH) == 0) return;
1856
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
1857
1858
if ((common.validateString(command.meshname, 1, 64) == true) && (command.meshname != mesh.name)) { change = 'Group name changed from "' + mesh.name + '" to "' + command.meshname + '"'; mesh.name = command.meshname; }
@@ -1894,7 +1879,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1879
if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; }
1880
mesh = parent.meshes[command.meshid];
1881
if (mesh == null) { err = 'Unknown group'; }
1897
- else if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) { err = 'Permission denied'; }
1882
+ else if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGEUSERS) == 0) { err = 'Permission denied'; }
1883
else if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = 'Invalid domain'; } // Invalid domain, operation only valid for current domain
1884
}
1885
} catch (ex) { err = 'Validation exception: ' + ex; }
@@ -1953,7 +1938,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1938
if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; }
1939
mesh = parent.meshes[command.meshid];
1940
if (mesh == null) { err = "Unknown device group"; }
1956
- else if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 2) == 0)) { err = "Permission denied"; }
1941
+ else if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGEUSERS) == 0) { err = "Permission denied"; }
1942
else if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) { err = "Invalid domain"; } // Invalid domain, operation only valid for current domain
1943
}
1944
} catch (ex) { err = "Validation exception: " + ex; }
@@ -2014,7 +1999,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1999
change = '';
2000
if (mesh) {
2001
// Check if this user has rights to do this
2017
- if ((mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) return;
2002
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_EDITMESH) == 0) return;
2003
if ((command.meshid.split('/').length != 3) || (command.meshid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
2004
2005
// TODO: Check if this is a change from the existing policy
@@ -2064,7 +2049,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2049
if (mesh.mtype != 1) return; // This operation is only allowed for mesh type 1, Intel AMT agentless mesh.
2050
2051
// Check if this user has rights to do this
2067
- if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
2052
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) return;
2053
2054
// Create a new nodeid
2055
parent.crypto.randomBytes(48, function (err, buf) {
@@ -2110,9 +2095,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2095
try { if (parent.meshes[node.meshid].mtype != parent.meshes[command.meshid].mtype) return; } catch (e) { return; };
2096
2097
// Make sure that we have rights on both source and destination mesh
2113
- const sourceMeshRights = user.links[node.meshid].rights;
2114
- const targetMeshRights = user.links[command.meshid].rights;
2115
- if (((sourceMeshRights & 4) == 0) || ((targetMeshRights & 4) == 0)) return;
2098
+ const sourceMeshRights = parent.GetMeshRights(user, node.meshid);
2099
+ const targetMeshRights = parent.GetMeshRights(user, command.meshid);
2100
+ if (((sourceMeshRights & MESHRIGHT_MANAGECOMPUTERS) == 0) || ((targetMeshRights & MESHRIGHT_MANAGECOMPUTERS) == 0)) return;
2101
2102
// Perform the switch, start by saving the node with the new meshid.
2103
const oldMeshId = node.meshid;
@@ -2169,7 +2154,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2154
mesh = parent.meshes[node.meshid];
2155
if (mesh) {
2156
// Check if this user has rights to do this
2172
- if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
2157
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) return;
2158
2159
// Delete this node including network interface information, events and timeline
2160
db.Remove(node._id); // Remove node with that id
@@ -2224,7 +2209,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2209
if (mesh) {
2210
2211
// Check if this user has rights to do this
2227
- if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 64) != 0)) {
2212
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_WAKEDEVICE) != 0) {
2213
2214
// If this device is connected on MQTT, send a wake action.
2215
if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.publish(node._id, 'powerAction', 'wake'); }
@@ -2241,7 +2226,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2226
2227
// Get the list of mesh this user as access to
2228
var targetMeshes = [];
2244
- for (i in user.links) { targetMeshes.push(i); }
2229
+ for (i in user.links) { targetMeshes.push(i); } // TODO: Include used security groups!!
2230
2231
// Go thru all the connected agents and send wake-on-lan on all the ones in the target mesh list
2232
for (i in parent.wsagents) {
@@ -2281,7 +2266,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2266
mesh = parent.meshes[node.meshid];
2267
if (mesh) {
2268
// Check if this user has rights to do this
2284
- if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & MESHRIGHT_UNINSTALL) != 0)) {
2269
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_UNINSTALL) != 0) {
2270
// Send uninstall command to connected agent
2271
var agent = parent.wsagents[node._id];
2272
if (agent != null) {
@@ -2317,8 +2302,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2302
if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.publish(nodeid, 'powerAction', ['', '', 'poweroff', 'reset', 'sleep'][command.actiontype]); }
2303
2304
// Check if this user has rights to do this
2320
- if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
2321
-
2305
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_REMOTECONTROL) != 0) { // "Remote Control permission"
2306
// Get this device
2307
var agent = parent.wsagents[node._id];
2308
if (agent != null) {
@@ -2354,7 +2338,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2338
mesh = parent.meshes[node.meshid];
2339
if (mesh) {
2340
// Check if this user has rights to do this
2357
- if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & MESHRIGHT_CHATNOTIFY) != 0)) {
2341
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_CHATNOTIFY) != 0) {
2342
// Get this device
2343
var agent = parent.wsagents[node._id];
2344
if (agent != null) {
@@ -2383,7 +2367,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2367
mesh = parent.meshes[node.meshid];
2368
if (mesh) {
2369
// Check if this user has rights to do this
2386
- if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); } catch (ex) { } return; }
2370
+ if (parent.GetMeshRights(user, mesh) == 0) { try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); } catch (ex) { } return; }
2371
2372
// Get network information about this node
2373
db.Get('if' + command.nodeid, function (err, netinfos) {
@@ -2411,7 +2395,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2395
mesh = parent.meshes[node.meshid];
2396
if (mesh) {
2397
// Check if this user has rights to do this
2414
- if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 4) == 0)) return;
2398
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_MANAGECOMPUTERS) == 0) return;
2399
2400
// Ready the node change event
2401
var changes = [], event = { etype: 'node', userid: user._id, username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
@@ -2477,7 +2461,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2461
mesh = parent.meshes[node.meshid];
2462
if (mesh) {
2463
// Check if this user has rights to do this
2480
- if (mesh.links[user._id] == null || (((mesh.links[user._id].rights & 16) == 0) && (user.siteadmin != 0xFFFFFFFF))) { return; }
2464
+ if (((parent.GetMeshRights(user, mesh) & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != 0xFFFFFFFF)) { return; }
2465
2466
if (command.type == 'default') {
2467
// Send the default core to the agent
@@ -2518,7 +2502,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2502
mesh = parent.meshes[node.meshid];
2503
if (mesh) {
2504
// Check if this user has rights to do this
2521
- if (mesh.links[user._id] == null || (((mesh.links[user._id].rights & 16) == 0) && (user.siteadmin != 0xFFFFFFFF))) return;
2505
+ if (((parent.GetMeshRights(user, mesh) & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != 0xFFFFFFFF)) return;
2506
2507
// Force mesh agent disconnection
2508
parent.forceMeshAgentDisconnect(user, domain, command.nodeid, command.disconnectMode);
@@ -2539,8 +2523,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2523
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2524
db.Get(command.nodeid, function (err, nodes) { // TODO: Make a NodeRights(user) method that also does not do a db call if agent is connected (???)
2525
if ((nodes == null) || (nodes.length == 1)) {
2542
- meshlinks = user.links[nodes[0].meshid];
2543
- if ((meshlinks) && (meshlinks.rights) && ((meshlinks.rights & MESHRIGHT_REMOTECONTROL) != 0)) {
2526
+ if ((parent.GetMeshRights(user, nodes[0].meshid) & MESHRIGHT_REMOTECONTROL) != 0) {
2527
// Add a user authentication cookie to a url
2528
var cookieContent = { userid: user._id, domainid: user.domain };
2529
if (command.nodeid) { cookieContent.nodeid = command.nodeid; }
@@ -2569,7 +2552,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2552
mesh = parent.meshes[command.meshid];
2553
if (mesh == null) { err = 'Unknown device group'; } // Check if the group exists
2554
else if (mesh.mtype != 2) { err = 'Invalid group type'; } // Check if this is the correct group type
2572
- else if (mesh.links[user._id] == null) { err = 'Not allowed'; } // Check if this user has rights to do this
2555
+ else if (parent.GetMeshRights(user, mesh) == 0) { err = 'Not allowed'; } // Check if this user has rights to do this
2556
}
2557
}
2558
} catch (ex) { err = 'Validation exception: ' + ex; }
@@ -2600,8 +2583,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2583
// Check if this user has rights on this id to set notes
2584
db.Get(command.nodeid, function (err, nodes) {
2585
if ((nodes == null) || (nodes.length == 1)) {
2603
- meshlinks = user.links[nodes[0].meshid];
2604
- if ((meshlinks) && (meshlinks.rights) && (meshlinks.rights != 0)) {
2586
+ if (parent.GetMeshRights(user, nodes[0].meshid) != 0) {
2587
// Add an event for this device
2588
var targets = ['*', 'server-users', user._id, nodes[0].meshid];
2589
var event = { etype: 'node', userid: user._id, username: user.name, nodeid: nodes[0]._id, action: 'manual', msg: decodeURIComponent(command.msg), domain: domain.id };
@@ -2625,8 +2607,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2607
// Check if this user has rights on this id to set notes
2608
db.Get(command.id, function (err, nodes) { // TODO: Make a NodeRights(user) method that also does not do a db call if agent is connected (???)
2609
if ((nodes == null) || (nodes.length == 1)) {
2628
- meshlinks = user.links[nodes[0].meshid];
2629
- if ((meshlinks) && (meshlinks.rights) && ((meshlinks.rights & MESHRIGHT_SETNOTES) != 0)) {
2610
+ if ((parent.GetMeshRights(user, nodes[0].meshid) & MESHRIGHT_SETNOTES) != 0) {
2611
// Set the id's notes
2612
if (common.validateString(command.notes, 1) == false) {
2613
db.Remove('nt' + command.id); // Delete the note for this node
@@ -2641,7 +2622,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2622
mesh = parent.meshes[command.id];
2623
if (mesh) {
2624
// Check if this user has rights to do this
2644
- if ((mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) { return; } // Must have rights to edit the mesh
2625
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_EDITMESH) == 0) return; // Must have rights to edit the mesh
2626
2627
// Set the id's notes
2628
if (common.validateString(command.notes, 1) == false) {
@@ -2921,7 +2902,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2902
mesh = parent.meshes[node.meshid];
2903
if (mesh) {
2904
// Check if this user has "remote" rights to do this
2924
- if ((mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 16) == 0)) return;
2905
+ var meshrights = parent.GetMeshRights(user, mesh);
2906
+ if ((meshrights & MESHRIGHT_AGENTCONSOLE) == 0) return;
2907
2908
// Ask for clipboard data from agent
2909
var agent = parent.wsagents[node._id];
@@ -2943,7 +2925,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2925
mesh = parent.meshes[node.meshid];
2926
if (mesh) {
2927
// Check if this user has "remote" rights to do this
2946
- if ((mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 16) == 0)) return;
2928
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_AGENTCONSOLE) == 0) return;
2929
2930
// Send clipboard data to the agent
2931
var agent = parent.wsagents[node._id];
@@ -2978,7 +2960,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2960
mesh = parent.meshes[node.meshid];
2961
if (mesh) {
2962
// Check if this user has rights to do this
2981
- if (mesh.links[user._id] == null || (mesh.links[user._id].rights == 0)) { return; }
2963
+ if (parent.GetMeshRights(user, mesh) == 0) return;
2964
2965
// Get the notes about this node
2966
db.Get('nt' + command.id, function (err, notes) {
@@ -2994,7 +2976,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2976
mesh = parent.meshes[command.id];
2977
if (mesh) {
2978
// Check if this user has rights to do this
2997
- if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 1) == 0)) { return; } // Must have rights to edit the mesh
2979
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_EDITMESH) == 0) return; // Must have rights to edit the mesh
2980
2981
// Get the notes about this node
2982
db.Get('nt' + command.id, function (err, notes) {
@@ -3082,7 +3064,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3064
mesh = parent.meshes[node.meshid];
3065
if (mesh) {
3066
// Check if this user has rights to do this
3085
- if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 64) != 0)) {
3067
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_WAKEDEVICE) != 0) {
3068
// If this device is connected on MQTT, send a wake action.
3069
if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.publish(node._id, command.topic, command.msg); }
3070
}
@@ -3112,7 +3094,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3094
var mesh = parent.meshes[node.meshid];
3095
if (mesh) {
3096
// Check if this user has rights to do this
3115
- if ((mesh.links[user._id] != null) && (mesh.links[user._id].rights == 0xFFFFFFFF)) {
3097
+ if ((parent.GetMeshRights(user, mesh) == 0xFFFFFFFF)) {
3098
var token = parent.parent.mqttbroker.generateLogin(mesh._id, node._id);
3099
var r = { action: 'getmqttlogin', responseid: command.responseid, nodeid: node._id, user: token.user, pass: token.pass };
3100
const serverName = parent.getWebServerName(domain);
@@ -3165,7 +3147,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3147
var mesh = parent.meshes[node.meshid];
3148
if (mesh) {
3149
// Check if this user has rights to do this
3168
- if (mesh.links[user._id] != null && ((mesh.links[user._id].rights & 8) != 0)) { // "Remote Control permission"
3150
+ if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_REMOTECONTROL) != 0) { // "Remote Control permission"
3151
handleAmtCommand(command, node);
3152
}
3153
}
@@ -3333,7 +3315,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3315
try { files.filetree.f[user._id].f = readFilesRec(parent.path.join(parent.filespath, domainx + "/user-" + usersplit[2])); } catch (e) { }
3316
}
3317
3336
- // Add files for each mesh
3318
+ // Add files for each mesh // TODO: Get all meshes including groups!!
3319
for (var i in user.links) {
3320
if ((user.links[i].rights & 32) != 0) { // Check that we have file permissions
3321
var mesh = parent.meshes[i];
webserver.js
+87
-47
@@ -11,7 +11,7 @@
11
/*jshint strict:false */
12
/*jshint -W097 */
13
/*jshint esversion: 6 */
14
-"use strict";
14
+'use strict';
15
16
/*
17
class SerialTunnel extends require('stream').Duplex {
@@ -63,7 +63,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
63
const constants = (obj.crypto.constants ? obj.crypto.constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
64
65
// Setup WebAuthn / FIDO2
66
- obj.webauthn = require("./webauthn.js").CreateWebAuthnModule();
66
+ obj.webauthn = require('./webauthn.js').CreateWebAuthnModule();
67
68
// Variables
69
obj.parent = parent;
@@ -75,11 +75,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
75
obj.tcpServer = null;
76
obj.certificates = certificates;
77
obj.args = args;
78
- obj.users = {};
79
- obj.meshes = {};
80
- obj.userAllowedIp = args.userallowedip; // List of allowed IP addresses for users
81
- obj.agentAllowedIp = args.agentallowedip; // List of allowed IP addresses for agents
82
- obj.agentBlockedIp = args.agentblockedip; // List of blocked IP addresses for agents
78
+ obj.users = {}; // UserID --> User
79
+ obj.meshes = {}; // MeshID --> Mesh (also called device group)
80
+ obj.userAllowedIp = args.userallowedip; // List of allowed IP addresses for users
81
+ obj.agentAllowedIp = args.agentallowedip; // List of allowed IP addresses for agents
82
+ obj.agentBlockedIp = args.agentblockedip; // List of blocked IP addresses for agents
83
obj.tlsSniCredentials = null;
84
obj.dnsDomains = {};
85
obj.relaySessionCount = 0;
@@ -196,7 +196,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
196
}
197
}
198
199
- function EscapeHtml(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
199
+ function EscapeHtml(x) { if (typeof x == 'string') return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, '''); if (typeof x == 'boolean') return x; if (typeof x == 'number') return x; }
200
//function EscapeHtmlBreaks(x) { if (typeof x == "string") return x.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''').replace(/\r/g, '<br />').replace(/\n/g, '').replace(/\t/g, ' '); if (typeof x == "boolean") return x; if (typeof x == "number") return x; }
201
// Fetch all users from the database, keep this in memory
202
obj.db.GetAllType('user', function (err, docs) {
@@ -506,7 +506,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
506
if (user != null) { obj.parent.DispatchEvent(['*'], obj, { etype: 'user', userid: user._id, username: user.name, action: 'logout', msg: 'Account logout', domain: domain.id }); }
507
}
508
req.session = null;
509
- if (req.query.key != null) { res.redirect(domain.url + "?key=" + req.query.key); } else { res.redirect(domain.url); }
509
+ if (req.query.key != null) { res.redirect(domain.url + '?key=' + req.query.key); } else { res.redirect(domain.url); }
510
parent.debug('web', 'handleLogoutRequest: success.');
511
}
512
@@ -1756,9 +1756,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1756
// Returns the server root certificate encoded in base64
1757
function getRootCertBase64() {
1758
var rootcert = obj.certificates.root.cert;
1759
- var i = rootcert.indexOf("-----BEGIN CERTIFICATE-----\r\n");
1759
+ var i = rootcert.indexOf('-----BEGIN CERTIFICATE-----\r\n');
1760
if (i >= 0) { rootcert = rootcert.substring(i + 29); }
1761
- i = rootcert.indexOf("-----END CERTIFICATE-----");
1761
+ i = rootcert.indexOf('-----END CERTIFICATE-----');
1762
if (i >= 0) { rootcert = rootcert.substring(i, 0); }
1763
return Buffer.from(rootcert, 'base64').toString('base64');
1764
}
@@ -1899,7 +1899,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1899
var domainname = 'domain', spliturl = decodeURIComponent(req.path).split('/'), filename = '';
1900
if ((spliturl.length < 3) || (obj.common.IsFilenameValid(spliturl[2]) == false) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
1901
if (domain.id != '') { domainname = 'domain-' + domain.id; }
1902
- var path = obj.path.join(obj.filespath, domainname + "/user-" + spliturl[2] + "/Public");
1902
+ var path = obj.path.join(obj.filespath, domainname + '/user-' + spliturl[2] + '/Public');
1903
for (var i = 3; i < spliturl.length; i++) { if (obj.common.IsFilenameValid(spliturl[i]) == true) { path += '/' + spliturl[i]; filename = spliturl[i]; } else { res.sendStatus(404); return; } }
1904
1905
var stat = null;
@@ -2046,7 +2046,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2046
obj.handleDomainRedirect = function (req, res) {
2047
const domain = checkUserIpAddress(req, res);
2048
if ((domain == null) || (domain.redirects == null)) { res.sendStatus(404); return; }
2049
- var urlArgs = '', urlName = null, splitUrl = req.originalUrl.split("?");
2049
+ var urlArgs = '', urlName = null, splitUrl = req.originalUrl.split('?');
2050
if (splitUrl.length > 1) { urlArgs = '?' + splitUrl[1]; }
2051
if ((splitUrl.length > 0) && (splitUrl[0].length > 1)) { urlName = splitUrl[0].substring(1).toLowerCase(); }
2052
if ((urlName == null) || (domain.redirects[urlName] == null) || (urlName[0] == '_')) { res.sendStatus(404); return; }
@@ -2837,7 +2837,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2837
try {
2838
if (req.headers.authorization) {
2839
var authstr = req.headers.authorization;
2840
- if (authstr.substring(0, 7) == "Digest ") {
2840
+ if (authstr.substring(0, 7) == 'Digest ') {
2841
var auth = obj.common.parseNameValueList(obj.common.quoteSplit(authstr.substring(7)));
2842
if ((req.url === auth.uri) && (obj.httpAuthRealm === auth.realm) && (auth.opaque === obj.crypto.createHmac('SHA384', obj.httpAuthRandom).update(auth.nonce).digest('hex'))) {
2843
@@ -2858,10 +2858,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2858
if (nodes.length == 1) {
2859
// Yes, the node exists, compute Intel AMT digest password
2860
var node = nodes[0];
2861
- var amtpass = obj.crypto.createHash('sha384').update(auth.username.toLowerCase() + ":" + nodeid + ":" + obj.parent.dbconfig.amtWsEventSecret).digest("base64").substring(0, 12).split("/").join("x").split("\\").join("x");
2861
+ var amtpass = obj.crypto.createHash('sha384').update(auth.username.toLowerCase() + ':' + nodeid + ":" + obj.parent.dbconfig.amtWsEventSecret).digest('base64').substring(0, 12).split('/').join('x').split('\\').join('x');
2862
2863
// Check the MD5 hash
2864
- if (auth.response === obj.common.ComputeDigesthash(auth.username, amtpass, auth.realm, "POST", auth.uri, auth.qop, auth.nonce, auth.nc, auth.cnonce)) {
2864
+ if (auth.response === obj.common.ComputeDigesthash(auth.username, amtpass, auth.realm, 'POST', auth.uri, auth.qop, auth.nonce, auth.nc, auth.cnonce)) {
2865
2866
// This is an authenticated Intel AMT event, update the host address
2867
var amthost = req.ip;
@@ -3014,14 +3014,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3014
3015
// Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly.
3016
var xdomain = (domain.dns == null) ? domain.id : '';
3017
- if (xdomain != '') xdomain += "/";
3018
- var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
3019
- if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + obj.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local\r\n"; }
3020
- if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
3021
- if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += "InstallFlags=" + req.query.installflags + "\r\n"; }
3022
- if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += "ignoreProxyFile=1\r\n"; }
3023
- if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + "\r\n"; } }
3024
- if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + "\r\n"; } }
3017
+ if (xdomain != '') xdomain += '/';
3018
+ var meshsettings = 'MeshName=' + mesh.name + '\r\nMeshType=' + mesh.mtype + '\r\nMeshID=0x' + meshidhex + '\r\nServerID=' + serveridhex + '\r\n';
3019
+ if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + obj.getWebServerName(domain) + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else { meshsettings += 'MeshServer=local\r\n'; }
3020
+ if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
3021
+ if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; }
3022
+ if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; }
3023
+ if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } }
3024
+ if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + '\r\n'; } }
3025
3026
try {
3027
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="' + meshfilename + '"' });
@@ -3178,15 +3178,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3178
3179
// Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly.
3180
var xdomain = (domain.dns == null) ? domain.id : '';
3181
- if (xdomain != '') xdomain += "/";
3182
- var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
3181
+ if (xdomain != '') xdomain += '/';
3182
+ var meshsettings = 'MeshName=' + mesh.name + '\r\nMeshType=' + mesh.mtype + '\r\nMeshID=0x' + meshidhex + '\r\nServerID=' + serveridhex + '\r\n';
3183
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
3184
- if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + obj.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local\r\n"; }
3185
- if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
3186
- if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += "InstallFlags=" + req.query.installflags + "\r\n"; }
3187
- if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += "ignoreProxyFile=1\r\n"; }
3188
- if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + "\r\n"; } }
3189
- if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + "\r\n"; } }
3184
+ if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + obj.getWebServerName(domain) + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else { meshsettings += 'MeshServer=local\r\n'; }
3185
+ if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
3186
+ if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; }
3187
+ if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; }
3188
+ if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } }
3189
+ if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + '\r\n'; } }
3190
3191
// Setup the response output
3192
var archive = require('archiver')('zip', { level: 5 }); // Sets the compression method.
@@ -3201,11 +3201,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3201
archive.pipe(res);
3202
3203
// Opens the "MeshAgentOSXPackager.zip"
3204
- var yauzl = require("yauzl");
3204
+ var yauzl = require('yauzl');
3205
yauzl.open(obj.path.join(__dirname, 'agents', 'MeshAgentOSXPackager.zip'), { lazyEntries: true }, function (err, zipfile) {
3206
if (err) { res.sendStatus(500); return; }
3207
zipfile.readEntry();
3208
- zipfile.on("entry", function (entry) {
3208
+ zipfile.on('entry', function (entry) {
3209
if (/\/$/.test(entry.fileName)) {
3210
// Skip all folder entries
3211
zipfile.readEntry();
@@ -3213,8 +3213,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3213
if (entry.fileName == 'MeshAgent.mpkg/Contents/distribution.dist') {
3214
// This is a special file entry, we need to fix it.
3215
zipfile.openReadStream(entry, function (err, readStream) {
3216
- readStream.on("data", function (data) { if (readStream.xxdata) { readStream.xxdata += data; } else { readStream.xxdata = data; } });
3217
- readStream.on("end", function () {
3216
+ readStream.on('data', function (data) { if (readStream.xxdata) { readStream.xxdata += data; } else { readStream.xxdata = data; } });
3217
+ readStream.on('end', function () {
3218
var meshname = mesh.name.split(']').join('').split('[').join(''); // We can't have ']]' in the string since it will terminate the CDATA.
3219
var welcomemsg = 'Welcome to the MeshCentral agent for MacOS\n\nThis installer will install the mesh agent for "' + meshname + '" and allow the administrator to remotely monitor and control this computer over the internet. For more information, go to https://www.meshcommander.com/meshcentral2.\n\nThis software is provided under Apache 2.0 license.\n';
3220
var installsize = Math.floor((argentInfo.size + meshsettings.length) / 1024);
@@ -3234,9 +3234,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3234
}
3235
}
3236
});
3237
- zipfile.on("end", function () {
3238
- archive.file(argentInfo.path, { name: "MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.bin" });
3239
- archive.append(meshsettings, { name: "MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.msh" });
3237
+ zipfile.on('end', function () {
3238
+ archive.file(argentInfo.path, { name: 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.bin' });
3239
+ archive.append(meshsettings, { name: 'MeshAgent.mpkg/Contents/Packages/internal.pkg/Contents/meshagent_osx64.msh' });
3240
archive.finalize();
3241
});
3242
});
@@ -3267,15 +3267,15 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3267
3268
// Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly.
3269
var xdomain = (domain.dns == null) ? domain.id : '';
3270
- if (xdomain != '') xdomain += "/";
3271
- var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
3270
+ if (xdomain != '') xdomain += '/';
3271
+ var meshsettings = 'MeshName=' + mesh.name + '\r\nMeshType=' + mesh.mtype + '\r\nMeshID=0x' + meshidhex + '\r\nServerID=' + serveridhex + '\r\n';
3272
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
3273
- if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + obj.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local\r\n"; }
3274
- if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
3275
- if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += "InstallFlags=" + req.query.installflags + "\r\n"; }
3276
- if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += "ignoreProxyFile=1\r\n"; }
3277
- if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + "\r\n"; } }
3278
- if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + "\r\n"; } }
3273
+ if (obj.args.lanonly != true) { meshsettings += 'MeshServer=ws' + (obj.args.notls ? '' : 's') + '://' + obj.getWebServerName(domain) + ':' + httpsPort + '/' + xdomain + 'agent.ashx\r\n'; } else { meshsettings += 'MeshServer=local\r\n'; }
3274
+ if (req.query.tag != null) { meshsettings += 'Tag=' + req.query.tag + '\r\n'; }
3275
+ if ((req.query.installflags != null) && (req.query.installflags != 0)) { meshsettings += 'InstallFlags=' + req.query.installflags + '\r\n'; }
3276
+ if ((domain.agentnoproxy === true) || (obj.args.lanonly == true)) { meshsettings += 'ignoreProxyFile=1\r\n'; }
3277
+ if (obj.args.agentconfig) { for (var i in obj.args.agentconfig) { meshsettings += obj.args.agentconfig[i] + '\r\n'; } }
3278
+ if (domain.agentconfig) { for (var i in domain.agentconfig) { meshsettings += domain.agentconfig[i] + '\r\n'; } }
3279
3280
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename="meshagent.msh"' });
3281
res.send(meshsettings);
@@ -3907,6 +3907,46 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3907
}
3908
};
3909
3910
+ // Returns a list of all meshes that this user has some rights too
3911
+ obj.GetAllMeshWithRights = function (user, rights) {
3912
+ if (typeof user == 'string') { user = obj.users[user]; }
3913
+ if ((user == null) || (user.links == null)) { return []; }
3914
+ var r = [];
3915
+ for (var i in user.links) { const m = obj.meshes[i]; if ((m) && (m.deleted == null) && ((rights == null) || ((m.rights & rights) != 0))) { r.push(m); } }
3916
+ return r;
3917
+ }
3918
+
3919
+ // Returns a list of all mesh id's that this user has some rights too
3920
+ obj.GetAllMeshIdWithRights = function (user, rights) {
3921
+ if (typeof user == 'string') { user = obj.users[user]; }
3922
+ if ((user == null) || (user.links == null)) { return []; }
3923
+ var r = [];
3924
+ for (var i in user.links) { const m = obj.meshes[i]; if ((m) && (m.deleted == null) && ((rights == null) || ((m.rights & rights) != 0))) { r.push(m._id); } }
3925
+ return r;
3926
+ }
3927
+
3928
+ // Get the right of a user on a given device group
3929
+ obj.GetMeshRights = function (user, mesh) {
3930
+ if ((user == null) || (mesh == null)) { return 0; }
3931
+ if (typeof user == 'string') { user = obj.users[user]; }
3932
+ if ((user == null) || (user.links == null)) { return 0; }
3933
+ var r = 0;
3934
+ if (typeof mesh == 'string') { r = user.links[mesh]; } else { r = user.links[mesh._id]; }
3935
+ if (r == null) { return 0; }
3936
+ return r.rights;
3937
+ }
3938
+
3939
+ // Returns true if the user can view the given device group
3940
+ obj.IsMeshViewable = function (user, mesh) {
3941
+ if ((user == null) || (mesh == null)) { return false; }
3942
+ if (typeof user == 'string') { user = obj.users[user]; }
3943
+ if ((user == null) || (user.links == null)) { return false; }
3944
+ var r = 0;
3945
+ if (typeof mesh == 'string') { r = user.links[mesh]; } else { r = user.links[mesh._id]; }
3946
+ if (r == null) { return false; }
3947
+ return true;
3948
+ }
3949
+
3950
// Clone a safe version of a user object, remove everything that is secret.
3951
obj.CloneSafeUser = function (user) {
3952
if (typeof user != 'object') { return user; }