More access control improvements, RPi icon.
Ylian Saint-Hilaire committed
Dec 27, 2019 at 15:18 UTC
c3efdb39c1a7bd6f9e02368704c838ebd2436e45
16 files changed
+719
-853
agents/meshcore.js
+2
-5
@@ -1919,13 +1919,10 @@ function createMeshCore(agent) {
1919
switch (cmd) {
1920
case 'help': { // Displays available commands
1921
var fin = '', f = '', availcommands = 'version,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper';
1922
- if (process.platform == 'win32')
1923
- {
1924
- availcommands += ',safemode,wpfhwacceleration';
1925
- }
1922
+ if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration'; }
1923
availcommands = availcommands.split(',').sort();
1924
while (availcommands.length > 0) {
1928
- if (f.length > 100) { fin += (f + ',\r\n'); f = ''; }
1925
+ if (f.length > 90) { fin += (f + ',\r\n'); f = ''; }
1926
f += (((f != '') ? ', ' : ' ') + availcommands.shift());
1927
}
1928
if (f != '') { fin += f; }
interceptor.js
+42
-42
@@ -12,10 +12,10 @@
12
/*jshint node: true */
13
/*jshint strict: false */
14
/*jshint esversion: 6 */
15
-"use strict";
15
+'use strict';
16
17
-const crypto = require("crypto");
18
-const common = require("./common.js");
17
+const crypto = require('crypto');
18
+const common = require('./common.js');
19
20
var HttpInterceptorAuthentications = {};
21
//var RedirInterceptorAuthentications = {};
@@ -28,8 +28,8 @@ module.exports.CreateHttpInterceptor = function (args) {
28
obj.randomValueHex = function (len) { return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len); };
29
30
obj.args = args;
31
- obj.amt = { acc: "", mode: 0, count: 0, error: false }; // mode: 0:Header, 1:LengthBody, 2:ChunkedBody, 3:UntilClose
32
- obj.ws = { acc: "", mode: 0, count: 0, error: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
31
+ obj.amt = { acc: '', mode: 0, count: 0, error: false }; // mode: 0:Header, 1:LengthBody, 2:ChunkedBody, 3:UntilClose
32
+ obj.ws = { acc: '', mode: 0, count: 0, error: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
33
obj.blockAmtStorage = false;
34
35
// Private method
@@ -38,7 +38,7 @@ module.exports.CreateHttpInterceptor = function (args) {
38
// Process data coming from Intel AMT
39
obj.processAmtData = function (data) {
40
obj.amt.acc += data; // Add data to accumulator
41
- data = "";
41
+ data = '';
42
var datalen = 0;
43
do {
44
datalen = data.length;
@@ -53,7 +53,7 @@ module.exports.CreateHttpInterceptor = function (args) {
53
if (obj.amt.mode == 0) { // Header Mode
54
// Decode the HTTP header
55
headerend = obj.amt.acc.indexOf('\r\n\r\n');
56
- if (headerend < 0) return "";
56
+ if (headerend < 0) return '';
57
var headerlines = obj.amt.acc.substring(0, headerend).split('\r\n');
58
obj.amt.acc = obj.amt.acc.substring(headerend + 4);
59
obj.amt.directive = headerlines[0].split(' ');
@@ -98,7 +98,7 @@ module.exports.CreateHttpInterceptor = function (args) {
98
} else if (obj.amt.mode == 2) { // Chunked Body Mode
99
// Send data one chunk at a time
100
headerend = obj.amt.acc.indexOf('\r\n');
101
- if (headerend < 0) return "";
101
+ if (headerend < 0) return '';
102
var chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
103
if ((chunksize == 0) && (obj.amt.acc.length >= headerend + 4)) {
104
// Send the ending chunk (NOTE: We do not support trailing headers)
@@ -114,16 +114,16 @@ module.exports.CreateHttpInterceptor = function (args) {
114
}
115
} else if (obj.amt.mode == 3) { // Until Close Mode
116
r = obj.amt.acc;
117
- obj.amt.acc = "";
117
+ obj.amt.acc = '';
118
return r;
119
}
120
- return "";
120
+ return '';
121
};
122
123
// Process data coming from the Browser
124
obj.processBrowserData = function (data) {
125
obj.ws.acc += data; // Add data to accumulator
126
- data = "";
126
+ data = '';
127
var datalen = 0;
128
do {
129
datalen = data.length;
@@ -138,7 +138,7 @@ module.exports.CreateHttpInterceptor = function (args) {
138
if (obj.ws.mode == 0) { // Header Mode
139
// Decode the HTTP header
140
headerend = obj.ws.acc.indexOf('\r\n\r\n');
141
- if (headerend < 0) return "";
141
+ if (headerend < 0) return '';
142
var headerlines = obj.ws.acc.substring(0, headerend).split('\r\n');
143
obj.ws.acc = obj.ws.acc.substring(headerend + 4);
144
obj.ws.directive = headerlines[0].split(' ');
@@ -199,7 +199,7 @@ module.exports.CreateHttpInterceptor = function (args) {
199
} else if (obj.amt.mode == 2) { // Chunked Body Mode
200
// Send data one chunk at a time
201
headerend = obj.amt.acc.indexOf('\r\n');
202
- if (headerend < 0) return "";
202
+ if (headerend < 0) return '';
203
var chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
204
if (isNaN(chunksize)) { // TODO: Check this path
205
// Chunk is not in this batch, move one
@@ -226,10 +226,10 @@ module.exports.CreateHttpInterceptor = function (args) {
226
}
227
} else if (obj.ws.mode == 3) { // Until Close Mode
228
r = obj.ws.acc;
229
- obj.ws.acc = "";
229
+ obj.ws.acc = '';
230
return r;
231
}
232
- return "";
232
+ return '';
233
};
234
235
// Parse authentication values from the HTTP header
@@ -249,9 +249,9 @@ module.exports.CreateHttpInterceptor = function (args) {
249
250
// Compute the MD5 digest hash for a set of values
251
obj.ComputeDigesthash = function (username, password, realm, method, path, qop, nonce, nc, cnonce) {
252
- var ha1 = crypto.createHash('md5').update(username + ":" + realm + ":" + password).digest("hex");
253
- var ha2 = crypto.createHash('md5').update(method + ":" + path).digest("hex");
254
- return crypto.createHash('md5').update(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2).digest("hex");
252
+ var ha1 = crypto.createHash('md5').update(username + ':' + realm + ':' + password).digest('hex');
253
+ var ha2 = crypto.createHash('md5').update(method + ':' + path).digest('hex');
254
+ return crypto.createHash('md5').update(ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2).digest('hex');
255
};
256
257
return obj;
@@ -266,8 +266,8 @@ module.exports.CreateRedirInterceptor = function (args) {
266
obj.randomValueHex = function (len) { return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len); };
267
268
obj.args = args;
269
- obj.amt = { acc: "", mode: 0, count: 0, error: false, direct: false };
270
- obj.ws = { acc: "", mode: 0, count: 0, error: false, direct: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
269
+ obj.amt = { acc: '', mode: 0, count: 0, error: false, direct: false };
270
+ obj.ws = { acc: '', mode: 0, count: 0, error: false, direct: false, authCNonce: obj.randomValueHex(10), authCNonceCount: 1 };
271
272
obj.RedirectCommands = { StartRedirectionSession: 0x10, StartRedirectionSessionReply: 0x11, EndRedirectionSession: 0x12, AuthenticateSession: 0x13, AuthenticateSessionReply: 0x14 };
273
obj.StartRedirectionSessionReplyStatus = { SUCCESS: 0, TYPE_UNKNOWN: 1, BUSY: 2, UNSUPPORTED: 3, ERROR: 0xFF };
@@ -280,7 +280,7 @@ module.exports.CreateRedirInterceptor = function (args) {
280
// Process data coming from Intel AMT
281
obj.processAmtData = function (data) {
282
obj.amt.acc += data; // Add data to accumulator
283
- data = "";
283
+ data = '';
284
var datalen = 0;
285
do { datalen = data.length; data += obj.processAmtDataEx(); } while (datalen != data.length); // Process as much data as possible
286
return data;
@@ -298,11 +298,11 @@ module.exports.CreateRedirInterceptor = function (args) {
298
//console.log(obj.amt.acc.charCodeAt(0));
299
switch (obj.amt.acc.charCodeAt(0)) {
300
case obj.RedirectCommands.StartRedirectionSessionReply: {
301
- if (obj.amt.acc.length < 4) return "";
301
+ if (obj.amt.acc.length < 4) return '';
302
if (obj.amt.acc.charCodeAt(1) == obj.StartRedirectionSessionReplyStatus.SUCCESS) {
303
- if (obj.amt.acc.length < 13) return "";
303
+ if (obj.amt.acc.length < 13) return '';
304
var oemlen = obj.amt.acc.charCodeAt(12);
305
- if (obj.amt.acc.length < 13 + oemlen) return "";
305
+ if (obj.amt.acc.length < 13 + oemlen) return '';
306
r = obj.amt.acc.substring(0, 13 + oemlen);
307
obj.amt.acc = obj.amt.acc.substring(13 + oemlen);
308
return r;
@@ -310,9 +310,9 @@ module.exports.CreateRedirInterceptor = function (args) {
310
break;
311
}
312
case obj.RedirectCommands.AuthenticateSessionReply: {
313
- if (obj.amt.acc.length < 9) return "";
313
+ if (obj.amt.acc.length < 9) return '';
314
var l = common.ReadIntX(obj.amt.acc, 5);
315
- if (obj.amt.acc.length < 9 + l) return "";
315
+ if (obj.amt.acc.length < 9 + l) return '';
316
var authstatus = obj.amt.acc.charCodeAt(1);
317
var authType = obj.amt.acc.charCodeAt(4);
318
@@ -337,17 +337,17 @@ module.exports.CreateRedirInterceptor = function (args) {
337
}
338
default: {
339
obj.amt.error = true;
340
- return "";
340
+ return '';
341
}
342
}
343
}
344
- return "";
344
+ return '';
345
};
346
347
// Process data coming from the Browser
348
obj.processBrowserData = function (data) {
349
obj.ws.acc += data; // Add data to accumulator
350
- data = "";
350
+ data = '';
351
var datalen = 0;
352
do { datalen = data.length; data += obj.processBrowserDataEx(); } while (datalen != data.length); // Process as much data as possible
353
return data;
@@ -356,39 +356,39 @@ module.exports.CreateRedirInterceptor = function (args) {
356
// Process data coming from the Browser in the accumulator
357
obj.processBrowserDataEx = function () {
358
var r;
359
- if (obj.ws.acc.length == 0) return "";
359
+ if (obj.ws.acc.length == 0) return '';
360
if (obj.ws.direct == true) {
361
var data = obj.ws.acc;
362
- obj.ws.acc = "";
362
+ obj.ws.acc = '';
363
return data;
364
} else {
365
switch (obj.ws.acc.charCodeAt(0)) {
366
case obj.RedirectCommands.StartRedirectionSession: {
367
- if (obj.ws.acc.length < 8) return "";
367
+ if (obj.ws.acc.length < 8) return '';
368
r = obj.ws.acc.substring(0, 8);
369
obj.ws.acc = obj.ws.acc.substring(8);
370
return r;
371
}
372
case obj.RedirectCommands.EndRedirectionSession: {
373
- if (obj.ws.acc.length < 4) return "";
373
+ if (obj.ws.acc.length < 4) return '';
374
r = obj.ws.acc.substring(0, 4);
375
obj.ws.acc = obj.ws.acc.substring(4);
376
return r;
377
}
378
case obj.RedirectCommands.AuthenticateSession: {
379
- if (obj.ws.acc.length < 9) return "";
379
+ if (obj.ws.acc.length < 9) return '';
380
var l = common.ReadIntX(obj.ws.acc, 5);
381
- if (obj.ws.acc.length < 9 + l) return "";
381
+ if (obj.ws.acc.length < 9 + l) return '';
382
383
var authType = obj.ws.acc.charCodeAt(4);
384
if (authType == obj.AuthenticationType.DIGEST && obj.args.user && obj.args.pass) {
385
- var authurl = "/RedirectionService";
385
+ var authurl = '/RedirectionService';
386
if (obj.amt.digestRealm) {
387
// Replace this authentication digest with a server created one
388
// We have everything we need to authenticate
389
var nc = obj.ws.authCNonceCount;
390
obj.ws.authCNonceCount++;
391
- var digest = obj.ComputeDigesthash(obj.args.user, obj.args.pass, obj.amt.digestRealm, "POST", authurl, obj.amt.digestQOP, obj.amt.digestNonce, nc, obj.ws.authCNonce);
391
+ var digest = obj.ComputeDigesthash(obj.args.user, obj.args.pass, obj.amt.digestRealm, 'POST', authurl, obj.amt.digestQOP, obj.amt.digestNonce, nc, obj.ws.authCNonce);
392
393
// Replace this authentication digest with a server created one
394
// We have everything we need to authenticate
@@ -434,18 +434,18 @@ module.exports.CreateRedirInterceptor = function (args) {
434
}
435
default: {
436
obj.ws.error = true;
437
- return "";
437
+ return '';
438
}
439
}
440
}
441
- return "";
441
+ return '';
442
};
443
444
// Compute the MD5 digest hash for a set of values
445
obj.ComputeDigesthash = function (username, password, realm, method, path, qop, nonce, nc, cnonce) {
446
- var ha1 = crypto.createHash('md5').update(username + ":" + realm + ":" + password).digest("hex");
447
- var ha2 = crypto.createHash('md5').update(method + ":" + path).digest("hex");
448
- return crypto.createHash('md5').update(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2).digest("hex");
446
+ var ha1 = crypto.createHash('md5').update(username + ':' + realm + ':' + password).digest('hex');
447
+ var ha2 = crypto.createHash('md5').update(method + ':' + path).digest('hex');
448
+ return crypto.createHash('md5').update(ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2).digest('hex');
449
};
450
451
return obj;
meshrelay.js
+2
-2
@@ -80,7 +80,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
80
var agent = parent.wsagents[command.nodeid];
81
if (agent != null) {
82
// Check if we have permission to send a message to that node
83
- rights = user.links[agent.dbMeshKey];
83
+ rights = user.links[agent.dbMeshKey]; // TODO: Need to include user group / node rights
84
mesh = parent.meshes[agent.dbMeshKey];
85
if ((rights != null) && (mesh != null) || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
86
if (ws.sessionId) { command.sessionid = ws.sessionId; } // Set the session id, required for responses.
@@ -98,7 +98,7 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
98
var routing = parent.parent.GetRoutingServerId(command.nodeid, 1); // 1 = MeshAgent routing type
99
if (routing != null) {
100
// Check if we have permission to send a message to that node
101
- rights = user.links[routing.meshid];
101
+ rights = user.links[routing.meshid]; // TODO: Need to include user groups / node rights
102
mesh = parent.meshes[routing.meshid];
103
if (rights != null || ((rights & 16) != 0)) { // TODO: 16 is console permission, may need more gradular permission checking
104
if (ws.sessionId) { command.fromSessionid = ws.sessionId; } // Set the session id, required for responses.
meshuser.js
+377
-591
@@ -152,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
155
- var meshrights = parent.GetMeshRights(user, agent.dbMeshKey);
155
+ var meshrights = parent.GetMeshRights(user, agent.dbMeshKey); // TODO: We will need to get the rights for this specific node.
156
var mesh = parent.meshes[agent.dbMeshKey];
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
159
- command.rights = meshrights; // 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
@@ -503,101 +503,74 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
503
}
504
case 'powertimeline':
505
{
506
- // Perform pre-validation
507
- if (common.validateString(command.nodeid, 0, 128) == false) break;
508
- var snode = command.nodeid.split('/');
509
- if ((snode.length != 3) || (snode[1] != domain.id)) break;
510
-
511
- // Check that we have permissions for this node.
512
- db.Get(command.nodeid, function (err, nodes) {
513
- if (nodes == null || nodes.length != 1) return;
514
- const node = nodes[0];
515
-
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) {
520
- if ((err == null) && (docs != null) && (docs.length > 0)) {
521
- var timeline = [], time = null, previousPower;
522
- for (i in docs) {
523
- var doc = docs[i], j = parseInt(i);
524
- doc.time = Date.parse(doc.time);
525
- if (time == null) { // First element
526
- // Skip all starting power 0 events.
527
- if ((doc.power == 0) && ((doc.oldPower == null) || (doc.oldPower == 0))) continue;
528
- time = doc.time;
529
- if (doc.oldPower) { timeline.push(doc.oldPower, time / 1000, doc.power); } else { timeline.push(0, time / 1000, doc.power); }
530
- } else if (previousPower != doc.power) { // Delta element
531
- // If this event is of a short duration (2 minutes or less), skip it.
532
- if ((docs.length > (j + 1)) && ((Date.parse(docs[j + 1].time) - doc.time) < 120000)) continue;
533
- timeline.push((doc.time - time) / 1000, doc.power);
534
- time = doc.time;
535
- }
536
- previousPower = doc.power;
506
+ // Get the node and the rights for this node
507
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
508
+ if (visible == false) return;
509
+ // Query the database for the power timeline for a given node
510
+ // The result is a compacted array: [ startPowerState, startTimeUTC, powerState ] + many[ deltaTime, powerState ]
511
+ db.getPowerTimeline(node._id, function (err, docs) {
512
+ if ((err == null) && (docs != null) && (docs.length > 0)) {
513
+ var timeline = [], time = null, previousPower;
514
+ for (i in docs) {
515
+ var doc = docs[i], j = parseInt(i);
516
+ doc.time = Date.parse(doc.time);
517
+ if (time == null) { // First element
518
+ // Skip all starting power 0 events.
519
+ if ((doc.power == 0) && ((doc.oldPower == null) || (doc.oldPower == 0))) continue;
520
+ time = doc.time;
521
+ if (doc.oldPower) { timeline.push(doc.oldPower, time / 1000, doc.power); } else { timeline.push(0, time / 1000, doc.power); }
522
+ } else if (previousPower != doc.power) { // Delta element
523
+ // If this event is of a short duration (2 minutes or less), skip it.
524
+ if ((docs.length > (j + 1)) && ((Date.parse(docs[j + 1].time) - doc.time) < 120000)) continue;
525
+ timeline.push((doc.time - time) / 1000, doc.power);
526
+ time = doc.time;
527
}
538
- try { ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: timeline, tag: command.tag })); } catch (ex) { }
539
- } else {
540
- // No records found, send current state if we have it
541
- var state = parent.parent.GetConnectivityState(command.nodeid);
542
- if (state != null) { try { ws.send(JSON.stringify({ action: 'powertimeline', nodeid: command.nodeid, timeline: [state.powerState, Date.now(), state.powerState], tag: command.tag })); } catch (ex) { } }
528
+ previousPower = doc.power;
529
}
544
- });
545
- }
530
+ try { ws.send(JSON.stringify({ action: 'powertimeline', nodeid: node._id, timeline: timeline, tag: command.tag })); } catch (ex) { }
531
+ } else {
532
+ // No records found, send current state if we have it
533
+ var state = parent.parent.GetConnectivityState(command.nodeid);
534
+ if (state != null) { try { ws.send(JSON.stringify({ action: 'powertimeline', nodeid: node._id, timeline: [state.powerState, Date.now(), state.powerState], tag: command.tag })); } catch (ex) { } }
535
+ }
536
+ });
537
});
538
break;
539
}
540
case 'getsysinfo':
541
{
551
- // Perform pre-validation
552
- if (common.validateString(command.nodeid, 0, 128) == false) break;
553
- var snode = command.nodeid.split('/');
554
- if ((snode.length != 3) || (snode[1] != domain.id)) break;
555
-
556
- // Check that we have permissions for this node.
557
- db.Get(command.nodeid, function (err, nodes) {
558
- if (nodes == null || nodes.length != 1) return;
559
- const node = nodes[0];
560
-
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)) {
565
- var doc = docs[0];
566
- doc.action = 'getsysinfo';
567
- doc.nodeid = command.nodeid;
568
- doc.tag = command.tag;
569
- delete doc.type;
570
- delete doc.domain;
571
- delete doc._id;
572
- try { ws.send(JSON.stringify(doc)); } catch (ex) { }
573
- } else {
574
- try { ws.send(JSON.stringify({ action: 'getsysinfo', nodeid: command.nodeid, tag: command.tag, noinfo: true })); } catch (ex) { }
575
- }
576
- });
577
- }
542
+ // Get the node and the rights for this node
543
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
544
+ if (visible == false) return;
545
+ // Query the database system information
546
+ db.Get('si' + command.nodeid, function (err, docs) {
547
+ if ((docs != null) && (docs.length > 0)) {
548
+ var doc = docs[0];
549
+ doc.action = 'getsysinfo';
550
+ doc.nodeid = node._id;
551
+ doc.tag = command.tag;
552
+ delete doc.type;
553
+ delete doc.domain;
554
+ delete doc._id;
555
+ try { ws.send(JSON.stringify(doc)); } catch (ex) { }
556
+ } else {
557
+ try { ws.send(JSON.stringify({ action: 'getsysinfo', nodeid: node._id, tag: command.tag, noinfo: true })); } catch (ex) { }
558
+ }
559
+ });
560
});
561
break;
562
}
563
case 'lastconnect':
564
{
583
- // Perform pre-validation
584
- if (common.validateString(command.nodeid, 0, 128) == false) return;
585
- var snode = command.nodeid.split('/');
586
- if ((snode.length != 3) || (snode[1] != domain.id)) break;
587
-
588
- // Check that we have permissions for this node.
589
- db.Get(command.nodeid, function (err, nodes) {
590
- if (nodes == null || nodes.length != 1) return;
591
- const node = nodes[0];
592
-
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)) {
597
- try { ws.send(JSON.stringify({ action: 'lastconnect', nodeid: command.nodeid, time: docs[0].time, addr: docs[0].addr })); } catch (ex) { }
598
- }
599
- });
600
- }
565
+ // Get the node and the rights for this node
566
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
567
+ if (visible == false) return;
568
+ // Query the database for the last time this node connected
569
+ db.Get('lc' + command.nodeid, function (err, docs) {
570
+ if ((docs != null) && (docs.length > 0)) {
571
+ try { ws.send(JSON.stringify({ action: 'lastconnect', nodeid: command.nodeid, time: docs[0].time, addr: docs[0].addr })); } catch (ex) { }
572
+ }
573
+ });
574
});
575
break;
576
}
@@ -963,31 +936,27 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
936
try { ws.send(JSON.stringify({ action: 'events', events: docs, user: command.user, tag: command.tag })); } catch (ex) { }
937
});
938
}
966
- } else if (common.validateString(command.nodeid, 0, 128) == true) { // Device filtered events
939
+ } else if (command.nodeid != null) { // Device filtered events
940
// Check that the user has access to this nodeid
968
- db.Get(command.nodeid, function (err, nodes) {
969
- if ((nodes == null) || (nodes.length != 1)) return;
970
- const node = nodes[0];
971
-
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
-
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;
982
- try { ws.send(JSON.stringify({ action: 'events', events: docs, nodeid: command.nodeid, tag: command.tag })); } catch (ex) { }
983
- });
984
- } else {
985
- // Send the list of most recent events for this nodeid, up to 'limit' count
986
- db.GetNodeEventsWithLimit(command.nodeid, domain.id, limit, function (err, docs) {
987
- if (err != null) return;
988
- try { ws.send(JSON.stringify({ action: 'events', events: docs, nodeid: command.nodeid, tag: command.tag })); } catch (ex) { }
989
- });
990
- }
941
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
942
+ if (node == null) return;
943
+
944
+ // Put a limit on the number of returned entries if present
945
+ var limit = 10000;
946
+ if (common.validateInt(command.limit, 1, 60000) == true) { limit = command.limit; }
947
+
948
+ if ((rights & MESHRIGHT_LIMITEVENTS) != 0) {
949
+ // Send the list of most recent events for this nodeid that only apply to us, up to 'limit' count
950
+ db.GetNodeEventsSelfWithLimit(node._id, domain.id, user._id, limit, function (err, docs) {
951
+ if (err != null) return;
952
+ try { ws.send(JSON.stringify({ action: 'events', events: docs, nodeid: node._id, tag: command.tag })); } catch (ex) { }
953
+ });
954
+ } else {
955
+ // Send the list of most recent events for this nodeid, up to 'limit' count
956
+ db.GetNodeEventsWithLimit(node._id, domain.id, limit, function (err, docs) {
957
+ if (err != null) return;
958
+ try { ws.send(JSON.stringify({ action: 'events', events: docs, nodeid: node._id, tag: command.tag })); } catch (ex) { }
959
+ });
960
}
961
});
962
} else {
@@ -997,7 +966,10 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
966
// All events
967
var exGroupFilter2 = [], filter = [], filter2 = user.subscriptions;
968
1000
- // Remove MeshID's that we do not have rights to see events for (TODO: user groups)
969
+ // Add all meshes for groups this user is part of
970
+ // TODO (UserGroups)
971
+
972
+ // Remove MeshID's that we do not have rights to see events for
973
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); } }
974
for (var i in filter2) { if (exGroupFilter2.indexOf(filter2[i]) == -1) { filter.push(filter2[i]); } }
975
@@ -1198,7 +1170,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1170
}
1171
}
1172
1201
- // TODO: Remove user groups??
1173
+ // TODO (UserGroups): Remove user groups??
1174
1175
db.Remove('ws' + deluser._id); // Remove user web state
1176
db.Remove('nt' + deluser._id); // Remove notes for this user
@@ -1507,17 +1479,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1479
if (common.validateString(command.meshid, 1, 1024) == false) { err = 'Invalid group identifier'; } // Check the meshid
1480
else if (command.meshid.indexOf('/') == -1) { command.meshid = 'mesh/' + domain.id + '/' + command.meshid; }
1481
if (common.validateInt(command.notify) == false) { err = 'Invalid notification flags'; }
1510
- if (parent.GetMeshRights(user, command.meshid) == 0) err = 'Access denied';
1482
+ if (parent.IsMeshViewable(user, command.meshid) == false) err = 'Access denied';
1483
} catch (ex) { err = 'Validation exception: ' + ex; }
1484
1485
// Handle any errors
1486
if (err != null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'changemeshnotify', responseid: command.responseid, result: err })); } catch (ex) { } } break; }
1487
1488
// 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 {
1520
- user.links[command.meshid].notify = command.notify;
1489
+ // TODO (UserGroups)
1490
+ if (user.links[command.meshid]) {
1491
+ if (command.notify == 0) {
1492
+ delete user.links[command.meshid].notify;
1493
+ } else {
1494
+ user.links[command.meshid].notify = command.notify;
1495
+ }
1496
}
1497
1498
// Save the user
@@ -1674,33 +1649,23 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1649
}
1650
}
1651
1677
- // Setup a user-to-node session
1678
- if (common.validateString(command.nodeid, 1, 2048)) {
1679
- if (args.lanonly == true) { return; } // User-to-device chat is not support in LAN-only mode yet. We need the agent to replace the IP address of the server??
1680
-
1681
- // Get the device
1682
- db.Get(command.nodeid, function (err, nodes) {
1683
- if ((nodes == null) || (nodes.length != 1)) return;
1684
- var node = nodes[0];
1685
-
1686
- // Get the mesh for this device
1687
- mesh = parent.meshes[node.meshid];
1688
- if (mesh) {
1689
- // Check if this user has rights to do this
1690
- if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_CHATNOTIFY) == 0) return;
1652
+ // User-to-device chat is not support in LAN-only mode yet. We need the agent to replace the IP address of the server??
1653
+ if (args.lanonly == true) { return; }
1654
1692
- // Create the server url
1693
- var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
1694
- var xdomain = (domain.dns == null) ? domain.id : '';
1695
- if (xdomain != '') xdomain += "/";
1696
- var url = "http" + (args.notls ? '' : 's') + "://" + parent.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "messenger?id=meshmessenger/" + encodeURIComponent(command.nodeid) + "/" + encodeURIComponent(user._id) + "&title=" + encodeURIComponent(user.name);
1655
+ // Setup a user-to-node session
1656
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
1657
+ // Check if this user has rights to do this
1658
+ if ((rights & MESHRIGHT_CHATNOTIFY) == 0) return;
1659
1698
- // Create the notification message
1699
- routeCommandToNode({ "action": "openUrl", "nodeid": command.nodeid, "userid": user._id, "username": user.name, "url": url });
1700
- }
1701
- });
1702
- }
1660
+ // Create the server url
1661
+ var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
1662
+ var xdomain = (domain.dns == null) ? domain.id : '';
1663
+ if (xdomain != '') xdomain += "/";
1664
+ var url = "http" + (args.notls ? '' : 's') + "://" + parent.getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "messenger?id=meshmessenger/" + encodeURIComponent(command.nodeid) + "/" + encodeURIComponent(user._id) + "&title=" + encodeURIComponent(user.name);
1665
1666
+ // Create the notification message
1667
+ routeCommandToNode({ "action": "openUrl", "nodeid": command.nodeid, "userid": user._id, "username": user.name, "url": url });
1668
+ });
1669
break;
1670
}
1671
case 'serverversion':
@@ -2084,20 +2049,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2049
2050
// For each nodeid, change the group
2051
for (var i = 0; i < command.nodeids.length; i++) {
2087
- db.Get(command.nodeids[i], function (err, nodes) {
2088
- if ((nodes == null) || (nodes.length != 1)) return;
2089
- const node = nodes[0];
2090
-
2052
+ // Get the node and the rights for this node
2053
+ parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
2054
// Check if already in the right mesh
2092
- if (node.meshid == command.meshid) return;
2055
+ if ((node == null) || (node.meshid == command.meshid)) return;
2056
2057
// Make sure both source and target mesh are the same type
2058
try { if (parent.meshes[node.meshid].mtype != parent.meshes[command.meshid].mtype) return; } catch (e) { return; };
2059
2060
// Make sure that we have rights on both source and destination mesh
2098
- const sourceMeshRights = parent.GetMeshRights(user, node.meshid);
2061
const targetMeshRights = parent.GetMeshRights(user, command.meshid);
2100
- if (((sourceMeshRights & MESHRIGHT_MANAGECOMPUTERS) == 0) || ((targetMeshRights & MESHRIGHT_MANAGECOMPUTERS) == 0)) return;
2062
+ if (((rights & MESHRIGHT_MANAGECOMPUTERS) == 0) || ((targetMeshRights & MESHRIGHT_MANAGECOMPUTERS) == 0)) return;
2063
2064
// Perform the switch, start by saving the node with the new meshid.
2065
const oldMeshId = node.meshid;
@@ -2139,146 +2101,103 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2101
case 'removedevices':
2102
{
2103
if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
2142
-
2104
for (i in command.nodeids) {
2144
- nodeid = command.nodeids[i];
2145
- if (common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
2146
- if ((nodeid.split('/').length != 3) || (nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
2147
-
2148
- // Get the device
2149
- db.Get(nodeid, function (err, nodes) {
2150
- if ((nodes == null) || (nodes.length != 1)) return;
2151
- var node = nodes[0];
2152
-
2153
- // Get the mesh for this device
2154
- mesh = parent.meshes[node.meshid];
2155
- if (mesh) {
2156
- // Check if this user has rights to do this
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
2161
- db.Remove('if' + node._id); // Remove interface information
2162
- db.Remove('nt' + node._id); // Remove notes
2163
- db.Remove('lc' + node._id); // Remove last connect time
2164
- db.Remove('si' + node._id); // Remove system information
2165
- db.RemoveSMBIOS(node._id); // Remove SMBios data
2166
- db.RemoveAllNodeEvents(node._id); // Remove all events for this node
2167
- db.removeAllPowerEventsForNode(node._id); // Remove all power events for this node
2168
- db.Get('ra' + obj.dbNodeKey, function (err, nodes) {
2169
- if ((nodes != null) && (nodes.length == 1)) { db.Remove('da' + nodes[0].daid); } // Remove diagnostic agent to real agent link
2170
- db.Remove('ra' + node._id); // Remove real agent to diagnostic agent link
2171
- });
2105
+ // Get the node and the rights for this node
2106
+ parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
2107
+ // Check we have the rights to delete this device
2108
+ if ((rights & MESHRIGHT_MANAGECOMPUTERS) == 0) return;
2109
+
2110
+ // Delete this node including network interface information, events and timeline
2111
+ db.Remove(node._id); // Remove node with that id
2112
+ db.Remove('if' + node._id); // Remove interface information
2113
+ db.Remove('nt' + node._id); // Remove notes
2114
+ db.Remove('lc' + node._id); // Remove last connect time
2115
+ db.Remove('si' + node._id); // Remove system information
2116
+ db.RemoveSMBIOS(node._id); // Remove SMBios data
2117
+ db.RemoveAllNodeEvents(node._id); // Remove all events for this node
2118
+ db.removeAllPowerEventsForNode(node._id); // Remove all power events for this node
2119
+ db.Get('ra' + obj.dbNodeKey, function (err, nodes) {
2120
+ if ((nodes != null) && (nodes.length == 1)) { db.Remove('da' + nodes[0].daid); } // Remove diagnostic agent to real agent link
2121
+ db.Remove('ra' + node._id); // Remove real agent to diagnostic agent link
2122
+ });
2123
2173
- // Event node deletion
2174
- var event = { etype: 'node', userid: user._id, username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from group ' + mesh.name, domain: domain.id };
2175
- // TODO: We can't use the changeStream for node delete because we will not know the meshid the device was in.
2176
- //if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to remove the node. Another event will come.
2177
- parent.parent.DispatchEvent(['*', node.meshid], obj, event);
2178
-
2179
- // Disconnect all connections if needed
2180
- var state = parent.parent.GetConnectivityState(nodeid);
2181
- if ((state != null) && (state.connectivity != null)) {
2182
- if ((state.connectivity & 1) != 0) { parent.wsagents[nodeid].close(); } // Disconnect mesh agent
2183
- if ((state.connectivity & 2) != 0) { parent.parent.mpsserver.close(parent.parent.mpsserver.ciraConnections[nodeid]); } // Disconnect CIRA connection
2184
- }
2124
+ // Event node deletion
2125
+ var event = { etype: 'node', userid: user._id, username: user.name, action: 'removenode', nodeid: node._id, msg: 'Removed device ' + node.name + ' from group ' + mesh.name, domain: domain.id };
2126
+ // TODO: We can't use the changeStream for node delete because we will not know the meshid the device was in.
2127
+ //if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to remove the node. Another event will come.
2128
+ parent.parent.DispatchEvent(['*', node.meshid], obj, event);
2129
+
2130
+ // Disconnect all connections if needed
2131
+ var state = parent.parent.GetConnectivityState(nodeid);
2132
+ if ((state != null) && (state.connectivity != null)) {
2133
+ if ((state.connectivity & 1) != 0) { parent.wsagents[nodeid].close(); } // Disconnect mesh agent
2134
+ if ((state.connectivity & 2) != 0) { parent.parent.mpsserver.close(parent.parent.mpsserver.ciraConnections[nodeid]); } // Disconnect CIRA connection
2135
}
2136
});
2137
}
2188
-
2138
break;
2139
}
2140
case 'wakedevices':
2141
{
2193
- if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
2142
// TODO: We can optimize this a lot.
2143
// - We should get a full list of all MAC's to wake first.
2144
// - We should try to only have one agent per subnet (using Gateway MAC) send a wake-on-lan.
2145
+ if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
2146
for (i in command.nodeids) {
2198
- nodeid = command.nodeids[i];
2199
- var wakeActions = 0;
2200
- if (common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
2201
- if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
2202
- // Get the device
2203
- db.Get(nodeid, function (err, nodes) {
2204
- if ((nodes == null) || (nodes.length != 1)) return;
2205
- var node = nodes[0];
2206
-
2207
- // Get the mesh for this device
2208
- mesh = parent.meshes[node.meshid];
2209
- if (mesh) {
2210
-
2211
- // Check if this user has rights to do this
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'); }
2216
-
2217
- // Get the device interface information
2218
- db.Get('if' + node._id, function (err, nodeifs) {
2219
- if ((nodeifs != null) && (nodeifs.length == 1)) {
2220
- var nodeif = nodeifs[0];
2221
- var macs = [];
2222
- for (var i in nodeif.netif) { if (nodeif.netif[i].mac) { macs.push(nodeif.netif[i].mac); } }
2223
-
2224
- // Have the server send a wake-on-lan packet (Will not work in WAN-only)
2225
- if (parent.parent.meshScanner != null) { parent.parent.meshScanner.wakeOnLan(macs); wakeActions++; }
2226
-
2227
- // Get the list of mesh this user as access to
2228
- var targetMeshes = [];
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) {
2233
- var agent = parent.wsagents[i];
2234
- if ((targetMeshes.indexOf(agent.dbMeshKey) >= 0) && (agent.authenticated == 2)) {
2235
- //console.log('Asking agent ' + agent.dbNodeKey + ' to wake ' + macs.join(','));
2236
- try { agent.send(JSON.stringify({ action: 'wakeonlan', macs: macs })); } catch (ex) { }
2237
- wakeActions++;
2238
- }
2239
- }
2240
- }
2241
- });
2242
-
2147
+ // Get the node and the rights for this node
2148
+ parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
2149
+ // Check we have the rights to delete this device
2150
+ if ((rights & MESHRIGHT_WAKEDEVICE) == 0) return;
2151
+
2152
+ // If this device is connected on MQTT, send a wake action.
2153
+ if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.publish(node._id, 'powerAction', 'wake'); }
2154
+
2155
+ // Get the device interface information
2156
+ db.Get('if' + node._id, function (err, nodeifs) {
2157
+ if ((nodeifs != null) && (nodeifs.length == 1)) {
2158
+ var macs = [], nodeif = nodeifs[0];
2159
+ for (var i in nodeif.netif) { if (nodeif.netif[i].mac) { macs.push(nodeif.netif[i].mac); } }
2160
+
2161
+ // Have the server send a wake-on-lan packet (Will not work in WAN-only)
2162
+ if (parent.parent.meshScanner != null) { parent.parent.meshScanner.wakeOnLan(macs); }
2163
+
2164
+ // Get the list of mesh this user as access to
2165
+ var targetMeshes = [];
2166
+ for (i in user.links) { targetMeshes.push(i); } // TODO: Include used security groups!!
2167
+
2168
+ // Go thru all the connected agents and send wake-on-lan on all the ones in the target mesh list
2169
+ for (i in parent.wsagents) {
2170
+ var agent = parent.wsagents[i];
2171
+ if ((targetMeshes.indexOf(agent.dbMeshKey) >= 0) && (agent.authenticated == 2)) {
2172
+ //console.log('Asking agent ' + agent.dbNodeKey + ' to wake ' + macs.join(','));
2173
+ try { agent.send(JSON.stringify({ action: 'wakeonlan', macs: macs })); } catch (ex) { }
2174
+ }
2175
}
2176
}
2177
});
2246
- }
2178
+ });
2179
// Confirm we may be doing something (TODO)
2180
try { ws.send(JSON.stringify({ action: 'wakedevices' })); } catch (ex) { }
2181
}
2250
-
2182
break;
2183
}
2184
case 'uninstallagent':
2185
{
2186
if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
2187
for (i in command.nodeids) {
2257
- nodeid = command.nodeids[i];
2258
- if (common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
2259
- if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
2260
- // Get the device
2261
- db.Get(nodeid, function (err, nodes) {
2262
- if ((nodes == null) || (nodes.length != 1)) return;
2263
- var node = nodes[0];
2264
-
2265
- // Get the mesh for this device
2266
- mesh = parent.meshes[node.meshid];
2267
- if (mesh) {
2268
- // Check if this user has rights to do this
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) {
2273
- //console.log('Asking agent ' + agent.dbNodeKey + ' to uninstall.');
2274
- try { agent.send(JSON.stringify({ action: 'uninstallagent' })); } catch (ex) { }
2275
- }
2276
- }
2277
- }
2278
- });
2279
- }
2188
+ // Get the node and the rights for this node
2189
+ parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
2190
+ // Check we have the rights to delete this device
2191
+ if ((rights & MESHRIGHT_UNINSTALL) == 0) return;
2192
+
2193
+ // Send uninstall command to connected agent
2194
+ const agent = parent.wsagents[node._id];
2195
+ if (agent != null) {
2196
+ //console.log('Asking agent ' + agent.dbNodeKey + ' to uninstall.');
2197
+ try { agent.send(JSON.stringify({ action: 'uninstallagent' })); } catch (ex) { }
2198
+ }
2199
+ });
2200
}
2281
-
2201
break;
2202
}
2203
case 'poweraction':
@@ -2286,34 +2205,21 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2205
if (common.validateArray(command.nodeids, 1) == false) break; // Check nodeid's
2206
if (common.validateInt(command.actiontype, 2, 4) == false) break; // Check actiontype
2207
for (i in command.nodeids) {
2289
- nodeid = command.nodeids[i];
2290
- var powerActions = 0;
2291
- if (common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
2292
- if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
2293
- // Get the device
2294
- db.Get(nodeid, function (err, nodes) {
2295
- if ((nodes == null) || (nodes.length != 1)) return;
2296
- var node = nodes[0];
2297
-
2298
- // Get the mesh for this device
2299
- mesh = parent.meshes[node.meshid];
2300
- if (mesh) {
2301
- // If this device is connected on MQTT, send a power action.
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
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) {
2309
- // Send the power command
2310
- try { agent.send(JSON.stringify({ action: 'poweraction', actiontype: command.actiontype })); } catch (ex) { }
2311
- powerActions++;
2312
- }
2313
- }
2314
- }
2315
- });
2316
- }
2208
+ // Get the node and the rights for this node
2209
+ parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
2210
+ // Check we have the rights to delete this device
2211
+ if ((rights & MESHRIGHT_REMOTECONTROL) == 0) return;
2212
+
2213
+ // If this device is connected on MQTT, send a power action.
2214
+ if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.publish(node._id, 'powerAction', ['', '', 'poweroff', 'reset', 'sleep'][command.actiontype]); }
2215
+
2216
+ // Get this device and send the power command
2217
+ const agent = parent.wsagents[node._id];
2218
+ if (agent != null) {
2219
+ try { agent.send(JSON.stringify({ action: 'poweraction', actiontype: command.actiontype })); } catch (ex) { }
2220
+ }
2221
+ });
2222
+
2223
// Confirm we may be doing something (TODO)
2224
try { ws.send(JSON.stringify({ action: 'poweraction' })); } catch (ex) { }
2225
}
@@ -2325,30 +2231,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2231
if (common.validateString(command.title, 1, 512) == false) break; // Check title
2232
if (common.validateString(command.msg, 1, 4096) == false) break; // Check message
2233
for (i in command.nodeids) {
2328
- nodeid = command.nodeids[i];
2329
- var powerActions = 0;
2330
- if (common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
2331
- if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
2332
- // Get the device
2333
- db.Get(nodeid, function (err, nodes) {
2334
- if ((nodes == null) || (nodes.length != 1)) return;
2335
- var node = nodes[0];
2336
-
2337
- // Get the mesh for this device
2338
- mesh = parent.meshes[node.meshid];
2339
- if (mesh) {
2340
- // Check if this user has rights to do this
2341
- if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_CHATNOTIFY) != 0) {
2342
- // Get this device
2343
- var agent = parent.wsagents[node._id];
2344
- if (agent != null) {
2345
- // Send the power command
2346
- try { agent.send(JSON.stringify({ action: 'toast', title: command.title, msg: command.msg, sessionid: ws.sessionId, username: user.name, userid: user._id })); } catch (ex) { }
2347
- }
2348
- }
2349
- }
2350
- });
2351
- }
2234
+ // Get the node and the rights for this node
2235
+ parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
2236
+ // Check we have the rights to delete this device
2237
+ if ((rights & MESHRIGHT_CHATNOTIFY) == 0) return;
2238
+
2239
+ // Get this device and send toast command
2240
+ const agent = parent.wsagents[node._id];
2241
+ if (agent != null) {
2242
+ try { agent.send(JSON.stringify({ action: 'toast', title: command.title, msg: command.msg, sessionid: ws.sessionId, username: user.name, userid: user._id })); } catch (ex) { }
2243
+ }
2244
+ });
2245
}
2246
break;
2247
}
@@ -2358,24 +2251,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2251
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2252
if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
2253
2361
- // Get the device
2362
- db.Get(command.nodeid, function (err, nodes) {
2363
- if ((nodes == null) || (nodes.length != 1)) { try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); } catch (ex) { } return; }
2364
- var node = nodes[0];
2365
-
2366
- // Get the mesh for this device
2367
- mesh = parent.meshes[node.meshid];
2368
- if (mesh) {
2369
- // Check if this user has rights to do this
2370
- if (parent.GetMeshRights(user, mesh) == 0) { try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); } catch (ex) { } return; }
2254
+ // Get the node and the rights for this node
2255
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2256
+ if (visible == false) return;
2257
2372
- // Get network information about this node
2373
- db.Get('if' + command.nodeid, function (err, netinfos) {
2374
- if ((netinfos == null) || (netinfos.length != 1)) { try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, netif: null })); } catch (ex) { } return; }
2375
- var netinfo = netinfos[0];
2376
- try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: command.nodeid, updateTime: netinfo.updateTime, netif: netinfo.netif })); } catch (ex) { }
2377
- });
2378
- }
2258
+ // Get network information about this node
2259
+ db.Get('if' + node._id, function (err, netinfos) {
2260
+ if ((netinfos == null) || (netinfos.length != 1)) { try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: node._id, netif: null })); } catch (ex) { } return; }
2261
+ var netinfo = netinfos[0];
2262
+ try { ws.send(JSON.stringify({ action: 'getnetworkinfo', nodeid: node._id, updateTime: netinfo.updateTime, netif: netinfo.netif })); } catch (ex) { }
2263
+ });
2264
});
2265
break;
2266
}
@@ -2383,106 +2268,89 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2268
{
2269
// Argument validation
2270
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2386
- if ((command.nodeid.split('/').length != 3) || (command.nodeid.split('/')[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
2271
if ((command.userloc) && (command.userloc.length != 2) && (command.userloc.length != 0)) return;
2272
2389
- // Change the device
2390
- db.Get(command.nodeid, function (err, nodes) {
2391
- if ((nodes == null) || (nodes.length != 1)) return;
2392
- var node = nodes[0];
2273
+ // Get the node and the rights for this node
2274
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2275
+ if ((rights & MESHRIGHT_MANAGECOMPUTERS) == 0) return;
2276
+ var mesh = parent.meshes[node.meshid];
2277
2394
- // Get the mesh for this device
2395
- mesh = parent.meshes[node.meshid];
2396
- if (mesh) {
2397
- // Check if this user has rights to do this
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 };
2402
- change = 0;
2403
- event.msg = ": ";
2404
-
2405
- // If we are in WAN-only mode, host is not used
2406
- if ((args.wanonly == true) && (command.host)) { delete command.host; }
2407
-
2408
- // Look for a change
2409
- if (command.icon && (command.icon != node.icon)) { change = 1; node.icon = command.icon; changes.push('icon'); }
2410
- if (command.name && (command.name != node.name)) { change = 1; node.name = command.name; changes.push('name'); }
2411
- if (command.host && (command.host != node.host)) { change = 1; node.host = command.host; changes.push('host'); }
2412
- if (domain.geolocation && command.userloc && ((node.userloc == null) || (command.userloc[0] != node.userloc[0]) || (command.userloc[1] != node.userloc[1]))) {
2413
- change = 1;
2414
- if ((command.userloc.length == 0) && (node.userloc)) {
2415
- delete node.userloc;
2416
- changes.push('location removed');
2417
- } else {
2418
- command.userloc.push((Math.floor((new Date()) / 1000)));
2419
- node.userloc = command.userloc.join(',');
2420
- changes.push('location');
2421
- }
2422
- }
2423
- if (command.desc != null && (command.desc != node.desc)) { change = 1; node.desc = command.desc; changes.push('description'); }
2424
- if (command.intelamt != null) {
2425
- if ((command.intelamt.user != null) && (command.intelamt.pass != undefined) && ((command.intelamt.user != node.intelamt.user) || (command.intelamt.pass != node.intelamt.pass))) { change = 1; node.intelamt.user = command.intelamt.user; node.intelamt.pass = command.intelamt.pass; changes.push('Intel AMT credentials'); }
2426
- if (command.intelamt.tls && (command.intelamt.tls != node.intelamt.tls)) { change = 1; node.intelamt.tls = command.intelamt.tls; changes.push('Intel AMT TLS'); }
2278
+ // Ready the node change event
2279
+ var changes = [], event = { etype: 'node', userid: user._id, username: user.name, action: 'changenode', nodeid: node._id, domain: domain.id };
2280
+ change = 0;
2281
+ event.msg = ': ';
2282
+
2283
+ // If we are in WAN-only mode, host is not used
2284
+ if ((args.wanonly == true) && (command.host)) { delete command.host; }
2285
+
2286
+ // Look for a change
2287
+ if (command.icon && (command.icon != node.icon)) { change = 1; node.icon = command.icon; changes.push('icon'); }
2288
+ if (command.name && (command.name != node.name)) { change = 1; node.name = command.name; changes.push('name'); }
2289
+ if (command.host && (command.host != node.host)) { change = 1; node.host = command.host; changes.push('host'); }
2290
+ if (domain.geolocation && command.userloc && ((node.userloc == null) || (command.userloc[0] != node.userloc[0]) || (command.userloc[1] != node.userloc[1]))) {
2291
+ change = 1;
2292
+ if ((command.userloc.length == 0) && (node.userloc)) {
2293
+ delete node.userloc;
2294
+ changes.push('location removed');
2295
+ } else {
2296
+ command.userloc.push((Math.floor((new Date()) / 1000)));
2297
+ node.userloc = command.userloc.join(',');
2298
+ changes.push('location');
2299
}
2428
- if (command.tags) { // Node grouping tag, this is a array of strings that can't be empty and can't contain a comma
2429
- var ok = true, group2 = [];
2430
- if (common.validateString(command.tags, 0, 4096) == true) { command.tags = command.tags.split(','); }
2431
- for (var i in command.tags) { var tname = command.tags[i].trim(); if ((tname.length > 0) && (tname.length < 64) && (group2.indexOf(tname) == -1)) { group2.push(tname); } }
2432
- group2.sort();
2433
- if (node.tags != group2) { node.tags = group2; change = 1; }
2434
- } else if ((command.tags === '') && node.tags) { delete node.tags; change = 1; }
2300
+ }
2301
+ if (command.desc != null && (command.desc != node.desc)) { change = 1; node.desc = command.desc; changes.push('description'); }
2302
+ if (command.intelamt != null) {
2303
+ if ((command.intelamt.user != null) && (command.intelamt.pass != undefined) && ((command.intelamt.user != node.intelamt.user) || (command.intelamt.pass != node.intelamt.pass))) { change = 1; node.intelamt.user = command.intelamt.user; node.intelamt.pass = command.intelamt.pass; changes.push('Intel AMT credentials'); }
2304
+ if (command.intelamt.tls && (command.intelamt.tls != node.intelamt.tls)) { change = 1; node.intelamt.tls = command.intelamt.tls; changes.push('Intel AMT TLS'); }
2305
+ }
2306
+ if (command.tags) { // Node grouping tag, this is a array of strings that can't be empty and can't contain a comma
2307
+ var ok = true, group2 = [];
2308
+ if (common.validateString(command.tags, 0, 4096) == true) { command.tags = command.tags.split(','); }
2309
+ for (var i in command.tags) { var tname = command.tags[i].trim(); if ((tname.length > 0) && (tname.length < 64) && (group2.indexOf(tname) == -1)) { group2.push(tname); } }
2310
+ group2.sort();
2311
+ if (node.tags != group2) { node.tags = group2; change = 1; }
2312
+ } else if ((command.tags === '') && node.tags) { delete node.tags; change = 1; }
2313
+
2314
+ if (change == 1) {
2315
+ // Save the node
2316
+ db.Set(node);
2317
2436
- if (change == 1) {
2437
- // Save the node
2438
- db.Set(node);
2439
-
2440
- // Event the node change. Only do this if the database will not do it.
2441
- event.msg = 'Changed device ' + node.name + ' from group ' + mesh.name + ': ' + changes.join(', ');
2442
- event.node = parent.CloneSafeNode(node);
2443
- if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
2444
- parent.parent.DispatchEvent(['*', node.meshid, user._id], obj, event);
2445
- }
2318
+ // Event the node change. Only do this if the database will not do it.
2319
+ event.msg = 'Changed device ' + node.name + ' from group ' + mesh.name + ': ' + changes.join(', ');
2320
+ event.node = parent.CloneSafeNode(node);
2321
+ if (db.changeStream) { event.noact = 1; } // If DB change stream is active, don't use this event to change the node. Another event will come.
2322
+ parent.parent.DispatchEvent(['*', node.meshid, user._id], obj, event);
2323
}
2324
});
2325
break;
2326
}
2327
case 'uploadagentcore':
2328
{
2452
- if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2329
if (common.validateString(command.type, 1, 40) == false) break; // Check path
2330
2455
- // Change the device
2456
- db.Get(command.nodeid, function (err, nodes) {
2457
- if ((nodes == null) || (nodes.length != 1)) return;
2458
- var node = nodes[0];
2459
-
2460
- // Get the mesh for this device
2461
- mesh = parent.meshes[node.meshid];
2462
- if (mesh) {
2463
- // Check if this user has rights to do this
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
2468
- parent.parent.updateMeshCore(function () { parent.sendMeshAgentCore(user, domain, command.nodeid, 'default'); });
2469
- } else if (command.type == 'clear') {
2470
- // Clear the mesh agent core on the mesh agent
2471
- parent.sendMeshAgentCore(user, domain, command.nodeid, 'clear');
2472
- } else if (command.type == 'recovery') {
2473
- // Send the recovery core to the agent
2474
- parent.sendMeshAgentCore(user, domain, command.nodeid, 'recovery');
2475
- } else if ((command.type == 'custom') && (common.validateString(command.path, 1, 2048) == true)) {
2476
- // Send a mesh agent core to the mesh agent
2477
- var file = parent.getServerFilePath(user, domain, command.path);
2478
- if (file != null) {
2479
- fs.readFile(file.fullpath, 'utf8', function (err, data) {
2480
- if (err != null) {
2481
- data = common.IntToStr(0) + data; // Add the 4 bytes encoding type & flags (Set to 0 for raw)
2482
- parent.sendMeshAgentCore(user, domain, command.nodeid, 'custom', data);
2483
- }
2484
- });
2485
- }
2331
+ // Get the node and the rights for this node
2332
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2333
+ if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != 0xFFFFFFFF))) return;
2334
+
2335
+ if (command.type == 'default') {
2336
+ // Send the default core to the agent
2337
+ parent.parent.updateMeshCore(function () { parent.sendMeshAgentCore(user, domain, node._id, 'default'); });
2338
+ } else if (command.type == 'clear') {
2339
+ // Clear the mesh agent core on the mesh agent
2340
+ parent.sendMeshAgentCore(user, domain, node._id, 'clear');
2341
+ } else if (command.type == 'recovery') {
2342
+ // Send the recovery core to the agent
2343
+ parent.sendMeshAgentCore(user, domain, node._id, 'recovery');
2344
+ } else if ((command.type == 'custom') && (common.validateString(command.path, 1, 2048) == true)) {
2345
+ // Send a mesh agent core to the mesh agent
2346
+ var file = parent.getServerFilePath(user, domain, command.path);
2347
+ if (file != null) {
2348
+ fs.readFile(file.fullpath, 'utf8', function (err, data) {
2349
+ if (err != null) {
2350
+ data = common.IntToStr(0) + data; // Add the 4 bytes encoding type & flags (Set to 0 for raw)
2351
+ parent.sendMeshAgentCore(user, domain, node._id, 'custom', data);
2352
+ }
2353
+ });
2354
}
2355
}
2356
});
@@ -2490,23 +2358,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2358
}
2359
case 'agentdisconnect':
2360
{
2493
- if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2361
if (common.validateInt(command.disconnectMode) == false) return; // Check disconnect mode
2362
2496
- // Change the device
2497
- db.Get(command.nodeid, function (err, nodes) {
2498
- if ((nodes == null) || (nodes.length != 1)) return;
2499
- var node = nodes[0];
2363
+ // Get the node and the rights for this node
2364
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2365
+ if ((node == null) || (((rights & MESHRIGHT_AGENTCONSOLE) == 0) && (user.siteadmin != 0xFFFFFFFF))) return;
2366
2501
- // Get the mesh for this device
2502
- mesh = parent.meshes[node.meshid];
2503
- if (mesh) {
2504
- // Check if this user has rights to do this
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);
2509
- }
2367
+ // Force mesh agent disconnection
2368
+ parent.forceMeshAgentDisconnect(user, domain, node._id, command.disconnectMode);
2369
});
2370
break;
2371
}
@@ -2552,7 +2411,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2411
mesh = parent.meshes[command.meshid];
2412
if (mesh == null) { err = 'Unknown device group'; } // Check if the group exists
2413
else if (mesh.mtype != 2) { err = 'Invalid group type'; } // Check if this is the correct group type
2555
- else if (parent.GetMeshRights(user, mesh) == 0) { err = 'Not allowed'; } // Check if this user has rights to do this
2414
+ else if (parent.IsMeshViewable(user, mesh) == false) { err = 'Not allowed'; } // Check if this user has rights to do this
2415
}
2416
}
2417
} catch (ex) { err = 'Validation exception: ' + ex; }
@@ -2574,24 +2433,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2433
{
2434
// Argument validation
2435
if (common.validateString(command.msg, 1, 4096) == false) break; // Check event
2577
- if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2578
- var splitid = command.nodeid.split('/');
2579
- if ((splitid.length != 3) || (splitid[1] != domain.id)) return; // Invalid domain, operation only valid for current domain
2580
- var idtype = splitid[0];
2581
- if ((idtype != 'node')) return;
2436
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)) {
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 };
2590
- parent.parent.DispatchEvent(targets, obj, event);
2591
- }
2592
- }
2593
- });
2437
+ // Get the node and the rights for this node
2438
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2439
+ if (rights == 0) return;
2440
2441
+ // Add an event for this device
2442
+ var targets = ['*', 'server-users', user._id, nodes[0].meshid];
2443
+ var event = { etype: 'node', userid: user._id, username: user.name, nodeid: nodes[0]._id, action: 'manual', msg: decodeURIComponent(command.msg), domain: domain.id };
2444
+ parent.parent.DispatchEvent(targets, obj, event);
2445
+ });
2446
break;
2447
}
2448
case 'setNotes':
@@ -2604,16 +2455,14 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2455
if ((idtype != 'user') && (idtype != 'mesh') && (idtype != 'node')) return;
2456
2457
if (idtype == 'node') {
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)) {
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
2614
- } else {
2615
- db.Set({ _id: 'nt' + command.id, type: 'note', value: command.notes }); // Set the note for this node
2616
- }
2458
+ // Get the node and the rights for this node
2459
+ parent.GetNodeWithRights(domain, user, command.id, function (node, rights, visible) {
2460
+ if ((rights & MESHRIGHT_SETNOTES) != 0) {
2461
+ // Set the id's notes
2462
+ if (common.validateString(command.notes, 1) == false) {
2463
+ db.Remove('nt' + node._id); // Delete the note for this node
2464
+ } else {
2465
+ db.Set({ _id: 'nt' + node._id, type: 'note', value: command.notes }); // Set the note for this node
2466
}
2467
}
2468
});
@@ -2893,44 +2742,26 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2742
case 'getClip': {
2743
if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2744
2896
- // Get the device
2897
- db.Get(command.nodeid, function (err, nodes) {
2898
- if ((nodes == null) || (nodes.length != 1)) return;
2899
- var node = nodes[0];
2900
-
2901
- // Get the mesh for this device
2902
- mesh = parent.meshes[node.meshid];
2903
- if (mesh) {
2904
- // Check if this user has "remote" rights to do this
2905
- var meshrights = parent.GetMeshRights(user, mesh);
2906
- if ((meshrights & MESHRIGHT_AGENTCONSOLE) == 0) return;
2745
+ // Get the node and the rights for this node
2746
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2747
+ if ((rights & MESHRIGHT_AGENTCONSOLE) == 0) return;
2748
2908
- // Ask for clipboard data from agent
2909
- var agent = parent.wsagents[node._id];
2910
- if (agent != null) { try { agent.send(JSON.stringify({ action: 'getClip' })); } catch (ex) { } }
2911
- }
2749
+ // Ask for clipboard data from agent
2750
+ var agent = parent.wsagents[node._id];
2751
+ if (agent != null) { try { agent.send(JSON.stringify({ action: 'getClip' })); } catch (ex) { } }
2752
});
2753
break;
2754
}
2755
case 'setClip': {
2916
- if (common.validateString(command.nodeid, 1, 1024) == false) break; // Check nodeid
2756
if (common.validateString(command.data, 1, 65535) == false) break; // Check
2757
2919
- // Get the device
2920
- db.Get(command.nodeid, function (err, nodes) {
2921
- if ((nodes == null) || (nodes.length != 1)) return;
2922
- var node = nodes[0];
2758
+ // Get the node and the rights for this node
2759
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2760
+ if ((rights & MESHRIGHT_AGENTCONSOLE) == 0) return;
2761
2924
- // Get the mesh for this device
2925
- mesh = parent.meshes[node.meshid];
2926
- if (mesh) {
2927
- // Check if this user has "remote" rights to do this
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];
2932
- if (agent != null) { try { agent.send(JSON.stringify({ action: 'setClip', data: command.data })); } catch (ex) { } }
2933
- }
2762
+ // Send clipboard data to the agent
2763
+ var agent = parent.wsagents[node._id];
2764
+ if (agent != null) { try { agent.send(JSON.stringify({ action: 'setClip', data: command.data })); } catch (ex) { } }
2765
});
2766
break;
2767
}
@@ -2951,25 +2782,17 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2782
if ((idtype != 'user') && (idtype != 'mesh') && (idtype != 'node')) return;
2783
2784
if (idtype == 'node') {
2954
- // Get the device
2955
- db.Get(command.id, function (err, nodes) {
2956
- if ((nodes == null) || (nodes.length != 1)) return;
2957
- var node = nodes[0];
2785
+ // Get the node and the rights for this node
2786
+ parent.GetNodeWithRights(domain, user, command.id, function (node, rights, visible) {
2787
+ if (visible == false) return;
2788
2959
- // Get the mesh for this device
2960
- mesh = parent.meshes[node.meshid];
2961
- if (mesh) {
2962
- // Check if this user has rights to do this
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) {
2967
- try {
2968
- if ((notes == null) || (notes.length != 1)) { ws.send(JSON.stringify({ action: 'getNotes', id: command.id, notes: null })); return; }
2969
- ws.send(JSON.stringify({ action: 'getNotes', id: command.id, notes: notes[0].value }));
2970
- } catch (ex) { }
2971
- });
2972
- }
2789
+ // Get the notes about this node
2790
+ db.Get('nt' + command.id, function (err, notes) {
2791
+ try {
2792
+ if ((notes == null) || (notes.length != 1)) { ws.send(JSON.stringify({ action: 'getNotes', id: command.id, notes: null })); return; }
2793
+ ws.send(JSON.stringify({ action: 'getNotes', id: command.id, notes: notes[0].value }));
2794
+ } catch (ex) { }
2795
+ });
2796
});
2797
} else if (idtype == 'mesh') {
2798
// Get the mesh for this device
@@ -3037,6 +2860,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2860
break;
2861
}
2862
case 'sendmqttmsg': {
2863
+ if (parent.parent.mqttbroker == null) { err = 'MQTT not supported on this server'; }; // MQTT not available
2864
if (common.validateArray(command.nodeids, 1) == false) { err = 'Invalid nodeids'; }; // Check nodeid's
2865
if (common.validateString(command.topic, 1, 64) == false) { err = 'Invalid topic'; } // Check the topic
2866
if (common.validateString(command.msg, 1, 4096) == false) { err = 'Invalid msg'; } // Check the message
@@ -3047,30 +2871,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2871
break;
2872
}
2873
3050
- // TODO: We can optimize this a lot.
3051
- // - We should get a full list of all MAC's to wake first.
3052
- // - We should try to only have one agent per subnet (using Gateway MAC) send a wake-on-lan.
2874
+ // Send the MQTT message
2875
for (i in command.nodeids) {
3054
- nodeid = command.nodeids[i];
3055
- var wakeActions = 0;
3056
- if (common.validateString(nodeid, 1, 1024) == false) break; // Check nodeid
3057
- if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
3058
- // Get the device
3059
- db.Get(nodeid, function (err, nodes) {
3060
- if ((nodes == null) || (nodes.length != 1)) return;
3061
- var node = nodes[0];
3062
-
3063
- // Get the mesh for this device
3064
- mesh = parent.meshes[node.meshid];
3065
- if (mesh) {
3066
- // Check if this user has rights to do this
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
- }
3071
- }
3072
- });
3073
- }
2876
+ // Get the node and the rights for this node
2877
+ parent.GetNodeWithRights(domain, user, command.nodeids[i], function (node, rights, visible) {
2878
+ // If this device is connected on MQTT, send a wake action.
2879
+ if (rights != 0) { parent.parent.mqttbroker.publish(node._id, command.topic, command.msg); }
2880
+ });
2881
}
2882
2883
break;
@@ -3083,43 +2890,33 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2890
// Handle any errors
2891
if (err != null) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'getmqttlogin', responseid: command.responseid, result: err })); } catch (ex) { } } break; }
2892
3086
- var nodeid = command.nodeid;
3087
- if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
3088
- // Get the device
3089
- db.Get(nodeid, function (err, nodes) {
3090
- if ((nodes == null) || (nodes.length != 1)) { if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'getmqttlogin', responseid: command.responseid, result: 'Invalid node id' })); } catch (ex) { } return; } }
3091
- var node = nodes[0];
3092
-
3093
- // Get the device group for this node
3094
- var mesh = parent.meshes[node.meshid];
3095
- if (mesh) {
3096
- // Check if this user has rights to do this
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);
3101
-
3102
- // Add MPS URL
3103
- if (parent.parent.mpsserver != null) {
3104
- r.mpsCertHashSha384 = parent.parent.certificateOperations.getCertHash(parent.parent.mpsserver.certificates.mps.cert);
3105
- r.mpsCertHashSha1 = parent.parent.certificateOperations.getCertHashSha1(parent.parent.mpsserver.certificates.mps.cert);
3106
- r.mpsUrl = 'mqtts://' + serverName + ':' + ((args.mpsaliasport != null) ? args.mpsaliasport : args.mpsport) + '/';
3107
- }
3108
-
3109
- // Add WS URL
3110
- var xdomain = (domain.dns == null) ? domain.id : '';
3111
- if (xdomain != '') xdomain += "/";
3112
- var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
3113
- r.wsUrl = "ws" + (args.notls ? '' : 's') + "://" + serverName + ":" + httpsPort + "/" + xdomain + "mqtt.ashx";
3114
- r.wsTrustedCert = parent.isTrustedCert(domain);
3115
-
3116
- try { ws.send(JSON.stringify(r)); } catch (ex) { }
3117
- } else {
3118
- if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'getmqttlogin', responseid: command.responseid, result: 'Unable to perform this operation' })); } catch (ex) { } }
3119
- }
3120
- }
3121
- });
3122
- }
2893
+ // Get the node and the rights for this node
2894
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2895
+ // Check if this user has rights to do this
2896
+ if (rights == 0xFFFFFFFF) {
2897
+ var token = parent.parent.mqttbroker.generateLogin(node.meshid, node._id);
2898
+ var r = { action: 'getmqttlogin', responseid: command.responseid, nodeid: node._id, user: token.user, pass: token.pass };
2899
+ const serverName = parent.getWebServerName(domain);
2900
+
2901
+ // Add MPS URL
2902
+ if (parent.parent.mpsserver != null) {
2903
+ r.mpsCertHashSha384 = parent.parent.certificateOperations.getCertHash(parent.parent.mpsserver.certificates.mps.cert);
2904
+ r.mpsCertHashSha1 = parent.parent.certificateOperations.getCertHashSha1(parent.parent.mpsserver.certificates.mps.cert);
2905
+ r.mpsUrl = 'mqtts://' + serverName + ':' + ((args.mpsaliasport != null) ? args.mpsaliasport : args.mpsport) + '/';
2906
+ }
2907
+
2908
+ // Add WS URL
2909
+ var xdomain = (domain.dns == null) ? domain.id : '';
2910
+ if (xdomain != '') xdomain += '/';
2911
+ var httpsPort = ((args.aliasport == null) ? args.port : args.aliasport); // Use HTTPS alias port is specified
2912
+ r.wsUrl = 'ws' + (args.notls ? '' : 's') + '://' + serverName + ':' + httpsPort + '/' + xdomain + 'mqtt.ashx';
2913
+ r.wsTrustedCert = parent.isTrustedCert(domain);
2914
+
2915
+ try { ws.send(JSON.stringify(r)); } catch (ex) { }
2916
+ } else {
2917
+ if (command.responseid != null) { try { ws.send(JSON.stringify({ action: 'getmqttlogin', responseid: command.responseid, result: 'Unable to perform this operation' })); } catch (ex) { } }
2918
+ }
2919
+ });
2920
break;
2921
}
2922
case 'amt': {
@@ -3136,23 +2933,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2933
} else if (command.mode == 3) {
2934
if (parent.parent.apfserver.apfConnections[command.nodeid] == null) break;
2935
}
3139
- var nodeid = command.nodeid;
3140
- if ((nodeid.split('/').length == 3) && (nodeid.split('/')[1] == domain.id)) { // Validate the domain, operation only valid for current domain
3141
- // Get the device
3142
- db.Get(nodeid, function (err, nodes) {
3143
- if ((nodes == null) || (nodes.length != 1)) return;
3144
- var node = nodes[0];
2936
3146
- // Get the mesh for this device
3147
- var mesh = parent.meshes[node.meshid];
3148
- if (mesh) {
3149
- // Check if this user has rights to do this
3150
- if ((parent.GetMeshRights(user, mesh) & MESHRIGHT_REMOTECONTROL) != 0) { // "Remote Control permission"
3151
- handleAmtCommand(command, node);
3152
- }
3153
- }
3154
- });
3155
- }
2937
+ // Get the node and the rights for this node
2938
+ parent.GetNodeWithRights(domain, user, command.nodeid, function (node, rights, visible) {
2939
+ if ((rights & MESHRIGHT_REMOTECONTROL) == 0) return;
2940
+ handleAmtCommand(command, node);
2941
+ });
2942
break;
2943
}
2944
case 'distributeCore': {
@@ -3304,15 +3090,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3090
3091
// Read all files recursively
3092
try {
3307
- files.filetree.f[user._id].f = readFilesRec(parent.path.join(parent.filespath, domainx + "/user-" + usersplit[2]));
3093
+ files.filetree.f[user._id].f = readFilesRec(parent.path.join(parent.filespath, domainx + '/user-' + usersplit[2]));
3094
} catch (e) {
3095
// TODO: We may want to fake this file structure until it's needed.
3096
// Got an error, try to create all the folders and try again...
3097
try { fs.mkdirSync(parent.filespath); } catch (e) { }
3098
try { fs.mkdirSync(parent.path.join(parent.filespath, domainx)); } catch (e) { }
3313
- try { fs.mkdirSync(parent.path.join(parent.filespath, domainx + "/user-" + usersplit[2])); } catch (e) { }
3314
- try { fs.mkdirSync(parent.path.join(parent.filespath, domainx + "/user-" + usersplit[2] + "/Public")); } catch (e) { }
3315
- try { files.filetree.f[user._id].f = readFilesRec(parent.path.join(parent.filespath, domainx + "/user-" + usersplit[2])); } catch (e) { }
3099
+ try { fs.mkdirSync(parent.path.join(parent.filespath, domainx + '/user-' + usersplit[2])); } catch (e) { }
3100
+ try { fs.mkdirSync(parent.path.join(parent.filespath, domainx + '/user-' + usersplit[2] + '/Public')); } catch (e) { }
3101
+ try { files.filetree.f[user._id].f = readFilesRec(parent.path.join(parent.filespath, domainx + '/user-' + usersplit[2])); } catch (e) { }
3102
}
3103
3104
// Add files for each mesh // TODO: Get all meshes including groups!!
@@ -3326,7 +3112,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3112
3113
// Read all files recursively
3114
try {
3329
- files.filetree.f[mesh._id].f = readFilesRec(parent.path.join(parent.filespath, domainx + "/mesh-" + meshsplit[2]));
3115
+ files.filetree.f[mesh._id].f = readFilesRec(parent.path.join(parent.filespath, domainx + '/mesh-' + meshsplit[2]));
3116
} catch (e) {
3117
files.filetree.f[mesh._id].f = {}; // Got an error, return empty folder. We will create the folder only when needed.
3118
}
@@ -3338,7 +3124,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3124
try { ws.send(JSON.stringify(files)); } catch (ex) { }
3125
}
3126
3341
- 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; }
3127
+ 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; }
3128
//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; }
3129
3130
// Split a string taking into account the quoats. Used for command line parsing
@@ -3388,13 +3174,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3174
node.intelamt.tls, tlsoptions, parent.parent, cmd.mode);
3175
var amt = new Amt(wsman);
3176
switch (cmd.command) {
3391
- case "Get-GeneralSettings": {
3392
- amt.Get("AMT_GeneralSettings", function (obj, name, response, status) {
3177
+ case 'Get-GeneralSettings': {
3178
+ amt.Get('AMT_GeneralSettings', function (obj, name, response, status) {
3179
if (status == 200) {
3180
var resp = { action: 'amt', nodeid: cmd.nodeid, command: 'Get-GeneralSettings', value: response.Body }
3181
ws.send(JSON.stringify(resp));
3182
} else {
3397
- ws.send(JSON.stringify({ "error": error }));
3183
+ ws.send(JSON.stringify({ 'error': error }));
3184
}
3185
});
3186
break;
mpsserver.js
+29
-29
@@ -11,7 +11,7 @@
11
/*jshint strict:false */
12
/*jshint -W097 */
13
/*jshint esversion: 6 */
14
-"use strict";
14
+'use strict';
15
16
// Construct a Intel AMT MPS server object
17
module.exports.CreateMpsServer = function (parent, db, args, certificates) {
@@ -24,9 +24,9 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
24
var tlsSessionStore = {}; // Store TLS session information for quick resume.
25
var tlsSessionStoreCount = 0; // Number of cached TLS session information in store.
26
const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
27
- const common = require("./common.js");
28
- const net = require("net");
29
- const tls = require("tls");
27
+ const common = require('./common.js');
28
+ const net = require('net');
29
+ const tls = require('tls');
30
const MAX_IDLE = 90000; // 90 seconds max idle time, higher than the typical KEEP-ALIVE periode of 60 seconds
31
32
if (obj.args.mpstlsoffload) {
@@ -42,9 +42,9 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
42
43
obj.server.listen(args.mpsport, function () { console.log("MeshCentral Intel(R) AMT server running on " + certificates.AmtMpsName + ":" + args.mpsport + ((args.mpsaliasport != null) ? (", alias port " + args.mpsaliasport) : "") + "."); }).on("error", function (err) { console.error("ERROR: MeshCentral Intel(R) AMT server port " + args.mpsport + " is not available."); if (args.exactports) { process.exit(); } });
44
obj.server.on('tlsClientError', function (err, tlssocket) { if (args.mpsdebug) { var remoteAddress = tlssocket.remoteAddress; if (tlssocket.remoteFamily == 'IPv6') { remoteAddress = '[' + remoteAddress + ']'; } console.log('MPS:Invalid TLS connection from ' + remoteAddress + ':' + tlssocket.remotePort + '.'); } });
45
- obj.parent.updateServerState("mps-port", args.mpsport);
46
- obj.parent.updateServerState("mps-name", certificates.AmtMpsName);
47
- if (args.mpsaliasport != null) { obj.parent.updateServerState("mps-alias-port", args.mpsaliasport); }
45
+ obj.parent.updateServerState('mps-port', args.mpsport);
46
+ obj.parent.updateServerState('mps-name', certificates.AmtMpsName);
47
+ if (args.mpsaliasport != null) { obj.parent.updateServerState('mps-alias-port', args.mpsaliasport); }
48
49
const APFProtocol = {
50
UNKNOWN: 0,
@@ -202,47 +202,47 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
202
function onConnection(socket) {
203
connectionCount++;
204
if (obj.args.mpstlsoffload) {
205
- socket.tag = { first: true, clientCert: null, accumulator: "", activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
205
+ socket.tag = { first: true, clientCert: null, accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
206
} else {
207
- socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: "", activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
207
+ socket.tag = { first: true, clientCert: socket.getPeerCertificate(true), accumulator: '', activetunnels: 0, boundPorts: [], socket: socket, host: null, nextchannelid: 4, channels: {}, nextsourceport: 0 };
208
}
209
- socket.setEncoding("binary");
209
+ socket.setEncoding('binary');
210
parent.debug('mps', "New CIRA connection");
211
212
// Setup the CIRA keep alive timer
213
socket.setTimeout(MAX_IDLE);
214
- socket.on("timeout", () => { ciraTimeoutCount++; parent.debug('mps', "CIRA timeout, disconnecting."); try { socket.end(); } catch (e) { } });
214
+ socket.on('timeout', () => { ciraTimeoutCount++; parent.debug('mps', "CIRA timeout, disconnecting."); try { socket.end(); } catch (e) { } });
215
216
- socket.addListener("data", function (data) {
217
- if (args.mpsdebug) { var buf = Buffer.from(data, "binary"); console.log("MPS <-- (" + buf.length + "):" + buf.toString('hex')); } // Print out received bytes
216
+ socket.addListener('data', function (data) {
217
+ if (args.mpsdebug) { var buf = Buffer.from(data, 'binary'); console.log("MPS <-- (" + buf.length + "):" + buf.toString('hex')); } // Print out received bytes
218
socket.tag.accumulator += data;
219
220
// Detect if this is an HTTPS request, if it is, return a simple answer and disconnect. This is useful for debugging access to the MPS port.
221
if (socket.tag.first == true) {
222
if (socket.tag.accumulator.length < 3) return;
223
//if (!socket.tag.clientCert.subject) { console.log("MPS Connection, no client cert: " + socket.remoteAddress); socket.write('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nMeshCentral2 MPS server.\r\nNo client certificate given.'); socket.end(); return; }
224
- if (socket.tag.accumulator.substring(0, 3) == "GET") { if (args.mpsdebug) { console.log("MPS Connection, HTTP GET detected: " + socket.remoteAddress); } socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset=\"UTF-8\"></head><body>MeshCentral2 MPS server.<br />Intel® AMT computers should connect here.</body></html>"); socket.end(); return; }
224
+ if (socket.tag.accumulator.substring(0, 3) == 'GET') { if (args.mpsdebug) { console.log("MPS Connection, HTTP GET detected: " + socket.remoteAddress); } socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><meta charset=\"UTF-8\"></head><body>MeshCentral2 MPS server.<br />Intel® AMT computers should connect here.</body></html>"); socket.end(); return; }
225
226
// If the MQTT broker is active, look for inbound MQTT connections
227
if (parent.mqttbroker != null) {
228
- var chunk = Buffer.from(socket.tag.accumulator, "binary");
228
+ var chunk = Buffer.from(socket.tag.accumulator, 'binary');
229
var packet_len = 0;
230
if (chunk.readUInt8(0) == 16) { packet_len = getMQTTPacketLength(chunk); }
231
if (chunk.readUInt8(0) == 16 && (socket.tag.accumulator.length < packet_len)) return; // Minimum MQTT detection
232
233
// check if it is MQTT, need more initial packet to probe
234
- if (chunk.readUInt8(0) == 16 && ((chunk.slice(4, 8).toString() === "MQTT") || (chunk.slice(5, 9).toString() === "MQTT")
235
- || (chunk.slice(6, 10).toString() === "MQTT") || (chunk.slice(7, 11).toString() === "MQTT"))) {
236
- parent.debug("mps", "MQTT connection detected.");
234
+ if (chunk.readUInt8(0) == 16 && ((chunk.slice(4, 8).toString() === 'MQTT') || (chunk.slice(5, 9).toString() === 'MQTT')
235
+ || (chunk.slice(6, 10).toString() === 'MQTT') || (chunk.slice(7, 11).toString() === 'MQTT'))) {
236
+ parent.debug('mps', "MQTT connection detected.");
237
socket.removeAllListeners("data");
238
socket.removeAllListeners("close");
239
socket.setNoDelay(true);
240
socket.serialtunnel = SerialTunnel();
241
socket.serialtunnel.xtransport = 'mps';
242
socket.serialtunnel.xip = socket.remoteAddress;
243
- socket.on("data", function (b) { socket.serialtunnel.updateBuffer(Buffer.from(b, "binary")) });
244
- socket.serialtunnel.forwardwrite = function (b) { socket.write(b, "binary") }
245
- socket.on("close", function () { socket.serialtunnel.emit("end"); });
243
+ socket.on('data', function (b) { socket.serialtunnel.updateBuffer(Buffer.from(b, 'binary')) });
244
+ socket.serialtunnel.forwardwrite = function (b) { socket.write(b, 'binary') }
245
+ socket.on('close', function () { socket.serialtunnel.emit('end'); });
246
247
// Pass socket wrapper to the MQTT broker
248
parent.mqttbroker.handle(socket.serialtunnel);
@@ -533,7 +533,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
533
var request = data.substring(5, 5 + requestLen);
534
//var wantResponse = data.charCodeAt(5 + requestLen);
535
536
- if (request == "tcpip-forward") {
536
+ if (request == 'tcpip-forward') {
537
var addrLen = common.ReadInt(data, 6 + requestLen);
538
if (len < 14 + requestLen + addrLen) return 0;
539
var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
@@ -545,7 +545,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
545
return 14 + requestLen + addrLen;
546
}
547
548
- if (request == "cancel-tcpip-forward") {
548
+ if (request == 'cancel-tcpip-forward') {
549
var addrLen = common.ReadInt(data, 6 + requestLen);
550
if (len < 14 + requestLen + addrLen) return 0;
551
var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
@@ -557,7 +557,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
557
return 14 + requestLen + addrLen;
558
}
559
560
- if (request == "udp-send-to@amt.intel.com") {
560
+ if (request == 'udp-send-to@amt.intel.com') {
561
var addrLen = common.ReadInt(data, 6 + requestLen);
562
if (len < 26 + requestLen + addrLen) return 0;
563
var addr = data.substring(10 + requestLen, 10 + requestLen + addrLen);
@@ -748,14 +748,14 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
748
}
749
}
750
751
- socket.addListener("close", function () {
751
+ socket.addListener('close', function () {
752
socketClosedCount++;
753
parent.debug('mps', 'CIRA connection closed');
754
try { delete obj.ciraConnections[socket.tag.nodeid]; } catch (e) { }
755
obj.parent.ClearConnectivityState(socket.tag.meshid, socket.tag.nodeid, 2);
756
});
757
758
- socket.addListener("error", function () {
758
+ socket.addListener('error', function () {
759
socketErrorCount++;
760
//console.log("MPS Error: " + socket.remoteAddress);
761
});
@@ -802,7 +802,7 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
802
*/
803
804
function SendChannelOpen(socket, direct, channelid, windowsize, target, targetport, source, sourceport) {
805
- var connectionType = ((direct == true) ? "direct-tcpip" : "forwarded-tcpip");
805
+ var connectionType = ((direct == true) ? 'direct-tcpip' : 'forwarded-tcpip');
806
if ((target == null) || (target == null)) target = ''; // TODO: Reports of target being undefined that causes target.length to fail. This is a hack.
807
Write(socket, String.fromCharCode(APFProtocol.CHANNEL_OPEN) + common.IntToStr(connectionType.length) + connectionType + common.IntToStr(channelid) + common.IntToStr(windowsize) + common.IntToStr(-1) + common.IntToStr(target.length) + target + common.IntToStr(targetport) + common.IntToStr(source.length) + source + common.IntToStr(sourceport));
808
}
@@ -837,11 +837,11 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) {
837
function Write(socket, data) {
838
if (args.mpsdebug) {
839
// Print out sent bytes
840
- var buf = Buffer.from(data, "binary");
840
+ var buf = Buffer.from(data, 'binary');
841
console.log('MPS --> (' + buf.length + '):' + buf.toString('hex'));
842
socket.write(buf);
843
} else {
844
- socket.write(Buffer.from(data, "binary"));
844
+ socket.write(Buffer.from(data, 'binary'));
845
}
846
}
847
multiserver.js
+5
-9
@@ -11,7 +11,7 @@
11
/*jshint strict:false */
12
/*jshint -W097 */
13
/*jshint esversion: 6 */
14
-"use strict";
14
+'use strict';
15
16
// Construct a Mesh Multi-Server object. This is used for MeshCentral-to-MeshCentral communication.
17
module.exports.CreateMultiServer = function (parent, args) {
@@ -552,14 +552,10 @@ module.exports.CreateMultiServer = function (parent, args) {
552
if (msg.fromNodeid != null) { msg.nodeid = msg.fromNodeid; delete msg.fromNodeid; }
553
var cmdstr = JSON.stringify(msg);
554
for (userid in obj.parent.webserver.wssessions) { // Find all connected users for this mesh and send the message
555
- var user = obj.parent.webserver.users[userid];
556
- if (user) {
557
- var rights = user.links[msg.meshid];
558
- if (rights != null) { // TODO: Look at what rights are needed for message routing
559
- var sessions = obj.parent.webserver.wssessions[userid];
560
- // Send the message to all users on this server
561
- for (i in sessions) { sessions[i].send(cmdstr); }
562
- }
555
+ if (parent.webserver.GetMeshRights(userid, msg.meshid) != 0) { // TODO: Look at what rights are needed for message routing
556
+ var sessions = obj.parent.webserver.wssessions[userid];
557
+ // Send the message to all users on this server
558
+ for (i in sessions) { sessions[i].send(cmdstr); }
559
}
560
}
561
}
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.4.6-p",
3
+ "version": "0.4.6-q",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
public/images/icons16.png
Binary files a/public/images/icons16.png and b/public/images/icons16.png differ
public/images/icons256-7-1.png
Binary files /dev/null and b/public/images/icons256-7-1.png differ
public/images/icons50.png
Binary files a/public/images/icons50.png and b/public/images/icons50.png differ
public/images/icons64.png
Binary files a/public/images/icons64.png and b/public/images/icons64.png differ
public/styles/style.css
+30
-6
@@ -1155,6 +1155,14 @@ a {
1155
border: none;
1156
}
1157
1158
+.i7 {
1159
+ background: url(../images/icons50.png) -300px 0px;
1160
+ height: 50px;
1161
+ width: 50px;
1162
+ cursor: pointer;
1163
+ border: none;
1164
+}
1165
+
1166
.j1 {
1167
background: url(../images/icons16.png) 0px 0px;
1168
height: 16px;
@@ -1203,6 +1211,14 @@ a {
1211
border: none;
1212
}
1213
1214
+.j7 {
1215
+ background: url(../images/icons16.png) -96px 0px;
1216
+ height: 16px;
1217
+ width: 16px;
1218
+ cursor: pointer;
1219
+ border: none;
1220
+}
1221
+
1222
.relayIcon16 {
1223
background: url(../images/icon-relay.png);
1224
height: 16px;
@@ -1339,7 +1355,7 @@ a {
1355
float: left;
1356
}
1357
1342
-.si0 {
1358
+.si1 {
1359
background: url(../images/icons16.png) 0px 0px;
1360
height: 16px;
1361
width: 16px;
@@ -1347,7 +1363,7 @@ a {
1363
float: left;
1364
}
1365
1350
-.si1 {
1366
+.si2 {
1367
background: url(../images/icons16.png) -16px 0px;
1368
height: 16px;
1369
width: 16px;
@@ -1355,7 +1371,7 @@ a {
1371
float: left;
1372
}
1373
1358
-.si2 {
1374
+.si3 {
1375
background: url(../images/icons16.png) -32px 0px;
1376
height: 16px;
1377
width: 16px;
@@ -1363,7 +1379,7 @@ a {
1379
float: left;
1380
}
1381
1366
-.si3 {
1382
+.si4 {
1383
background: url(../images/icons16.png) -48px 0px;
1384
height: 16px;
1385
width: 16px;
@@ -1371,7 +1387,7 @@ a {
1387
float: left;
1388
}
1389
1374
-.si4 {
1390
+.si5 {
1391
background: url(../images/icons16.png) -64px 0px;
1392
height: 16px;
1393
width: 16px;
@@ -1379,7 +1395,7 @@ a {
1395
float: left;
1396
}
1397
1382
-.si5 {
1398
+.si6 {
1399
background: url(../images/icons16.png) -80px 0px;
1400
height: 16px;
1401
width: 16px;
@@ -1387,6 +1403,14 @@ a {
1403
float: left;
1404
}
1405
1406
+.si7 {
1407
+ background: url(../images/icons16.png) -96px 0px;
1408
+ height: 16px;
1409
+ width: 16px;
1410
+ border: none;
1411
+ float: left;
1412
+}
1413
+
1414
.mi {
1415
background: url(../images/meshicon50.png) 0px 0px;
1416
height: 50px;
translate/translate.json
+2
-3
@@ -8,8 +8,7 @@
8
"nl": "0",
9
"xloc": [
10
"default.handlebars->container->masthead->7->notificationCount",
11
- "default-mobile.handlebars->9->229",
12
- { "$ref": "#" }
11
+ "default-mobile.handlebars->9->229"
12
]
13
},
14
{
@@ -5610,7 +5609,7 @@
5609
{
5610
"en": "free",
5611
"fr": "libre",
5613
- "pt": "Livre",
5612
+ "pt": "livre",
5613
"ja": "無料",
5614
"cs": "volné",
5615
"nl": "vrij",
views/default-mobile.handlebars
+70
-42
@@ -1327,7 +1327,7 @@
1327
count++;
1328
1329
// Mesh rights
1330
- var meshrights = meshes[i].links[userinfo._id].rights;
1330
+ var meshrights = GetMeshRights(meshes[i]);
1331
var rights = "Partial Rights";
1332
if (meshrights == 0xFFFFFFFF) rights = "Full Administrator"; else if (meshrights == 0) rights = "No Rights";
1333
@@ -1576,8 +1576,7 @@
1576
if (desktop && !xxdialogMode && xxcurrentView == 10) {
1577
// Check what keys we are allows to send
1578
if (currentNode != null) {
1579
- var mesh = meshes[currentNode.meshid];
1580
- var meshrights = mesh.links[userinfo._id].rights;
1579
+ var meshrights = GetMeshRights(currentNode.meshid);
1580
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
1581
if (inputAllowed == false) return false;
1582
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
@@ -1594,8 +1593,7 @@
1593
if (desktop && !xxdialogMode && xxcurrentView == 10) {
1594
// Check what keys we are allows to send
1595
if (currentNode != null) {
1597
- var mesh = meshes[currentNode.meshid];
1598
- var meshrights = mesh.links[userinfo._id].rights;
1596
+ var meshrights = GetMeshRights(currentNode.meshid);
1597
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
1598
if (inputAllowed == false) return false;
1599
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
@@ -1612,8 +1610,7 @@
1610
if (desktop && !xxdialogMode && xxcurrentView == 10) {
1611
// Check what keys we are allows to send
1612
if (currentNode != null) {
1615
- var mesh = meshes[currentNode.meshid];
1616
- var meshrights = mesh.links[userinfo._id].rights;
1613
+ var meshrights = GetMeshRights(currentNode.meshid);
1614
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
1615
if (inputAllowed == false) return false;
1616
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
@@ -1655,9 +1652,7 @@
1652
// Go thru the list of nodes and display them
1653
for (var i in nodes) {
1654
if (nodes[i].v == false) continue;
1658
- var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links[userinfo._id];
1659
- if (meshlinks == null) continue;
1660
- var meshrights = meshlinks.rights;
1655
+ //var meshrights = GetNodeRights(nodes[i]);
1656
1657
if (sort == 0) {
1658
// Mesh header
@@ -1668,7 +1663,7 @@
1663
if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span style=color:lightgray>' + ", Intel® AMT only" + '</span>'; }
1664
if (current != null) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } if (r != '') { r += '</tr></table>'; } }
1665
r += '<div class=DevSt style=padding-top:4px><span style=float:right>';
1671
- //r += getMeshActions(mesh2, meshrights);
1666
+ //r += getMeshActions(meshes[nodes[i].meshid], meshrights);
1667
r += '</span><span id=MxMESH style=cursor:pointer onclick=goForward("' + nodes[i].meshid + '")>' + EscapeHtml(meshes[nodes[i].meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' style=color:lightgray></span></div>';
1668
current = nodes[i].meshid;
1669
displayedMeshes[current] = 1;
@@ -1726,20 +1721,17 @@
1721
// Display all empty meshes, we need to do this because users can add devices to these at any time.
1722
if (sort == 0) {
1723
for (var i in meshes) {
1729
- var mesh = meshes[i], meshlink = mesh.links[userinfo._id];
1730
- if (meshlink != null) {
1731
- var meshrights = meshlink.rights;
1732
- if (displayedMeshes[mesh._id] == null) {
1733
- if ((current != '') && (r != '')) { r += '</tr></table>'; }
1734
- r += '<div><div colspan=3 class=DevSt><span style=float:right>';
1735
- //r += getMeshActions(mesh, meshrights);
1736
- r += '</span><span id=MxMESH style=cursor:pointer onclick=goForward("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></div>';
1737
- if (mesh.mtype == 1) { r += '<div style=padding:10px><i>' + "No Intel® AMT devices in this group"; }
1738
- if (mesh.mtype == 2) { r += '<div style=padding:10px><i>' + "No devices in this group"; }
1739
- r += '.</i></div></div>';
1740
- current = mesh._id;
1741
- count++;
1742
- }
1724
+ var mesh = meshes[i];
1725
+ if (IsMeshViewable(mesh)) {
1726
+ if ((current != '') && (r != '')) { r += '</tr></table>'; }
1727
+ r += '<div><div colspan=3 class=DevSt><span style=float:right>';
1728
+ //r += getMeshActions(mesh, meshrights);
1729
+ r += '</span><span id=MxMESH style=cursor:pointer onclick=goForward("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></div>';
1730
+ if (mesh.mtype == 1) { r += '<div style=padding:10px><i>' + "No Intel® AMT devices in this group"; }
1731
+ if (mesh.mtype == 2) { r += '<div style=padding:10px><i>' + "No devices in this group"; }
1732
+ r += '.</i></div></div>';
1733
+ current = mesh._id;
1734
+ count++;
1735
}
1736
}
1737
}
@@ -1813,11 +1805,6 @@
1805
gotoDevice(nodeid, xxcurrentView, true);
1806
}
1807
1816
- function getNodeRights(nodeid) {
1817
- var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
1818
- return mesh.links[userinfo._id].rights;
1819
- }
1820
-
1808
var currentDevicePanel = 0;
1809
var currentNode;
1810
var powerTimelineNode = null;
@@ -1837,7 +1824,7 @@
1824
if (node == null) { goBack(); return; }
1825
var mesh = meshes[node.meshid];
1826
if (mesh == null) { goBack(); return; }
1840
- var meshrights = mesh.links[userinfo._id].rights;
1827
+ var meshrights = GetMeshRights(mesh);
1828
if (!currentNode || currentNode._id != node._id || refresh == true) {
1829
currentNode = node;
1830
@@ -2008,8 +1995,7 @@
1995
}
1996
1997
function setupDeviceMenu(op, obj) {
2011
- var meshrights = 0;
2012
- if (currentNode) { meshrights = meshes[currentNode.meshid].links[userinfo._id].rights; }
1998
+ var meshrights = GetNodeRights(currentNode);
1999
if (op != null) { currentDevicePanel = op; }
2000
QV('p10general', currentDevicePanel == 0);
2001
QV('p10desktop', currentDevicePanel == 1); // Show if we have remote control rights or desktop view only rights
@@ -2027,7 +2013,7 @@
2013
2014
function deviceActionFunction() {
2015
if (xxdialogMode) return;
2030
- var meshrights = meshes[currentNode.meshid].links[userinfo._id].rights;
2016
+ var meshrights = GetNodeRights(currentNode);
2017
var x = "Select an operation to perform on this device." + '<br /><br />';
2018
var y = '<select id=d2deviceop style=float:right;width:170px>';
2019
if ((meshrights & 64) != 0) { y += '<option value=100>' + "Wake-up" + '</option>'; } // Wake-up permission
@@ -2117,7 +2103,7 @@
2103
2104
function editDeviceAmtSettings(nodeid, func) {
2105
if (xxdialogMode) return;
2120
- var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
2106
+ var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = GetNodeRights(node);
2107
if ((meshrights & 4) == 0) return;
2108
x += addHtmlValue("Username", '<input id=dp10username style=width:170px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
2109
x += addHtmlValue("Password", '<input id=dp10password type=password style=width:170px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
@@ -2166,9 +2152,8 @@
2152
2153
function p10showiconselector() {
2154
if (xxdialogMode) return;
2169
- var mesh = meshes[currentNode.meshid];
2170
- var meshrights = mesh.links[userinfo._id].rights;
2171
- if ((meshrights & 4) == 0) return;
2155
+ var rights = GetNodeRights(currentNode);
2156
+ if ((rights & 4) == 0) return;
2157
2158
var x = '<table align=center><td>';
2159
x += '<div style=display:inline-block class=i1 onclick=p10setIcon(1)></div>';
@@ -2245,7 +2230,7 @@
2230
var mesh = meshes[currentNode.meshid];
2231
var deskState = 0;
2232
if (desktop != null) { deskState = desktop.State; }
2248
- var meshrights = mesh.links[userinfo._id].rights;
2233
+ var meshrights = GetNodeRights(currentNode);
2234
2235
// Show the right buttons
2236
QV('disconnectbutton1', (deskState != 0));
@@ -3096,7 +3081,7 @@
3081
if (currentMesh == null) return;
3082
QH('p20meshName', EscapeHtml(currentMesh.name));
3083
var meshtype = format("Unknown #{0}", currentMesh.mtype);
3099
- var meshrights = currentMesh.links[userinfo._id].rights;
3084
+ var meshrights = GetMeshRights(currentMesh);
3085
if (currentMesh.mtype == 1) meshtype = "Intel® AMT only, no agent";
3086
if (currentMesh.mtype == 2) meshtype = "Managed using a software agent";
3087
@@ -3229,7 +3214,7 @@
3214
}
3215
3216
function p20validateAddMeshUserDialog() {
3232
- var meshrights = currentMesh.links[userinfo._id].rights;
3217
+ var meshrights = GetMeshRights(currentMesh);
3218
var nc = !Q('p20fulladmin').checked;
3219
QE('p20fulladmin', meshrights == 0xFFFFFFFF);
3220
QE('p20editmesh', nc && (meshrights == 0xFFFFFFFF));
@@ -3278,7 +3263,7 @@
3263
function p20viewuser(userid) {
3264
if (xxdialogMode) return;
3265
userid = decodeURIComponent(userid);
3281
- var r = [], cmeshrights = currentMesh.links[userinfo._id].rights, meshrights = currentMesh.links[userid].rights;
3266
+ var r = [], cmeshrights = GetMeshRights(currentMesh), meshrights = GetMeshRights(currentMesh, userid);
3267
if (meshrights == 0xFFFFFFFF) r.push("Full Administrator"); else {
3268
if ((meshrights & 1) != 0) r.push("Edit Device Group");
3269
if ((meshrights & 2) != 0) r.push("Manage Device Group Users");
@@ -3361,6 +3346,49 @@
3346
if (((b & 8) || x) && f) f(x, t);
3347
}
3348
3349
+ //
3350
+ // Access Control Functions
3351
+ // These must match server
3352
+ //
3353
+
3354
+ // Get the right of a user on a given device group
3355
+ function GetMeshRights(mesh, user) {
3356
+ if (mesh == null) { return 0; }
3357
+ if (user == null) { user = userinfo._id; }
3358
+ if (typeof mesh == 'string') { mesh = meshes[mesh] }
3359
+ if ((mesh == null) || (mesh.links == null)) { return 0; }
3360
+ var rights = mesh.links[user];
3361
+ if (rights == null) { return 0; }
3362
+ return rights.rights;
3363
+ }
3364
+
3365
+ // Returns true if the user can view the given device group
3366
+ function IsMeshViewable(mesh, user) {
3367
+ if (mesh == null) { return 0; }
3368
+ if (user == null) { user = userinfo._id; }
3369
+ if (typeof mesh == 'string') { mesh = meshes[mesh] }
3370
+ if ((mesh == null) || (mesh.links == null)) { return false; }
3371
+ var rights = mesh.links[user];
3372
+ if (rights == null) { return false; }
3373
+ return true;
3374
+ }
3375
+
3376
+ // Return the user rights for a given node
3377
+ function GetNodeRights(node, user) {
3378
+ if (node == null) { return 0; }
3379
+ if (user == null) { user = userinfo._id; }
3380
+ if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return 0; } }
3381
+ var mesh = meshes[node.meshid];
3382
+ if ((mesh == null) || (mesh.links == null)) { return 0; }
3383
+ var meshlinks = mesh.links[user];
3384
+ if (meshlinks == null) { return 0; }
3385
+ return meshlinks.rights;
3386
+ }
3387
+
3388
+ //
3389
+ // Generic Methods
3390
+ //
3391
+
3392
function putstore(name, val) { try { if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return; if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); } } catch (e) { } if (name[0] != '_') { var s = {}; for (var i = 0, len = localStorage.length; i < len; ++i) { var k = localStorage.key(i); if (k[0] != '_') { s[k] = localStorage.getItem(k); } } meshserver.send({ action: 'userWebState', state: JSON.stringify(s) }); } }
3393
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
3394
function center() { QS('dialog').left = ((((getDocWidth() - 300) / 2)) + 'px'); deskAdjust(); deskAdjust(); /*drawDeviceTimeline();*/ }
views/default.handlebars
+115
-91
@@ -2587,8 +2587,7 @@
2587
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
2588
// Check what keys we are allows to send
2589
if (currentNode != null) {
2590
- var mesh = meshes[currentNode.meshid];
2591
- var meshrights = mesh.links[userinfo._id].rights;
2590
+ var meshrights = GetMeshRights(currentNode.meshid);
2591
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2592
if (inputAllowed == false) return false;
2593
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
@@ -2647,8 +2646,7 @@
2646
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
2647
// Check what keys we are allows to send
2648
if (currentNode != null) {
2650
- var mesh = meshes[currentNode.meshid];
2651
- var meshrights = mesh.links[userinfo._id].rights;
2649
+ var meshrights = GetMeshRights(currentNode.meshid);
2650
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2651
if (inputAllowed == false) return false;
2652
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
@@ -2682,8 +2680,7 @@
2680
if (!xxdialogMode && xxcurrentView == 11 && desktop && Q('DeskControl').checked) {
2681
// Check what keys we are allows to send
2682
if (currentNode != null) {
2685
- var mesh = meshes[currentNode.meshid];
2686
- var meshrights = mesh.links[userinfo._id].rights;
2683
+ var meshrights = GetMeshRights(currentNode.meshid);
2684
var inputAllowed = ((meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0)));
2685
if (inputAllowed == false) return false;
2686
var limitedInputAllowed = ((meshrights != 0xFFFFFFFF) && (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) != 0)));
@@ -2783,10 +2780,9 @@
2780
for (var i in nodes) {
2781
var node = nodes[i];
2782
if (node.v == false) continue;
2786
- var mesh2 = meshes[node.meshid], meshlinks = mesh2.links[userinfo._id];
2787
- if (meshlinks == null) continue;
2788
- var meshrights = meshlinks.rights;
2783
+ var mesh2 = meshes[node.meshid];
2784
if ((view == 3) && (mesh2.mtype == 1)) continue;
2785
+ var meshrights = GetNodeRights(node);
2786
if (sort == 0) {
2787
// Mesh header
2788
if (node.meshid != current) {
@@ -2948,37 +2944,34 @@
2944
if ((sort == 0) && (Q('SearchInput').value == '') && (view < 3)) {
2945
var deviceHeaderId2 = deviceHeaderId;
2946
for (var i in meshes) {
2951
- var mesh = meshes[i], meshlink = mesh.links[userinfo._id];
2952
- if (meshlink != null) {
2953
- var meshrights = meshlink.rights;
2954
- if (displayedMeshes[mesh._id] == null) {
2955
- if ((current != '') && (r != '')) { r += '</tr></table>'; }
2956
- r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt>';
2947
+ var mesh = meshes[i], meshrights = GetMeshRights(mesh);
2948
+ if (displayedMeshes[mesh._id] == null) {
2949
+ if ((current != '') && (r != '')) { r += '</tr></table>'; }
2950
+ r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt>';
2951
2958
- // Collapsing header & start collapsing area
2959
- deviceHeaderId2++;
2960
- var collapsed = CollapsedGroups[mesh._id];
2961
- r += '<img class=collapseImage id=\"DevxColImg' + deviceHeaderId2 + '\" src=images/c' + ((collapsed === true)?'1':'2') + '.png height=8 width=8 style=margin-left:2px;margin-right:2px;cursor:pointer onclick=toggleCollapseGroup(\"' + deviceHeaderId2 + '\",\"' + mesh._id + '\")></img>'; // Collapse action
2962
-
2963
- r += '<span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span><span>';
2964
- r += getMeshActions(mesh, meshrights);
2965
- r += '</span></td></tr><tr>';
2966
- if (mesh.mtype == 1) {
2967
- r += '<td><div style=padding:10px><i>' + "No Intel® AMT devices in this mesh";
2968
- if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addDeviceToMesh(\"' + mesh._id + '\")\'>' + "add one" + '</a>'; }
2969
- }
2970
- if (mesh.mtype == 2) {
2971
- r += '<td>';
2972
- r += '<div id=DevxCol' + deviceHeaderId2 + ((collapsed === true)?' style=display:none':'') + '>'; // Open collapse div
2973
- r += '<div style=padding:10px><i>' + "No devices in this group";
2974
- if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addAgentToMesh(\"' + mesh._id + '\")\'>' + "add one" + '</a>'; }
2975
- }
2976
- r += '.</i></div></td>';
2977
- r += '</div>'; // End collapsing area
2978
-
2979
- current = mesh._id;
2980
- count++;
2952
+ // Collapsing header & start collapsing area
2953
+ deviceHeaderId2++;
2954
+ var collapsed = CollapsedGroups[mesh._id];
2955
+ r += '<img class=collapseImage id=\"DevxColImg' + deviceHeaderId2 + '\" src=images/c' + ((collapsed === true)?'1':'2') + '.png height=8 width=8 style=margin-left:2px;margin-right:2px;cursor:pointer onclick=toggleCollapseGroup(\"' + deviceHeaderId2 + '\",\"' + mesh._id + '\")></img>'; // Collapse action
2956
+
2957
+ r += '<span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span><span>';
2958
+ r += getMeshActions(mesh, meshrights);
2959
+ r += '</span></td></tr><tr>';
2960
+ if (mesh.mtype == 1) {
2961
+ r += '<td><div style=padding:10px><i>' + "No Intel® AMT devices in this mesh";
2962
+ if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addDeviceToMesh(\"' + mesh._id + '\")\'>' + "add one" + '</a>'; }
2963
+ }
2964
+ if (mesh.mtype == 2) {
2965
+ r += '<td>';
2966
+ r += '<div id=DevxCol' + deviceHeaderId2 + ((collapsed === true)?' style=display:none':'') + '>'; // Open collapse div
2967
+ r += '<div style=padding:10px><i>' + "No devices in this group";
2968
+ if ((meshrights & 4) != 0) { r += ', <a href=# style=cursor:pointer onclick=\'return addAgentToMesh(\"' + mesh._id + '\")\'>' + "add one" + '</a>'; }
2969
}
2970
+ r += '.</i></div></td>';
2971
+ r += '</div>'; // End collapsing area
2972
+
2973
+ current = mesh._id;
2974
+ count++;
2975
}
2976
}
2977
}
@@ -3107,8 +3100,8 @@
3100
3101
function toggleKvmDevice(node) {
3102
if (typeof node == 'string') { node = getNodeFromId(node); } // Convert nodeid to node if needed
3110
- var mesh = meshes[node.meshid], meshrights = mesh.links[userinfo._id].rights;
3111
- if ((meshrights & 8) || (meshrights & 256)) { // Requires remote control rights or desktop view only rights
3103
+ var rights = GetNodeRights(node);
3104
+ if ((rights & 8) || (rights & 256)) { // Requires remote control rights or desktop view only rights
3105
//var conn = 0;
3106
//if ((node.conn & 1) != 0) { conn = 1; } else if ((node.conn & 6) != 0) { conn = 2; } // Check what type of connect we can do (Agent vs AMT)
3107
if (node.conn & 1) { connectMultiDesktop(node, 1); }
@@ -3133,8 +3126,8 @@
3126
for (var i in nodes) {
3127
var node = nodes[i], nodeid = nodes[i]._id;
3128
if ((multiDesktop[nodeid] == null) && ((multiDesktopFilter.length == 0) || (multiDesktopFilter.indexOf('devid_' + nodeid) >= 0))) {
3136
- var mesh = meshes[node.meshid], meshrights = mesh.links[userinfo._id].rights;
3137
- if ((meshrights & 8) || (meshrights & 256)) { // Requires remote control rights or desktop view only rights
3129
+ var rights = GetNodeRights(node);
3130
+ if ((rights & 8) || (rights & 256)) { // Requires remote control rights or desktop view only rights
3131
//var conn = 0;
3132
//if ((node.conn & 1) != 0) { conn = 1; } else if ((node.conn & 6) != 0) { conn = 2; } // Check what type of connect we can do (Agent vs AMT)
3133
if ((node.conn & 1) && (node.v == true)) { count++; }
@@ -3646,9 +3639,8 @@
3639
// Display the "Uninstall Agent" option if allowed and we selected connected devices.
3640
for (var i in nodeids) {
3641
var node = getNodeFromId(nodeids[i]);
3649
- var mesh = meshes[node.meshid];
3650
- var meshrights = mesh.links[userinfo._id].rights;
3651
- if (((node.conn & 1) != 0) && ((meshrights & 32768) != 0)) { addedOptions += '<option value=104>' + "Uninstall Agent" + '</option>'; break; }
3642
+ var rights = GetNodeRights(node);
3643
+ if (((node.conn & 1) != 0) && ((rights & 32768) != 0)) { addedOptions += '<option value=104>' + "Uninstall Agent" + '</option>'; break; }
3644
}
3645
3646
var x = "Select an operation to perform on all selected devices. Actions will be performed only with proper rights." + '<br /><br />';
@@ -3790,19 +3782,18 @@
3782
var nodeid = contextelement.children[1].attributes.onclick.value;
3783
var node = getNodeFromId(nodeid.substring(12, nodeid.length - 18));
3784
var mesh = meshes[node.meshid];
3793
- var meshlinks = mesh.links[userinfo._id];
3794
- var meshrights = meshlinks.rights;
3795
- var consoleRights = ((meshrights & 16) != 0);
3785
+ var rights = GetNodeRights(node);
3786
+ var consoleRights = ((rights & 16) != 0);
3787
3788
// Check if we have terminal and file access
3798
- var terminalAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 512) == 0));
3799
- var fileAccess = ((meshrights == 0xFFFFFFFF) || ((meshrights & 1024) == 0));
3789
+ var terminalAccess = ((rights == 0xFFFFFFFF) || ((rights & 512) == 0));
3790
+ var fileAccess = ((rights == 0xFFFFFFFF) || ((rights & 1024) == 0));
3791
3801
- QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((meshrights & 8) || (meshrights & 256)));
3802
- QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (meshrights & 8) && terminalAccess);
3803
- QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (meshrights & 8) && fileAccess);
3804
- QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (meshrights & 8));
3805
- QV('cxconsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (meshrights & 8));
3792
+ QV('cxdesktop', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 1) != 0) || (node.intelamt && (node.intelamt.state == 2))) && ((rights & 8) || (rights & 256)));
3793
+ QV('cxterminal', ((mesh.mtype == 1) || (node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 2) != 0) || (node.intelamt && (node.intelamt.state == 2))) && (rights & 8) && terminalAccess);
3794
+ QV('cxfiles', ((mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 4) != 0))) && (rights & 8) && fileAccess);
3795
+ QV('cxevents', (node.intelamt != null) && ((node.intelamt.state == 2) || (node.conn & 2)) && (rights & 8));
3796
+ QV('cxconsole', (consoleRights && (mesh.mtype == 2) && ((node.agent == null) || (node.agent.caps == null) || ((node.agent.caps & 8) != 0))) && (rights & 8));
3797
}
3798
3799
return haltEvent(event);
@@ -4488,11 +4479,6 @@
4479
gotoDevice(nodeid, xxcurrentView, true);
4480
}
4481
4491
- function getNodeRights(nodeid) {
4492
- var node = getNodeFromId(nodeid), mesh = meshes[node.meshid];
4493
- return mesh.links[userinfo._id].rights;
4494
- }
4495
-
4482
var currentNode;
4483
var powerTimelineNode = null;
4484
var powerTimelineReq = null;
@@ -4515,7 +4501,7 @@
4501
//disconnectAllKvmFunction();
4502
var node = getNodeFromId(nodeid);
4503
var mesh = meshes[node.meshid];
4518
- var meshrights = mesh.links[userinfo._id].rights;
4504
+ var meshrights = GetNodeRights(node);
4505
if (!currentNode || currentNode._id != node._id || refresh == true) {
4506
currentNode = node;
4507
@@ -4857,13 +4843,13 @@
4843
4844
function deviceActionFunction() {
4845
if (xxdialogMode) return;
4860
- var meshrights = meshes[currentNode.meshid].links[userinfo._id].rights;
4846
+ var rights = GetNodeRights(currentNode);
4847
var x = "Select an operation to perform on this device." + '<br /><br />';
4848
var y = '<select id=d2deviceop style=float:right;width:250px>';
4863
- if ((meshrights & 64) != 0) { y += '<option value=100>' + "Wake-up" + '</option>'; } // Wake-up permission
4864
- if ((meshrights & 8) != 0) { y += '<option value=4>' + "Sleep" + '</option><option value=3>' + "Reset" + '</option><option value=2>' + "Power off" + '</option>'; } // Remote control permission
4849
+ if ((rights & 64) != 0) { y += '<option value=100>' + "Wake-up" + '</option>'; } // Wake-up permission
4850
+ if ((rights & 8) != 0) { y += '<option value=4>' + "Sleep" + '</option><option value=3>' + "Reset" + '</option><option value=2>' + "Power off" + '</option>'; } // Remote control permission
4851
if ((currentNode.conn & 16) != 0) { y += '<option value=103>' + "Send MQTT Message" + '</option>'; }
4866
- if (((currentNode.conn & 1) != 0) && ((meshrights & 32768) != 0)) { y += '<option value=104>' + "Uninstall Agent" + '</option>'; }
4852
+ if (((currentNode.conn & 1) != 0) && ((rights & 32768) != 0)) { y += '<option value=104>' + "Uninstall Agent" + '</option>'; }
4853
y += '</select>';
4854
x += addHtmlValue("Operation", y);
4855
setDialogMode(2, "Device Action", 3, deviceActionFunctionEx, x);
@@ -4975,7 +4961,7 @@
4961
4962
function editDeviceAmtSettings(nodeid, func, arg) {
4963
if (xxdialogMode) return;
4978
- var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = getNodeRights(nodeid);
4964
+ var x = '', node = getNodeFromId(nodeid), buttons = 3, meshrights = GetNodeRights(node);
4965
if ((meshrights & 4) == 0) return;
4966
x += addHtmlValue("Username", '<input id=dp10username style=width:230px maxlength=32 autocomplete=nope placeholder="admin" onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
4967
x += addHtmlValue("Password", '<input id=dp10password type=password style=width:230px autocomplete=nope maxlength=32 onchange=validateDeviceAmtSettings() onkeyup=validateDeviceAmtSettings() />');
@@ -5049,7 +5035,7 @@
5035
// List all available alternative groups
5036
var y = '<select id=p10newGroup style=width:236px>', count = 0;
5037
for (var i in meshes) {
5052
- var meshrights = meshes[i].links[userinfo._id].rights;
5038
+ var meshrights = GetMeshRights(i);
5039
if ((meshes[i]._id != targetMeshId) && (meshrights & 4)) { count++; y += '<option value=\'' + meshes[i]._id + '\'>' + meshes[i].name + '</option>'; }
5040
}
5041
y += '</select>';
@@ -5195,17 +5181,16 @@
5181
5182
function p10showiconselector() {
5183
if (xxdialogMode) return;
5198
- var mesh = meshes[currentNode.meshid];
5199
- var meshrights = mesh.links[userinfo._id].rights;
5200
- if ((meshrights & 4) == 0) return;
5184
+ if ((GetNodeRights(currentNode) & 4) == 0) return;
5185
5202
- var x = '<br><div style=display:inline-block;width:40px></div>';
5186
+ var x = '<br><div style=display:inline-block;width:16px></div>';
5187
x += '<div tabindex=0 style=display:inline-block class=i1 onclick=p10setIcon(1) onkeypress="if (event.key==\'Enter\') p10setIcon(1)"></div>';
5188
x += '<div tabindex=0 style=display:inline-block class=i2 onclick=p10setIcon(2) onkeypress="if (event.key==\'Enter\') p10setIcon(2)"></div>';
5189
x += '<div tabindex=0 style=display:inline-block class=i3 onclick=p10setIcon(3) onkeypress="if (event.key==\'Enter\') p10setIcon(3)"></div>';
5190
x += '<div tabindex=0 style=display:inline-block class=i4 onclick=p10setIcon(4) onkeypress="if (event.key==\'Enter\') p10setIcon(4)"></div>';
5191
x += '<div tabindex=0 style=display:inline-block class=i5 onclick=p10setIcon(5) onkeypress="if (event.key==\'Enter\') p10setIcon(5)"></div>';
5208
- x += '<div tabindex=0 style=display:inline-block class=i6 onclick=p10setIcon(6) onkeypress="if (event.key==\'Enter\') p10setIcon(6)"></div><br><br>';
5192
+ x += '<div tabindex=0 style=display:inline-block class=i6 onclick=p10setIcon(6) onkeypress="if (event.key==\'Enter\') p10setIcon(6)"></div>';
5193
+ x += '<div tabindex=0 style=display:inline-block class=i7 onclick=p10setIcon(7) onkeypress="if (event.key==\'Enter\') p10setIcon(7)"></div><br><br>';
5194
setDialogMode(2, "Icon Selection", 0, null, x);
5195
QV('id_dialogclose', true);
5196
}
@@ -5292,14 +5277,14 @@
5277
var mesh = meshes[currentNode.meshid];
5278
var deskState = 0;
5279
if (desktop != null) { deskState = desktop.State; }
5295
- var meshrights = mesh.links[userinfo._id].rights;
5280
+ var rights = GetNodeRights(currentNode);
5281
5282
// Show the right buttons
5283
QV('disconnectbutton1span', (deskState != 0));
5299
- QV('connectbutton1span', (deskState == 0) && ((meshrights & 8) || (meshrights & 256)) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
5284
+ QV('connectbutton1span', (deskState == 0) && ((rights & 8) || (rights & 256)) && (mesh.mtype == 2) && (currentNode.agent.caps & 1));
5285
QV('connectbutton1hspan',
5286
(deskState == 0) &&
5302
- (meshrights & 8) &&
5287
+ (rights & 8) &&
5288
((mesh.mtype == 1) ||
5289
((currentNode.intelamt != null) &&
5290
(currentNode.intelamt.state == 2) &&
@@ -5314,7 +5299,7 @@
5299
QV('d7meshkvm', (webRtcDesktop) || ((mesh.mtype == 2) && (currentNode.agent.caps & 1) && ((deskState == false) || (desktop.contype == 1))));
5300
5301
// Enable buttons
5317
- var inputAllowed = (meshrights == 0xFFFFFFFF) || (((meshrights & 8) != 0) && ((meshrights & 256) == 0) && ((meshrights & 4096) == 0));
5302
+ var inputAllowed = (rights == 0xFFFFFFFF) || (((rights & 8) != 0) && ((rights & 256) == 0) && ((rights & 4096) == 0));
5303
var online = ((currentNode.conn & 1) != 0); // If Agent (1) connected, enable remote desktop
5304
QE('connectbutton1', online);
5305
var hwonline = ((currentNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
@@ -5330,8 +5315,8 @@
5315
QE('deskkeys', deskState == 3);
5316
5317
// Display this only if we have Chat & Notify permissions
5333
- QV('DeskChatButton', ((meshrights & 16384) != 0) && (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
5334
- QV('DeskNotifyButton', ((meshrights & 16384) != 0) && (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (mesh.mtype == 2) && online);
5318
+ QV('DeskChatButton', ((rights & 16384) != 0) && (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
5319
+ QV('DeskNotifyButton', ((rights & 16384) != 0) && (browserfullscreen == false) && (currentNode.agent) && (currentNode.agent.id < 5) && (inputAllowed) && (mesh.mtype == 2) && online);
5320
5321
QV('DeskToolsButton', (inputAllowed) && (mesh.mtype == 2) && online);
5322
QV('DeskOpenWebButton', (browserfullscreen == false) && (inputAllowed) && (mesh.mtype == 2) && online);
@@ -5339,7 +5324,7 @@
5324
QV('DeskControlSpan', inputAllowed)
5325
QV('deskActionsBtn', (browserfullscreen == false));
5326
QV('deskActionsSettings', (browserfullscreen == false));
5342
- if (meshrights & 8) { Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); } else { Q('DeskControl').checked = false; }
5327
+ if (rights & 8) { Q('DeskControl').checked = (getstore('DeskControl', 1) == 1); } else { Q('DeskControl').checked = false; }
5328
if (online == false) QV('DeskTools', false);
5329
}
5330
@@ -6966,8 +6951,8 @@
6951
consoleNode = currentNode;
6952
6953
var mesh = meshes[consoleNode.meshid];
6969
- var meshrights = mesh.links[userinfo._id].rights;
6970
- if ((meshrights & 16) != 0) {
6954
+ var rights = GetNodeRights(currentNode);
6955
+ if ((rights & 16) != 0) {
6956
if (consoleNode.consoleText == null) { consoleNode.consoleText = ''; }
6957
if (samenode == false) {
6958
QH('p15agentConsoleText', consoleNode.consoleText);
@@ -7443,8 +7428,7 @@
7428
count++;
7429
7430
// Mesh rights
7446
- var meshrights = 0;
7447
- if (meshes[i].links[userinfo._id]) { meshrights = meshes[i].links[userinfo._id].rights; }
7431
+ var meshrights = GetMeshRights(meshes[i]);
7432
var rights = "Partial Rights";
7433
if (meshrights == 0xFFFFFFFF) rights = "Full Administrator"; else if (meshrights == 0) rights = "No Rights";
7434
@@ -7511,8 +7495,7 @@
7495
if (currentMesh == null) return;
7496
QH('p20meshName', EscapeHtml(currentMesh.name));
7497
var meshtype = format("Unknown #{0}", currentMesh.mtype);
7514
- var meshrights = 0;
7515
- try { meshrights = currentMesh.links[userinfo._id].rights; } catch (ex) { }
7498
+ var meshrights = GetMeshRights(currentMesh);
7499
if (currentMesh.mtype == 1) meshtype = "Intel® AMT only, no agent";
7500
if (currentMesh.mtype == 2) meshtype = "Managed using a software agent";
7501
@@ -7580,10 +7563,9 @@
7563
if (meshrights & 1) { x += '<br><input type=button value=' + "Notes" + ' title=\"' + "View notes about this device group" + '\" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />'; }
7564
7565
x += '<br style=clear:both><br>';
7583
- var currentMeshLinks = currentMesh.links[userinfo._id];
7584
- if (currentMeshLinks && ((currentMeshLinks.rights & 2) != 0)) { x += '<a href=# onclick="return p20showAddMeshUserDialog()" style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> ' + "Add Users" + '</a>'; }
7566
+ if (meshrights & 2) { x += '<a href=# onclick="return p20showAddMeshUserDialog()" style=cursor:pointer;margin-right:10px><img src=images/icon-addnew.png border=0 height=12 width=12> ' + "Add Users" + '</a>'; }
7567
7586
- if ((meshrights & 4) != 0) {
7568
+ if (meshrights & 4) {
7569
if (currentMesh.mtype == 1) {
7570
x += '<a href=# onclick=\'return addCiraDeviceToMesh(\"' + currentMesh._id + '\")\' style=cursor:pointer;margin-right:10px title=\"' + "Add a new Intel® AMT computer that is located on the internet." + '\"><img src=images/icon-installmesh.png border=0 height=12 width=12> ' + "Install CIRA" + '</a>';
7571
x += '<a href=# onclick=\'return addDeviceToMesh(\"' + currentMesh._id + '\")\' style=cursor:pointer;margin-right:10px title=\"' + "Add a new Intel® AMT computer that is located on the local network." + '\"><img src=images/icon-installmesh.png border=0 height=12 width=12> ' + "Install local" + '</a>';
@@ -7838,7 +7820,7 @@
7820
Q('dp20username').focus();
7821
} else {
7822
setDialogMode(2, "Edit User Device Group Permissions", 7, p20showAddMeshUserDialogEx, x, userid);
7841
- var cmeshrights = currentMesh.links[userinfo._id].rights, meshrights = currentMesh.links[userid].rights;
7823
+ var cmeshrights = GetMeshRights(currentMesh), meshrights = GetMeshRights(currentMesh, userid);
7824
if (meshrights == 0xFFFFFFFF) {
7825
Q('p20fulladmin').checked = true;
7826
} else {
@@ -7877,7 +7859,7 @@
7859
}
7860
7861
function p20validateAddMeshUserDialog() {
7880
- var meshrights = currentMesh.links[userinfo._id].rights;
7862
+ var meshrights = GetMeshRights(currentMesh);
7863
var ok = true;
7864
if (Q('dp20username')) {
7865
var xusers = Q('dp20username').value.split(',');
@@ -7964,7 +7946,7 @@
7946
function p20viewuser(userid) {
7947
if (xxdialogMode) return;
7948
var xuserid = decodeURIComponent(userid);
7967
- var cmeshrights = currentMesh.links[userinfo._id].rights, meshrights = currentMesh.links[xuserid].rights;
7949
+ var cmeshrights = GetMeshRights(currentMesh), meshrights = GetMeshRights(currentMesh, xuserid);
7950
if (((userinfo._id) != xuserid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) {
7951
p20showAddMeshUserDialog(userid);
7952
} else {
@@ -10063,7 +10045,49 @@
10045
if (pname == null) { Q('p43iframe').src = ''; } else { QH('p43title', title); Q('p43iframe').src = '/pluginadmin.ashx?pin=' + pname; go(43); }
10046
}
10047
10048
+ //
10049
+ // Access Control Functions
10050
+ // These must match server
10051
+ //
10052
+
10053
+ // Get the right of a user on a given device group
10054
+ function GetMeshRights(mesh, user) {
10055
+ if (mesh == null) { return 0; }
10056
+ if (user == null) { user = userinfo._id; }
10057
+ if (typeof mesh == 'string') { mesh = meshes[mesh] }
10058
+ if ((mesh == null) || (mesh.links == null)) { return 0; }
10059
+ var rights = mesh.links[user];
10060
+ if (rights == null) { return 0; }
10061
+ return rights.rights;
10062
+ }
10063
+
10064
+ // Returns true if the user can view the given device group
10065
+ function IsMeshViewable(mesh, user) {
10066
+ if (mesh == null) { return 0; }
10067
+ if (user == null) { user = userinfo._id; }
10068
+ if (typeof mesh == 'string') { mesh = meshes[mesh] }
10069
+ if ((mesh == null) || (mesh.links == null)) { return false; }
10070
+ var rights = mesh.links[user];
10071
+ if (rights == null) { return false; }
10072
+ return true;
10073
+ }
10074
+
10075
+ // Return the user rights for a given node
10076
+ function GetNodeRights(node, user) {
10077
+ if (node == null) { return 0; }
10078
+ if (user == null) { user = userinfo._id; }
10079
+ if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return 0; } }
10080
+ var mesh = meshes[node.meshid];
10081
+ if ((mesh == null) || (mesh.links == null)) { return 0; }
10082
+ var meshlinks = mesh.links[user];
10083
+ if (meshlinks == null) { return 0; }
10084
+ return meshlinks.rights;
10085
+ }
10086
+
10087
+ //
10088
// Generic methods
10089
+ //
10090
+
10091
function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
10092
function putstore(name, val) {
10093
try {
webserver.js
+44
-32
@@ -2065,7 +2065,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2065
if ((splitpath.length < 3) || (splitpath[0] != 'user' && splitpath[0] != 'mesh') || (splitpath[1] != domain.id)) return null; // Basic validation
2066
var objid = splitpath[0] + '/' + splitpath[1] + '/' + splitpath[2];
2067
if (splitpath[0] == 'user' && (objid != user._id)) return null; // User validation, only self allowed
2068
- if (splitpath[0] == 'mesh') { var link = user.links[objid]; if ((link == null) || (link.rights == null) || ((link.rights & 32) == 0)) { return null; } } // Check mesh server file rights
2068
+ if (splitpath[0] == 'mesh') { if ((obj.GetMeshRights(user, objid) & 32) == 0) { return null; } } // Check mesh server file rights
2069
if (splitpath[1] != '') { serverpath += '-' + splitpath[1]; } // Add the domain if needed
2070
serverpath += ('/' + splitpath[0] + '-' + splitpath[2]);
2071
for (var i = 3; i < splitpath.length; i++) { if (obj.common.IsFilenameValid(splitpath[i]) == true) { serverpath += '/' + splitpath[i]; filename = splitpath[i]; } else { return null; } } // Check that each folder is correct
@@ -2265,8 +2265,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2265
if (!node.intelamt) { console.log('ERR: Not AMT node'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
2266
2267
// Check if this user has permission to manage this computer
2268
- var meshlinks = user.links[node.meshid];
2269
- if ((!meshlinks) || (!meshlinks.rights) || ((meshlinks.rights & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (2)'); try { ws.close(); } catch (e) { } return; }
2268
+ if ((obj.GetMeshRights(user, node.meshid) & MESHRIGHT_REMOTECONTROL) == 0) { console.log('ERR: Access denied (2)'); try { ws.close(); } catch (e) { } return; }
2269
2270
// Check what connectivity is available for this node
2271
var state = parent.GetConnectivityState(req.query.host);
@@ -2998,9 +2997,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2997
2998
// If required, check if this user has rights to do this
2999
if ((obj.parent.config.settings != null) && ((obj.parent.config.settings.lockagentdownload == true) || (domain.lockagentdownload == true))) {
3001
- var user = obj.users[req.session.userid];
3002
- if ((user == null) || (mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) { res.sendStatus(401); return; }
3003
- if (domain.id != mesh.domain) { res.sendStatus(401); return; }
3000
+ if ((domain.id != mesh.domain) || ((obj.GetMeshRights(req.session.userid, mesh) & 1) == 0)) { res.sendStatus(401); return; }
3001
}
3002
3003
var meshidhex = Buffer.from(req.query.meshid.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
@@ -3168,9 +3165,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3165
3166
// If required, check if this user has rights to do this
3167
if ((obj.parent.config.settings != null) && ((obj.parent.config.settings.lockagentdownload == true) || (domain.lockagentdownload == true))) {
3171
- var user = obj.users[req.session.userid];
3172
- if ((user == null) || (mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) { res.sendStatus(401); return; }
3173
- if (domain.id != mesh.domain) { res.sendStatus(401); return; }
3168
+ if ((domain.id != mesh.domain) || ((obj.GetMeshRights(req.session.userid, mesh) & 1) == 0)) { res.sendStatus(401); return; }
3169
}
3170
3171
var meshidhex = Buffer.from(req.query.meshid.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
@@ -3257,9 +3252,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3252
3253
// If needed, check if this user has rights to do this
3254
if ((obj.parent.config.settings != null) && ((obj.parent.config.settings.lockagentdownload == true) || (domain.lockagentdownload == true))) {
3260
- var user = obj.users[req.session.userid];
3261
- if ((user == null) || (mesh.links[user._id] == null) || ((mesh.links[user._id].rights & 1) == 0)) { res.sendStatus(401); return; }
3262
- if (domain.id != mesh.domain) { res.sendStatus(401); return; }
3255
+ if ((domain.id != mesh.domain) || ((obj.GetMeshRights(req.session.userid, mesh) & 1) == 0)) { res.sendStatus(401); return; }
3256
}
3257
3258
var meshidhex = Buffer.from(req.query.id.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
@@ -3297,9 +3290,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3290
var node = docs[0];
3291
3292
// Check if we have right to this node
3300
- var rights = 0;
3301
- for (var i in user.links) { if (i == node.meshid) { rights = user.links[i].rights; } }
3302
- if (rights == 0) { res.sendStatus(401); return; }
3293
+ if (obj.GetMeshRights(user, node.meshid) == 0) { res.sendStatus(401); return; }
3294
3295
// Get the list of power events and send them
3296
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="powerevents.csv"' });
@@ -3772,8 +3763,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3763
if (agent == null) return;
3764
3765
// Check we have agent rights
3775
- var rights = user.links[agent.dbMeshKey].rights;
3776
- if ((rights != null) && ((rights & MESHRIGHT_AGENTCONSOLE) != 0) || (user.siteadmin == 0xFFFFFFFF)) { agent.close(disconnectMode); }
3766
+ if (((obj.GetMeshRights(user, agent.dbMeshKey) & MESHRIGHT_AGENTCONSOLE) != 0) || (user.siteadmin == 0xFFFFFFFF)) { agent.close(disconnectMode); }
3767
};
3768
3769
// Send the core module to the mesh agent
@@ -3787,8 +3777,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3777
if (agent == null) return;
3778
3779
// Check we have agent rights
3790
- var rights = user.links[agent.dbMeshKey].rights;
3791
- if ((rights != null) && ((rights & MESHRIGHT_AGENTCONSOLE) != 0) || (user.siteadmin == 0xFFFFFFFF)) {
3780
+ if (((obj.GetMeshRights(user, agent.dbMeshKey) & MESHRIGHT_AGENTCONSOLE) != 0) || (user.siteadmin == 0xFFFFFFFF)) {
3781
if (coretype == 'clear') {
3782
// Clear the mesh agent core
3783
agent.agentCoreCheck = 1000; // Tell the agent object we are using a custom core.
@@ -3907,6 +3896,32 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3896
}
3897
};
3898
3899
+ //
3900
+ // Access Control Functions
3901
+ //
3902
+
3903
+ // Return the node and rights for a given nodeid
3904
+ obj.GetNodeWithRights = function (domain, user, nodeid, func) {
3905
+ // Perform user pre-validation
3906
+ if ((user == null) || (nodeid == null)) { func(null, 0, false); return; } // Invalid user
3907
+ if (typeof user == 'string') { user = obj.users[user]; }
3908
+ if ((user == null) || (user.links == null)) { func(null, 0, false); return; } // No rights
3909
+
3910
+ // Perform node pre-validation
3911
+ if (obj.common.validateString(nodeid, 0, 128) == false) { func(null, 0, false); return; } // Invalid nodeid
3912
+ const snode = nodeid.split('/');
3913
+ if ((snode.length != 3) || (snode[0] != 'node')) { func(null, 0, false); return; } // Invalid nodeid
3914
+ if ((domain != null) && (snode[1] != domain.id)) { func(null, 0, false); return; } // Invalid domain
3915
+
3916
+ // Check that we have permissions for this node.
3917
+ db.Get(nodeid, function (err, nodes) {
3918
+ if ((nodes == null) || (nodes.length != 1)) { func(null, 0, false); return; } // No such nodeid
3919
+ var rights = user.links[nodes[0].meshid];
3920
+ if (rights == null) { func(null, 0, false); return; } // No rights to this mesh
3921
+ func(nodes[0], rights.rights, true);
3922
+ });
3923
+ }
3924
+
3925
// Returns a list of all meshes that this user has some rights too
3926
obj.GetAllMeshWithRights = function (user, rights) {
3927
if (typeof user == 'string') { user = obj.users[user]; }
@@ -4076,9 +4091,9 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4091
if (typeof command.sessionid != 'string') return;
4092
var splitsessionid = command.sessionid.split('/');
4093
// Check that we are in the same domain and the user has rights over this node.
4079
- if ((splitsessionid[0] == 'user') && (splitsessionid[1] == domainid)) {
4094
+ if ((splitsessionid.length == 4) && (splitsessionid[0] == 'user') && (splitsessionid[1] == domainid)) {
4095
// Check if this user has rights to get this message
4081
- //if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
4096
+ if (obj.GetMeshRights(splitsessionid[0] + '/' + splitsessionid[1] + '/' + splitsessionid[2], meshid) == 0) return; // TODO: Check if this is ok
4097
4098
// See if the session is connected. If so, go ahead and send this message to the target node
4099
var ws = obj.wssessions2[command.sessionid];
@@ -4101,7 +4116,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4116
// Check that we are in the same domain and the user has rights over this node.
4117
if ((splituserid[0] == 'user') && (splituserid[1] == domainid)) {
4118
// Check if this user has rights to get this message
4104
- //if (mesh.links[user._id] == null || ((mesh.links[user._id].rights & 16) == 0)) return; // TODO!!!!!!!!!!!!!!!!!!!!!
4119
+ if (obj.GetMeshRights(command.userid, meshid) == 0) return; // TODO: Check if this is ok
4120
4121
// See if the session is connected
4122
var sessions = obj.wssessions[command.userid];
@@ -4120,16 +4135,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4135
} else { // Route this command to the mesh
4136
command.nodeid = nodeid;
4137
var cmdstr = JSON.stringify(command);
4123
- for (var userid in obj.wssessions) { // Find all connected users for this mesh and send the message
4124
- var user = obj.users[userid];
4125
- if ((user != null) && (user.links != null)) {
4126
- var rights = user.links[meshid];
4127
- if (rights != null) { // TODO: Look at what rights are needed for message routing
4128
- var xsessions = obj.wssessions[userid];
4129
- // Send the message to all users on this server
4130
- for (i in xsessions) { try { xsessions[i].send(cmdstr); } catch (e) { } }
4131
- }
4132
- }
4138
+ if (obj.GetMeshRights(userid, meshid) == 0) return; // TODO: Check if this is ok
4139
+
4140
+ // Find all connected users for this mesh and send the message
4141
+ for (var userid in obj.wssessions) {
4142
+ var xsessions = obj.wssessions[userid];
4143
+ // Send the message to all users on this server
4144
+ for (i in xsessions) { try { xsessions[i].send(cmdstr); } catch (e) { } }
4145
}
4146
4147
// Send the message to all users of other servers